diff --git a/agent/mod_mikrotik_old.py b/agent/mod_mikrotik_old.py deleted file mode 100644 index b085d64..0000000 --- a/agent/mod_mikrotik_old.py +++ /dev/null @@ -1,514 +0,0 @@ -import re -import socket -import binascii -from abc import ABCMeta -from hashlib import md5 -from typing import Iterable, Optional, Tuple -from djing.lib import Singleton -from .structs import TariffStruct, AbonStruct, IpStruct, VectorAbon, VectorTariff -from . import settings as local_settings -from django.conf import settings -from djing import ping -from agent.core import BaseTransmitter, NasNetworkError, NasFailedResult - -DEBUG = getattr(settings, 'DEBUG', False) - -LIST_USERS_ALLOWED = 'DjingUsersAllowed' -LIST_DEVICES_ALLOWED = 'DjingDevicesAllowed' - - -class ApiRos(metaclass=Singleton): - """Routeros api""" - sk = None - is_login = False - - def __init__(self, ip: str, port: int): - if self.sk is None: - sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - if port is None: - port = local_settings.NAS_PORT - sk.connect((ip, port or 8728)) - self.sk = sk - - self.currenttag = 0 - - def login(self, username, pwd): - if self.is_login: - return - chal = None - for repl, attrs in self.talk_iter(("/login",)): - chal = binascii.unhexlify(attrs['=ret']) - md = md5() - md.update(b'\x00') - md.update(bytes(pwd, 'utf-8')) - md.update(chal) - for _ in self.talk_iter(("/login", "=name=" + username, - "=response=00" + binascii.hexlify(md.digest()).decode('utf-8'))): - pass - self.is_login = True - - def talk_iter(self, words: Iterable): - if self.write_sentence(words) == 0: - return - while 1: - i = self.read_sentence() - if len(i) == 0: - continue - reply = i[0] - attrs = {} - for w in i[1:]: - j = w.find('=', 1) - if j == -1: - attrs[w] = '' - else: - attrs[w[:j]] = w[j + 1:] - yield (reply, attrs) - if reply == '!done': - return - - def write_sentence(self, words: Iterable): - ret = 0 - for w in words: - self.write_word(w) - ret += 1 - self.write_word('') - return ret - - def read_sentence(self): - r = [] - while 1: - w = self.read_word() - if w == '': - return r - r.append(w) - - def write_word(self, w): - if DEBUG: - print("<<< " + w) - b = bytes(w, "utf-8") - self.write_len(len(b)) - self.write_bytes(b) - - def read_word(self): - ret = self.read_bytes(self.read_len()).decode('utf-8') - if DEBUG: - print(">>> " + ret) - return ret - - def write_len(self, l): - if l < 0x80: - self.write_bytes(bytes((l,))) - elif l < 0x4000: - l |= 0x8000 - self.write_bytes(bytes(((l >> 8) & 0xff, l & 0xff))) - elif l < 0x200000: - l |= 0xC00000 - self.write_bytes(bytes(((l >> 16) & 0xff, (l >> 8) & 0xff, l & 0xff))) - elif l < 0x10000000: - l |= 0xE0000000 - self.write_bytes(bytes(((l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, l & 0xff))) - else: - self.write_bytes(bytes((0xf0, (l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, l & 0xff))) - - def read_len(self): - c = self.read_bytes(1)[0] - if (c & 0x80) == 0x00: - pass - elif (c & 0xC0) == 0x80: - c &= ~0xC0 - c <<= 8 - c += self.read_bytes(1)[0] - elif (c & 0xE0) == 0xC0: - c &= ~0xE0 - c <<= 8 - c += self.read_bytes(1)[0] - c <<= 8 - c += self.read_bytes(1)[0] - elif (c & 0xF0) == 0xE0: - c &= ~0xF0 - c <<= 8 - c += self.read_bytes(1)[0] - c <<= 8 - c += self.read_bytes(1)[0] - c <<= 8 - c += self.read_bytes(1)[0] - elif (c & 0xF8) == 0xF0: - c = self.read_bytes(1)[0] - c <<= 8 - c += self.read_bytes(1)[0] - c <<= 8 - c += self.read_bytes(1)[0] - c <<= 8 - c += self.read_bytes(1)[0] - return c - - def write_bytes(self, s): - n = 0 - while n < len(s): - r = self.sk.send(s[n:]) - if r == 0: - raise NasFailedResult("connection closed by remote end") - n += r - - def read_bytes(self, length): - ret = b'' - while len(ret) < length: - s = self.sk.recv(length - len(ret)) - if len(s) == 0: - raise NasFailedResult("connection closed by remote end") - ret += s - return ret - - def __del__(self): - if hasattr(self, 'sk'): - self.sk.close() - - -class TransmitterManager(BaseTransmitter, metaclass=ABCMeta): - def __init__(self, login=None, password=None, ip=None, port=None): - ip = ip or getattr(local_settings, 'NAS_IP') - if ip is None or ip == '': - raise NasNetworkError('Ip address of NAS does not specified') - if not ping(ip): - raise NasNetworkError('NAS %(ip_addr)s does not pinged' % { - 'ip_addr': ip - }) - try: - self.ar = ApiRos(ip, port) - self.ar.login(login or getattr(local_settings, 'NAS_LOGIN'), - password or getattr(local_settings, 'NAS_PASSW')) - except ConnectionRefusedError: - raise NasNetworkError('Connection to %s is Refused' % ip) - - def _exec_cmd(self, cmd: Iterable) -> list: - if not isinstance(cmd, (list, tuple)): - raise TypeError - result_iter = self.ar.talk_iter(cmd) - res = [] - for rt in result_iter: - if rt[0] == '!trap': - raise NasFailedResult(rt[1]['=message']) - res.append(rt[1]) - return res - - def _exec_cmd_iter(self, cmd: Iterable) -> Iterable: - if not isinstance(cmd, (list, tuple)): - raise TypeError - result_iter = self.ar.talk_iter(cmd) - for rt in result_iter: - if len(rt) < 2: - continue - if rt[0] == '!trap': - raise NasFailedResult(rt[1]['=message']) - yield rt - - # Build object ShapeItem from information from mikrotik - @staticmethod - def _build_shape_obj(info: dict) -> AbonStruct: - # Переводим приставку скорости Mikrotik в Mbit/s - def parse_speed(text_speed): - text_speed_digit = float(text_speed[:-1] or 0.0) - text_append = text_speed[-1:] - if text_append == 'M': - res = text_speed_digit - elif text_append == 'k': - res = text_speed_digit / 1000 - # elif text_append == 'G': - # res = text_speed_digit * 0x400 - else: - res = float(re.sub(r'[a-zA-Z]', '', text_speed)) / 1000 ** 2 - return res - - speeds = info['=max-limit'].split('/') - t = TariffStruct( - speed_in=parse_speed(speeds[1]), - speed_out=parse_speed(speeds[0]) - ) - try: - a = AbonStruct( - uid=int(info['=name'][3:]), - # FIXME: тут в разных микротиках или =target-addresses или =target - ip=info['=target'][:-3], - tariff=t, - is_active=False if info['=disabled'] == 'false' else True - ) - a.queue_id = info['=.id'] - return a - except ValueError: - pass - - -class QueueManager(TransmitterManager, metaclass=ABCMeta): - # Find queue by name - def find(self, name: str) -> AbonStruct: - ret = self._exec_cmd(('/queue/simple/print', '?name=%s' % name)) - if len(ret) > 1: - return self._build_shape_obj(ret[0]) - - def add(self, user: AbonStruct): - if not isinstance(user, AbonStruct): - raise TypeError - if user.tariff is None or not isinstance(user.tariff, TariffStruct): - return - return self._exec_cmd(('/queue/simple/add', - '=name=uid%d' % user.uid, - # FIXME: тут в разных микротиках или =target-addresses или =target - '=target=%s' % user.ip, - '=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn), - '=queue=MikroBILL_SFQ/MikroBILL_SFQ', - '=burst-time=1/1' - )) - - def remove(self, user: AbonStruct): - if not isinstance(user, AbonStruct): - raise TypeError - q = self.find('uid%d' % user.uid) - if q is not None: - return self._exec_cmd(('/queue/simple/remove', '=.id=' + getattr(q, 'queue_id', ''),)) - - def remove_range(self, q_ids: Iterable[str]): - try: - # q_ids = [q.queue_id for q in q_ids] - return self._exec_cmd(('/queue/simple/remove', '=numbers=' + ','.join(q_ids))) - except TypeError as e: - print(e) - - def update(self, user: AbonStruct): - if not isinstance(user, AbonStruct): - raise TypeError - if user.tariff is None or not isinstance(user.tariff, TariffStruct): - return - queue = self.find('uid%d' % user.uid) - if queue is None: - return self.add(user) - else: - mk_id = getattr(queue, 'queue_id', '') - return self._exec_cmd(('/queue/simple/set', '=.id=' + mk_id, - '=name=uid%d' % user.uid, - '=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn), - # FIXME: тут в разных микротиках или =target-addresses или =target - '=target=%s' % user.ip, - '=queue=MikroBILL_SFQ/MikroBILL_SFQ', - '=burst-time=1/1' - )) - - def read_queue_iter(self): - for code, dat in self._exec_cmd_iter(('/queue/simple/print', '=detail')): - if code == '!done': - return - sobj = self._build_shape_obj(dat) - if sobj is not None: - yield sobj - - def disable(self, user: AbonStruct): - if not isinstance(user, AbonStruct): - raise TypeError - q = self.find('uid%d' % user.uid) - if q is None: - self.add(user) - return self.disable(user) - else: - return self._exec_cmd(('/queue/simple/disable', '=.id=*' + getattr(q, 'queue_id', ''))) - - def enable(self, user: AbonStruct): - if not isinstance(user, AbonStruct): - raise TypeError - q = self.find('uid%d' % user.uid) - if q is None: - self.add(user) - self.enable(user) - else: - return self._exec_cmd(('/queue/simple/enable', '=.id=*' + getattr(q, 'queue_id', ''))) - - -class IpAddressListObj(IpStruct): - __slots__ = ('__ip', 'mk_id') - - def __init__(self, ip, mk_id): - super(IpAddressListObj, self).__init__(ip) - self.mk_id = str(mk_id).replace('*', '') - - -class IpAddressListManager(TransmitterManager, metaclass=ABCMeta): - def add(self, list_name: str, ip: IpStruct): - if not isinstance(ip, IpStruct): - raise TypeError - commands = ( - '/ip/firewall/address-list/add', - '=list=%s' % list_name, - '=address=%s' % ip - ) - return self._exec_cmd(commands) - - def remove(self, mk_id): - return self._exec_cmd(( - '/ip/firewall/address-list/remove', - '=.id=*' + str(mk_id).replace('*', '') - )) - - def remove_range(self, items: Iterable[IpAddressListObj]): - ids = tuple(ip.mk_id for ip in items if isinstance(ip, IpAddressListObj)) - if len(ids) > 0: - return self._exec_cmd([ - '/ip/firewall/address-list/remove', - '=numbers=*%s' % ',*'.join(ids) - ]) - - def find(self, ip: IpStruct, list_name: str): - if not isinstance(ip, IpStruct): - raise TypeError - return self._exec_cmd(( - '/ip/firewall/address-list/print', 'where', - '?list=%s' % list_name, - '?address=%s' % ip - )) - - def read_ips_iter(self, list_name: str): - ips = self._exec_cmd_iter(( - '/ip/firewall/address-list/print', 'where', - '?list=%s' % list_name, - '?dynamic=no' - )) - for code, dat in ips: - if dat != {}: - yield IpAddressListObj(dat['=address'], dat['=.id']) - - def disable(self, user: AbonStruct): - r = IpAddressListManager.find(self, user.ip, LIST_USERS_ALLOWED) - if len(r) > 1: - mk_id = r[0]['=.id'] - return self._exec_cmd(( - '/ip/firewall/address-list/disable', - '=.id=' + str(mk_id), - )) - - def enable(self, user): - r = IpAddressListManager.find(self, user.ip, LIST_USERS_ALLOWED) - if len(r) > 1: - mk_id = r[0]['=.id'] - return self._exec_cmd(( - '/ip/firewall/address-list/enable', - '=.id=' + str(mk_id), - )) - - -class MikrotikTransmitter(QueueManager, IpAddressListManager): - def add_user_range(self, user_list: VectorAbon): - for usr in user_list: - self.add_user(usr) - - def remove_user_range(self, users: VectorAbon): - if not isinstance(users, (tuple, list, set)): - raise ValueError('*users* is used twice, generator does not fit') - queue_ids = (usr.queue_id for usr in users if usr is not None) - QueueManager.remove_range(self, queue_ids) - for ip in (user.ip for user in users if isinstance(user, AbonStruct)): - ip_list_entity = IpAddressListManager.find(self, ip, LIST_USERS_ALLOWED) - if ip_list_entity is not None and len(ip_list_entity) > 1: - IpAddressListManager.remove(self, ip_list_entity[0]['=.id']) - - def add_user(self, user: AbonStruct, *args): - if not isinstance(user.ip, IpStruct): - raise TypeError - if user.tariff is None: - return - if not isinstance(user.tariff, TariffStruct): - raise TypeError - try: - QueueManager.add(self, user) - except (NasNetworkError, NasFailedResult) as e: - print('Error:', e) - try: - IpAddressListManager.add(self, LIST_USERS_ALLOWED, user.ip) - except (NasNetworkError, NasFailedResult) as e: - print('Error:', e) - - def remove_user(self, user: AbonStruct): - QueueManager.remove(self, user) - firewall_ip_list_obj = IpAddressListManager.find(self, user.ip, LIST_USERS_ALLOWED) - if firewall_ip_list_obj is not None and len(firewall_ip_list_obj) > 1: - IpAddressListManager.remove(self, firewall_ip_list_obj[0]['=.id']) - - def update_user(self, user: AbonStruct, *args): - if not isinstance(user.ip, IpStruct): - raise TypeError - - find_res = IpAddressListManager.find(self, user.ip, LIST_USERS_ALLOWED) - queue = QueueManager.find(self, 'uid%d' % user.uid) - - if not user.is_active: - # если не активен - то и обновлять не надо - # но и выключить на всяк случай надо, а то вдруг был включён - if len(find_res) > 1: - # и если найден был - то удалим ip из разрешённых - IpAddressListManager.remove(self, find_res[0]['=.id']) - if queue is not None: - QueueManager.remove(self, user) - return - - # если нет услуги то её не должно быть и в nas - if user.tariff is None or not isinstance(user.tariff, TariffStruct): - if queue is not None: - QueueManager.remove(self, user) - return - - # если не найден (mikrotik возвращает пустой словарь в списке если ничего нет) - if len(find_res) < 2: - # добавим запись об абоненте - IpAddressListManager.add(self, LIST_USERS_ALLOWED, user.ip) - - # Проверяем шейпер - - if queue is None: - QueueManager.add(self, user) - return - if queue != user: - QueueManager.update(self, user) - - def ping(self, host, count=10) -> Optional[Tuple[int, int]]: - r = self._exec_cmd(( - '/ip/arp/print', - '?address=%s' % host - )) - if r == [{}]: - return - interface = r[0]['=interface'] - r = self._exec_cmd(( - '/ping', '=address=%s' % host, '=arp-ping=yes', '=interval=100ms', '=count=%d' % count, - '=interface=%s' % interface - )) - received, sent = int(r[-2:][0]['=received']), int(r[-2:][0]['=sent']) - return received, sent - - # Тарифы хранить нам не надо, так что методы тарифов ниже не реализуем - def add_tariff_range(self, tariff_list: VectorTariff): - pass - - # соответственно и удалять тарифы не надо - def remove_tariff_range(self, tariff_list: VectorTariff): - pass - - # и добавлять тоже - def add_tariff(self, tariff: TariffStruct): - pass - - # и обновлять - def update_tariff(self, tariff: TariffStruct): - pass - - def remove_tariff(self, tid: int): - pass - - def read_users(self) -> Iterable[AbonStruct]: - # shapes is ShapeItem - allowed_ips = set(IpAddressListManager.read_ips_iter(self, LIST_USERS_ALLOWED)) - queues = tuple(q for q in QueueManager.read_queue_iter(self) if q.ip in allowed_ips) - - ips_from_queues = set(q.ip for q in queues) - - # delete ip addresses that are in firewall/address-list and there are no corresponding in queues - diff = tuple(allowed_ips - ips_from_queues) - if len(diff) > 0: - IpAddressListManager.remove_range(self, diff) - - return queues diff --git a/devapp/base_intr.py b/devapp/base_intr.py index 0345527..5157232 100644 --- a/devapp/base_intr.py +++ b/devapp/base_intr.py @@ -66,8 +66,8 @@ class DevBase(object, metaclass=ABCMeta): def get_is_use_device_port(cls) -> bool: return cls.is_use_device_port - @classmethod - def validate_extra_snmp_info(cls, v: str) -> None: + @staticmethod + def validate_extra_snmp_info(v: str) -> None: """ Validate extra snmp field for each device. If validation failed then raise en exception from djing.lib.tln.ValidationError diff --git a/devapp/dev_types.py b/devapp/dev_types.py index ee07a11..c073063 100644 --- a/devapp/dev_types.py +++ b/devapp/dev_types.py @@ -103,14 +103,14 @@ class DLinkDevice(DevBase, SNMPBaseWorker): def get_template_name(self): return 'ports.html' - @classmethod - def validate_extra_snmp_info(cls, v: str) -> None: + @staticmethod + def validate_extra_snmp_info(v: str) -> None: # Dlink has no require snmp info pass def monitoring_template(self, *args, **kwargs) -> Optional[str]: device = self.db_instance - return plain_ip_device_mon_template(device, *args, **kwargs) + return plain_ip_device_mon_template(device) def register_device(self, extra_data: Dict): pass @@ -180,8 +180,8 @@ class OLTDevice(DevBase, SNMPBaseWorker): def get_template_name(self): return 'olt.html' - @classmethod - def validate_extra_snmp_info(cls, v: str) -> None: + @staticmethod + def validate_extra_snmp_info(v: str) -> None: # Olt has no require snmp info pass @@ -253,7 +253,7 @@ class OnuDevice(DevBase, SNMPBaseWorker): return {'err': "%s: %s" % (_('ONU not connected'), e)} @staticmethod - def validate_extra_snmp_info(cls, v: str) -> None: + def validate_extra_snmp_info(v: str) -> None: # DBCOM Onu have en integer snmp port try: int(v) @@ -439,8 +439,8 @@ class ZteOnuDevice(OnuDevice): def get_template_name(self): return 'onu_for_zte.html' - @classmethod - def validate_extra_snmp_info(cls, v: str) -> None: + @staticmethod + def validate_extra_snmp_info(v: str) -> None: # for example 268501760.5 try: fiber_num, onu_port = v.split('.') diff --git a/devapp/migrations/0001_initial.py b/devapp/migrations/0001_initial.py index 9ac128b..92c4075 100644 --- a/devapp/migrations/0001_initial.py +++ b/devapp/migrations/0001_initial.py @@ -20,8 +20,7 @@ class Migration(migrations.Migration): name='Device', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ( - 'ip_address', MyGenericIPAddressField(max_length=8, protocol='ipv4', verbose_name='Ip address')), + ('ip_address', MyGenericIPAddressField(max_length=8, protocol='ipv4', verbose_name='Ip address')), ('mac_addr', djing.fields.MACAddressField(blank=True, integer=True, null=True, unique=True, verbose_name='Mac address')), ('comment', models.CharField(max_length=256, verbose_name='Comment')), @@ -66,6 +65,6 @@ class Migration(migrations.Migration): ), migrations.AlterUniqueTogether( name='port', - unique_together=set([('device', 'num')]), + unique_together={('device', 'num')}, ), ] diff --git a/dialing.py b/dialing.py index e8b5a4c..7bd1858 100755 --- a/dialing.py +++ b/dialing.py @@ -147,15 +147,16 @@ def handle_shutdown(event, mngr): def signal_handler(signum, frame): - if signum != 10: return + if signum != 10: + return global outbox_messages outbox_messages = True -def handle_inbox_long_sms_message(event, manager): +def handle_inbox_long_sms_message(event, mngr): if event.has_header('Message'): pdu = event.get_header('Message') - pdu = re.sub(r'^\+CMGR\:\s\d\,\,\d{1,3}\\r\\n', '', pdu) + pdu = re.sub(r'^\+CMGR:\s\d,,\d{1,3}\\r\\n', '', pdu) sd = SmsDeliver(pdu) data = sd.data chunks_count = data.get('cnt') @@ -166,10 +167,10 @@ def handle_inbox_long_sms_message(event, manager): ) if chunks_count is not None: # more than 1 message - manager.push_text(sms=sms, ref=data.get('ref'), cnt=chunks_count) + mngr.push_text(sms=sms, ref=data.get('ref'), cnt=chunks_count) else: # one message - manager.save_sms(sms) + mngr.save_sms(sms) @pidfile(pidname='dialing.py.pid', piddir='/run') diff --git a/dialing_app/views.py b/dialing_app/views.py index 9c221bd..4fd757c 100644 --- a/dialing_app/views.py +++ b/dialing_app/views.py @@ -164,7 +164,7 @@ class SmsManager(SecureApiView): http_method_names = ('get',) @staticmethod - def bad_cmd(**kwargs) -> JSONType: + def bad_cmd() -> JSONType: return {'text': 'Command is not allowed'} @method_decorator(json_view) @@ -198,7 +198,7 @@ class SmsManager(SecureApiView): return {'text': 'Bad mid parameter'} @staticmethod - def get_new(**kwargs) -> JSONType: + def get_new() -> JSONType: msgs = SMSOut.objects.filter(status='nw').defer('status') res = [{ 'when': round(m.timestamp), diff --git a/msg_app/migrations/0001_initial.py b/msg_app/migrations/0001_initial.py index d51da03..686430c 100644 --- a/msg_app/migrations/0001_initial.py +++ b/msg_app/migrations/0001_initial.py @@ -109,6 +109,6 @@ class Migration(migrations.Migration): ), migrations.AlterUniqueTogether( name='messagestatus', - unique_together=set([('msg', 'user', 'state')]), + unique_together={('msg', 'user', 'state')}, ), ] diff --git a/msg_app/models.py b/msg_app/models.py index a0becae..526be03 100644 --- a/msg_app/models.py +++ b/msg_app/models.py @@ -123,7 +123,8 @@ class ConversationManager(models.Manager): ) return conversation - def get_new_messages_count(self, account): + @staticmethod + def get_new_messages_count(account): if isinstance(account, UserProfile): return MessageStatus.objects.filter(user=account, state='new').count() else: @@ -176,7 +177,8 @@ class Conversation(models.Model): except ChatException as e: raise MessageError(e) - def remove_message(self, msg): + @staticmethod + def remove_message(msg): if isinstance(msg, Message): m = msg else: diff --git a/requirements.txt b/requirements.txt index 0dd7879..86bab65 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,6 +24,7 @@ pyst2 django-jsonview django-bitfield transliterate +asterisk # django-xmlview for pay system allpay -e git://github.com/nerosketch/django-xmlview.git#egg=django-xmlview diff --git a/statistics/fields.py b/statistics/fields.py index f3ff199..82fcadf 100644 --- a/statistics/fields.py +++ b/statistics/fields.py @@ -35,7 +35,8 @@ class UnixDateTimeField(models.DateTimeField): else: return datetime.datetime.fromtimestamp(float(val)) - def _is_string(value, val): + @staticmethod + def _is_string(val): return isinstance(val, str) def get_db_prep_value(self, val, *args, **kwargs): diff --git a/systemd_units/webdav_backup.py b/systemd_units/webdav_backup.py index 68388e0..c5c50ee 100644 --- a/systemd_units/webdav_backup.py +++ b/systemd_units/webdav_backup.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import os from sys import argv from datetime import datetime, timedelta import webdav.client as wc @@ -15,7 +16,7 @@ def remove_old_files(border_time: datetime, client): for file in client.list('ISBackups'): fdate = datetime.strptime(file, 'djing%Y-%m-%d_%H.%M.%S.sql.gz') if fdate < border_time: - del_fname = 'ISBackups/%' % file + del_fname = os.path.join('ISBackups', file) client.clean(del_fname) print("rm %s" % del_fname) @@ -25,9 +26,12 @@ if __name__ == '__main__': try: client = wc.Client(options) if reqfile == 'rotate': - border_time = datetime.now() - timedelta(month=3) + border_time = datetime.now() - timedelta(weeks=12) remove_old_files(border_time, client) else: - client.upload_sync(remote_path="ISBackups/%s" % reqfile, local_path="/var/backups/%s" % reqfile) + client.upload_sync( + remote_path=os.path.join('ISBackups', reqfile), + local_path=os.path.join('var', 'backups', reqfile) + ) except wc.WebDavException as we: print(we, type(we))