[entropy.services] goodbye old and ugly RPC service, R.I.P.
This commit is contained in:
+1
-6
@@ -25,11 +25,6 @@ sys.path.insert(0, '../client')
|
||||
|
||||
from entropy.exceptions import SystemDatabaseError, OnlineMirrorError, \
|
||||
RepositoryError, PermissionDenied, FileNotFound, SPMError
|
||||
try:
|
||||
from entropy.services.exceptions import ServiceConnectionError
|
||||
except ImportError:
|
||||
# backward compatibility
|
||||
ServiceConnectionError = None
|
||||
try:
|
||||
from entropy.transceivers.exceptions import TransceiverError, \
|
||||
TransceiverConnectionError
|
||||
@@ -872,7 +867,7 @@ def handle_exception(exc_class, exc_instance, exc_tb):
|
||||
|
||||
generic_exc_classes = (OnlineMirrorError, RepositoryError,
|
||||
TransceiverError, PermissionDenied, TransceiverConnectionError,
|
||||
ServiceConnectionError, FileNotFound, SPMError, SystemError)
|
||||
FileNotFound, SPMError, SystemError)
|
||||
if exc_class in generic_exc_classes:
|
||||
print_error("%s %s. %s." % (
|
||||
darkred(" * "), exc_instance, _("Cannot continue"),))
|
||||
|
||||
@@ -18,7 +18,6 @@ import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from entropy.services.exceptions import TimeoutError
|
||||
from entropy.const import etpConst, etpUi, const_debug_write
|
||||
from entropy.output import red, darkred, blue, brown, bold, darkgreen, green, \
|
||||
print_info, print_warning, print_error, purple, teal
|
||||
|
||||
@@ -26,7 +26,6 @@ from entropy.cache import EntropyCacher
|
||||
from entropy.db import EntropyRepository
|
||||
from entropy.exceptions import RepositoryError, SystemDatabaseError, \
|
||||
PermissionDenied
|
||||
from entropy.services.exceptions import EntropyServicesError
|
||||
from entropy.security import Repository as RepositorySecurity
|
||||
from entropy.misc import TimeScheduled
|
||||
from entropy.i18n import _
|
||||
|
||||
@@ -1,795 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Client Services UGC Base Commands}.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
from entropy.services.exceptions import TransmissionError, \
|
||||
EntropyServicesError, ServiceConnectionError
|
||||
from entropy.const import etpConst, const_get_stringtype, const_debug_write, \
|
||||
const_convert_to_rawstring
|
||||
from entropy.output import darkblue, bold, blue, darkgreen, darkred, brown
|
||||
from entropy.i18n import _
|
||||
from entropy.core.settings.base import SystemSettings
|
||||
import entropy.tools
|
||||
import entropy.dump
|
||||
|
||||
class Base:
|
||||
|
||||
def __init__(self, OutputInterface, Service):
|
||||
|
||||
if not hasattr(OutputInterface, 'output'):
|
||||
raise AttributeError(
|
||||
"OutputInterface does not have an output method")
|
||||
elif not hasattr(OutputInterface.output, '__call__'):
|
||||
raise AttributeError(
|
||||
"OutputInterface does not have an output method")
|
||||
|
||||
from entropy.services.ugc.interfaces import Client as Cl
|
||||
if not isinstance(Service, Cl):
|
||||
raise AttributeError(
|
||||
"entropy.services.ugc.interfaces.Client needed")
|
||||
|
||||
import socket, zlib, struct
|
||||
self.socket, self.zlib, self.struct = socket, zlib, struct
|
||||
self.Output = OutputInterface
|
||||
self.Service = Service
|
||||
self.output_header = ''
|
||||
self._settings = SystemSettings()
|
||||
self.standard_answers_map = {
|
||||
'all_fine': 0,
|
||||
'not_supported_remotely': 1,
|
||||
'service_temp_not_avail': 2,
|
||||
'command_failed': 3,
|
||||
'wrong_answer': 4,
|
||||
}
|
||||
|
||||
|
||||
def handle_standard_answer(self, data, repository = None, arch = None,
|
||||
product = None):
|
||||
|
||||
do_skip = False
|
||||
answer_id = self.standard_answers_map['all_fine']
|
||||
|
||||
# elaborate answer
|
||||
if data is None:
|
||||
mytxt = _("feature not supported remotely")
|
||||
self.Output.output(
|
||||
"[%s:%s|%s:%s|%s:%s] %s" % (
|
||||
darkblue(_("repo")),
|
||||
bold(str(repository)),
|
||||
darkred(_("arch")),
|
||||
bold(str(arch)),
|
||||
darkgreen(_("product")),
|
||||
bold(str(product)),
|
||||
blue(mytxt),
|
||||
),
|
||||
importance = 1,
|
||||
level = "error",
|
||||
header = self.output_header
|
||||
)
|
||||
do_skip = True
|
||||
answer_id = self.standard_answers_map['not_supported_remotely']
|
||||
elif not data:
|
||||
mytxt = _("service temporarily not available")
|
||||
self.Output.output(
|
||||
"[%s:%s|%s:%s|%s:%s] %s" % (
|
||||
darkblue(_("repo")),
|
||||
bold(str(repository)),
|
||||
darkred(_("arch")),
|
||||
bold(str(arch)),
|
||||
darkgreen(_("product")),
|
||||
bold(str(product)),
|
||||
blue(mytxt),
|
||||
),
|
||||
importance = 1,
|
||||
level = "error",
|
||||
header = self.output_header
|
||||
)
|
||||
do_skip = True
|
||||
answer_id = self.standard_answers_map['service_temp_not_avail']
|
||||
elif data == self.Service.answers['no']:
|
||||
# command failed
|
||||
mytxt = _("command failed")
|
||||
self.Output.output(
|
||||
"[%s:%s|%s:%s|%s:%s] %s" % (
|
||||
darkblue(_("repo")),
|
||||
bold(str(repository)),
|
||||
darkred(_("arch")),
|
||||
bold(str(arch)),
|
||||
darkgreen(_("product")),
|
||||
bold(str(product)),
|
||||
blue(mytxt),
|
||||
),
|
||||
importance = 1,
|
||||
level = "error",
|
||||
header = self.output_header
|
||||
)
|
||||
do_skip = True
|
||||
answer_id = self.standard_answers_map['command_failed']
|
||||
elif data != self.Service.answers['ok']:
|
||||
mytxt = _("received wrong answer")
|
||||
|
||||
# do not spam terminal
|
||||
if isinstance(data, const_get_stringtype()):
|
||||
if len(data) > 10:
|
||||
data = data[:10] + "[...]"
|
||||
|
||||
self.Output.output(
|
||||
"[%s:%s|%s:%s|%s:%s] %s: %s" % (
|
||||
darkblue(_("repo")),
|
||||
bold(str(repository)),
|
||||
darkred(_("arch")),
|
||||
bold(str(arch)),
|
||||
darkgreen(_("product")),
|
||||
bold(str(product)),
|
||||
blue(mytxt),
|
||||
repr(data),
|
||||
),
|
||||
importance = 1,
|
||||
level = "error",
|
||||
header = self.output_header
|
||||
)
|
||||
do_skip = True
|
||||
answer_id = self.standard_answers_map['wrong_answer']
|
||||
|
||||
return do_skip, answer_id
|
||||
|
||||
def get_result(self, session):
|
||||
# get the information
|
||||
cmd = "%s rc" % (session,)
|
||||
try:
|
||||
self.Service.transmit(cmd)
|
||||
except TransmissionError:
|
||||
entropy.tools.print_traceback()
|
||||
return None
|
||||
try:
|
||||
data = self.Service.receive()
|
||||
return data
|
||||
except Exception:
|
||||
entropy.tools.print_traceback()
|
||||
return None
|
||||
|
||||
def convert_stream_to_object(self, data, gzipped, repository = None,
|
||||
arch = None, product = None):
|
||||
|
||||
# unstream object
|
||||
error = False
|
||||
try:
|
||||
data = self.Service.stream_to_object(data, gzipped)
|
||||
except (EOFError, IOError, self.zlib.error, entropy.dump.pickle.UnpicklingError,):
|
||||
const_debug_write(__name__, entropy.tools.get_traceback())
|
||||
mytxt = _("cannot convert stream into object")
|
||||
self.Output.output(
|
||||
"[%s:%s|%s:%s|%s:%s] %s" % (
|
||||
darkblue(_("repo")),
|
||||
bold(str(repository)),
|
||||
darkred(_("arch")),
|
||||
bold(str(arch)),
|
||||
darkgreen(_("product")),
|
||||
bold(str(product)),
|
||||
blue(mytxt),
|
||||
),
|
||||
importance = 1,
|
||||
level = "error",
|
||||
header = self.output_header
|
||||
)
|
||||
data = None
|
||||
error = True
|
||||
return data, error
|
||||
|
||||
def retrieve_command_answer(self, cmd, session_id, repository = None,
|
||||
arch = None, product = None, compression = False):
|
||||
|
||||
tries = 3
|
||||
lasterr = None
|
||||
while True:
|
||||
|
||||
if tries <= 0:
|
||||
return lasterr
|
||||
tries -= 1
|
||||
|
||||
try:
|
||||
# send command
|
||||
self.Service.transmit(cmd)
|
||||
except TransmissionError:
|
||||
return None
|
||||
# receive answer
|
||||
data = self.Service.receive()
|
||||
|
||||
skip, answer_id = self.handle_standard_answer(data, repository,
|
||||
arch, product)
|
||||
if skip:
|
||||
if tries <= 0:
|
||||
const_debug_write(__name__,
|
||||
darkred("skipping command, NOT reconnecting"))
|
||||
else:
|
||||
const_debug_write(__name__,
|
||||
darkred("skipping command, reconnect+retry!"))
|
||||
const_debug_write(__name__, str(answer_id))
|
||||
# reconnect host and retry
|
||||
self.Service.reconnect_socket()
|
||||
continue
|
||||
|
||||
data = self.get_result(session_id)
|
||||
if data is None:
|
||||
lasterr = None
|
||||
continue
|
||||
elif not data:
|
||||
lasterr = False
|
||||
continue
|
||||
|
||||
objdata, error = self.convert_stream_to_object(data, compression,
|
||||
repository, arch, product)
|
||||
if not error:
|
||||
return objdata
|
||||
|
||||
def do_generic_handler(self, cmd, session_id, tries = 10, compression = False):
|
||||
|
||||
try:
|
||||
self.Service.check_socket_connection()
|
||||
except ServiceConnectionError:
|
||||
return False, 'connection error'
|
||||
|
||||
while True:
|
||||
try:
|
||||
result = self.retrieve_command_answer(cmd, session_id,
|
||||
compression = compression)
|
||||
if result is None:
|
||||
return False, 'command not supported' # untranslated on purpose
|
||||
return result
|
||||
except (self.socket.error, self.struct.error,) as err:
|
||||
try:
|
||||
self.Service.reconnect_socket()
|
||||
except self.socket.error as exc:
|
||||
return False, 'connection error %s' % (exc,)
|
||||
tries -= 1
|
||||
if tries < 1:
|
||||
return False, 'connection error %s' % (err,)
|
||||
|
||||
def _set_gzip_compression(self, session, do):
|
||||
self.Service.check_socket_connection()
|
||||
cmd = "%s %s %s %s zlib" % (
|
||||
const_convert_to_rawstring(session),
|
||||
const_convert_to_rawstring('session_config'),
|
||||
const_convert_to_rawstring('compression'),
|
||||
const_convert_to_rawstring(do),
|
||||
)
|
||||
fail_count = 5
|
||||
while True:
|
||||
try:
|
||||
self.Service.transmit(cmd)
|
||||
data = self.Service.receive()
|
||||
except TransmissionError as err:
|
||||
const_debug_write(__name__,
|
||||
darkred("_set_gzip_compression: error: " + repr(err)))
|
||||
fail_count -= 1
|
||||
if fail_count == 0:
|
||||
raise
|
||||
continue
|
||||
if data == self.Service.answers['ok']:
|
||||
return True
|
||||
return False
|
||||
|
||||
def service_login(self, username, password, session_id):
|
||||
|
||||
cmd = "%s %s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('login'),
|
||||
const_convert_to_rawstring(username),
|
||||
const_convert_to_rawstring(password),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def service_logout(self, username, session_id):
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('logout'),
|
||||
const_convert_to_rawstring(username),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def get_logged_user_data(self, session_id):
|
||||
|
||||
cmd = "%s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('user_data'),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def is_user(self, session_id):
|
||||
|
||||
cmd = "%s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('is_user'),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def is_developer(self, session_id):
|
||||
|
||||
cmd = "%s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('is_developer'),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def is_moderator(self, session_id):
|
||||
|
||||
cmd = "%s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('is_moderator'),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def is_administrator(self, session_id):
|
||||
|
||||
cmd = "%s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('is_administrator'),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def available_commands(self, session_id):
|
||||
|
||||
cmd = "%s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('available_commands'),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
|
||||
class Client(Base):
|
||||
|
||||
def __init__(self, EntropyInterface, ServiceInterface):
|
||||
Base.__init__(self, EntropyInterface, ServiceInterface)
|
||||
|
||||
def differential_packages_comparison(self, session_id, idpackages,
|
||||
repository, arch, product):
|
||||
|
||||
myidlist = const_convert_to_rawstring(
|
||||
' '.join([str(x) for x in idpackages]))
|
||||
cmd = "%s %s %s %s %s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('repository_server:dbdiff'),
|
||||
const_convert_to_rawstring(repository),
|
||||
const_convert_to_rawstring(arch),
|
||||
const_convert_to_rawstring(product),
|
||||
const_convert_to_rawstring(
|
||||
self._settings['repositories']['branch']),
|
||||
myidlist,
|
||||
)
|
||||
|
||||
# enable zlib compression
|
||||
try:
|
||||
compression = self._set_gzip_compression(session_id, True)
|
||||
except EntropyServicesError:
|
||||
return False, 'connection error'
|
||||
|
||||
data = self.do_generic_handler(cmd, session_id, tries = 5,
|
||||
compression = compression)
|
||||
|
||||
# disable compression
|
||||
try:
|
||||
compression = self._set_gzip_compression(session_id, False)
|
||||
except EntropyServicesError:
|
||||
return False, 'connection error'
|
||||
|
||||
return data
|
||||
|
||||
def get_repository_treeupdates(self, session_id, repository, arch, product):
|
||||
|
||||
cmd = "%s %s %s %s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('repository_server:treeupdates'),
|
||||
const_convert_to_rawstring(repository),
|
||||
const_convert_to_rawstring(arch),
|
||||
const_convert_to_rawstring(product),
|
||||
const_convert_to_rawstring(
|
||||
self._settings['repositories']['branch']),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id, tries = 5)
|
||||
|
||||
def get_package_sets(self, session_id, repository, arch, product):
|
||||
|
||||
cmd = "%s %s %s %s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('repository_server:get_package_sets'),
|
||||
const_convert_to_rawstring(repository),
|
||||
const_convert_to_rawstring(arch),
|
||||
const_convert_to_rawstring(product),
|
||||
const_convert_to_rawstring(
|
||||
self._settings['repositories']['branch']),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id, tries = 5)
|
||||
|
||||
def get_repository_metadata(self, session_id, repository, arch, product):
|
||||
|
||||
cmd = "%s %s %s %s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring(
|
||||
'repository_server:get_repository_metadata'),
|
||||
const_convert_to_rawstring(repository),
|
||||
const_convert_to_rawstring(arch),
|
||||
const_convert_to_rawstring(product),
|
||||
const_convert_to_rawstring(
|
||||
self._settings['repositories']['branch']),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id, tries = 5)
|
||||
|
||||
def get_strict_package_information(self, session_id, idpackages,
|
||||
repository, arch, product):
|
||||
|
||||
cmd = "%s %s %s %s %s %s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('repository_server:pkginfo_strict'),
|
||||
True,
|
||||
const_convert_to_rawstring(repository),
|
||||
const_convert_to_rawstring(arch),
|
||||
const_convert_to_rawstring(product),
|
||||
const_convert_to_rawstring(
|
||||
self._settings['repositories']['branch']),
|
||||
const_convert_to_rawstring(' '.join([str(x) for x in idpackages])),
|
||||
)
|
||||
|
||||
# enable zlib compression
|
||||
try:
|
||||
compression = self._set_gzip_compression(session_id, True)
|
||||
except EntropyServicesError:
|
||||
return False, 'connection error'
|
||||
|
||||
data = self.do_generic_handler(cmd, session_id, compression = compression)
|
||||
|
||||
# disable compression
|
||||
try:
|
||||
compression = self._set_gzip_compression(session_id, False)
|
||||
except EntropyServicesError:
|
||||
return False, 'connection error'
|
||||
|
||||
return data
|
||||
|
||||
def ugc_do_download_stats(self, session_id, package_names):
|
||||
|
||||
sub_lists = entropy.tools.split_indexable_into_chunks(
|
||||
package_names, 100)
|
||||
|
||||
last_srv_rc_data = None
|
||||
for pkgkeys in sub_lists:
|
||||
|
||||
release_string = '--N/A--'
|
||||
rel_file = etpConst['systemreleasefile']
|
||||
if os.path.isfile(rel_file) and os.access(rel_file, os.R_OK):
|
||||
with open(rel_file, "r") as f:
|
||||
release_string = f.read(512)
|
||||
|
||||
hw_hash = self._settings['hw_hash']
|
||||
if not hw_hash:
|
||||
hw_hash = ''
|
||||
|
||||
mydict = {
|
||||
'branch': self._settings['repositories']['branch'],
|
||||
'release_string': release_string,
|
||||
'hw_hash': hw_hash,
|
||||
'pkgkeys': ' '.join(pkgkeys),
|
||||
}
|
||||
xml_string = entropy.tools.xml_from_dict(mydict)
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:do_download_stats'),
|
||||
const_convert_to_rawstring(xml_string),
|
||||
)
|
||||
last_srv_rc_data = self.do_generic_handler(cmd, session_id)
|
||||
if not isinstance(last_srv_rc_data, tuple):
|
||||
return last_srv_rc_data
|
||||
elif last_srv_rc_data[0] != True:
|
||||
return last_srv_rc_data
|
||||
return last_srv_rc_data
|
||||
|
||||
def ugc_get_downloads(self, session_id, pkgkey):
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:get_downloads'),
|
||||
pkgkey,
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_get_alldownloads(self, session_id):
|
||||
|
||||
cmd = "%s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:get_alldownloads'),
|
||||
)
|
||||
|
||||
# enable zlib compression
|
||||
try:
|
||||
compression = self._set_gzip_compression(session_id, True)
|
||||
except EntropyServicesError:
|
||||
return False, 'connection error'
|
||||
|
||||
rc = self.do_generic_handler(cmd, session_id, compression = compression)
|
||||
|
||||
# disable compression
|
||||
try:
|
||||
compression = self._set_gzip_compression(session_id, False)
|
||||
except EntropyServicesError:
|
||||
return False, 'connection error'
|
||||
|
||||
return rc
|
||||
|
||||
def ugc_do_vote(self, session_id, pkgkey, vote):
|
||||
|
||||
cmd = "%s %s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:do_vote'),
|
||||
const_convert_to_rawstring(pkgkey),
|
||||
const_convert_to_rawstring(vote),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_get_vote(self, session_id, pkgkey):
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:get_vote'),
|
||||
const_convert_to_rawstring(pkgkey),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_get_allvotes(self, session_id):
|
||||
|
||||
cmd = "%s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:get_allvotes'),
|
||||
)
|
||||
|
||||
# enable zlib compression
|
||||
try:
|
||||
compression = self._set_gzip_compression(session_id, True)
|
||||
except EntropyServicesError:
|
||||
return False, 'connection error'
|
||||
|
||||
rc = self.do_generic_handler(cmd, session_id, compression = compression)
|
||||
|
||||
# disable compression
|
||||
try:
|
||||
compression = self._set_gzip_compression(session_id, False)
|
||||
except EntropyServicesError:
|
||||
return False, 'connection error'
|
||||
|
||||
return rc
|
||||
|
||||
def ugc_add_comment(self, session_id, pkgkey, comment, title, keywords):
|
||||
|
||||
mydict = {
|
||||
'comment': comment,
|
||||
'title': title,
|
||||
'keywords': keywords,
|
||||
}
|
||||
xml_string = entropy.tools.xml_from_dict(mydict)
|
||||
|
||||
cmd = "%s %s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:add_comment'),
|
||||
const_convert_to_rawstring(pkgkey),
|
||||
const_convert_to_rawstring(xml_string),
|
||||
)
|
||||
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_edit_comment(self, session_id, iddoc, new_comment, new_title, new_keywords):
|
||||
|
||||
mydict = {
|
||||
'comment': new_comment,
|
||||
'title': new_title,
|
||||
'keywords': new_keywords,
|
||||
}
|
||||
xml_string = entropy.tools.xml_from_dict(mydict)
|
||||
|
||||
cmd = "%s %s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:edit_comment'),
|
||||
const_convert_to_rawstring(iddoc),
|
||||
const_convert_to_rawstring(xml_string),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_remove_comment(self, session_id, iddoc):
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:remove_comment'),
|
||||
const_convert_to_rawstring(iddoc),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_remove_image(self, session_id, iddoc):
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:remove_image'),
|
||||
const_convert_to_rawstring(iddoc),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_remove_file(self, session_id, iddoc):
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:remove_file'),
|
||||
const_convert_to_rawstring(iddoc),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_remove_youtube_video(self, session_id, iddoc):
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:remove_youtube_video'),
|
||||
const_convert_to_rawstring(iddoc),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_get_docs(self, session_id, pkgkey):
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:get_alldocs'),
|
||||
const_convert_to_rawstring(pkgkey),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_get_textdocs(self, session_id, pkgkey):
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:get_textdocs'),
|
||||
const_convert_to_rawstring(pkgkey),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_get_textdocs_by_identifiers(self, session_id, identifiers):
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:get_textdocs_by_identifiers'),
|
||||
const_convert_to_rawstring(' '.join([str(x) for x in identifiers])),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_get_documents_by_identifiers(self, session_id, identifiers):
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:get_documents_by_identifiers'),
|
||||
const_convert_to_rawstring(' '.join([str(x) for x in identifiers])),
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def ugc_send_file_stream(self, session_id, file_path):
|
||||
|
||||
if not (os.path.isfile(file_path) and os.access(file_path, os.R_OK)):
|
||||
return False, False, 'cannot read file_path'
|
||||
|
||||
import zlib
|
||||
# enable stream
|
||||
cmd = "%s %s %s on" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('session_config'),
|
||||
const_convert_to_rawstring('stream'),
|
||||
)
|
||||
status, msg = self.do_generic_handler(cmd, session_id)
|
||||
if not status:
|
||||
return False, status, msg
|
||||
|
||||
# enable zlib compression
|
||||
try:
|
||||
compression = self._set_gzip_compression(session_id, True)
|
||||
except EntropyServicesError:
|
||||
return False, 'connection error'
|
||||
|
||||
# start streamer
|
||||
stream_status = True
|
||||
stream_msg = 'ok'
|
||||
f = open(file_path, "rb")
|
||||
chunk = f.read(8192)
|
||||
base_path = os.path.basename(file_path)
|
||||
transferred = len(chunk)
|
||||
max_size = entropy.tools.get_file_size(file_path)
|
||||
while chunk:
|
||||
|
||||
if (not self.Service.quiet) or self.Service.show_progress:
|
||||
self.Output.output(
|
||||
"%s, %s: %s" % (
|
||||
blue(_("User Generated Content")),
|
||||
darkgreen(_("sending file")),
|
||||
darkred(base_path),
|
||||
),
|
||||
importance = 1,
|
||||
level = "info",
|
||||
header = brown(" @@ "),
|
||||
back = True,
|
||||
count = (transferred, max_size,),
|
||||
percent = True
|
||||
)
|
||||
|
||||
chunk = zlib.compress(chunk, 7) # compression level 1-9
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
'stream',
|
||||
chunk,
|
||||
)
|
||||
status, msg = self.do_generic_handler(cmd, session_id, compression = compression)
|
||||
if not status:
|
||||
stream_status = status
|
||||
stream_msg = msg
|
||||
break
|
||||
chunk = f.read(8192)
|
||||
transferred += len(chunk)
|
||||
|
||||
f.close()
|
||||
|
||||
# disable compression
|
||||
try:
|
||||
compression = self._set_gzip_compression(session_id, False)
|
||||
except EntropyServicesError:
|
||||
return False, 'connection error'
|
||||
|
||||
# disable config
|
||||
cmd = "%s %s %s off" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('session_config'),
|
||||
const_convert_to_rawstring('stream'),
|
||||
)
|
||||
status, msg = self.do_generic_handler(cmd, session_id)
|
||||
if not status:
|
||||
return False, status, msg
|
||||
|
||||
return True, stream_status, stream_msg
|
||||
|
||||
def ugc_send_file(self, session_id, pkgkey, file_path, doc_type, title,
|
||||
description, keywords):
|
||||
|
||||
status, rem_status, err_msg = self.ugc_send_file_stream(session_id, file_path)
|
||||
if not (status and rem_status):
|
||||
return False, err_msg
|
||||
|
||||
mydict = {
|
||||
'doc_type': str(doc_type),
|
||||
'title': title,
|
||||
'description': description,
|
||||
'keywords': keywords,
|
||||
'file_name': os.path.join(pkgkey, os.path.basename(file_path)),
|
||||
'real_filename': os.path.basename(file_path),
|
||||
}
|
||||
xml_string = entropy.tools.xml_from_dict(mydict)
|
||||
|
||||
cmd = "%s %s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:register_stream'),
|
||||
pkgkey,
|
||||
xml_string,
|
||||
)
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
|
||||
def report_error(self, session_id, error_data):
|
||||
|
||||
import zlib
|
||||
xml_string = entropy.tools.xml_from_dict_extended(error_data)
|
||||
xml_comp_string = zlib.compress(xml_string)
|
||||
|
||||
cmd = "%s %s %s" % (
|
||||
const_convert_to_rawstring(session_id),
|
||||
const_convert_to_rawstring('ugc:report_error'),
|
||||
const_convert_to_rawstring(xml_comp_string),
|
||||
)
|
||||
|
||||
return self.do_generic_handler(cmd, session_id)
|
||||
@@ -1,916 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Client Services UGC Base Interfaces}.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from entropy.core import Singleton
|
||||
from entropy.core.settings.base import SystemSettings
|
||||
from entropy.exceptions import RepositoryError, PermissionDenied
|
||||
from entropy.services.exceptions import ServiceConnectionError, \
|
||||
EntropyServicesError
|
||||
from entropy.cache import MtimePingus, EntropyCacher
|
||||
from entropy.const import etpConst, const_setup_file, const_setup_perms
|
||||
from entropy.i18n import _
|
||||
|
||||
import entropy.dump
|
||||
|
||||
class Client:
|
||||
|
||||
ssl_connection = True
|
||||
def __init__(self, entropy_client, quiet = True, show_progress = False):
|
||||
|
||||
from entropy.client.interfaces import Client as Cl
|
||||
if not isinstance(entropy_client, Cl):
|
||||
mytxt = "A valid Client based instance is needed"
|
||||
raise AttributeError(mytxt)
|
||||
|
||||
import socket, threading
|
||||
self.socket, self.threading = socket, threading
|
||||
import struct
|
||||
self.struct = struct
|
||||
self.Entropy = entropy_client
|
||||
self.store = AuthStore()
|
||||
self.quiet = quiet
|
||||
self.show_progress = show_progress
|
||||
self.UGCCache = Cache(self)
|
||||
self.TxLocks = {}
|
||||
self._cacher = EntropyCacher()
|
||||
|
||||
def connect_to_service(self, repository, timeout = None):
|
||||
|
||||
sys_settings = SystemSettings()
|
||||
avail_data = sys_settings['repositories']['available']
|
||||
# also try excluded repos
|
||||
if repository not in avail_data:
|
||||
avail_data = sys_settings['repositories']['excluded']
|
||||
if repository not in avail_data:
|
||||
raise RepositoryError('repository is not available')
|
||||
|
||||
# unsupported by repository?
|
||||
if 'service_uri' not in avail_data[repository]:
|
||||
return None
|
||||
if 'service_port' not in avail_data[repository]:
|
||||
return None
|
||||
|
||||
url = avail_data[repository]['service_uri']
|
||||
port = avail_data[repository]['service_port']
|
||||
if self.ssl_connection:
|
||||
port = avail_data[repository]['ssl_service_port']
|
||||
|
||||
from entropy.services.ugc.interfaces import Client
|
||||
from entropy.client.services.ugc.commands import Client as CommandsClient
|
||||
args = [self.Entropy, CommandsClient]
|
||||
kwargs = {
|
||||
'ssl': self.ssl_connection,
|
||||
'quiet': self.quiet,
|
||||
'show_progress': self.show_progress
|
||||
}
|
||||
if timeout is not None:
|
||||
kwargs['socket_timeout'] = timeout
|
||||
|
||||
srv = Client(*args, **kwargs)
|
||||
srv.connect(url, port)
|
||||
return srv
|
||||
|
||||
def get_service_connection(self, repository, check = True, timeout = None):
|
||||
if check:
|
||||
if not self.is_repository_eapi3_aware(repository):
|
||||
return None
|
||||
try:
|
||||
srv = self.connect_to_service(repository, timeout = timeout)
|
||||
except (RepositoryError, ServiceConnectionError,):
|
||||
return None
|
||||
return srv
|
||||
|
||||
def is_repository_eapi3_aware(self, repository, _use_cache = True):
|
||||
|
||||
aware = self.UGCCache._get_live_cache_item(repository,
|
||||
'is_repository_eapi3_aware')
|
||||
if aware is not None:
|
||||
return aware
|
||||
|
||||
def _get_awareness():
|
||||
try:
|
||||
srv = self.get_service_connection(repository, check = False,
|
||||
timeout = 6)
|
||||
if srv is None:
|
||||
rc = False
|
||||
else:
|
||||
session = srv.open_session()
|
||||
if session is not None:
|
||||
srv.close_session(session)
|
||||
srv.disconnect()
|
||||
rc = True
|
||||
else:
|
||||
rc = False
|
||||
except EntropyServicesError:
|
||||
rc = False
|
||||
return rc
|
||||
|
||||
# Life is hard, and socket communication can be very annoying
|
||||
# over a non-performant connection. So, the only way to circumvent this
|
||||
# is to cache results somewhere.
|
||||
cache_id = "entropy.client.interfaces.ugc.is_repository_eapi3_aware_" \
|
||||
+ repository
|
||||
pingus = MtimePingus()
|
||||
|
||||
passed = True
|
||||
if _use_cache:
|
||||
# are 3 days passed?
|
||||
passed = pingus.hours_passed(cache_id, 24*3)
|
||||
|
||||
if passed:
|
||||
aware = _get_awareness()
|
||||
# update pingus mtime
|
||||
pingus.ping(cache_id)
|
||||
else:
|
||||
# then load data from disk cache
|
||||
cached = self._cacher.pop(cache_id)
|
||||
if cached is None:
|
||||
# no cache on disk
|
||||
aware = _get_awareness()
|
||||
self._cacher.push(cache_id, aware, async = False)
|
||||
pingus.ping(cache_id)
|
||||
else:
|
||||
aware = cached
|
||||
|
||||
self.UGCCache._set_live_cache_item(repository,
|
||||
'is_repository_eapi3_aware', aware)
|
||||
return aware
|
||||
|
||||
def read_login(self, repository):
|
||||
return self.store.read_login(repository)
|
||||
|
||||
def remove_login(self, repository):
|
||||
return self.store.remove_login(repository)
|
||||
|
||||
def do_login(self, repository, force = False):
|
||||
|
||||
login_data = self.read_login(repository)
|
||||
if (login_data is not None) and not force:
|
||||
return True, _('ok')
|
||||
|
||||
aware = self.is_repository_eapi3_aware(repository)
|
||||
if not aware:
|
||||
return False, _('repository does not support EAPI3')
|
||||
|
||||
def fake_callback(*args, **kwargs):
|
||||
return True
|
||||
|
||||
attempts = 3
|
||||
while attempts:
|
||||
|
||||
# use input box to read login
|
||||
input_params = [
|
||||
('username', _('Username'), fake_callback, False),
|
||||
('password', _('Password'), fake_callback, True)
|
||||
]
|
||||
login_data = self.Entropy.input_box(
|
||||
"%s %s %s" % (
|
||||
_('Please login against'), repository, _('repository'),),
|
||||
input_params,
|
||||
cancel_button = True
|
||||
)
|
||||
if not login_data:
|
||||
return False, _('login abort')
|
||||
|
||||
# now verify
|
||||
srv = self.get_service_connection(repository)
|
||||
if srv is None:
|
||||
return False, _('connection issues')
|
||||
session = srv.open_session()
|
||||
if session is None:
|
||||
return False, _('cannot open a session')
|
||||
login_status, login_msg = srv.CmdInterface.service_login(
|
||||
login_data['username'], login_data['password'], session)
|
||||
if not login_status:
|
||||
srv.close_session(session)
|
||||
srv.disconnect()
|
||||
self.Entropy.ask_question("%s: %s" % (
|
||||
_("Access denied. Login failed"), login_msg,),
|
||||
responses = [_("Ok")])
|
||||
attempts -= 1
|
||||
continue
|
||||
|
||||
# login accepted, store it?
|
||||
srv.close_session(session)
|
||||
srv.disconnect()
|
||||
rc = self.Entropy.ask_question(
|
||||
_("Login successful. Do you want to save these credentials ?"))
|
||||
save = False
|
||||
if rc == _("Yes"):
|
||||
save = True
|
||||
self.store.store_login(login_data['username'],
|
||||
login_data['password'], repository, save = save)
|
||||
return True, _('ok')
|
||||
|
||||
|
||||
def login(self, repository, force = False):
|
||||
|
||||
if repository not in self.TxLocks:
|
||||
self.TxLocks[repository] = self.threading.Lock()
|
||||
|
||||
with self.TxLocks[repository]:
|
||||
return self.do_login(repository, force = force)
|
||||
|
||||
def logout(self, repository):
|
||||
return self.store.remove_login(repository)
|
||||
|
||||
def do_cmd(self, repository, login_required, func, args, kwargs):
|
||||
|
||||
if repository not in self.TxLocks:
|
||||
self.TxLocks[repository] = self.threading.Lock()
|
||||
|
||||
with self.TxLocks[repository]:
|
||||
|
||||
if login_required:
|
||||
status, err_msg = self.do_login(repository)
|
||||
if not status:
|
||||
return False, err_msg
|
||||
|
||||
srv = self.get_service_connection(repository)
|
||||
if srv is None:
|
||||
return False, 'no connection'
|
||||
session = srv.open_session()
|
||||
if session is None:
|
||||
return False, 'no session'
|
||||
args.insert(0, session)
|
||||
|
||||
if login_required:
|
||||
stored_pass = False
|
||||
while True:
|
||||
# login
|
||||
login_data = self.read_login(repository)
|
||||
if login_data is None:
|
||||
status, msg = self.login(repository)
|
||||
if not status:
|
||||
return status, msg
|
||||
username, password = self.read_login(repository)
|
||||
else:
|
||||
stored_pass = True
|
||||
username, password = login_data
|
||||
logged, error = srv.CmdInterface.service_login(username,
|
||||
password, session)
|
||||
if not logged:
|
||||
if stored_pass:
|
||||
stored_pass = False
|
||||
self.remove_login(repository)
|
||||
continue
|
||||
srv.close_session(session)
|
||||
srv.disconnect()
|
||||
return logged, error
|
||||
break
|
||||
|
||||
try:
|
||||
cmd_func = getattr(srv.CmdInterface, func)
|
||||
except AttributeError:
|
||||
return False, 'local function not available'
|
||||
rslt = cmd_func(*args, **kwargs)
|
||||
try:
|
||||
srv.close_session(session)
|
||||
srv.disconnect()
|
||||
except ServiceConnectionError:
|
||||
return False, 'no connection'
|
||||
|
||||
return rslt
|
||||
|
||||
def get_comments(self, repository, pkgkey):
|
||||
return self.do_cmd(repository, False, "ugc_get_textdocs", [pkgkey], {})
|
||||
|
||||
def get_comments_by_identifiers(self, repository, identifiers):
|
||||
return self.do_cmd(repository, False,
|
||||
"ugc_get_textdocs_by_identifiers", [identifiers], {})
|
||||
|
||||
def get_documents_by_identifiers(self, repository, identifiers):
|
||||
return self.do_cmd(repository, False,
|
||||
"ugc_get_documents_by_identifiers", [identifiers], {})
|
||||
|
||||
def add_comment(self, repository, pkgkey, comment, title, keywords):
|
||||
self.UGCCache.clear_alldocs_cache(repository)
|
||||
return self.do_cmd(repository, True, "ugc_add_comment",
|
||||
[pkgkey, comment, title, keywords], {})
|
||||
|
||||
def edit_comment(self, repository, iddoc, new_comment, new_title, new_keywords):
|
||||
self.UGCCache.clear_alldocs_cache(repository)
|
||||
return self.do_cmd(repository, True, "ugc_edit_comment",
|
||||
[iddoc, new_comment, new_title, new_keywords], {})
|
||||
|
||||
def remove_comment(self, repository, iddoc):
|
||||
self.UGCCache.clear_alldocs_cache(repository)
|
||||
return self.do_cmd(repository, True, "ugc_remove_comment", [iddoc], {})
|
||||
|
||||
def add_vote(self, repository, pkgkey, vote):
|
||||
data = self.do_cmd(repository, True, "ugc_do_vote", [pkgkey, vote], {})
|
||||
if isinstance(data, tuple):
|
||||
voted, add_err_msg = data
|
||||
else:
|
||||
return False, 'wrong server answer'
|
||||
if voted:
|
||||
self.get_vote(repository, pkgkey)
|
||||
return voted, add_err_msg
|
||||
|
||||
def get_vote(self, repository, pkgkey):
|
||||
vote, err_msg = self.do_cmd(repository, False, "ugc_get_vote", [pkgkey], {})
|
||||
if isinstance(vote, float):
|
||||
mydict = {pkgkey: vote}
|
||||
self.UGCCache.update_vote_cache(repository, mydict)
|
||||
return vote, err_msg
|
||||
|
||||
def get_all_votes(self, repository):
|
||||
votes_dict, err_msg = self.do_cmd(repository, False, "ugc_get_allvotes", [], {})
|
||||
if isinstance(votes_dict, dict):
|
||||
self.UGCCache.update_vote_cache(repository, votes_dict)
|
||||
return votes_dict, err_msg
|
||||
|
||||
def get_downloads(self, repository, pkgkey):
|
||||
data = self.do_cmd(repository, False, "ugc_get_downloads", [pkgkey], {})
|
||||
if isinstance(data, tuple):
|
||||
downloads, err_msg = data
|
||||
else:
|
||||
return False, 'wrong server answer'
|
||||
if downloads:
|
||||
mydict = {pkgkey: downloads}
|
||||
self.UGCCache.update_downloads_cache(repository, mydict)
|
||||
return downloads, err_msg
|
||||
|
||||
def get_all_downloads(self, repository):
|
||||
down_dict, err_msg = self.do_cmd(repository, False, "ugc_get_alldownloads", [], {})
|
||||
if isinstance(down_dict, dict):
|
||||
self.UGCCache.update_downloads_cache(repository, down_dict)
|
||||
return down_dict, err_msg
|
||||
|
||||
def add_download_stats(self, repository, pkgkeys):
|
||||
return self.do_cmd(repository, False, "ugc_do_download_stats", [pkgkeys], {})
|
||||
|
||||
def send_file(self, repository, pkgkey, file_path, title, description, keywords):
|
||||
self.UGCCache.clear_alldocs_cache(repository)
|
||||
return self.do_cmd(repository, True, "ugc_send_file",
|
||||
[pkgkey, file_path, etpConst['ugc_doctypes']['generic_file'], title, description, keywords], {})
|
||||
|
||||
def remove_file(self, repository, iddoc):
|
||||
self.UGCCache.clear_alldocs_cache(repository)
|
||||
return self.do_cmd(repository, True, "ugc_remove_file", [iddoc], {})
|
||||
|
||||
def send_image(self, repository, pkgkey, image_path, title, description, keywords):
|
||||
self.UGCCache.clear_alldocs_cache(repository)
|
||||
return self.do_cmd(repository, True, "ugc_send_file",
|
||||
[pkgkey, image_path, etpConst['ugc_doctypes']['image'], title, description, keywords], {})
|
||||
|
||||
def remove_image(self, repository, iddoc):
|
||||
self.UGCCache.clear_alldocs_cache(repository)
|
||||
return self.do_cmd(repository, True, "ugc_remove_image", [iddoc], {})
|
||||
|
||||
def send_youtube_video(self, repository, pkgkey, video_path, title, description, keywords):
|
||||
self.UGCCache.clear_alldocs_cache(repository)
|
||||
return self.do_cmd(repository, True, "ugc_send_file",
|
||||
[pkgkey, video_path, etpConst['ugc_doctypes']['youtube_video'], title, description, keywords], {})
|
||||
|
||||
def remove_youtube_video(self, repository, iddoc):
|
||||
self.UGCCache.clear_alldocs_cache(repository)
|
||||
return self.do_cmd(repository, True, "ugc_remove_youtube_video", [iddoc], {})
|
||||
|
||||
def get_docs(self, repository, pkgkey):
|
||||
data = self.do_cmd(repository, False, "ugc_get_docs", [pkgkey], {})
|
||||
if isinstance(data, tuple):
|
||||
docs_data, err_msg = data
|
||||
else:
|
||||
return False, 'wrong server answer'
|
||||
self.UGCCache.save_alldocs_cache(pkgkey, repository, docs_data)
|
||||
return docs_data, err_msg
|
||||
|
||||
def get_icon(self, repository, pkgkey):
|
||||
docs_data, err_msg = self.get_docs(repository, pkgkey)
|
||||
if not docs_data:
|
||||
return None
|
||||
elif not isinstance(docs_data, (tuple, list)):
|
||||
return None
|
||||
return self.UGCCache.get_icon_cache(pkgkey, repository)
|
||||
|
||||
def send_document_autosense(self, repository, pkgkey, ugc_type, data,
|
||||
title, description, keywords):
|
||||
|
||||
if ugc_type == etpConst['ugc_doctypes']['generic_file']:
|
||||
return self.send_file(repository, pkgkey, data, title,
|
||||
description, keywords)
|
||||
elif ugc_type == etpConst['ugc_doctypes']['image']:
|
||||
return self.send_image(repository, pkgkey, data, title,
|
||||
description, keywords)
|
||||
elif ugc_type == etpConst['ugc_doctypes']['youtube_video']:
|
||||
return self.send_youtube_video(repository, pkgkey, data, title,
|
||||
description, keywords)
|
||||
elif ugc_type == etpConst['ugc_doctypes']['comments']:
|
||||
return self.add_comment(repository, pkgkey,
|
||||
description, title, keywords)
|
||||
|
||||
return None, 'type not supported locally'
|
||||
|
||||
def remove_document_autosense(self, repository, iddoc, ugc_type):
|
||||
if ugc_type == etpConst['ugc_doctypes']['generic_file']:
|
||||
return self.remove_file(repository, iddoc)
|
||||
elif ugc_type == etpConst['ugc_doctypes']['image']:
|
||||
return self.remove_image(repository, iddoc)
|
||||
elif ugc_type == etpConst['ugc_doctypes']['youtube_video']:
|
||||
return self.remove_youtube_video(repository, iddoc)
|
||||
elif ugc_type == etpConst['ugc_doctypes']['comments']:
|
||||
return self.remove_comment(repository, iddoc)
|
||||
return None, 'type not supported locally'
|
||||
|
||||
def report_error(self, repository, error_data):
|
||||
return self.do_cmd(repository, False, "report_error", [error_data], {})
|
||||
|
||||
|
||||
class AuthStore(Singleton):
|
||||
|
||||
access_file = etpConst['ugc_accessfile']
|
||||
def init_singleton(self):
|
||||
|
||||
from xml.dom import minidom
|
||||
from xml.parsers import expat
|
||||
self.expat = expat
|
||||
self.minidom = minidom
|
||||
self.setup_store_paths()
|
||||
try:
|
||||
self.setup_permissions()
|
||||
except IOError:
|
||||
pass
|
||||
self.store = {}
|
||||
try:
|
||||
self.xmldoc = self.minidom.parse(self.access_file)
|
||||
except (self.expat.ExpatError, IOError, ValueError,):
|
||||
# ValueError: bad marshal data, wtf!?
|
||||
self.xmldoc = None
|
||||
if self.xmldoc is not None:
|
||||
try:
|
||||
self.parse_document()
|
||||
except self.expat.ExpatError:
|
||||
self.xmldoc = None
|
||||
self.store = {}
|
||||
|
||||
def setup_store_paths(self):
|
||||
myhome = os.getenv("HOME")
|
||||
if myhome is not None:
|
||||
if os.path.isdir(myhome) and os.access(myhome, os.W_OK):
|
||||
self.access_file = os.path.join(myhome, ".config/entropy",
|
||||
os.path.basename(self.access_file))
|
||||
self.access_dir = os.path.dirname(self.access_file)
|
||||
|
||||
def setup_permissions(self):
|
||||
if not os.path.isdir(self.access_dir):
|
||||
os.makedirs(self.access_dir)
|
||||
if not os.path.isfile(self.access_file):
|
||||
f = open(self.access_file, "w")
|
||||
f.close()
|
||||
gid = etpConst['entropygid']
|
||||
if gid is None:
|
||||
gid = 0
|
||||
|
||||
try:
|
||||
const_setup_file(self.access_dir, gid, 0o700)
|
||||
except OSError:
|
||||
pass
|
||||
try:
|
||||
const_setup_file(self.access_file, gid, 0o600)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def parse_document(self):
|
||||
self.store.clear()
|
||||
store = self.xmldoc.getElementsByTagName("store")[0]
|
||||
repositories = store.getElementsByTagName("repository")
|
||||
for repository in repositories:
|
||||
repoid = repository.getAttribute("id")
|
||||
if not repoid:
|
||||
continue
|
||||
username = repository.getElementsByTagName("username")[0].firstChild.data.strip()
|
||||
password = repository.getElementsByTagName("password")[0].firstChild.data.strip()
|
||||
self.store[repoid] = {'username': username, 'password': password}
|
||||
|
||||
def store_login(self, username, password, repository, save = True):
|
||||
self.store[repository] = {'username': username, 'password': password}
|
||||
if save:
|
||||
self.save_store()
|
||||
|
||||
def save_store(self):
|
||||
|
||||
self.xmldoc = self.minidom.Document()
|
||||
store = self.xmldoc.createElement("store")
|
||||
|
||||
for repository in self.store:
|
||||
repo = self.xmldoc.createElement("repository")
|
||||
repo.setAttribute('id', repository)
|
||||
# username
|
||||
username = self.xmldoc.createElement("username")
|
||||
username_value = self.xmldoc.createTextNode(
|
||||
self.store[repository]['username'])
|
||||
username.appendChild(username_value)
|
||||
repo.appendChild(username)
|
||||
# password
|
||||
password = self.xmldoc.createElement("password")
|
||||
password_value = self.xmldoc.createTextNode(
|
||||
self.store[repository]['password'])
|
||||
password.appendChild(password_value)
|
||||
repo.appendChild(password)
|
||||
store.appendChild(repo)
|
||||
|
||||
self.xmldoc.appendChild(store)
|
||||
f = None
|
||||
try:
|
||||
f = open(self.access_file, "w")
|
||||
f.writelines(self.xmldoc.toprettyxml(indent=" "))
|
||||
f.flush()
|
||||
self.setup_permissions()
|
||||
except IOError:
|
||||
# no permissions?
|
||||
pass
|
||||
finally:
|
||||
if f is not None:
|
||||
try:
|
||||
f.close()
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
self.parse_document()
|
||||
|
||||
def remove_login(self, repository, save = True):
|
||||
if repository in self.store:
|
||||
del self.store[repository]
|
||||
if save:
|
||||
self.save_store()
|
||||
|
||||
def read_login(self, repository):
|
||||
data = self.store.get(repository)
|
||||
if data is None:
|
||||
return None
|
||||
return data['username'], data['password']
|
||||
|
||||
|
||||
class Cache:
|
||||
|
||||
CACHE_KEYS = {
|
||||
'ugc_votes': 'ugc_votes',
|
||||
'ugc_downloads': 'ugc_downloads',
|
||||
'ugc_docs': 'ugc_docs',
|
||||
}
|
||||
CACHE_DIR = os.path.join(etpConst['entropyworkdir'], "ugc_cache")
|
||||
PKG_ICON_IDENTIFIER = "__icon__"
|
||||
|
||||
def __init__(self, UGCClientInstance):
|
||||
|
||||
if not isinstance(UGCClientInstance, Client):
|
||||
raise AttributeError(
|
||||
"entropy.client.services.ugc.Client instance required")
|
||||
|
||||
import threading
|
||||
self.CacheLock = threading.Lock()
|
||||
self.Service = UGCClientInstance
|
||||
self.xcache = {}
|
||||
|
||||
def _get_live_cache_item(self, repository, item):
|
||||
if repository not in self.xcache:
|
||||
return None
|
||||
return self.xcache[repository].get(item)
|
||||
|
||||
def _is_live_cache_item_available(self, repository, item):
|
||||
if repository not in self.xcache:
|
||||
return False
|
||||
return item in self.xcache[repository]
|
||||
|
||||
def _set_live_cache_item(self, repository, item, obj):
|
||||
if repository not in self.xcache:
|
||||
self.xcache[repository] = {}
|
||||
if type(obj) in (list, tuple,):
|
||||
my_obj = obj[:]
|
||||
elif type(obj) in (set, frozenset, dict,):
|
||||
my_obj = obj.copy()
|
||||
else:
|
||||
my_obj = obj
|
||||
self.xcache[repository][item] = my_obj
|
||||
|
||||
def _clear_live_cache_item(self, repository, item):
|
||||
if repository not in self.xcache:
|
||||
return
|
||||
if item not in self.xcache[repository]:
|
||||
return
|
||||
del self.xcache[repository][item]
|
||||
|
||||
def _get_store_cache_file(self, iddoc, repository, doc_url,
|
||||
setup_dir = False):
|
||||
base_dir = os.path.join(Cache.CACHE_DIR,
|
||||
Cache.CACHE_KEYS['ugc_docs'], repository, str(iddoc))
|
||||
cache_path = os.path.join(base_dir, "_"+doc_url)
|
||||
cache_dir = os.path.dirname(cache_path)
|
||||
|
||||
if setup_dir and (not os.path.isdir(cache_dir)):
|
||||
try:
|
||||
os.makedirs(cache_dir, 0o775)
|
||||
const_setup_perms(cache_dir, etpConst['entropygid'])
|
||||
except (OSError, IOError,):
|
||||
return cache_path
|
||||
|
||||
return cache_path
|
||||
|
||||
def _get_vote_cache_file(self, repository):
|
||||
return os.path.join(Cache.CACHE_DIR,
|
||||
self._get_vote_cache_dir(repository))
|
||||
|
||||
def _get_downloads_cache_file(self, repository):
|
||||
return os.path.join(Cache.CACHE_DIR,
|
||||
self._get_downloads_cache_dir(repository))
|
||||
|
||||
def _get_alldocs_cache_file(self, pkgkey, repository):
|
||||
return os.path.join(Cache.CACHE_DIR,
|
||||
self._get_alldocs_cache_dir(repository)+"/"+pkgkey)
|
||||
|
||||
def _get_alldocs_cache_dir(self, repository):
|
||||
return Cache.CACHE_KEYS['ugc_docs']+"/"+repository
|
||||
|
||||
def _get_downloads_cache_dir(self, repository):
|
||||
return Cache.CACHE_KEYS['ugc_downloads']+"/"+repository
|
||||
|
||||
def _get_vote_cache_dir(self, repository):
|
||||
return Cache.CACHE_KEYS['ugc_votes']+"/"+repository
|
||||
|
||||
def _get_vote_cache_key(self, repository):
|
||||
return 'get_vote_cache_'+repository
|
||||
|
||||
def _get_downloads_cache_key(self, repository):
|
||||
return 'get_downloads_cache_'+repository
|
||||
|
||||
def _get_alldocs_cache_key(self, repository):
|
||||
return 'get_package_alldocs_cache_'+repository
|
||||
|
||||
def _clear_cache_dir(self, cache_dir):
|
||||
try:
|
||||
shutil.rmtree(cache_dir, True)
|
||||
except (shutil.Error, OSError, IOError,):
|
||||
return
|
||||
|
||||
def _complete_cache_path(self, cache_file):
|
||||
return os.path.join(Cache.CACHE_DIR, cache_file)
|
||||
|
||||
def store_document(self, iddoc, repository, doc_url):
|
||||
cache_file = self._get_store_cache_file(iddoc, repository, doc_url,
|
||||
setup_dir = True)
|
||||
cache_dir = os.path.dirname(cache_file)
|
||||
|
||||
if not os.access(cache_dir, os.W_OK):
|
||||
raise PermissionDenied("PermissionDenied: %s %s" % (
|
||||
_("Cannot write to cache directory"), cache_dir,))
|
||||
|
||||
if os.path.isfile(cache_file) or os.path.islink(cache_file):
|
||||
try:
|
||||
os.remove(cache_file)
|
||||
except OSError:
|
||||
raise PermissionDenied("PermissionDenied: %s %s" % (
|
||||
_("Cannot remove cache file"), cache_file,))
|
||||
|
||||
fetcher = self.Service.Entropy._url_fetcher(doc_url, cache_file,
|
||||
resume = False)
|
||||
rc = fetcher.download()
|
||||
if rc in ("-1", "-2", "-3", "-4"):
|
||||
return None
|
||||
if not os.path.isfile(cache_file):
|
||||
return None
|
||||
|
||||
try:
|
||||
os.chmod(cache_file, 0o664)
|
||||
if etpConst['entropygid'] is not None:
|
||||
os.chown(cache_file, -1, etpConst['entropygid'])
|
||||
except OSError:
|
||||
raise PermissionDenied("PermissionDenied: %s %s" % (
|
||||
_("Cannot write to cache file"), cache_file,))
|
||||
|
||||
del fetcher
|
||||
return cache_file
|
||||
|
||||
def get_stored_document(self, iddoc, repository, doc_url):
|
||||
cache_file = self._get_store_cache_file(iddoc, repository, doc_url)
|
||||
if os.path.isfile(cache_file) and os.access(cache_file, os.R_OK):
|
||||
return cache_file
|
||||
|
||||
def update_vote_cache(self, repository, vote_dict):
|
||||
cached = self.get_vote_cache(repository)
|
||||
if cached is None:
|
||||
cached = vote_dict.copy()
|
||||
else:
|
||||
cached.update(vote_dict)
|
||||
self.save_vote_cache(repository, cached)
|
||||
|
||||
def update_downloads_cache(self, repository, down_dict):
|
||||
cached = self.get_downloads_cache(repository)
|
||||
if cached is None:
|
||||
cached = down_dict.copy()
|
||||
else:
|
||||
cached.update(down_dict)
|
||||
self.save_downloads_cache(repository, cached)
|
||||
|
||||
def clear_alldocs_cache(self, repository):
|
||||
with self.CacheLock:
|
||||
self._clear_cache_dir(
|
||||
self._get_alldocs_cache_dir(repository))
|
||||
self._clear_live_cache_item(repository,
|
||||
self._get_alldocs_cache_key(repository))
|
||||
|
||||
def clear_downloads_cache(self, repository):
|
||||
with self.CacheLock:
|
||||
self._clear_cache_dir(
|
||||
self._get_downloads_cache_dir(repository))
|
||||
self._clear_live_cache_item(repository,
|
||||
self._get_downloads_cache_key(repository))
|
||||
|
||||
def clear_vote_cache(self, repository):
|
||||
with self.CacheLock:
|
||||
self._clear_cache_dir(
|
||||
self._get_vote_cache_dir(repository))
|
||||
self._clear_live_cache_item(repository,
|
||||
self._get_vote_cache_key(repository))
|
||||
|
||||
def clear_live_cache(self):
|
||||
self.xcache.clear()
|
||||
|
||||
def clear_cache(self, repository):
|
||||
self.clear_alldocs_cache(repository)
|
||||
self.clear_downloads_cache(repository)
|
||||
self.clear_vote_cache(repository)
|
||||
self.xcache.clear()
|
||||
|
||||
def get_vote_cache(self, repository):
|
||||
cache_key = self._get_vote_cache_key(repository)
|
||||
cached = self._get_live_cache_item(repository, cache_key)
|
||||
if cached is not None:
|
||||
return cached
|
||||
with self.CacheLock:
|
||||
cache_file = self._get_vote_cache_file(repository)
|
||||
try:
|
||||
data = entropy.dump.loadobj(
|
||||
cache_file,
|
||||
complete_path = True)
|
||||
if data is not None:
|
||||
self._set_live_cache_item(repository, cache_key, data)
|
||||
except (IOError, EOFError, OSError):
|
||||
data = None
|
||||
return data
|
||||
|
||||
def is_vote_cached(self, repository):
|
||||
|
||||
cache_key = self._get_vote_cache_key(repository)
|
||||
cached = self._is_live_cache_item_available(repository, cache_key)
|
||||
if cached:
|
||||
return True
|
||||
|
||||
cache_file = self._get_vote_cache_file(repository)
|
||||
avail = os.path.isfile(cache_file) and os.access(cache_file, os.R_OK)
|
||||
if not avail:
|
||||
return False
|
||||
|
||||
try:
|
||||
entropy.dump.loadobj(cache_file, complete_path = True)
|
||||
except (IOError, EOFError, OSError):
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_downloads_cache(self, repository):
|
||||
cache_key = self._get_downloads_cache_key(repository)
|
||||
cached = self._get_live_cache_item(repository, cache_key)
|
||||
if cached is not None:
|
||||
return cached
|
||||
with self.CacheLock:
|
||||
cache_file = self._get_downloads_cache_file(repository)
|
||||
try:
|
||||
data = entropy.dump.loadobj(cache_file, complete_path = True)
|
||||
if data is not None:
|
||||
self._set_live_cache_item(repository, cache_key, data)
|
||||
except (IOError, EOFError, OSError):
|
||||
data = None
|
||||
return data
|
||||
|
||||
def is_downloads_cached(self, repository):
|
||||
|
||||
cache_key = self._get_downloads_cache_key(repository)
|
||||
cached = self._is_live_cache_item_available(repository, cache_key)
|
||||
if cached:
|
||||
return True
|
||||
|
||||
cache_file = self._get_downloads_cache_file(repository)
|
||||
avail = os.path.isfile(cache_file) and os.access(cache_file, os.R_OK)
|
||||
if not avail:
|
||||
return False
|
||||
|
||||
try:
|
||||
entropy.dump.loadobj(cache_file, complete_path = True)
|
||||
except (IOError, EOFError, OSError):
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_alldocs_cache(self, pkgkey, repository):
|
||||
cache_key = self._get_alldocs_cache_key(repository)
|
||||
cached = self._get_live_cache_item(repository, cache_key)
|
||||
if isinstance(cached, dict):
|
||||
if pkgkey in cached:
|
||||
return cached[pkgkey]
|
||||
else:
|
||||
cached = {}
|
||||
with self.CacheLock:
|
||||
cache_file = self._get_alldocs_cache_file(pkgkey, repository)
|
||||
try:
|
||||
data = entropy.dump.loadobj(cache_file, complete_path = True)
|
||||
if data is not None:
|
||||
cached[pkgkey] = data
|
||||
self._set_live_cache_item(repository, cache_key, cached)
|
||||
except (IOError, EOFError, OSError):
|
||||
data = None
|
||||
return data
|
||||
|
||||
def is_alldocs_cached(self, pkgkey, repository):
|
||||
|
||||
cache_key = self._get_alldocs_cache_key(repository)
|
||||
cached = self._is_live_cache_item_available(repository, cache_key)
|
||||
if cached:
|
||||
return True
|
||||
|
||||
cache_file = self._get_alldocs_cache_file(pkgkey, repository)
|
||||
avail = os.path.isfile(cache_file) and os.access(cache_file, os.R_OK)
|
||||
if not avail:
|
||||
return False
|
||||
|
||||
try:
|
||||
entropy.dump.loadobj(cache_file, complete_path = True)
|
||||
except (IOError, EOFError, OSError):
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_icon_cache(self, pkgkey, repository):
|
||||
docs_cache = self.get_alldocs_cache(pkgkey, repository)
|
||||
if docs_cache is None:
|
||||
return None
|
||||
elif not isinstance(docs_cache, (list, tuple)):
|
||||
return None
|
||||
|
||||
img_doc_type = etpConst['ugc_doctypes']['image']
|
||||
icon_id = Cache.PKG_ICON_IDENTIFIER
|
||||
|
||||
try:
|
||||
icon_elements = [x for x in docs_cache if \
|
||||
x['iddoctype'] == img_doc_type and x['title'] == icon_id]
|
||||
except TypeError:
|
||||
# cache corruption, invalid data, misc bullshit
|
||||
return None
|
||||
if not icon_elements:
|
||||
return None
|
||||
# get first (chronologically) icon
|
||||
icon_elements = sorted(icon_elements, key = lambda x: x['ts'])
|
||||
return icon_elements[0]
|
||||
|
||||
def save_vote_cache(self, repository, vote_dict):
|
||||
with self.CacheLock:
|
||||
self._clear_live_cache_item(repository,
|
||||
self._get_vote_cache_key(repository))
|
||||
|
||||
cache_file = self._get_vote_cache_file(repository)
|
||||
entropy.dump.dumpobj(cache_file, vote_dict, complete_path = True)
|
||||
|
||||
def save_downloads_cache(self, repository, down_dict):
|
||||
with self.CacheLock:
|
||||
self._clear_live_cache_item(repository,
|
||||
self._get_downloads_cache_key(repository))
|
||||
cache_file = self._get_downloads_cache_file(repository)
|
||||
entropy.dump.dumpobj(cache_file, down_dict, complete_path = True)
|
||||
|
||||
def save_alldocs_cache(self, pkgkey, repository, alldocs_dict):
|
||||
with self.CacheLock:
|
||||
self._clear_live_cache_item(repository,
|
||||
self._get_alldocs_cache_key(repository))
|
||||
cache_file = self._get_alldocs_cache_file(pkgkey, repository)
|
||||
entropy.dump.dumpobj(cache_file, alldocs_dict, complete_path = True)
|
||||
|
||||
def get_package_vote(self, repository, pkgkey):
|
||||
cache = self.get_vote_cache(repository)
|
||||
if not cache:
|
||||
return 0.0
|
||||
elif not isinstance(cache, dict):
|
||||
return 0.0
|
||||
elif pkgkey not in cache:
|
||||
return 0.0
|
||||
return cache[pkgkey]
|
||||
|
||||
def get_package_downloads(self, repository, pkgkey):
|
||||
cache = self.get_downloads_cache(repository)
|
||||
if not cache:
|
||||
return 0
|
||||
elif not isinstance(cache, dict):
|
||||
return 0
|
||||
elif pkgkey not in cache:
|
||||
return 0
|
||||
try:
|
||||
return int(cache[pkgkey])
|
||||
except ValueError:
|
||||
return 0
|
||||
@@ -1,786 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Services Authentication Interfaces}.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import time
|
||||
import random
|
||||
from entropy.services.skel import Authenticator, RemoteDatabase
|
||||
from entropy.exceptions import PermissionDenied
|
||||
from entropy.const import etpConst, const_isstring, const_convert_to_unicode
|
||||
from entropy.i18n import _
|
||||
|
||||
import entropy.tools
|
||||
|
||||
class phpBB3Auth(Authenticator, RemoteDatabase):
|
||||
|
||||
def __init__(self):
|
||||
Authenticator.__init__(self)
|
||||
RemoteDatabase.__init__(self)
|
||||
|
||||
self.itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
||||
self.USER_NORMAL = 0
|
||||
self.USER_INACTIVE = 1
|
||||
self.USER_IGNORE = 2
|
||||
self.USER_FOUNDER = 3
|
||||
self.REGISTERED_USERS_GROUP = 7895
|
||||
self.ADMIN_GROUPS = [7893, 7898]
|
||||
self.MODERATOR_GROUPS = [484]
|
||||
self.DEVELOPER_GROUPS = [7900]
|
||||
self.USERNAME_LENGTH_RANGE = list(range(3, 21))
|
||||
self.PASSWORD_LENGTH_RANGE = list(range(6, 31))
|
||||
self.PRIVMSGS_NO_BOX = -3
|
||||
self.NOTIFY_EMAIL = 0
|
||||
self.FAKE_USERNAME = 'already_authed'
|
||||
self.USER_AGENT = "Entropy/%s (compatible; %s; %s: %s %s %s)" % (
|
||||
etpConst['entropyversion'],
|
||||
"Entropy",
|
||||
"UGC",
|
||||
os.uname()[0],
|
||||
os.uname()[4],
|
||||
os.uname()[2],
|
||||
)
|
||||
self.TABLE_PREFIX = 'phpbb_'
|
||||
self.do_update_session_table = True
|
||||
|
||||
def validate_username_regex(self, username):
|
||||
allow_name_chars = self._get_config_value("allow_name_chars")
|
||||
if allow_name_chars == "USERNAME_CHARS_ANY":
|
||||
regex = '.+'
|
||||
elif allow_name_chars == "USERNAME_ALPHA_ONLY":
|
||||
regex = '[A-Za-z0-9]+'
|
||||
elif allow_name_chars == "USERNAME_ALPHA_SPACERS":
|
||||
regex = '[A-Za-z0-9-[\]_+ ]+'
|
||||
elif allow_name_chars == "USERNAME_LETTER_NUM":
|
||||
regex = '[a-zA-Z0-9]+'
|
||||
elif allow_name_chars == "USERNAME_LETTER_NUM_SPACERS":
|
||||
regex = '[-\]_+ [a-zA-Z0-9]+'
|
||||
else: # USERNAME_ASCII
|
||||
regex = '[\x01-\x7F]+'
|
||||
regex = "^%s$" % (regex,)
|
||||
import re
|
||||
myreg = re.compile(regex)
|
||||
if myreg.match(username):
|
||||
del myreg
|
||||
return True
|
||||
return False
|
||||
|
||||
def does_username_exist(self, username, username_clean):
|
||||
self.check_connection()
|
||||
self.cursor.execute('SELECT user_id FROM '+self.TABLE_PREFIX+'users WHERE `username_clean` = %s OR LOWER(`username`) = %s', (username_clean, username.lower(),))
|
||||
data = self.cursor.fetchone()
|
||||
if not data:
|
||||
return False
|
||||
if not isinstance(data, dict):
|
||||
return False
|
||||
if 'user_id' not in data:
|
||||
return False
|
||||
return True
|
||||
|
||||
def does_email_exist(self, email):
|
||||
self.check_connection()
|
||||
self.cursor.execute('SELECT user_id FROM '+self.TABLE_PREFIX+'users WHERE `user_email` = %s', (email,))
|
||||
data = self.cursor.fetchone()
|
||||
if not data:
|
||||
return False
|
||||
if not isinstance(data, dict):
|
||||
return False
|
||||
if 'user_id' not in data:
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_username_allowed(self, username):
|
||||
self.check_connection()
|
||||
self.cursor.execute('SELECT disallow_id FROM '+self.TABLE_PREFIX+'disallow WHERE `disallow_username` = %s', (username,))
|
||||
data = self.cursor.fetchone()
|
||||
if not data:
|
||||
return True
|
||||
if not isinstance(data, dict):
|
||||
return True
|
||||
if 'disallow_id' not in data:
|
||||
return True
|
||||
return False
|
||||
|
||||
def validate_username_string(self, username, username_clean):
|
||||
|
||||
try:
|
||||
const_convert_to_unicode(username.encode('utf-8'))
|
||||
except (UnicodeDecodeError, UnicodeEncodeError,):
|
||||
return False, 'Invalid username'
|
||||
if (""" in username) or ("'" in username) or ('"' in username) or \
|
||||
(" " in username):
|
||||
return False, 'Invalid username'
|
||||
|
||||
try:
|
||||
valid = self.validate_username_regex(username)
|
||||
except:
|
||||
return False, 'Username contains bad characters'
|
||||
if not valid:
|
||||
return False, 'Invalid username'
|
||||
|
||||
exists = self.does_username_exist(username, username_clean)
|
||||
if exists:
|
||||
return False, 'Username already taken'
|
||||
|
||||
allowed = self.is_username_allowed(username)
|
||||
if not allowed:
|
||||
return False, 'Username not allowed'
|
||||
|
||||
return True, 'All fine'
|
||||
|
||||
def _generate_email_hash(self, email):
|
||||
import binascii
|
||||
return str(binascii.crc32(email.lower())) + str(len(email))
|
||||
|
||||
def activate_user(self, user_id):
|
||||
self.check_connection()
|
||||
self.cursor.execute('UPDATE '+self.TABLE_PREFIX+'users SET user_type = %s WHERE `user_id` = %s', (self.USER_NORMAL, user_id,))
|
||||
return True, user_id
|
||||
|
||||
def generate_username_clean(self, username):
|
||||
import re
|
||||
username_clean = username.lower()
|
||||
username_clean = re.sub(r'(?:[\x00-\x1F\x7F]+|(?:\xC2[\x80-\x9F])+)', '', username_clean)
|
||||
username_clean = re.sub(r' {2,}', ' ', username_clean)
|
||||
username_clean = username_clean.strip()
|
||||
return username_clean
|
||||
|
||||
def register_user(self, username, password, email, activate = False):
|
||||
|
||||
if len(username) not in self.USERNAME_LENGTH_RANGE:
|
||||
return False, 'Username not in range'
|
||||
if len(password) not in self.PASSWORD_LENGTH_RANGE:
|
||||
return False, 'Password not in range'
|
||||
valid = entropy.tools.is_valid_email(email)
|
||||
if not valid:
|
||||
return False, 'Invalid email'
|
||||
|
||||
# create the clean one
|
||||
username_clean = self.generate_username_clean(username)
|
||||
|
||||
# check username validity
|
||||
status, err_msg = self.validate_username_string(username, username_clean)
|
||||
if not status:
|
||||
return False, err_msg
|
||||
|
||||
# check email
|
||||
exists = self.does_email_exist(email)
|
||||
if exists:
|
||||
return False, 'Email already in use'
|
||||
|
||||
# now cross fingers
|
||||
status, user_id = self.__register(username, username_clean, password, email, activate)
|
||||
if not status:
|
||||
return False, 'Invalid username (duplicated)'
|
||||
|
||||
return True, user_id
|
||||
|
||||
|
||||
def __register(self, username, username_clean, password, email, activate):
|
||||
|
||||
email_hash = self._generate_email_hash(email)
|
||||
password_hash = self._get_password_hash(password.encode('utf-8'))
|
||||
time_now = int(time.time())
|
||||
|
||||
user_type = self.USER_INACTIVE
|
||||
if activate:
|
||||
user_type = self.USER_NORMAL
|
||||
|
||||
registration_data = {
|
||||
'username': username,
|
||||
'username_clean': username_clean,
|
||||
'user_password': password_hash,
|
||||
'user_pass_convert': 0,
|
||||
'user_email': email.lower(),
|
||||
'user_email_hash': email_hash,
|
||||
'group_id': self.REGISTERED_USERS_GROUP,
|
||||
'user_type': user_type,
|
||||
'user_permissions': '',
|
||||
'user_timezone': self._get_config_value('board_timezone'),
|
||||
'user_dateformat': self._get_config_value('default_dateformat'),
|
||||
'user_lang': self._get_config_value('default_lang'),
|
||||
'user_style': self._get_config_value('default_style'),
|
||||
'user_actkey': '',
|
||||
'user_ip': '',
|
||||
'user_regdate': time_now,
|
||||
'user_passchg': time_now,
|
||||
'user_options': 895, # ? don't ask me
|
||||
'user_inactive_reason': 0,
|
||||
'user_inactive_time': 0,
|
||||
'user_lastmark': time_now,
|
||||
'user_lastvisit': 0,
|
||||
'user_lastpost_time': 0,
|
||||
'user_lastpage': '',
|
||||
'user_posts': 0,
|
||||
'user_dst': self._get_config_value('board_dst'),
|
||||
'user_colour': '',
|
||||
'user_occ': '',
|
||||
'user_interests': '',
|
||||
'user_avatar': '',
|
||||
'user_avatar_type': 0,
|
||||
'user_avatar_width': 0,
|
||||
'user_avatar_height': 0,
|
||||
'user_new_privmsg': 0,
|
||||
'user_unread_privmsg': 0,
|
||||
'user_last_privmsg': 0,
|
||||
'user_message_rules': 0,
|
||||
'user_full_folder': self.PRIVMSGS_NO_BOX,
|
||||
'user_emailtime': 0,
|
||||
'user_notify': 0,
|
||||
'user_notify_pm': 1,
|
||||
'user_notify_type': self.NOTIFY_EMAIL,
|
||||
'user_allow_pm': 1,
|
||||
'user_allow_viewonline': 1,
|
||||
'user_allow_viewemail': 1,
|
||||
'user_allow_massemail': 1,
|
||||
'user_sig': '',
|
||||
'user_sig_bbcode_uid': '',
|
||||
'user_sig_bbcode_bitfield': '',
|
||||
'user_form_salt': self._get_unique_id(),
|
||||
}
|
||||
|
||||
sql = self._generate_sql('insert', self.TABLE_PREFIX+'users', registration_data)
|
||||
self.cursor.execute(sql)
|
||||
user_id = self.cursor.lastrowid
|
||||
|
||||
# now insert into the default group
|
||||
group_data = {
|
||||
'user_id': user_id,
|
||||
'group_id': self.REGISTERED_USERS_GROUP,
|
||||
'user_pending': 0,
|
||||
}
|
||||
sql = self._generate_sql('insert', self.TABLE_PREFIX+'user_group', group_data)
|
||||
try:
|
||||
self.cursor.execute(sql)
|
||||
except self.mysql_exceptions.IntegrityError as e:
|
||||
# for sure it's about duplicated entry
|
||||
return False, 1062
|
||||
|
||||
# set some misc config shit
|
||||
self._set_config_value('newest_user_id', user_id)
|
||||
self._set_config_value('newest_username', username)
|
||||
self._set_config_value('num_users', int(self._get_config_value('num_users'))+1)
|
||||
self.cursor.execute('SELECT group_colour FROM '+self.TABLE_PREFIX+'groups WHERE group_id = %s', (group_data['group_id'],))
|
||||
data = self.cursor.fetchone()
|
||||
gcolor = None
|
||||
if isinstance(data, dict):
|
||||
if 'group_colour' in data:
|
||||
gcolor = data['group_colour']
|
||||
if gcolor:
|
||||
self._set_config_value('newest_user_colour', gcolor)
|
||||
|
||||
return True, user_id
|
||||
|
||||
|
||||
def login(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
|
||||
if 'username' not in self.login_data:
|
||||
raise PermissionDenied('PermissionDenied: %s' % (_('no username specified'),))
|
||||
elif 'password' not in self.login_data:
|
||||
raise PermissionDenied('PermissionDenied: %s' % (_('no password specified'),))
|
||||
|
||||
if not self.login_data['password']:
|
||||
raise PermissionDenied('PermissionDenied: %s' % (_('empty password'),))
|
||||
elif not self.login_data['username']:
|
||||
raise PermissionDenied('PermissionDenied: %s' % (_('empty username'),))
|
||||
|
||||
self.cursor.execute('SELECT * FROM '+self.TABLE_PREFIX+'users WHERE username = %s', (self.login_data['username'],))
|
||||
data = self.cursor.fetchone()
|
||||
if not data:
|
||||
raise PermissionDenied('PermissionDenied: %s' % (_('user not found'),))
|
||||
|
||||
if data['user_pass_convert']:
|
||||
raise PermissionDenied('PermissionDenied: %s' % (
|
||||
_('you need to login on the website to update your password format'),
|
||||
)
|
||||
)
|
||||
|
||||
valid = self._phpbb3_check_hash(self.login_data['password'], data['user_password'])
|
||||
if not valid:
|
||||
raise PermissionDenied('PermissionDenied: %s' % (_('wrong password'),))
|
||||
|
||||
user_type = data['user_type']
|
||||
if (user_type == self.USER_INACTIVE) or (user_type == self.USER_IGNORE):
|
||||
raise PermissionDenied('PermissionDenied: %s' % (_('user inactive'),))
|
||||
|
||||
banned = self.is_user_banned(data['user_id'])
|
||||
if banned:
|
||||
raise PermissionDenied('PermissionDenied: %s' % (_('user banned'),))
|
||||
|
||||
self.login_data.update(data)
|
||||
self.logged_in = True
|
||||
return self.logged_in
|
||||
|
||||
def disconnect(self):
|
||||
if self.is_logged_in():
|
||||
self.logout()
|
||||
RemoteDatabase.disconnect(self)
|
||||
|
||||
def logout(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.logged_in = False
|
||||
self.login_data.clear()
|
||||
return True
|
||||
|
||||
def get_user_data(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
|
||||
self.cursor.execute('SELECT * FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
|
||||
return self.cursor.fetchone()
|
||||
|
||||
def get_user_birthday(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
|
||||
self.cursor.execute('SELECT user_birthday FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
|
||||
bday = self.cursor.fetchone()
|
||||
if not bday:
|
||||
return None
|
||||
elif 'user_birthday' not in bday:
|
||||
return None
|
||||
return bday['user_birthday']
|
||||
|
||||
def get_username(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
|
||||
self.cursor.execute('SELECT username_clean FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
|
||||
data = self.cursor.fetchone()
|
||||
if not data:
|
||||
return ''
|
||||
elif 'username_clean' not in data:
|
||||
return ''
|
||||
return data['username_clean']
|
||||
|
||||
def is_developer(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
|
||||
# search into phpbb_groups
|
||||
groups = self.get_user_groups()
|
||||
for group in groups:
|
||||
if group in self.DEVELOPER_GROUPS:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def is_administrator(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
|
||||
self.cursor.execute('SELECT user_type FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
|
||||
data = self.cursor.fetchone()
|
||||
if data:
|
||||
if data['user_type'] == self.USER_FOUNDER:
|
||||
return True
|
||||
|
||||
# search into phpbb_groups
|
||||
groups = self.get_user_groups()
|
||||
for group in groups:
|
||||
if group in self.ADMIN_GROUPS:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def is_moderator(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
|
||||
# search into phpbb_groups
|
||||
groups = self.get_user_groups()
|
||||
for group in groups:
|
||||
if group in self.MODERATOR_GROUPS:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def is_user(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
|
||||
if self.is_moderator():
|
||||
return False
|
||||
elif self.is_administrator():
|
||||
return False
|
||||
elif self.is_developer():
|
||||
return False
|
||||
|
||||
self.cursor.execute('SELECT user_type,user_id FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
|
||||
data = self.cursor.fetchone()
|
||||
if not data:
|
||||
return False
|
||||
if self.is_user_banned(data['user_id']):
|
||||
return False
|
||||
elif data['user_type'] in [self.USER_NORMAL]:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
# user == user_id
|
||||
def is_user_banned(self, user):
|
||||
self.check_connection()
|
||||
self.cursor.execute('SELECT ban_userid FROM '+self.TABLE_PREFIX+'banlist WHERE ban_userid = %s', (user,))
|
||||
data = self.cursor.fetchone()
|
||||
if data:
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_in_group(self, group):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
groups = self.get_user_groups()
|
||||
if isinstance(group, int):
|
||||
if group in groups:
|
||||
return True
|
||||
elif const_isstring(group):
|
||||
self.cursor.execute('SELECT group_id FROM '+self.TABLE_PREFIX+'groups WHERE group_name = %s', (group,))
|
||||
data = self.cursor.fetchone()
|
||||
if not data:
|
||||
return False
|
||||
elif data['group_id'] in groups:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_user_groups(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
|
||||
self.cursor.execute('SELECT '+self.TABLE_PREFIX+'user_group.group_id,'+self.TABLE_PREFIX+'groups.group_name FROM '+self.TABLE_PREFIX+'user_group,'+self.TABLE_PREFIX+'users,'+self.TABLE_PREFIX+'groups WHERE '+self.TABLE_PREFIX+'users.user_id = %s and '+self.TABLE_PREFIX+'users.user_id = '+self.TABLE_PREFIX+'user_group.user_id and '+self.TABLE_PREFIX+'user_group.group_id = '+self.TABLE_PREFIX+'groups.group_id', (self.login_data['user_id'],))
|
||||
data = self.cursor.fetchall()
|
||||
mydata = {}
|
||||
for mydict in data:
|
||||
mydata[mydict['group_id']] = mydict['group_name']
|
||||
|
||||
return mydata
|
||||
|
||||
def get_user_group(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
|
||||
self.cursor.execute('SELECT group_id FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
|
||||
data = self.cursor.fetchone()
|
||||
if data:
|
||||
if 'group_id' in data:
|
||||
return data['group_id']
|
||||
|
||||
return -1
|
||||
|
||||
def get_user_id(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
return self.login_data['user_id']
|
||||
|
||||
def get_permission_data(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self.cursor.execute('SELECT user_permissions FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
|
||||
return self.cursor.fetchone()
|
||||
|
||||
def update_email(self, email):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
|
||||
email_hash = self._generate_email_hash(email)
|
||||
mydata = {
|
||||
'user_email_hash': email_hash,
|
||||
'user_email': email.lower(),
|
||||
}
|
||||
|
||||
try:
|
||||
sql = self._generate_sql("update", self.TABLE_PREFIX+'users', mydata, 'user_id = %s' % (self.login_data['user_id'],))
|
||||
self.cursor.execute(sql)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def update_password_hash(self, password_hash):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
|
||||
mydata = {
|
||||
'user_password': password_hash,
|
||||
}
|
||||
|
||||
try:
|
||||
sql = self._generate_sql("update", self.TABLE_PREFIX+'users', mydata, 'user_id = %s' % (self.login_data['user_id'],))
|
||||
self.cursor.execute(sql)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def get_email(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self.cursor.execute('SELECT user_email FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],))
|
||||
data = self.cursor.fetchone()
|
||||
if not data:
|
||||
return ''
|
||||
elif 'user_email' not in data:
|
||||
return ''
|
||||
return data['user_email']
|
||||
|
||||
def update_user_id_profile(self, profile_data):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
|
||||
# filter valid params
|
||||
valid_params = [
|
||||
"user_icq", "user_yim", "user_msnm",
|
||||
"user_jabber", "user_website", "user_from",
|
||||
"user_interests", "user_occ", "user_birthday",
|
||||
"user_sig"
|
||||
]
|
||||
|
||||
my_params = {}
|
||||
for param in valid_params:
|
||||
d = profile_data.get(param)
|
||||
if d is None:
|
||||
continue
|
||||
my_params[param] = d
|
||||
|
||||
if not my_params:
|
||||
return False, 'no parameters'
|
||||
|
||||
|
||||
# validate parameters
|
||||
b_day = my_params.get('user_birthday')
|
||||
if const_isstring(b_day):
|
||||
import re
|
||||
myre = re.compile("(0[1-9]|[12][0-9]|3[01])[-](0[1-9]|1[012])[-](19|20)\d\d")
|
||||
if not myre.match(b_day):
|
||||
del my_params['user_birthday']
|
||||
|
||||
try:
|
||||
sql = self._generate_sql("update", self.TABLE_PREFIX+'users', my_params, 'user_id = %s' % (self.login_data['user_id'],))
|
||||
self.cursor.execute(sql)
|
||||
return True, None
|
||||
except Exception as e:
|
||||
return False, str(e)
|
||||
|
||||
|
||||
def _set_config_value(self, config_name, data):
|
||||
self.cursor.execute('UPDATE '+self.TABLE_PREFIX+'config SET config_value = %s WHERE config_name = %s', (data, config_name,))
|
||||
|
||||
def _get_config_value(self, config_name):
|
||||
self.check_connection()
|
||||
self.cursor.execute('SELECT config_value FROM '+self.TABLE_PREFIX+'config WHERE config_name = %s', (config_name,))
|
||||
myconfig = self.cursor.fetchone()
|
||||
if isinstance(myconfig, dict):
|
||||
if 'config_value' in myconfig:
|
||||
return myconfig['config_value']
|
||||
return None
|
||||
|
||||
def _update_session_table(self, user_id, ip_address):
|
||||
self.check_connection()
|
||||
time_now = int(time.time())
|
||||
autologin = self._get_config_value("allow_autologin")
|
||||
self.cursor.execute('SELECT user_allow_viewonline FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (user_id,))
|
||||
myuserprefs = self.cursor.fetchone()
|
||||
session_admin = 0
|
||||
session_data = {
|
||||
'session_id': None,
|
||||
'session_user_id': user_id,
|
||||
'session_last_visit': time_now,
|
||||
'session_start': time_now,
|
||||
'session_time': time_now,
|
||||
'session_ip': ip_address,
|
||||
'session_browser': self.USER_AGENT,
|
||||
'session_forwarded_for': '',
|
||||
'session_page': 'index.php',
|
||||
'session_viewonline': myuserprefs['user_allow_viewonline'],
|
||||
'session_autologin': autologin,
|
||||
'session_admin': session_admin,
|
||||
'session_forum_id': 0,
|
||||
}
|
||||
import hashlib
|
||||
m = hashlib.md5()
|
||||
m.update(str(user_id)+str(time_now)+str(self.USER_AGENT)+str(ip_address)+str(autologin)+str(myuserprefs['user_allow_viewonline']))
|
||||
session_data['session_id'] = m.hexdigest()
|
||||
|
||||
self.cursor.execute('SELECT * FROM '+self.TABLE_PREFIX+'sessions WHERE session_user_id = %s', (user_id,))
|
||||
mydata = self.cursor.fetchone()
|
||||
do_update = False
|
||||
if mydata:
|
||||
do_update = True
|
||||
# update
|
||||
session_data['session_id'] = mydata['session_id']
|
||||
session_data['session_viewonline'] = mydata['session_viewonline']
|
||||
session_data['session_autologin'] = mydata['session_autologin']
|
||||
session_data['session_forwarded_for'] = mydata['session_forwarded_for']
|
||||
session_data['session_forum_id'] = mydata['session_forum_id']
|
||||
session_data['session_page'] = mydata['session_page']
|
||||
session_data['session_browser'] = mydata['session_browser']
|
||||
session_data['session_admin'] = mydata['session_admin']
|
||||
|
||||
if do_update:
|
||||
where = "session_id = '%s'" % (session_data['session_id'],)
|
||||
del session_data['session_id']
|
||||
sql = self._generate_sql('update', self.TABLE_PREFIX+'sessions', session_data, where)
|
||||
else:
|
||||
sql = self._generate_sql('insert', self.TABLE_PREFIX+'sessions', session_data)
|
||||
if sql:
|
||||
self.cursor.execute(sql)
|
||||
self.dbconn.commit()
|
||||
|
||||
|
||||
def _is_ip_banned(self, ip):
|
||||
self.check_connection()
|
||||
self.cursor.execute('SELECT ban_ip FROM '+self.TABLE_PREFIX+'banlist WHERE ban_ip = %s', (ip,))
|
||||
data = self.cursor.fetchone()
|
||||
if data:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _get_unique_id(self):
|
||||
import hashlib
|
||||
m = hashlib.md5()
|
||||
rnd = str(abs(hash(os.urandom(1))))
|
||||
m.update(rnd)
|
||||
x = m.hexdigest()[:-16]
|
||||
del m
|
||||
return x
|
||||
|
||||
def _get_random_number(self):
|
||||
myrand = 0
|
||||
low_n = 100000
|
||||
high_n = 999999
|
||||
while (myrand < low_n) or (myrand > high_n):
|
||||
try:
|
||||
myrand = hash(os.urandom(1))%high_n
|
||||
except NotImplementedError:
|
||||
random.seed()
|
||||
myrand = random.randint(low_n, high_n)
|
||||
return myrand
|
||||
|
||||
def _get_password_hash(self, password):
|
||||
|
||||
#random_state = self._get_unique_id()
|
||||
myrandom = str(self._get_random_number())
|
||||
|
||||
myhash = self._hash_crypt_private(password, self._hash_gensalt_private(myrandom))
|
||||
|
||||
if len(myhash) == 34:
|
||||
return myhash
|
||||
|
||||
import hashlib
|
||||
m = hashlib.md5()
|
||||
m.update(myhash)
|
||||
return m.hexdigest()
|
||||
|
||||
|
||||
def _hash_gensalt_private(self, myinput, iteration_count_log2 = 6):
|
||||
|
||||
if (iteration_count_log2 < 4) or (iteration_count_log2 > 31):
|
||||
iteration_count_log2 = 8
|
||||
|
||||
myoutput = '$H$'
|
||||
myoutput += self.itoa64[min(iteration_count_log2 + 5, 30)]
|
||||
myoutput += self._hash_encode64(myinput, 6)
|
||||
|
||||
return myoutput
|
||||
|
||||
def _hash_crypt_private(self, password, setting):
|
||||
|
||||
myoutput = '*'
|
||||
# Check for correct hash
|
||||
if setting[:3] != '$H$':
|
||||
return myoutput
|
||||
|
||||
count_log2 = self.itoa64.find(setting[3])
|
||||
if count_log2 == -1:
|
||||
count_log2 = 0
|
||||
|
||||
if (count_log2 < 7) or (count_log2 > 30):
|
||||
return myoutput
|
||||
|
||||
count = 1 << count_log2
|
||||
salt = setting[4:12]
|
||||
|
||||
if len(salt) != 8:
|
||||
return myoutput
|
||||
|
||||
import hashlib
|
||||
m = hashlib.md5()
|
||||
m.update(salt+password)
|
||||
myhash = m.digest()
|
||||
while count:
|
||||
m = hashlib.md5()
|
||||
m.update(myhash+password)
|
||||
myhash = m.digest()
|
||||
count -= 1
|
||||
|
||||
myoutput = setting[:12]
|
||||
myoutput += self._hash_encode64(myhash, 16)
|
||||
|
||||
return myoutput
|
||||
|
||||
def _hash_encode64(self, myinput, count):
|
||||
|
||||
output = ''
|
||||
i = 0
|
||||
while i < count:
|
||||
|
||||
value = ord(myinput[i])
|
||||
i += 1
|
||||
output += self.itoa64[value & 0x3f]
|
||||
if i < count:
|
||||
value |= ord(myinput[i]) << 8
|
||||
|
||||
output += self.itoa64[(value >> 6) & 0x3f]
|
||||
|
||||
if i >= count:
|
||||
break
|
||||
i += 1
|
||||
|
||||
if i < count:
|
||||
value |= ord(myinput[i]) << 16
|
||||
|
||||
output += self.itoa64[(value >> 12) & 0x3f]
|
||||
|
||||
if (i >= count):
|
||||
break
|
||||
i += 1
|
||||
|
||||
output += self.itoa64[(value >> 18) & 0x3f]
|
||||
|
||||
return output
|
||||
|
||||
def _phpbb3_check_hash(self, password, myhash):
|
||||
|
||||
if len(myhash) == 34:
|
||||
return self._hash_crypt_private(password, myhash) == myhash
|
||||
|
||||
import hashlib
|
||||
m = hashlib.md5()
|
||||
m.update(password)
|
||||
rhash = m.hexdigest()
|
||||
return rhash == myhash
|
||||
@@ -1,115 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Services Authenticators Interface}.
|
||||
|
||||
"""
|
||||
|
||||
from entropy.const import const_get_stringtype
|
||||
from entropy.services.auth_interfaces import phpBB3Auth
|
||||
from entropy.services.skel import SocketAuthenticator
|
||||
from entropy.exceptions import PermissionDenied
|
||||
|
||||
# Authenticator that can be used by SocketHostInterface based instances
|
||||
class phpBB3(phpBB3Auth, SocketAuthenticator):
|
||||
|
||||
def __init__(self, HostInterface, *args, **kwargs):
|
||||
SocketAuthenticator.__init__(self, HostInterface)
|
||||
phpBB3Auth.__init__(self)
|
||||
self.set_connection_data(kwargs)
|
||||
self.connect()
|
||||
|
||||
def set_session(self, session):
|
||||
self.session = session
|
||||
session_data = self.HostInterface.sessions.get(self.session)
|
||||
if not session_data:
|
||||
return
|
||||
auth_id = session_data['auth_uid']
|
||||
if auth_id:
|
||||
self.logged_in = True
|
||||
# fill login_data with fake information
|
||||
self.login_data = {
|
||||
'username': self.FAKE_USERNAME,
|
||||
'password': 'look elsewhere, this is not a password',
|
||||
'user_id': auth_id
|
||||
}
|
||||
ip_address = session_data.get('ip_address')
|
||||
if ip_address and self.do_update_session_table:
|
||||
self._update_session_table(auth_id, ip_address)
|
||||
|
||||
def docmd_login(self, arguments):
|
||||
|
||||
# filter n00bs
|
||||
if not arguments or (len(arguments) != 2):
|
||||
return False, None, None, 'wrong arguments'
|
||||
|
||||
ip_address = None
|
||||
session_data = self.HostInterface.sessions.get(self.session)
|
||||
if session_data:
|
||||
ip_address = session_data.get('ip_address')
|
||||
user = arguments[0]
|
||||
password = arguments[1]
|
||||
|
||||
if ip_address:
|
||||
if self._is_ip_banned(ip_address):
|
||||
return False, user, None, "banned IP"
|
||||
|
||||
login_data = {'username': user, 'password': password}
|
||||
self.set_login_data(login_data)
|
||||
rc = False
|
||||
try:
|
||||
rc = self.login()
|
||||
except PermissionDenied as e:
|
||||
return rc, user, None, e.value
|
||||
|
||||
if rc:
|
||||
uid = self.get_user_id()
|
||||
is_admin = self.is_administrator()
|
||||
is_dev = self.is_developer()
|
||||
is_mod = self.is_moderator()
|
||||
is_user = self.is_user()
|
||||
self.HostInterface.sessions[self.session]['admin'] = is_admin
|
||||
self.HostInterface.sessions[self.session]['developer'] = is_dev
|
||||
self.HostInterface.sessions[self.session]['moderator'] = is_mod
|
||||
self.HostInterface.sessions[self.session]['user'] = is_user
|
||||
if ip_address and uid and self.do_update_session_table:
|
||||
self._update_session_table(uid, ip_address)
|
||||
return True, user, uid, "ok"
|
||||
return rc, user, None, "login failed"
|
||||
|
||||
# if we get here it means we are logged in
|
||||
def docmd_userdata(self):
|
||||
data = self.get_user_data()
|
||||
return True, data, 'ok'
|
||||
|
||||
def docmd_logout(self, myargs):
|
||||
|
||||
# filter n00bs
|
||||
if (len(myargs) < 1) or (len(myargs) > 1):
|
||||
return False, None, 'wrong arguments'
|
||||
|
||||
user = myargs[0]
|
||||
# filter n00bs
|
||||
if not user or not isinstance(user, const_get_stringtype()):
|
||||
return False, None, "wrong user"
|
||||
|
||||
if not self.is_logged_in():
|
||||
return False, user, "already logged out"
|
||||
|
||||
return True, user, "ok"
|
||||
|
||||
def set_exc_permissions(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def hide_login_data(self, args):
|
||||
myargs = args[:]
|
||||
myargs[-1] = 'hidden'
|
||||
return myargs
|
||||
|
||||
def terminate_instance(self):
|
||||
self.disconnect()
|
||||
@@ -1,73 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Services Command Interfaces}.
|
||||
|
||||
"""
|
||||
from entropy.services.skel import SocketCommands
|
||||
|
||||
class phpBB3(SocketCommands):
|
||||
|
||||
def __init__(self, HostInterface):
|
||||
|
||||
SocketCommands.__init__(self, HostInterface, inst_name = "phpbb3-commands")
|
||||
|
||||
self.valid_commands = {
|
||||
'is_user': {
|
||||
'auth': True,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_is_user,
|
||||
'args': ["authenticator"],
|
||||
'as_user': False,
|
||||
'desc': "returns whether the username linked with the session belongs to a simple user",
|
||||
'syntax': "<SESSION_ID> is_user",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'is_developer': {
|
||||
'auth': True,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_is_developer,
|
||||
'args': ["authenticator"],
|
||||
'as_user': False,
|
||||
'desc': "returns whether the username linked with the session belongs to a developer",
|
||||
'syntax': "<SESSION_ID> is_developer",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'is_moderator': {
|
||||
'auth': True,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_is_moderator,
|
||||
'args': ["authenticator"],
|
||||
'as_user': False,
|
||||
'desc': "returns whether the username linked with the session belongs to a moderator",
|
||||
'syntax': "<SESSION_ID> is_moderator",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'is_administrator': {
|
||||
'auth': True,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_is_administrator,
|
||||
'args': ["authenticator"],
|
||||
'as_user': False,
|
||||
'desc': "returns whether the username linked with the session belongs to an administrator",
|
||||
'syntax': "<SESSION_ID> is_administrator",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
}
|
||||
|
||||
def docmd_is_user(self, authenticator):
|
||||
return authenticator.is_user(), 'ok'
|
||||
|
||||
def docmd_is_developer(self, authenticator):
|
||||
return authenticator.is_developer(), 'ok'
|
||||
|
||||
def docmd_is_administrator(self, authenticator):
|
||||
return authenticator.is_administrator(), 'ok'
|
||||
|
||||
def docmd_is_moderator(self, authenticator):
|
||||
return authenticator.is_moderator(), 'ok'
|
||||
@@ -1,31 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Services Exceptions module}.
|
||||
These are the exceptions raised by Entropy Services RPC system.
|
||||
|
||||
"""
|
||||
from entropy.exceptions import EntropyException
|
||||
|
||||
class EntropyServicesError(EntropyException):
|
||||
""" Generic Entropy Services exception. All classes here belong to this. """
|
||||
|
||||
class TransmissionError(EntropyServicesError):
|
||||
""" Generic transmission error exception """
|
||||
|
||||
class BrokenPipe(TransmissionError):
|
||||
""" Broken pipe transmission error """
|
||||
|
||||
class SSLTransmissionError(TransmissionError):
|
||||
""" Error on SSL socket """
|
||||
|
||||
class ServiceConnectionError(EntropyServicesError):
|
||||
"""Cannot connect to service"""
|
||||
|
||||
class TimeoutError(EntropyServicesError):
|
||||
""" Timeout error """
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,368 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Services Repository Management Command Interface}.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
from entropy.services.skel import SocketCommands
|
||||
from entropy.const import etpConst
|
||||
import entropy.tools
|
||||
|
||||
class Repository(SocketCommands):
|
||||
|
||||
|
||||
def __init__(self, HostInterface):
|
||||
|
||||
SocketCommands.__init__(self, HostInterface, inst_name = "repository_server")
|
||||
|
||||
self.valid_commands = {
|
||||
'repository_server:dbdiff': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_dbdiff,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "returns idpackage differences against the latest available repository",
|
||||
'syntax': "<SESSION_ID> repository_server:dbdiff <repository> <arch> <product> <branch> [idpackages]",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'repository_server:pkginfo_strict': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_pkginfo_strict,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "returns metadata of the provided idpackages excluding 'content'",
|
||||
'syntax': "<SESSION_ID> repository_server:pkginfo_strict <content fmt True/False> <repository> <arch> <product> <branch> <idpackage>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'repository_server:treeupdates': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_treeupdates,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "returns repository treeupdates metadata",
|
||||
'syntax': "<SESSION_ID> repository_server:treeupdates <repository> <arch> <product> <branch>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'repository_server:get_package_sets': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_package_sets,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "returns repository package sets metadata",
|
||||
'syntax': "<SESSION_ID> repository_server:get_package_sets <repository> <arch> <product> <branch>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'repository_server:get_repository_metadata': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_repository_metadata,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "returns repository metadata (package sets, treeupdates, libraries <=> idpackages map)",
|
||||
'syntax': "<SESSION_ID> repository_server:get_repository_metadata <repository> <arch> <product> <branch>",
|
||||
'from': str(self), # from what class
|
||||
}
|
||||
}
|
||||
|
||||
def docmd_dbdiff(self, myargs):
|
||||
|
||||
if len(myargs) < 5:
|
||||
return None
|
||||
repository = myargs[0]
|
||||
arch = myargs[1]
|
||||
product = myargs[2]
|
||||
try:
|
||||
branch = str(myargs[3])
|
||||
except (UnicodeEncodeError, UnicodeDecodeError,):
|
||||
return None
|
||||
foreign_idpackages = myargs[4:]
|
||||
x = (repository, arch, product, branch,)
|
||||
|
||||
valid = self.HostInterface.is_repository_active(x)
|
||||
if not valid:
|
||||
return valid
|
||||
|
||||
dbpath = self.get_database_path(repository, arch, product, branch)
|
||||
mtime = self.get_database_mtime(repository, arch, product, branch)
|
||||
rev_id = self.get_database_revision(repository, arch, product, branch)
|
||||
|
||||
cached = self.HostInterface.get_dcache(
|
||||
x + ('docmd_dbdiff', mtime, rev_id,), repository)
|
||||
if cached is not None:
|
||||
std_checksum, secure_checksum, myids = cached
|
||||
else:
|
||||
acquired = self.HostInterface.master_slave_lock.slave_acquire(x,
|
||||
timeout = 1)
|
||||
if not acquired:
|
||||
return False
|
||||
try:
|
||||
dbconn = self.HostInterface.open_repository(dbpath,
|
||||
docache = False)
|
||||
std_checksum = dbconn.checksum(do_order = True, strict = False,
|
||||
strings = True)
|
||||
secure_checksum = dbconn.checksum(do_order = True,
|
||||
strict = False, strings = True, include_signatures = True)
|
||||
myids = dbconn.listAllPackageIds()
|
||||
cached = std_checksum, secure_checksum, myids
|
||||
self.HostInterface.set_dcache(
|
||||
x + ('docmd_dbdiff', mtime, rev_id,), cached, repository)
|
||||
dbconn.close()
|
||||
finally:
|
||||
self.HostInterface.master_slave_lock.slave_release(x)
|
||||
|
||||
foreign_idpackages = set(foreign_idpackages)
|
||||
|
||||
removed_ids = foreign_idpackages - myids
|
||||
added_ids = myids - foreign_idpackages
|
||||
|
||||
data = {
|
||||
'removed': removed_ids,
|
||||
'added': added_ids,
|
||||
'checksum': std_checksum,
|
||||
'secure_checksum': secure_checksum,
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
def docmd_repository_metadata(self, myargs):
|
||||
|
||||
if len(myargs) < 4:
|
||||
return None
|
||||
repository = myargs[0]
|
||||
arch = myargs[1]
|
||||
product = myargs[2]
|
||||
try:
|
||||
branch = str(myargs[3])
|
||||
except (UnicodeEncodeError, UnicodeDecodeError,):
|
||||
return None
|
||||
|
||||
x = (repository, arch, product, branch,)
|
||||
valid = self.HostInterface.is_repository_active(x)
|
||||
if not valid:
|
||||
return valid
|
||||
|
||||
mtime = self.get_database_mtime(repository, arch, product, branch)
|
||||
rev_id = self.get_database_revision(repository, arch, product, branch)
|
||||
cached = self.HostInterface.get_dcache(
|
||||
(repository, arch, product, branch, 'docmd_repository_metadata',
|
||||
mtime, rev_id), repository)
|
||||
if cached is not None:
|
||||
return cached
|
||||
|
||||
metadata = {}
|
||||
dbpath = self.get_database_path(repository, arch, product, branch)
|
||||
acquired = self.HostInterface.master_slave_lock.slave_acquire(x,
|
||||
timeout = 1)
|
||||
if not acquired:
|
||||
return False
|
||||
try:
|
||||
dbconn = self.HostInterface.open_repository(dbpath, docache = False)
|
||||
metadata['sets'] = dbconn.retrievePackageSets()
|
||||
metadata['treeupdates_actions'] = dbconn.listAllTreeUpdatesActions()
|
||||
metadata['treeupdates_digest'] = \
|
||||
dbconn.retrieveRepositoryUpdatesDigest(repository)
|
||||
# NOTE: kept for backward compatibility (<=0.99.0.x) remove in future
|
||||
metadata['library_idpackages'] = []
|
||||
metadata['revision'] = self.get_database_revision(repository, arch,
|
||||
product, branch)
|
||||
dbconn.close()
|
||||
finally:
|
||||
self.HostInterface.master_slave_lock.slave_release(x)
|
||||
|
||||
|
||||
self.HostInterface.set_dcache(
|
||||
(repository, arch, product, branch, 'docmd_repository_metadata',
|
||||
mtime, rev_id,), metadata, repository)
|
||||
|
||||
return metadata
|
||||
|
||||
|
||||
def docmd_package_sets(self, myargs):
|
||||
|
||||
if len(myargs) < 4:
|
||||
return None
|
||||
repository = myargs[0]
|
||||
arch = myargs[1]
|
||||
product = myargs[2]
|
||||
try:
|
||||
branch = str(myargs[3])
|
||||
except (UnicodeEncodeError, UnicodeDecodeError,):
|
||||
return None
|
||||
|
||||
x = (repository, arch, product, branch,)
|
||||
valid = self.HostInterface.is_repository_active(x)
|
||||
if not valid:
|
||||
return valid
|
||||
|
||||
mtime = self.get_database_mtime(repository, arch, product, branch)
|
||||
rev_id = self.get_database_revision(repository, arch, product, branch)
|
||||
cached = self.HostInterface.get_dcache(
|
||||
(repository, arch, product, branch, 'docmd_package_sets',
|
||||
mtime, rev_id,), repository)
|
||||
if cached is not None:
|
||||
return cached
|
||||
|
||||
dbpath = self.get_database_path(repository, arch, product, branch)
|
||||
acquired = self.HostInterface.master_slave_lock.slave_acquire(x,
|
||||
timeout = 1)
|
||||
if not acquired:
|
||||
return False
|
||||
try:
|
||||
dbconn = self.HostInterface.open_repository(dbpath, docache = False)
|
||||
data = dbconn.retrievePackageSets()
|
||||
dbconn.close()
|
||||
finally:
|
||||
self.HostInterface.master_slave_lock.slave_release(x)
|
||||
|
||||
self.HostInterface.set_dcache(
|
||||
(repository, arch, product, branch, 'docmd_package_sets',
|
||||
mtime, rev_id,), data, repository)
|
||||
return data
|
||||
|
||||
|
||||
def docmd_treeupdates(self, myargs):
|
||||
|
||||
if len(myargs) < 4:
|
||||
return None
|
||||
repository = myargs[0]
|
||||
arch = myargs[1]
|
||||
product = myargs[2]
|
||||
try:
|
||||
branch = str(myargs[3])
|
||||
except (UnicodeEncodeError, UnicodeDecodeError,):
|
||||
return None
|
||||
|
||||
x = (repository, arch, product, branch,)
|
||||
valid = self.HostInterface.is_repository_active(x)
|
||||
if not valid:
|
||||
return valid
|
||||
|
||||
mtime = self.get_database_mtime(repository, arch, product, branch)
|
||||
rev_id = self.get_database_revision(repository, arch, product, branch)
|
||||
cached = self.HostInterface.get_dcache(
|
||||
(repository, arch, product, branch, 'docmd_treeupdates', mtime,
|
||||
rev_id), repository)
|
||||
if cached is not None:
|
||||
return cached
|
||||
|
||||
dbpath = self.get_database_path(repository, arch, product, branch)
|
||||
acquired = self.HostInterface.master_slave_lock.slave_acquire(x,
|
||||
timeout = 1)
|
||||
if not acquired:
|
||||
return False
|
||||
try:
|
||||
dbconn = self.HostInterface.open_repository(dbpath, docache = False)
|
||||
data = {}
|
||||
data['actions'] = dbconn.listAllTreeUpdatesActions()
|
||||
data['digest'] = dbconn.retrieveRepositoryUpdatesDigest(repository)
|
||||
dbconn.close()
|
||||
dbconn = None
|
||||
finally:
|
||||
self.HostInterface.master_slave_lock.slave_release(x)
|
||||
|
||||
self.HostInterface.set_dcache(
|
||||
(repository, arch, product, branch, 'docmd_treeupdates', mtime,
|
||||
rev_id,), data, repository)
|
||||
return data
|
||||
|
||||
|
||||
def docmd_pkginfo_strict(self, myargs):
|
||||
|
||||
if len(myargs) < 6:
|
||||
return None
|
||||
format_content_for_insert = myargs[0]
|
||||
if not isinstance(format_content_for_insert, bool):
|
||||
format_content_for_insert = False
|
||||
repository = myargs[1]
|
||||
arch = myargs[2]
|
||||
product = myargs[3]
|
||||
try:
|
||||
branch = str(myargs[4])
|
||||
except (UnicodeEncodeError, UnicodeDecodeError,):
|
||||
return None
|
||||
zidpackages = myargs[5:]
|
||||
idpackages = []
|
||||
for idpackage in zidpackages:
|
||||
if isinstance(idpackage, int):
|
||||
idpackages.append(idpackage)
|
||||
if not idpackages:
|
||||
return None
|
||||
idpackages = tuple(sorted(idpackages))
|
||||
x = (repository, arch, product, branch,)
|
||||
|
||||
valid = self.HostInterface.is_repository_active(x)
|
||||
if not valid:
|
||||
return valid
|
||||
|
||||
mtime = self.get_database_mtime(repository, arch, product, branch)
|
||||
rev_id = self.get_database_revision(repository, arch, product, branch)
|
||||
cached = self.HostInterface.get_dcache(
|
||||
(repository, arch, product, branch, idpackages,
|
||||
'docmd_pkginfo_strict', mtime, rev_id),
|
||||
repository)
|
||||
if cached is not None:
|
||||
return cached
|
||||
|
||||
dbpath = self.get_database_path(repository, arch, product, branch)
|
||||
acquired = self.HostInterface.master_slave_lock.slave_acquire(x,
|
||||
timeout = 1)
|
||||
if not acquired:
|
||||
return False
|
||||
try:
|
||||
dbconn = self.HostInterface.open_repository(dbpath, docache = False)
|
||||
result = {}
|
||||
for idpackage in idpackages:
|
||||
try:
|
||||
mydata = dbconn.getPackageData(
|
||||
idpackage,
|
||||
content_insert_formatted = format_content_for_insert,
|
||||
get_content = False, get_changelog = False
|
||||
)
|
||||
except Exception:
|
||||
tb = entropy.tools.get_traceback()
|
||||
print(tb)
|
||||
self.HostInterface.socketLog.write(tb)
|
||||
dbconn.close()
|
||||
return None
|
||||
result[idpackage] = mydata.copy()
|
||||
dbconn.close()
|
||||
finally:
|
||||
self.HostInterface.master_slave_lock.slave_release(x)
|
||||
|
||||
self.HostInterface.set_dcache(
|
||||
(repository, arch, product, branch, idpackages,
|
||||
'docmd_pkginfo_strict', mtime, rev_id,),
|
||||
result, repository)
|
||||
return result
|
||||
|
||||
def get_database_path(self, repository, arch, product, branch):
|
||||
repoitems = (repository, arch, product, branch,)
|
||||
mydbroot = self.HostInterface.repositories[repoitems]['dbpath']
|
||||
dbpath = os.path.join(mydbroot, etpConst['etpdatabasefile'])
|
||||
return dbpath
|
||||
|
||||
def get_database_mtime(self, repository, arch, product, branch):
|
||||
dbpath = self.get_database_path(repository, arch, product, branch)
|
||||
try:
|
||||
mtime = os.path.getmtime(dbpath)
|
||||
except (OSError, IOError,):
|
||||
mtime = 0.0
|
||||
return mtime
|
||||
|
||||
def get_database_revision(self, repository, arch, product, branch):
|
||||
x = (repository, arch, product, branch,)
|
||||
try:
|
||||
return int(self.HostInterface.repositories[x]['dbrevision'])
|
||||
except ValueError:
|
||||
return -1
|
||||
@@ -1,315 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Services Repository Management Interface}.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import errno
|
||||
import threading
|
||||
import shutil
|
||||
|
||||
from entropy.core.settings.base import SystemSettings
|
||||
from entropy.output import TextInterface, blue, brown, darkred, teal
|
||||
from entropy.const import etpConst
|
||||
from entropy.misc import TimeScheduled, MasterSlaveLock
|
||||
from entropy.cache import EntropyCacher
|
||||
from entropy.services.interfaces import SocketHost
|
||||
from entropy.services.repository.commands import Repository
|
||||
from entropy.client.interfaces import Client
|
||||
|
||||
import entropy.dump
|
||||
import entropy.tools
|
||||
|
||||
class Server(SocketHost):
|
||||
|
||||
CACHE_ID = 'reposerver/item'
|
||||
|
||||
class ServiceInterface(TextInterface):
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def __init__(self, repositories, repository_lock_scanner = True,
|
||||
do_ssl = False, stdout_logging = True, **kwargs):
|
||||
|
||||
self.master_slave_lock = MasterSlaveLock()
|
||||
# instantiate critical constants
|
||||
etpConst['socket_service']['max_connections'] = 5000
|
||||
|
||||
self.__repository_commands_class = Repository
|
||||
self._entropy = Client(installed_repo = -1)
|
||||
self.__cacher = EntropyCacher()
|
||||
self.__lock_scanner = None
|
||||
self.__dbcache = {}
|
||||
|
||||
# setup System Settings
|
||||
self._settings = SystemSettings()
|
||||
self._settings['socket_service']['max_connections'] = 5000
|
||||
|
||||
etpConst['socketloglevel'] = 1
|
||||
if 'external_cmd_classes' not in kwargs:
|
||||
kwargs['external_cmd_classes'] = []
|
||||
if repository_lock_scanner:
|
||||
kwargs['external_cmd_classes'].insert(0,
|
||||
self.__repository_commands_class)
|
||||
SocketHost.__init__(
|
||||
self,
|
||||
Server.ServiceInterface,
|
||||
installed_repo = -1,
|
||||
sock_output = self._entropy,
|
||||
ssl = do_ssl,
|
||||
**kwargs
|
||||
)
|
||||
self.stdout_logging = stdout_logging
|
||||
self.repositories = repositories.copy()
|
||||
self._expand_repositories()
|
||||
if repository_lock_scanner:
|
||||
# start timed lock file scanning
|
||||
self._start_repository_lock_scanner()
|
||||
|
||||
def killall(self):
|
||||
SocketHost.killall(self)
|
||||
if self.__lock_scanner != None:
|
||||
self.__lock_scanner.kill()
|
||||
|
||||
def is_repository_active(self, repo_tuple):
|
||||
|
||||
if repo_tuple not in self.repositories:
|
||||
return None
|
||||
if self.repositories[repo_tuple]['fatal_error']:
|
||||
return False
|
||||
# is repository being updated
|
||||
if self.repositories[repo_tuple]['locked']:
|
||||
return False
|
||||
# repository database does not exist
|
||||
if not self.repositories[repo_tuple]['enabled']:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_dcache(self, item, repo = '_norepo_'):
|
||||
return entropy.dump.loadobj(Server.CACHE_ID+"/"+repo+"/"+str(hash(item)))
|
||||
|
||||
def set_dcache(self, item, data, repo = '_norepo_'):
|
||||
entropy.dump.dumpobj(Server.CACHE_ID+"/"+repo+"/"+str(hash(item)), data)
|
||||
|
||||
def close_repository(self, dbpath):
|
||||
try:
|
||||
dbc = self.__dbcache.pop(dbpath)
|
||||
dbc.close()
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def open_repository(self, dbpath, docache = True):
|
||||
if docache:
|
||||
cached = self.__dbcache.get(dbpath)
|
||||
if cached != None:
|
||||
return cached
|
||||
dbc = self._entropy.open_generic_repository(
|
||||
dbpath,
|
||||
xcache = False,
|
||||
read_only = True,
|
||||
skip_checks = True
|
||||
)
|
||||
if docache:
|
||||
self.__dbcache[dbpath] = dbc
|
||||
return dbc
|
||||
|
||||
def _start_repository_lock_scanner(self):
|
||||
self.__lock_scanner = TimeScheduled(10, self.__lock_scan)
|
||||
self.__lock_scanner.start()
|
||||
|
||||
def _is_repository_available(self, repo_tuple):
|
||||
|
||||
if self.repositories[repo_tuple]['fatal_error']:
|
||||
return False
|
||||
|
||||
xxx, yyy, compressed_dbpath = self.__get_unpack_metadata(repo_tuple)
|
||||
if not os.path.exists(compressed_dbpath):
|
||||
return False
|
||||
return True
|
||||
|
||||
def __get_unpack_metadata(self, repo_tuple):
|
||||
|
||||
cmethod = self.repositories[repo_tuple]['cmethod']
|
||||
cmethod_data = etpConst['etpdatabasecompressclasses'].get(
|
||||
cmethod)
|
||||
unpack_method = cmethod_data[1]
|
||||
compressed_dbfile = etpConst[cmethod_data[2]]
|
||||
compressed_dbpath = os.path.join(
|
||||
self.repositories[repo_tuple]['dbpath'], compressed_dbfile)
|
||||
return cmethod, unpack_method, compressed_dbpath
|
||||
|
||||
def __unpack_repository(self, db_path, repo_tuple):
|
||||
|
||||
cmethod, unpack_method, compressed_dbpath = self.__get_unpack_metadata(
|
||||
repo_tuple)
|
||||
try:
|
||||
unpack_func = getattr(entropy.tools, unpack_method, None)
|
||||
except (IOError, OSError):
|
||||
return False
|
||||
|
||||
if unpack_func is None:
|
||||
return False
|
||||
generated_outpath = unpack_func(compressed_dbpath)
|
||||
if db_path != generated_outpath:
|
||||
try:
|
||||
os.rename(generated_outpath, db_path)
|
||||
except OSError:
|
||||
shutil.move(generated_outpath, db_path)
|
||||
return True
|
||||
|
||||
def __drop_cache_now(self, repo):
|
||||
return EntropyCacher.clear_cache_item(Server.CACHE_ID+"/"+repo+"/")
|
||||
|
||||
def __lock_scan(self):
|
||||
|
||||
do_clear = set()
|
||||
for repository, arch, product, branch in self.repositories:
|
||||
|
||||
repo_tuple = (repository, arch, product, branch,)
|
||||
db_path = os.path.join(self.repositories[repo_tuple]['dbpath'],
|
||||
etpConst['etpdatabasefile'])
|
||||
|
||||
available = self._is_repository_available(repo_tuple)
|
||||
if not available:
|
||||
if self.repositories[repo_tuple]['enabled']:
|
||||
self.repositories[repo_tuple]['enabled'] = False
|
||||
self.close_repository(db_path)
|
||||
do_clear.add(repository)
|
||||
continue
|
||||
|
||||
signal_file = os.path.join(self.repositories[repo_tuple]['dbpath'],
|
||||
etpConst['etpdatabaseeapi3updates'])
|
||||
if os.path.lexists(signal_file) or \
|
||||
self.repositories[repo_tuple]['locked']:
|
||||
|
||||
# make sure to mark it as locked
|
||||
self.repositories[repo_tuple]['locked'] = True
|
||||
# acquire write lock
|
||||
self.master_slave_lock.master_acquire(repo_tuple)
|
||||
try:
|
||||
|
||||
self.close_repository(db_path)
|
||||
do_clear.add(repository)
|
||||
|
||||
mytxt = blue("%s.") % (
|
||||
"repository is now locked, there is something new!",)
|
||||
self.output(
|
||||
"[%s] %s" % (
|
||||
brown(str(repo_tuple)),
|
||||
mytxt,
|
||||
),
|
||||
importance = 1,
|
||||
level = "info"
|
||||
)
|
||||
|
||||
status = self.__unpack_repository(db_path, repo_tuple)
|
||||
if status:
|
||||
mytxt = blue("%s. %s:") % (
|
||||
"unlocking and indexing database",
|
||||
"hash",
|
||||
)
|
||||
self.output(
|
||||
"[%s] %s" % (
|
||||
brown(str(repo_tuple)),
|
||||
mytxt,
|
||||
),
|
||||
importance = 1,
|
||||
level = "info"
|
||||
)
|
||||
# update revision
|
||||
self.repositories[repo_tuple]['dbrevision'] = \
|
||||
self.__read_revision(repo_tuple)
|
||||
|
||||
dbc = self.open_repository(db_path, docache = False)
|
||||
dbc.createAllIndexes()
|
||||
db_ck = dbc.checksum(do_order = True, strict = False,
|
||||
strings = True)
|
||||
self.output(
|
||||
teal(str(db_ck)),
|
||||
importance = 1,
|
||||
level = "info"
|
||||
)
|
||||
dbc.close()
|
||||
self.__cacher.discard()
|
||||
self.__drop_cache_now(repository)
|
||||
self.repositories[repo_tuple]['locked'] = False
|
||||
self.repositories[repo_tuple]['enabled'] = True
|
||||
|
||||
else:
|
||||
mytxt = darkred("%s.") % (
|
||||
"error during repository unpack, disabling repository",)
|
||||
self.output(
|
||||
"[%s] %s" % (
|
||||
brown(str(repo_tuple)),
|
||||
mytxt,
|
||||
),
|
||||
importance = 1,
|
||||
level = "info"
|
||||
)
|
||||
self.repositories[repo_tuple]['fatal_error'] = True
|
||||
self.repositories[repo_tuple]['enabled'] = False
|
||||
self.repositories[repo_tuple]['locked'] = False
|
||||
|
||||
finally:
|
||||
try:
|
||||
os.remove(signal_file)
|
||||
except OSError as err:
|
||||
if err.errno != errno.ENOENT:
|
||||
raise
|
||||
self.master_slave_lock.master_release(repo_tuple)
|
||||
|
||||
else:
|
||||
# if repository is not locked and signal file is not found
|
||||
# consider the repository enabled.
|
||||
self.repositories[repo_tuple]['enabled'] = True
|
||||
|
||||
|
||||
self.__cacher.discard()
|
||||
for repo in do_clear:
|
||||
self.__drop_cache_now(repo)
|
||||
|
||||
def __read_revision(self, repo_tuple):
|
||||
db_dir = self.repositories[repo_tuple]['dbpath']
|
||||
rev_file = os.path.join(db_dir, etpConst['etpdatabaserevisionfile'])
|
||||
myrev = '0'
|
||||
if os.path.isfile(rev_file) and os.access(rev_file, os.R_OK):
|
||||
with open(rev_file, "r") as f:
|
||||
try:
|
||||
myrev = str(int(f.readline().strip()))
|
||||
except ValueError:
|
||||
myrev = '-1'
|
||||
return myrev
|
||||
|
||||
def _expand_repositories(self):
|
||||
|
||||
for repository, arch, product, branch in self.repositories:
|
||||
x = (repository, arch, product, branch,)
|
||||
|
||||
if 'cmethod' not in self.repositories[x]:
|
||||
raise AttributeError("cmethod not specified for: %s" % (x,))
|
||||
if self.repositories[x]['cmethod'] not in \
|
||||
etpConst['etpdatabasesupportedcformats']:
|
||||
raise AttributeError("wrong cmethod for: %s" % (x,))
|
||||
|
||||
# repository is locked by default, its db needs to be unpacked
|
||||
self.repositories[x]['locked'] = True
|
||||
# repository can become faulty (inability of unpacking data, etc)
|
||||
# and run into unrecoverable errors
|
||||
self.repositories[x]['fatal_error'] = False
|
||||
|
||||
db_path = os.path.join(self.repositories[x]['dbpath'],
|
||||
etpConst['etpdatabasefile'])
|
||||
if os.path.isfile(db_path) and os.access(db_path, os.R_OK):
|
||||
self.repositories[x]['enabled'] = True
|
||||
else:
|
||||
self.repositories[x]['enabled'] = False
|
||||
|
||||
self.repositories[x]['dbrevision'] = self.__read_revision(x)
|
||||
@@ -1,419 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Services Stub Interfaces}.
|
||||
|
||||
"""
|
||||
import os
|
||||
from entropy.const import const_convert_to_unicode
|
||||
from entropy.exceptions import PermissionDenied, LibraryNotFound
|
||||
from entropy.services.exceptions import ServiceConnectionError
|
||||
from entropy.i18n import _
|
||||
|
||||
class SocketCommands:
|
||||
|
||||
def __str__(self):
|
||||
return self.inst_name
|
||||
|
||||
inst_name = 'command-skel'
|
||||
def __init__(self, HostInterface, inst_name = 'command-skel'):
|
||||
self.HostInterface = HostInterface
|
||||
self.no_acked_commands = []
|
||||
self.termination_commands = []
|
||||
self.initialization_commands = []
|
||||
self.login_pass_commands = []
|
||||
self.no_session_commands = []
|
||||
self.raw_commands = []
|
||||
self.config_commands = []
|
||||
self.valid_commands = set()
|
||||
self.inst_name = inst_name
|
||||
|
||||
def register(
|
||||
self,
|
||||
valid_commands,
|
||||
no_acked_commands,
|
||||
termination_commands,
|
||||
initialization_commands,
|
||||
login_pass_commads,
|
||||
no_session_commands,
|
||||
raw_commands,
|
||||
config_commands
|
||||
):
|
||||
valid_commands.update(self.valid_commands)
|
||||
no_acked_commands.extend(self.no_acked_commands)
|
||||
termination_commands.extend(self.termination_commands)
|
||||
initialization_commands.extend(self.initialization_commands)
|
||||
login_pass_commads.extend(self.login_pass_commands)
|
||||
no_session_commands.extend(self.no_session_commands)
|
||||
raw_commands.extend(self.raw_commands)
|
||||
config_commands.extend(self.config_commands)
|
||||
|
||||
class SocketAuthenticator:
|
||||
|
||||
"""
|
||||
Base class for Entropy SocketHost RPC authentication.
|
||||
"""
|
||||
|
||||
def __init__(self, HostInterface):
|
||||
self.HostInterface = HostInterface
|
||||
self.session = None
|
||||
|
||||
def set_session(self, session):
|
||||
"""
|
||||
Set Entropy SocketHost connection session id.
|
||||
|
||||
@param session: connection session
|
||||
@type session: int
|
||||
"""
|
||||
self.session = session
|
||||
|
||||
def hide_login_data(self, args):
|
||||
"""
|
||||
Given Entropy SocketHost RPC login command in list form, hide password
|
||||
data (which is going to be stored in log file).
|
||||
NOTE: this method MUST be reimplemented
|
||||
|
||||
@param args: arguments of RPC login command
|
||||
@type args: list
|
||||
@return: filtered list
|
||||
@rtype: list
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def set_exc_permissions(self, uid, gid):
|
||||
"""
|
||||
Set execution permissions (setuid, setgid) for the running process.
|
||||
|
||||
@param uid: user id
|
||||
@type: int
|
||||
@param gid: group id
|
||||
@type: int
|
||||
"""
|
||||
if gid != None:
|
||||
os.setgid(gid)
|
||||
if uid != None:
|
||||
os.setuid(uid)
|
||||
|
||||
def terminate_instance(self):
|
||||
"""
|
||||
This function is called when the Authenticator is going to be destroyed.
|
||||
You can reimplement this to execute arbitrary code (for eg. terminate
|
||||
a database connection).
|
||||
NOTE: there is no need to reimplement this if you are not using any
|
||||
fancy stuff.
|
||||
"""
|
||||
pass
|
||||
|
||||
class RemoteDatabase:
|
||||
|
||||
def escape_fake(self, mystr):
|
||||
return mystr
|
||||
|
||||
def __init__(self):
|
||||
self.dbconn = None
|
||||
self.cursor = None
|
||||
self.plain_cursor = None
|
||||
self.escape_string = self.escape_fake
|
||||
self.connection_data = {}
|
||||
try:
|
||||
import MySQLdb, _mysql_exceptions
|
||||
from MySQLdb.constants import FIELD_TYPE
|
||||
from MySQLdb.converters import conversions
|
||||
except ImportError:
|
||||
raise LibraryNotFound('LibraryNotFound: dev-python/mysql-python not found')
|
||||
self.mysql = MySQLdb
|
||||
self.mysql_exceptions = _mysql_exceptions
|
||||
self.FIELD_TYPE = FIELD_TYPE
|
||||
self.conversion_dict = conversions.copy()
|
||||
self.conversion_dict[self.FIELD_TYPE.DECIMAL] = int
|
||||
self.conversion_dict[self.FIELD_TYPE.LONG] = int
|
||||
self.conversion_dict[self.FIELD_TYPE.FLOAT] = float
|
||||
self.conversion_dict[self.FIELD_TYPE.NEWDECIMAL] = float
|
||||
|
||||
def check_connection(self):
|
||||
if self.dbconn == None:
|
||||
raise ServiceConnectionError("not connected to service")
|
||||
self._check_needed_reconnect()
|
||||
|
||||
def _check_needed_reconnect(self):
|
||||
if self.dbconn == None:
|
||||
return
|
||||
try:
|
||||
self.dbconn.ping()
|
||||
except self.mysql_exceptions.OperationalError as e:
|
||||
if e[0] != 2006:
|
||||
raise
|
||||
else:
|
||||
self.connect()
|
||||
return True
|
||||
return False
|
||||
|
||||
def _raise_not_implemented_error(self):
|
||||
raise NotImplementedError('NotImplementedError: %s' % (_('method not implemented'),))
|
||||
|
||||
def set_connection_data(self, data):
|
||||
self.connection_data = data.copy()
|
||||
if 'converters' not in self.connection_data and self.conversion_dict:
|
||||
self.connection_data['converters'] = self.conversion_dict.copy()
|
||||
|
||||
def connect(self):
|
||||
kwargs = {}
|
||||
keys = [
|
||||
('host', "hostname"),
|
||||
('user', "username"),
|
||||
('passwd', "password"),
|
||||
('db', "dbname"),
|
||||
('port', "port"),
|
||||
('conv', "converters"), # mysql type converter dict
|
||||
]
|
||||
for ckey, dkey in keys:
|
||||
if dkey not in self.connection_data:
|
||||
continue
|
||||
kwargs[ckey] = self.connection_data.get(dkey)
|
||||
|
||||
try:
|
||||
self.dbconn = self.mysql.connect(**kwargs)
|
||||
except self.mysql_exceptions.OperationalError as e:
|
||||
raise ServiceConnectionError(repr(e))
|
||||
self.plain_cursor = self.dbconn.cursor()
|
||||
self.cursor = self.mysql.cursors.DictCursor(self.dbconn)
|
||||
self.escape_string = self.dbconn.escape_string
|
||||
return True
|
||||
|
||||
def disconnect(self):
|
||||
self.check_connection()
|
||||
self.escape_string = self.escape_fake
|
||||
if hasattr(self.cursor, 'close'):
|
||||
self.cursor.close()
|
||||
if hasattr(self.dbconn, 'close'):
|
||||
self.dbconn.close()
|
||||
self.dbconn = None
|
||||
self.cursor = None
|
||||
self.plain_cursor = None
|
||||
self.connection_data.clear()
|
||||
return True
|
||||
|
||||
def commit(self):
|
||||
self.check_connection()
|
||||
return self.dbconn.commit()
|
||||
|
||||
def execute_script(self, myscript):
|
||||
pty = None
|
||||
for line in myscript.split(";"):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
pty = self.cursor.execute(line)
|
||||
return pty
|
||||
|
||||
def execute_query(self, *args):
|
||||
return self.cursor.execute(*args)
|
||||
|
||||
def execute_many(self, query, myiter):
|
||||
return self.cursor.executemany(query, myiter)
|
||||
|
||||
def fetchone(self):
|
||||
return self.cursor.fetchone()
|
||||
|
||||
def fetchall(self):
|
||||
return self.cursor.fetchall()
|
||||
|
||||
def fetchmany(self, *args, **kwargs):
|
||||
return self.cursor.fetchmany(*args, **kwargs)
|
||||
|
||||
def lastrowid(self):
|
||||
return self.cursor.lastrowid
|
||||
|
||||
def table_exists(self, table):
|
||||
self.check_connection()
|
||||
self.cursor.execute("show tables like %s", (table,))
|
||||
rslt = self.cursor.fetchone()
|
||||
if rslt:
|
||||
return True
|
||||
return False
|
||||
|
||||
def column_in_table_exists(self, table, column):
|
||||
t_ex = self.table_exists(table)
|
||||
if not t_ex:
|
||||
return False
|
||||
self.cursor.execute("show columns from "+table)
|
||||
data = self.cursor.fetchall()
|
||||
for row in data:
|
||||
if row['Field'] == column:
|
||||
return True
|
||||
return False
|
||||
|
||||
def fetchall2set(self, item):
|
||||
mycontent = set()
|
||||
for x in item:
|
||||
mycontent |= set(x)
|
||||
return mycontent
|
||||
|
||||
def fetchall2list(self, item):
|
||||
content = []
|
||||
for x in item:
|
||||
content += list(x)
|
||||
return content
|
||||
|
||||
def fetchone2list(self, item):
|
||||
return list(item)
|
||||
|
||||
def fetchone2set(self, item):
|
||||
return set(item)
|
||||
|
||||
def _generate_sql(self, action, table, data, where = ''):
|
||||
sql = ''
|
||||
keys = sorted(data.keys())
|
||||
if action == "update":
|
||||
sql += 'UPDATE %s SET ' % (self.escape_string(table),)
|
||||
keys_data = []
|
||||
for key in keys:
|
||||
keys_data.append("%s = '%s'" % (
|
||||
self.escape_string(key),
|
||||
self.escape_string(
|
||||
const_convert_to_unicode(data[key], 'utf-8').encode('utf-8')).decode('utf-8')
|
||||
)
|
||||
)
|
||||
sql += ', '.join(keys_data)
|
||||
sql += ' WHERE %s' % (where,)
|
||||
elif action == "insert":
|
||||
sql = 'INSERT INTO %s (%s) VALUES (%s)' % (
|
||||
self.escape_string(table),
|
||||
', '.join([self.escape_string(x) for x in keys]),
|
||||
', '.join(["'" + \
|
||||
self.escape_string(
|
||||
const_convert_to_unicode(data[x], 'utf-8').encode('utf-8')).decode('utf-8') + \
|
||||
"'" for x in keys])
|
||||
)
|
||||
return sql
|
||||
|
||||
class Authenticator:
|
||||
|
||||
def __init__(self):
|
||||
self.login_data = {}
|
||||
self.logged_in = False
|
||||
|
||||
def check_login(self):
|
||||
if not self.logged_in:
|
||||
raise PermissionDenied("not logged in")
|
||||
|
||||
def set_login_data(self, data):
|
||||
self.login_data = data.copy()
|
||||
|
||||
def check_login_data(self):
|
||||
if not self.login_data:
|
||||
raise PermissionDenied("no login data")
|
||||
|
||||
def check_logged_in(self):
|
||||
if not self.is_logged_in():
|
||||
raise PermissionDenied("not logged in")
|
||||
|
||||
def _raise_not_implemented_error(self):
|
||||
raise NotImplementedError("not implemented")
|
||||
|
||||
def check_connection(self):
|
||||
pass
|
||||
|
||||
def login(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self._raise_not_implemented_error()
|
||||
self.logged_in = True
|
||||
return True
|
||||
|
||||
def logout(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self._raise_not_implemented_error()
|
||||
return True
|
||||
|
||||
def is_developer(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self._raise_not_implemented_error()
|
||||
return True
|
||||
|
||||
def is_administrator(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self._raise_not_implemented_error()
|
||||
return True
|
||||
|
||||
def is_moderator(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self._raise_not_implemented_error()
|
||||
return True
|
||||
|
||||
def is_user(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self._raise_not_implemented_error()
|
||||
return True
|
||||
|
||||
def is_user_banned(self, user):
|
||||
self.check_connection()
|
||||
self._raise_not_implemented_error()
|
||||
return False
|
||||
|
||||
def is_in_group(self, group):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self._raise_not_implemented_error()
|
||||
return True
|
||||
|
||||
def get_user_groups(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self._raise_not_implemented_error()
|
||||
return {}
|
||||
|
||||
def get_user_group(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self._raise_not_implemented_error()
|
||||
return -1
|
||||
|
||||
def get_user_id(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self._raise_not_implemented_error()
|
||||
return -1
|
||||
|
||||
def is_logged_in(self):
|
||||
return self.logged_in
|
||||
|
||||
def get_permission_data(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self._raise_not_implemented_error()
|
||||
return {}
|
||||
|
||||
def get_user_data(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self._raise_not_implemented_error()
|
||||
return {}
|
||||
|
||||
def get_username(self):
|
||||
self.check_connection()
|
||||
self.check_login_data()
|
||||
self.check_logged_in()
|
||||
self._raise_not_implemented_error()
|
||||
return {}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Services Testing Command Interface}.
|
||||
|
||||
"""
|
||||
from entropy.services.skel import SocketCommands
|
||||
|
||||
class Test(SocketCommands):
|
||||
|
||||
def __init__(self, HostInterface):
|
||||
|
||||
SocketCommands.__init__(self, HostInterface, inst_name = "test-commands")
|
||||
self.raw_commands = ['test:echo']
|
||||
|
||||
self.valid_commands = {
|
||||
'test:echo': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_echo,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "print arguments echo",
|
||||
'syntax': "<SESSION_ID> test:echo <raw_data>",
|
||||
'from': str(self),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def docmd_echo(self, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
|
||||
return True, ' '.join(myargs)
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Services Testing Interface}.
|
||||
|
||||
"""
|
||||
from entropy.services.interfaces import SocketHost
|
||||
from entropy.output import TextInterface
|
||||
|
||||
class Server(SocketHost):
|
||||
|
||||
class FakeServiceInterface:
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.Text = TextInterface()
|
||||
self.Text.output(":: FakeServiceInterface loaded ::")
|
||||
|
||||
def __init__(self, do_ssl = False, stdout_logging = True,
|
||||
entropy_interface_kwargs = None, **kwargs):
|
||||
if entropy_interface_kwargs is None:
|
||||
entropy_interface_kwargs = {}
|
||||
|
||||
from entropy.services.system.commands import Base
|
||||
if 'external_cmd_classes' not in kwargs:
|
||||
kwargs['external_cmd_classes'] = []
|
||||
kwargs['external_cmd_classes'].insert(0, Base)
|
||||
|
||||
self.Text = TextInterface()
|
||||
SocketHost.__init__(
|
||||
self,
|
||||
self.FakeServiceInterface,
|
||||
sock_output = self.Text,
|
||||
ssl = do_ssl,
|
||||
**kwargs
|
||||
)
|
||||
self.stdout_logging = stdout_logging
|
||||
|
||||
@@ -1,834 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Services UGC Base Command Interface}.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from entropy.services.skel import SocketCommands
|
||||
from entropy.const import etpConst, const_get_stringtype
|
||||
from entropy.services.ugc.interfaces import Server
|
||||
from entropy.misc import EmailSender
|
||||
|
||||
import entropy.tools
|
||||
|
||||
class UGC(SocketCommands):
|
||||
|
||||
ERROR_REPORT_MAIL = os.environ.get('ETP_ERROR_REPORT_MAIL',
|
||||
'website@sabayon.org')
|
||||
if not entropy.tools.is_valid_email(ERROR_REPORT_MAIL):
|
||||
raise AttributeError("ETP_ERROR_REPORT_MAIL is bad")
|
||||
SENDER_EMAIL_FALLBACK = os.environ.get('ETP_SENDER_EMAIL_FALLBACK',
|
||||
'www-data@sabayon.org')
|
||||
if not entropy.tools.is_valid_email(SENDER_EMAIL_FALLBACK):
|
||||
raise AttributeError("ETP_SENDER_EMAIL_FALLBACK is bad")
|
||||
|
||||
def __init__(self, HostInterface, connection_data, store_path, store_url):
|
||||
|
||||
SocketCommands.__init__(self, HostInterface, inst_name = "ugc-commands")
|
||||
self.connection_data = connection_data.copy()
|
||||
self.store_path = store_path
|
||||
self.store_url = store_url
|
||||
self.DOC_TYPES = etpConst['ugc_doctypes'].copy()
|
||||
self.SUPPORTED_DOCFILE_TYPES = [
|
||||
self.DOC_TYPES['image'],
|
||||
self.DOC_TYPES['generic_file'],
|
||||
self.DOC_TYPES['youtube_video'],
|
||||
]
|
||||
self.raw_commands = [
|
||||
'ugc:add_comment', 'ugc:edit_comment',
|
||||
'ugc:register_stream', 'ugc:do_download_stats',
|
||||
'ugc:report_error'
|
||||
]
|
||||
|
||||
self.valid_commands = {
|
||||
'ugc:get_comments': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_get_comments,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "get the comments of the provided package key",
|
||||
'syntax': "<SESSION_ID> ugc:get_comments app-foo/foo",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:get_comments_by_identifiers': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_get_comments_by_identifiers,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "get the comments belonging to the provided identifiers",
|
||||
'syntax': "<SESSION_ID> ugc:get_comments_by_identifiers <identifier1> <identifier2> <identifier3>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:get_documents_by_identifiers': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_get_documents_by_identifiers,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "get the documents belonging to the provided identifiers",
|
||||
'syntax': "<SESSION_ID> ugc:get_documents_by_identifiers <identifier1> <identifier2> <identifier3>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:get_vote': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_get_vote,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "get the vote of the provided package key",
|
||||
'syntax': "<SESSION_ID> ugc:get_vote app-foo/foo",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:get_downloads': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_get_downloads,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "get the number of downloads of the provided package key",
|
||||
'syntax': "<SESSION_ID> ugc:get_downloads app-foo/foo",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:get_textdocs': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_get_textdocs,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "get the text documents belonging to the provided package key",
|
||||
'syntax': "<SESSION_ID> ugc:get_textdocs app-foo/foo",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:get_textdocs_by_identifiers': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_get_textdocs_by_identifiers,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "get the text documents belonging to the provided identifiers",
|
||||
'syntax': "<SESSION_ID> ugc:get_textdocs_by_identifiers <identifier1> <identifier2> <identifier3>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:get_alldocs': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_get_alldocs,
|
||||
'args': ["myargs"],
|
||||
'as_user': False,
|
||||
'desc': "get the all the documents belonging to the provided package key",
|
||||
'syntax': "<SESSION_ID> ugc:get_alldocs app-foo/foo",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:get_allvotes': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_get_allvotes,
|
||||
'args': [],
|
||||
'as_user': False,
|
||||
'desc': "get vote information for every available package key",
|
||||
'syntax': "<SESSION_ID> ugc:get_allvotes",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:get_alldownloads': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_get_alldownloads,
|
||||
'args': [],
|
||||
'as_user': False,
|
||||
'desc': "get download information for every available package key",
|
||||
'syntax': "<SESSION_ID> ugc:get_alldownloads",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:do_vote': {
|
||||
'auth': True,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_do_vote,
|
||||
'args': ["authenticator", "myargs"],
|
||||
'as_user': False,
|
||||
'desc': "vote the specified application (from 0 to 5)",
|
||||
'syntax': "<SESSION_ID> ugc:do_vote app-foo/foo <0..5>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:add_comment': {
|
||||
'auth': True,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_add_comment,
|
||||
'args': ["authenticator", "myargs"],
|
||||
'as_user': False,
|
||||
'desc': "insert a comment related to a package key",
|
||||
'syntax': "<SESSION_ID> ugc:add_comment app-foo/foo <valid xml formatted data>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:remove_comment': {
|
||||
'auth': True,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_remove_comment,
|
||||
'args': ["authenticator", "myargs"],
|
||||
'as_user': False,
|
||||
'desc': "remove a comment (you need its iddoc and mod/admin privs)",
|
||||
'syntax': "<SESSION_ID> ugc:remove_comment <iddoc>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:edit_comment': {
|
||||
'auth': True,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_edit_comment,
|
||||
'args': ["authenticator", "myargs"],
|
||||
'as_user': False,
|
||||
'desc': "edit a comment related to a package key (you need its iddoc, mod/admin privs or being the author)",
|
||||
'syntax': "<SESSION_ID> ugc:edit_comment <iddoc> <valid xml formatted data>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:register_stream': {
|
||||
'auth': True,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_register_stream,
|
||||
'args': ["authenticator", "myargs"],
|
||||
'as_user': False,
|
||||
'desc': "register an uploaded file (through stream cmd) to the relative place (image, file, videos)",
|
||||
'syntax': "<SESSION_ID> ugc:register_stream app-foo/foo <valid xml formatted data>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:remove_image': {
|
||||
'auth': True,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_remove_image,
|
||||
'args': ["authenticator", "myargs"],
|
||||
'as_user': False,
|
||||
'desc': "remove an image (you need its iddoc and mod/admin privs)",
|
||||
'syntax': "<SESSION_ID> ugc:remove_image <iddoc>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:remove_file': {
|
||||
'auth': True,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_remove_file,
|
||||
'args': ["authenticator", "myargs"],
|
||||
'as_user': False,
|
||||
'desc': "remove a file (you need its iddoc and mod/admin privs)",
|
||||
'syntax': "<SESSION_ID> ugc:remove_file <iddoc>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:remove_youtube_video': {
|
||||
'auth': True,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_remove_youtube_video,
|
||||
'args': ["authenticator", "myargs"],
|
||||
'as_user': False,
|
||||
'desc': "remove a youtube video (you need its iddoc and mod/admin privs)",
|
||||
'syntax': "<SESSION_ID> ugc:remove_youtube_video <iddoc>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:do_download_stats': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_do_download_stats,
|
||||
'args': ["authenticator", "myargs"],
|
||||
'as_user': False,
|
||||
'desc': "send information regarding downloads and distribution used",
|
||||
'syntax': "<SESSION_ID> ugc:do_download_stats <valid xml formatted data>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
'ugc:report_error': {
|
||||
'auth': False,
|
||||
'built_in': False,
|
||||
'cb': self.docmd_do_report_error,
|
||||
'args': ["authenticator", "myargs"],
|
||||
'as_user': False,
|
||||
'desc': "submit an Entropy Error Report",
|
||||
'syntax': "<SESSION_ID> ugc:report_error <valid xml formatted data>",
|
||||
'from': str(self), # from what class
|
||||
},
|
||||
}
|
||||
|
||||
def _load_ugc_interface(self):
|
||||
return Server(self.connection_data, self.store_path, self.store_url)
|
||||
|
||||
def _get_userid(self, authenticator):
|
||||
session_data = self.HostInterface.sessions.get(authenticator.session)
|
||||
if not session_data:
|
||||
return False
|
||||
elif 'auth_uid' not in session_data:
|
||||
return False
|
||||
return session_data['auth_uid']
|
||||
|
||||
def _get_username(self, authenticator):
|
||||
return authenticator.get_username()
|
||||
|
||||
def _get_session_file(self, authenticator):
|
||||
session_data = self.HostInterface.sessions.get(authenticator.session)
|
||||
if not session_data:
|
||||
return False
|
||||
elif 'stream_path' not in session_data:
|
||||
return False
|
||||
elif not session_data['stream_path']:
|
||||
return False
|
||||
mypath = session_data['stream_path']
|
||||
if not (os.path.isfile(mypath) and os.access(mypath, os.R_OK)):
|
||||
return False
|
||||
return mypath
|
||||
|
||||
def _get_session_ip_address(self, authenticator):
|
||||
session_data = self.HostInterface.sessions.get(authenticator.session)
|
||||
if not session_data:
|
||||
return None
|
||||
elif 'ip_address' not in session_data:
|
||||
return None
|
||||
return session_data['ip_address']
|
||||
|
||||
def docmd_register_stream(self, authenticator, myargs):
|
||||
|
||||
if len(myargs) < 3:
|
||||
return None, 'wrong arguments'
|
||||
pkgkey = myargs[0]
|
||||
|
||||
xml_string = ' '.join(myargs[1:])
|
||||
try:
|
||||
mydict = entropy.tools.dict_from_xml(xml_string)
|
||||
except Exception as e:
|
||||
return None, "error: %s" % (e,)
|
||||
if not ('doc_type' in mydict \
|
||||
and 'title' in mydict \
|
||||
and 'description' in mydict \
|
||||
and 'keywords' in mydict \
|
||||
and 'file_name' in mydict ):
|
||||
return None, 'wrong dict arguments, xml must have 5 items with attr value -> doc_type, title, description, keywords, file_name'
|
||||
doc_type = mydict.get('doc_type')
|
||||
title = mydict.get('title')
|
||||
description = mydict.get('description')
|
||||
keywords = mydict.get('keywords')
|
||||
file_name = mydict.get('file_name')
|
||||
real_filename = mydict.get('real_filename')
|
||||
|
||||
try:
|
||||
doc_type = int(doc_type)
|
||||
except (ValueError,):
|
||||
return None, 'wrong arguments (doc_type)'
|
||||
if doc_type not in self.SUPPORTED_DOCFILE_TYPES:
|
||||
return None, 'unsupported doc type (SUPPORTED_DOCFILE_TYPES)'
|
||||
|
||||
if not title:
|
||||
title = 'No title'
|
||||
if not description:
|
||||
description = 'No description'
|
||||
if not keywords:
|
||||
keywords = ''
|
||||
|
||||
userid = self._get_userid(authenticator)
|
||||
if userid == None:
|
||||
return False, 'no session userid available'
|
||||
elif isinstance(userid, bool) and not userid:
|
||||
return False, 'no session data available'
|
||||
username = self._get_username(authenticator)
|
||||
|
||||
# get file path
|
||||
stream_path = self._get_session_file(authenticator)
|
||||
if not stream_path:
|
||||
return False, 'no stream path available'
|
||||
orig_stream_path = os.path.dirname(stream_path)
|
||||
new_stream_path = orig_stream_path
|
||||
|
||||
scount = -1
|
||||
while os.path.lexists(new_stream_path):
|
||||
scount += 1
|
||||
b_name = os.path.basename(stream_path)
|
||||
b_name = "%s.%s" % (scount, b_name,)
|
||||
new_stream_path = os.path.join(os.path.dirname(orig_stream_path), b_name)
|
||||
if scount > 1000000:
|
||||
return False, 'while loop interrupted while looking for new_stream_path'
|
||||
shutil.move(stream_path, new_stream_path)
|
||||
stream_path = new_stream_path
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
|
||||
rslt = None, 'invalid doc type'
|
||||
if doc_type == self.DOC_TYPES['image']:
|
||||
rslt = ugc.insert_image(pkgkey, userid, username, stream_path, file_name, title, description, keywords)
|
||||
elif doc_type == self.DOC_TYPES['generic_file']:
|
||||
rslt = ugc.insert_file(pkgkey, userid, username, stream_path, file_name, title, description, keywords)
|
||||
elif doc_type == self.DOC_TYPES['youtube_video']:
|
||||
rslt = ugc.insert_youtube_video(pkgkey, userid, username, stream_path, real_filename, title, description, keywords)
|
||||
ugc.commit()
|
||||
return rslt
|
||||
|
||||
def docmd_add_comment(self, authenticator, myargs):
|
||||
|
||||
if len(myargs) < 2:
|
||||
return None, 'wrong arguments'
|
||||
pkgkey = myargs[0]
|
||||
xml_string = ' '.join(myargs[1:])
|
||||
try:
|
||||
mydict = entropy.tools.dict_from_xml(xml_string)
|
||||
except Exception as e:
|
||||
return None, "error: %s" % (e,)
|
||||
if not ('comment' in mydict and 'title' in mydict and 'keywords' in mydict):
|
||||
return None, 'wrong dict arguments, xml must have 3 items with attr value -> comment, title, keywords'
|
||||
comment = mydict.get('comment')
|
||||
title = mydict.get('title')
|
||||
keywords = mydict.get('keywords')
|
||||
|
||||
userid = self._get_userid(authenticator)
|
||||
if userid == None:
|
||||
return False, 'no session userid available'
|
||||
elif isinstance(userid, bool) and not userid:
|
||||
return False, 'no session data available'
|
||||
username = self._get_username(authenticator)
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
status, iddoc = ugc.insert_comment(pkgkey, userid, username, comment, title, keywords)
|
||||
if not status:
|
||||
t = 'unable to add comment'
|
||||
if isinstance(iddoc, const_get_stringtype()):
|
||||
t = iddoc
|
||||
return False, t
|
||||
ugc.commit()
|
||||
return iddoc, 'ok'
|
||||
|
||||
def docmd_remove_comment(self, authenticator, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
try:
|
||||
iddoc = int(myargs[0])
|
||||
except (ValueError,):
|
||||
return False, 'not a valid iddoc'
|
||||
|
||||
userid = self._get_userid(authenticator)
|
||||
if userid == None:
|
||||
return False, 'no session userid available'
|
||||
elif isinstance(userid, bool) and not userid:
|
||||
return False, 'no session data available'
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
iddoc_userid = ugc.get_iddoc_userid(iddoc)
|
||||
if iddoc_userid == None:
|
||||
return False, 'document not available'
|
||||
|
||||
# check if admin/mod or author
|
||||
if authenticator.is_user() and (userid != iddoc_userid):
|
||||
return False, 'permission denied'
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
status, iddoc = ugc.remove_comment(iddoc)
|
||||
if not status:
|
||||
return False, 'document not removed or not available'
|
||||
ugc.commit()
|
||||
|
||||
return iddoc, 'ok'
|
||||
|
||||
def docmd_edit_comment(self, authenticator, myargs):
|
||||
|
||||
if len(myargs) < 2:
|
||||
return None, 'wrong arguments'
|
||||
try:
|
||||
iddoc = int(myargs[0])
|
||||
except (ValueError,):
|
||||
return False, 'not a valid iddoc'
|
||||
|
||||
xml_string = ' '.join(myargs[1:])
|
||||
try:
|
||||
mydict = entropy.tools.dict_from_xml(xml_string)
|
||||
except Exception as e:
|
||||
return None, "error: %s" % (e,)
|
||||
if not ('comment' in mydict and 'title' in mydict and 'keywords' in mydict):
|
||||
return None, 'wrong dict arguments, xml must have two item with attr value -> comment, title'
|
||||
new_comment = mydict.get('comment')
|
||||
new_title = mydict.get('title')
|
||||
new_keywords = mydict.get('keywords')
|
||||
|
||||
userid = self._get_userid(authenticator)
|
||||
if userid == None:
|
||||
return False, 'no session userid available'
|
||||
elif isinstance(userid, bool) and not userid:
|
||||
return False, 'no session data available'
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
iddoc_userid = ugc.get_iddoc_userid(iddoc)
|
||||
if iddoc_userid == None:
|
||||
return False, 'document not available'
|
||||
|
||||
# check if admin/mod or author
|
||||
if authenticator.is_user() and (userid != iddoc_userid):
|
||||
return False, 'permission denied'
|
||||
|
||||
status, iddoc = ugc.edit_comment(iddoc, new_comment, new_title, new_keywords)
|
||||
if not status:
|
||||
return False, 'document not removed or not available'
|
||||
ugc.commit()
|
||||
|
||||
return iddoc, 'ok'
|
||||
|
||||
def docmd_remove_image(self, authenticator, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
try:
|
||||
iddoc = int(myargs[0])
|
||||
except (ValueError,):
|
||||
return False, 'not a valid iddoc'
|
||||
|
||||
userid = self._get_userid(authenticator)
|
||||
if userid == None:
|
||||
return False, 'no session userid available'
|
||||
elif isinstance(userid, bool) and not userid:
|
||||
return False, 'no session data available'
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
iddoc_userid = ugc.get_iddoc_userid(iddoc)
|
||||
if iddoc_userid == None:
|
||||
return False, 'document not available'
|
||||
|
||||
# check if admin/mod or author
|
||||
if authenticator.is_user() and (userid != iddoc_userid):
|
||||
return False, 'permission denied'
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
status, iddoc = ugc.delete_image(iddoc)
|
||||
if not status:
|
||||
return False, 'document not removed or not available'
|
||||
ugc.commit()
|
||||
|
||||
return iddoc, 'ok'
|
||||
|
||||
def docmd_remove_file(self, authenticator, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
try:
|
||||
iddoc = int(myargs[0])
|
||||
except (ValueError,):
|
||||
return False, 'not a valid iddoc'
|
||||
|
||||
userid = self._get_userid(authenticator)
|
||||
if userid == None:
|
||||
return False, 'no session userid available'
|
||||
elif isinstance(userid, bool) and not userid:
|
||||
return False, 'no session data available'
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
iddoc_userid = ugc.get_iddoc_userid(iddoc)
|
||||
if iddoc_userid == None:
|
||||
return False, 'document not available'
|
||||
|
||||
# check if admin/mod or author
|
||||
if authenticator.is_user() and (userid != iddoc_userid):
|
||||
return False, 'permission denied'
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
status, iddoc = ugc.delete_file(iddoc)
|
||||
if not status:
|
||||
return False, 'document not removed or not available'
|
||||
ugc.commit()
|
||||
|
||||
return iddoc, 'ok'
|
||||
|
||||
def docmd_remove_youtube_video(self, authenticator, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
try:
|
||||
iddoc = int(myargs[0])
|
||||
except (ValueError,):
|
||||
return False, 'not a valid iddoc'
|
||||
|
||||
userid = self._get_userid(authenticator)
|
||||
if userid == None:
|
||||
return False, 'no session userid available'
|
||||
elif isinstance(userid, bool) and not userid:
|
||||
return False, 'no session data available'
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
iddoc_userid = ugc.get_iddoc_userid(iddoc)
|
||||
if iddoc_userid == None:
|
||||
return False, 'document not available'
|
||||
|
||||
# check if admin/mod or author
|
||||
if authenticator.is_user() and (userid != iddoc_userid):
|
||||
return False, 'permission denied'
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
status, iddoc = ugc.remove_youtube_video(iddoc)
|
||||
if not status:
|
||||
return False, 'document not removed or not available'
|
||||
ugc.commit()
|
||||
|
||||
return iddoc, 'ok'
|
||||
|
||||
def docmd_do_vote(self, authenticator, myargs):
|
||||
|
||||
if len(myargs) < 2:
|
||||
return None, 'wrong arguments'
|
||||
pkgkey = myargs[0]
|
||||
vote = myargs[1]
|
||||
|
||||
userid = self._get_userid(authenticator)
|
||||
if userid == None:
|
||||
return False, 'no session userid available'
|
||||
elif isinstance(userid, bool) and not userid:
|
||||
return userid, 'no session data available'
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
voted = ugc.do_vote(pkgkey, userid, vote)
|
||||
if not voted:
|
||||
return voted, 'already voted'
|
||||
ugc.commit()
|
||||
return voted, 'ok'
|
||||
|
||||
def docmd_do_download_stats(self, authenticator, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
|
||||
xml_string = ' '.join(myargs)
|
||||
try:
|
||||
mydict = entropy.tools.dict_from_xml(xml_string)
|
||||
except Exception as e:
|
||||
return None, "error: %s" % (e,)
|
||||
if not ('branch' in mydict and \
|
||||
'release_string' in mydict and \
|
||||
'pkgkeys' in mydict):
|
||||
return None, 'wrong dict arguments, xml must have 3 items with attr value -> branch, release_string, pkgkeys'
|
||||
|
||||
branch = mydict.get('branch')
|
||||
release_string = mydict.get('release_string')
|
||||
hw_hash = mydict.get('hw_hash')
|
||||
pkgkeys = mydict.get('pkgkeys').split()
|
||||
ip_addr = self._get_session_ip_address(authenticator)
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
done = ugc.do_download_stats(branch, release_string, hw_hash, pkgkeys,
|
||||
ip_addr)
|
||||
if not done:
|
||||
return done, 'stats not stored'
|
||||
ugc.commit()
|
||||
return done, 'ok'
|
||||
|
||||
def _get_generic_doctypes(self, pkgkey, doctypes):
|
||||
ugc = self._load_ugc_interface()
|
||||
metadata = ugc.get_ugc_metadata_doctypes(pkgkey, doctypes)
|
||||
if not metadata:
|
||||
return None
|
||||
return metadata
|
||||
|
||||
def _get_generic_doctypes_by_identifiers(self, identifiers, doctypes):
|
||||
ugc = self._load_ugc_interface()
|
||||
metadata = ugc.get_ugc_metadata_doctypes_by_identifiers(identifiers, doctypes)
|
||||
if not metadata:
|
||||
return None
|
||||
return metadata
|
||||
|
||||
def _get_generic_documents_by_identifiers(self, identifiers):
|
||||
ugc = self._load_ugc_interface()
|
||||
metadata = ugc.get_ugc_metadata_by_identifiers(identifiers)
|
||||
if not metadata:
|
||||
return None
|
||||
return metadata
|
||||
|
||||
def docmd_get_comments(self, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
pkgkey = myargs[0]
|
||||
|
||||
metadata = self._get_generic_doctypes(pkgkey, [self.DOC_TYPES['comments']])
|
||||
if metadata == None:
|
||||
return None, 'no metadata available'
|
||||
|
||||
return metadata, 'ok'
|
||||
|
||||
def docmd_get_comments_by_identifiers(self, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
|
||||
identifiers = []
|
||||
for myarg in myargs:
|
||||
try:
|
||||
identifiers.append(int(myarg))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if not identifiers:
|
||||
return None, 'wrong arguments'
|
||||
|
||||
metadata = self._get_generic_doctypes_by_identifiers(identifiers, [self.DOC_TYPES['comments']])
|
||||
if metadata == None:
|
||||
return None, 'no metadata available'
|
||||
|
||||
return metadata, 'ok'
|
||||
|
||||
def docmd_get_documents_by_identifiers(self, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
|
||||
identifiers = []
|
||||
for myarg in myargs:
|
||||
try:
|
||||
identifiers.append(int(myarg))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if not identifiers:
|
||||
return None, 'wrong arguments'
|
||||
|
||||
metadata = self._get_generic_documents_by_identifiers(identifiers)
|
||||
if metadata == None:
|
||||
return None, 'no metadata available'
|
||||
|
||||
return metadata, 'ok'
|
||||
|
||||
def docmd_get_allvotes(self):
|
||||
ugc = self._load_ugc_interface()
|
||||
metadata = ugc.get_ugc_allvotes()
|
||||
if not metadata:
|
||||
return None, 'no metadata available'
|
||||
return metadata, 'ok'
|
||||
|
||||
def docmd_get_alldownloads(self):
|
||||
ugc = self._load_ugc_interface()
|
||||
metadata = ugc.get_ugc_alldownloads()
|
||||
if not metadata:
|
||||
return None, 'no metadata available'
|
||||
return metadata, 'ok'
|
||||
|
||||
def docmd_get_vote(self, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
pkgkey = myargs[0]
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
vote = ugc.get_ugc_vote(pkgkey)
|
||||
return vote, 'ok'
|
||||
|
||||
def docmd_get_downloads(self, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
pkgkey = myargs[0]
|
||||
|
||||
ugc = self._load_ugc_interface()
|
||||
downloads = ugc.get_ugc_downloads(pkgkey)
|
||||
return downloads, 'ok'
|
||||
|
||||
def docmd_get_textdocs(self, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
pkgkey = myargs[0]
|
||||
|
||||
metadata = self._get_generic_doctypes(pkgkey, [self.DOC_TYPES['comments'], self.DOC_TYPES['bbcode_doc']])
|
||||
if metadata == None:
|
||||
return None, 'no metadata available'
|
||||
|
||||
return metadata, 'ok'
|
||||
|
||||
def docmd_get_textdocs_by_identifiers(self, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
|
||||
identifiers = []
|
||||
for myarg in myargs:
|
||||
try:
|
||||
identifiers.append(int(myarg))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if not identifiers:
|
||||
return None, 'wrong arguments'
|
||||
|
||||
metadata = self._get_generic_doctypes_by_identifiers(identifiers, [self.DOC_TYPES['comments'], self.DOC_TYPES['bbcode_doc']])
|
||||
if metadata == None:
|
||||
return None, 'no metadata available'
|
||||
|
||||
return metadata, 'ok'
|
||||
|
||||
def docmd_get_alldocs(self, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
pkgkey = myargs[0]
|
||||
|
||||
metadata = self._get_generic_doctypes(pkgkey, [self.DOC_TYPES[x] for x in self.DOC_TYPES])
|
||||
if metadata == None:
|
||||
return None, 'no metadata available'
|
||||
|
||||
return metadata, 'ok'
|
||||
|
||||
def docmd_do_report_error(self, authenticator, myargs):
|
||||
|
||||
if not myargs:
|
||||
return None, 'wrong arguments'
|
||||
|
||||
import zlib
|
||||
comp_xml_string = ' '.join(myargs)
|
||||
try:
|
||||
xml_string = zlib.decompress(comp_xml_string)
|
||||
mydict = entropy.tools.dict_from_xml_extended(xml_string)
|
||||
except Exception as e:
|
||||
return None, "error: %s" % (e,)
|
||||
|
||||
subject = 'Entropy Error Reporting Handler'
|
||||
|
||||
sender_email = mydict.get('email', UGC.SENDER_EMAIL_FALLBACK)
|
||||
if not entropy.tools.is_valid_email(sender_email):
|
||||
sender_email = UGC.SENDER_EMAIL_FALLBACK
|
||||
keys_to_file = ['errordata', 'processes', 'lspci', 'dmesg', 'locale',
|
||||
'lsof', 'repositories.conf', 'client.conf']
|
||||
|
||||
# call it over
|
||||
mail_txt = ''
|
||||
for key in sorted(mydict):
|
||||
if key in keys_to_file:
|
||||
continue
|
||||
mail_txt += '%s: %s\n' % (key, mydict.get(key),)
|
||||
|
||||
from datetime import datetime
|
||||
import time
|
||||
import tempfile
|
||||
date = datetime.fromtimestamp(time.time())
|
||||
|
||||
# add ip address
|
||||
ip_addr = self._get_session_ip_address(authenticator)
|
||||
mail_txt += 'ip_address: %s\n' % (ip_addr,)
|
||||
mail_txt += 'date: %s\n' % (date,)
|
||||
|
||||
files = []
|
||||
rm_paths = []
|
||||
for key in keys_to_file:
|
||||
if key not in mydict:
|
||||
continue
|
||||
|
||||
fd, path = tempfile.mkstemp(suffix = "__%s.txt" % (key,))
|
||||
try:
|
||||
with os.fdopen(fd, "w") as f_path:
|
||||
f_path.write(mydict.get(key, ''))
|
||||
f_path.flush()
|
||||
except IOError:
|
||||
continue
|
||||
finally:
|
||||
rm_paths.append(path)
|
||||
|
||||
files.append(path)
|
||||
|
||||
sender = EmailSender()
|
||||
sender.send_mime_email(sender_email, [UGC.ERROR_REPORT_MAIL], subject,
|
||||
mail_txt, files)
|
||||
del sender
|
||||
|
||||
for rm_path in rm_paths:
|
||||
os.remove(rm_path)
|
||||
|
||||
return True, 'ok'
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
cmd = 'test:echo %s' % ('c'*90000,)
|
||||
|
||||
from entropy.const import const_get_stringtype
|
||||
from entropy.output import print_generic
|
||||
from entropy.dump import unserialize_string
|
||||
from entropy.client.interfaces import Client
|
||||
from entropy.client.services.ugc.commands import Base
|
||||
from entropy.services.ugc.interfaces import Client as SockClient
|
||||
|
||||
cl = Client()
|
||||
srv = SockClient(cl, Base, ssl = True)
|
||||
srv.connect('192.168.1.1', 2000)
|
||||
session = srv.open_session()
|
||||
srv.transmit('%s %s' % (session, cmd,))
|
||||
print_generic("cmd answer", srv.receive())
|
||||
srv.transmit('%s rc' % (session,))
|
||||
raw_data = srv.receive()
|
||||
if isinstance(raw_data, const_get_stringtype):
|
||||
raw_data = unserialize_string(raw_data)
|
||||
print_generic(raw_data)
|
||||
|
||||
srv.close_session(session)
|
||||
srv.disconnect()
|
||||
|
||||
cl.destroy()
|
||||
raise SystemExit(0)
|
||||
@@ -1,13 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
from entropy.const import const_convert_to_unicode
|
||||
from entropy.services.skel import RemoteDatabase
|
||||
rd = RemoteDatabase()
|
||||
action = "insert"
|
||||
table = const_convert_to_unicode("òtableò", "utf-8")
|
||||
data = {
|
||||
'user': const_convert_to_unicode("Aleò", 'utf-8'),
|
||||
'name': const_convert_to_unicode("Pippo", 'utf-8'),
|
||||
}
|
||||
sql = rd._generate_sql(action, table, data)
|
||||
sys.stdout.write(sql.encode("utf-8") + "\n")
|
||||
@@ -1,169 +0,0 @@
|
||||
#!/usr/bin/python2
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Package Manager Service}.
|
||||
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import signal
|
||||
import threading
|
||||
|
||||
sys.path.insert(0,'/usr/lib/entropy/libraries')
|
||||
sys.path.insert(0,'/usr/lib/entropy/client')
|
||||
sys.path.insert(0,'../libraries')
|
||||
sys.path.insert(0,'../client')
|
||||
# disable pid management
|
||||
sys.argv.append("--no-pid-handling")
|
||||
do_ssl = False
|
||||
do_stdout_logging = True
|
||||
if "--ssl" in sys.argv:
|
||||
do_ssl = True
|
||||
if "--nostdout" in sys.argv:
|
||||
do_stdout_logging = False
|
||||
|
||||
from entropy.i18n import _
|
||||
from entropy.output import nocolor
|
||||
from entropy.tools import get_year, print_traceback
|
||||
from entropy.misc import ParallelTask
|
||||
from entropy.core.settings.base import SystemSettings
|
||||
from text_tools import print_menu
|
||||
SysSettings = SystemSettings()
|
||||
|
||||
myopts = [
|
||||
None,
|
||||
(0," ~ "+SysSettings['system']['name']+" ~ "+sys.argv[0]+" ~ ",1,'Repository Services daemon - (C) %s' % (get_year(),) ),
|
||||
None,
|
||||
(0,_('Basic Options'),0,None),
|
||||
None,
|
||||
(1,'--help',2,_('this output')),
|
||||
(1,'--nocolor',1,_('disable colorized output')),
|
||||
None,
|
||||
(0,_('Application Options'),0,None),
|
||||
None,
|
||||
(1,'--ssl',2,_('enable SSL service too')),
|
||||
(1,'--nostdout',1,_('disable output to stdout, redirect to log file')),
|
||||
None,
|
||||
]
|
||||
|
||||
if "--nocolor" in sys.argv:
|
||||
nocolor()
|
||||
|
||||
if "--help" in sys.argv:
|
||||
print_menu(myopts)
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
from entropy.services.repository.interfaces import Server
|
||||
from entropy.services.auth_interfaces import phpBB3Auth as phpBB3AuthInterface
|
||||
from entropy.services.authenticators import phpBB3
|
||||
from entropy.services.commands import phpBB3 as phpBB3Commands
|
||||
from entropy.services.ugc.commands import UGC
|
||||
|
||||
connection_data = {
|
||||
'hostname': 'localhost',
|
||||
'port': 3306,
|
||||
'username': 'phpbb_user',
|
||||
'password': 'mypassword',
|
||||
'dbname': 'phpbb_db'
|
||||
}
|
||||
ugc_connection_data = {
|
||||
'hostname': 'localhost',
|
||||
'username': 'entropy',
|
||||
'password': 'password',
|
||||
'dbname': 'entropy',
|
||||
'google_email': 'your@gmail.com', # valid google account
|
||||
'google_password': 'yourgmailpassword', # valid google e-mail
|
||||
'google_developer_key': 'xxxxx', # valid google developer key
|
||||
'google_client_id': 'xxxx', # valid google client id connected to the developer key
|
||||
}
|
||||
ugc_store_path = "/path/to/your/ugc/store"
|
||||
ugc_store_url = "http://www.yoursite.com"
|
||||
ugc_args = [ugc_connection_data,ugc_store_path,ugc_store_url]
|
||||
|
||||
# configure my repositories
|
||||
repositories = {
|
||||
('sabayonlinux.org','amd64','standard','5',): {
|
||||
'dbpath': '/repos/new.sabayonlinux.org/standard/amd64/5',
|
||||
'cmethod': 'bz2',
|
||||
},
|
||||
}
|
||||
|
||||
def kill_threads():
|
||||
for th in threading.enumerate():
|
||||
if hasattr(th, 'kill'):
|
||||
th.kill()
|
||||
|
||||
def term_myself():
|
||||
os.kill(os.getpid(), signal.SIGTERM)
|
||||
|
||||
def run_srv(s):
|
||||
try:
|
||||
s.go()
|
||||
except:
|
||||
print_traceback()
|
||||
raise
|
||||
finally:
|
||||
if s is not None:
|
||||
s.killall()
|
||||
kill_threads()
|
||||
term_myself()
|
||||
|
||||
sock_auth = (phpBB3,[],connection_data)
|
||||
srv_ssl = None
|
||||
srv = Server(
|
||||
do_ssl = False,
|
||||
repositories = repositories,
|
||||
stdout_logging = do_stdout_logging,
|
||||
sock_auth = sock_auth,
|
||||
external_cmd_classes = [phpBB3Commands,(UGC,ugc_args,)]
|
||||
)
|
||||
if do_ssl:
|
||||
srv_ssl = Server(
|
||||
do_ssl = True,
|
||||
repositories = repositories,
|
||||
stdout_logging = do_stdout_logging,
|
||||
sock_auth = sock_auth,
|
||||
external_cmd_classes = [phpBB3Commands,(UGC,ugc_args,)]
|
||||
)
|
||||
|
||||
task = ParallelTask(run_srv, srv)
|
||||
task.setName('repodaemon')
|
||||
task.start()
|
||||
task2 = None
|
||||
if srv_ssl is not None:
|
||||
task2 = ParallelTask(run_srv, srv_ssl)
|
||||
task2.setName('repodaemon_ssl')
|
||||
task2.start()
|
||||
|
||||
run_map = {
|
||||
"repodaemon": srv,
|
||||
}
|
||||
if srv_ssl is not None:
|
||||
run_map["repodaemon_ssl"] = srv_ssl
|
||||
t_map = {
|
||||
"repodaemon": task,
|
||||
}
|
||||
if task2 is not None:
|
||||
t_map["repodaemon_ssl"] = task2
|
||||
|
||||
def threads_alive():
|
||||
for th in t_map.values():
|
||||
if th.isAlive():
|
||||
return True
|
||||
return False
|
||||
|
||||
try:
|
||||
while threads_alive():
|
||||
time.sleep(2)
|
||||
finally:
|
||||
for serv in run_map.values():
|
||||
serv.killall()
|
||||
kill_threads()
|
||||
term_myself()
|
||||
@@ -39,7 +39,6 @@ if "/usr/lib/entropy/sulfur" not in sys.path:
|
||||
sys.path.insert(4, "/usr/lib/entropy/sulfur")
|
||||
|
||||
from entropy.exceptions import OnlineMirrorError, PermissionDenied
|
||||
from entropy.services.exceptions import EntropyServicesError
|
||||
import entropy.tools
|
||||
from entropy.const import etpConst, const_get_stringtype, \
|
||||
initconfig_entropy_constants, const_convert_to_unicode, \
|
||||
|
||||
@@ -28,7 +28,6 @@ import pango
|
||||
from entropy.i18n import _, _LOCALE
|
||||
from entropy.output import decolorize
|
||||
from entropy.exceptions import *
|
||||
from entropy.services.exceptions import TimeoutError
|
||||
from entropy.const import *
|
||||
from entropy.misc import ParallelTask
|
||||
from entropy.services.client import WebService
|
||||
|
||||
Reference in New Issue
Block a user