Esempio n. 1
0
    def test_sync_insufficient_space(self, now_mock, _, __,
                                     upload_chunked_mock):
        now_mock.return_value = timezone.make_aware(
            timezone.datetime(2000, 1, 1))

        # Crash the party, no more space available!
        upload_chunked_mock.side_effect = dropbox.exceptions.ApiError(
            12345,
            "UploadError('path', UploadWriteFailed(reason=WriteError('insufficient_space', None), ...)",
            'x', 'y')

        Notification.objects.all().delete()
        self.assertEqual(Notification.objects.count(), 0)

        with self.assertRaises(dropbox.exceptions.ApiError):
            dsmr_dropbox.services.sync_file(
                dropbox_settings=DropboxSettings.get_solo(),
                local_root_dir='/var/tmp/',
                abs_file_path='/var/tmp/fake')

        # Warning message should be created and next sync should be skipped ahead.
        self.assertEqual(Notification.objects.count(), 1)
        self.assertGreater(
            DropboxSettings.get_solo().next_sync,
            timezone.now() + timezone.timedelta(
                hours=settings.DSMRREADER_DROPBOX_ERROR_INTERVAL - 1))
Esempio n. 2
0
    def setUp(self):
        DropboxSettings.get_solo()
        DropboxSettings.objects.all().update(refresh_token='FAKE')

        self.schedule_process = ScheduledProcess.objects.get(
            module=settings.DSMRREADER_MODULE_DROPBOX_EXPORT)
        self.schedule_process.update(active=True,
                                     planned=timezone.make_aware(
                                         timezone.datetime(2000, 1, 1)))
Esempio n. 3
0
    def test_reschedule_dropbox_sync(self, now_mock):
        URL = reverse('admin:dsmr_backup_dropboxsettings_changelist')
        now_mock.return_value = timezone.make_aware(timezone.datetime(2019, 1, 1))  # Lock time

        DropboxSettings.get_solo()
        DropboxSettings.objects.all().update(next_sync=timezone.now() + timezone.timedelta(hours=1))
        self.assertFalse(DropboxSettings.objects.filter(next_sync__lte=timezone.now()).exists())

        # Just posting should reset it.
        response = self.client.post(URL)
        self.assertEqual(response.status_code, 302)
        self.assertTrue(DropboxSettings.objects.filter(next_sync__lte=timezone.now()).exists())
Esempio n. 4
0
    def test_sync(self, now_mock, upload_chunked_mock):
        now_mock.return_value = timezone.make_aware(timezone.datetime(2016, 1, 1))

        old_next_sync = timezone.now() - timezone.timedelta(weeks=1)
        dropbox_settings = DropboxSettings.get_solo()
        dropbox_settings.next_sync = old_next_sync
        dropbox_settings.save()

        self.assertFalse(upload_chunked_mock.called)
        self.assertIsNotNone(DropboxSettings.get_solo().access_token)

        dsmr_backup.services.dropbox.sync()
        self.assertTrue(upload_chunked_mock.called)
        self.assertNotEqual(DropboxSettings.get_solo().next_sync, old_next_sync)
    def test_sync(self, now_mock, upload_chunked_mock):
        now_mock.return_value = timezone.make_aware(timezone.datetime(2016, 1, 1))

        old_latest_sync = timezone.now() - timezone.timedelta(weeks=1)
        dropbox_settings = DropboxSettings.get_solo()
        dropbox_settings.latest_sync = old_latest_sync
        dropbox_settings.save()

        self.assertFalse(upload_chunked_mock.called)
        self.assertIsNotNone(DropboxSettings.get_solo().access_token)

        dsmr_backup.services.dropbox.sync()
        self.assertTrue(upload_chunked_mock.called)
        self.assertNotEqual(DropboxSettings.get_solo().latest_sync, old_latest_sync)
Esempio n. 6
0
def sync():
    dropbox_settings = DropboxSettings.get_solo()

    # Skip when either no token was entered.
    if not dropbox_settings.access_token:
        return

    if dropbox_settings.next_sync and dropbox_settings.next_sync > timezone.now(
    ):
        return

    backup_directory = dsmr_backup.services.backup.get_backup_directory()

    # Sync each file, recursively.
    for current_file in list_files_in_dir(directory=backup_directory):
        if not should_sync_file(current_file):
            continue

        sync_file(dropbox_settings=dropbox_settings,
                  local_root_dir=backup_directory,
                  abs_file_path=current_file)

    # Try again in a while.
    DropboxSettings.objects.update(
        latest_sync=timezone.now(),
        next_sync=timezone.now() +
        timezone.timedelta(hours=settings.DSMRREADER_DROPBOX_SYNC_INTERVAL))
Esempio n. 7
0
def get_dropbox_client(scheduled_process: ScheduledProcess) -> dropbox.Dropbox:
    """
    The Dropbox refresh token we locally store (after linking the user's Dropbox account) never expires. This method
    returns a new and authenticated instance of the Dropbox client that can be used for its (short) duration.
    """
    dropbox_settings = DropboxSettings.get_solo()
    dbx = dropbox.Dropbox(oauth2_refresh_token=dropbox_settings.refresh_token,
                          app_key=settings.DSMRREADER_DROPBOX_APP_KEY)

    try:
        dbx.refresh_access_token()
        dbx.check_user()  # No-op, just to verify the client/session.
    except Exception as error:
        logger.error(' - Dropbox error: %s', error)

        # Network errors should NOT reset the client side app token (see further below). Only API errors should do so.
        if not isinstance(error, dropbox.exceptions.DropboxException):
            scheduled_process.delay(minutes=1)
            raise

        logger.error(' - Removing Dropbox credentials due to API failure')
        message = _(
            "Unable to authenticate with Dropbox, removing credentials. Error: {}"
            .format(error))
        dsmr_frontend.services.display_dashboard_message(message=message)
        DropboxSettings.objects.update(refresh_token=None,
                                       )  # Does not trigger auto disable
        scheduled_process.disable()
        raise

    logger.info('Dropbox: Auth/user check OK')
    return dbx
Esempio n. 8
0
def sync():
    dropbox_settings = DropboxSettings.get_solo()

    # Skip when either no token was entered.
    if not dropbox_settings.access_token:
        return

    if dropbox_settings.next_sync and dropbox_settings.next_sync > timezone.now(
    ):
        return

    backup_directory = dsmr_backup.services.backup.get_backup_directory()

    # Just check for modified files since the last sync.
    for (_, _, filenames) in os.walk(backup_directory):
        for current_file in filenames:
            current_file_path = os.path.join(backup_directory, current_file)
            check_synced_file(file_path=current_file_path,
                              dropbox_settings=dropbox_settings)

    # Try again in a while.
    DropboxSettings.objects.update(
        latest_sync=timezone.now(),
        next_sync=timezone.now() +
        timezone.timedelta(hours=settings.DSMRREADER_DROPBOX_SYNC_INTERVAL))
Esempio n. 9
0
    def test_sync_insufficient_space(self, now_mock, upload_chunked_mock):
        now_mock.return_value = timezone.make_aware(
            timezone.datetime(2000, 1, 1))

        # Crash the party, no more space available!
        upload_chunked_mock.side_effect = dropbox.exceptions.ApiError(
            12345,
            "UploadError('path', UploadWriteFailed(reason=WriteError('insufficient_space', None), ...)",
            'x', 'y')

        Notification.objects.all().delete()
        self.assertEqual(Notification.objects.count(), 0)

        with self.assertRaises(dropbox.exceptions.ApiError):
            dsmr_backup.services.dropbox.sync()

        # Warning message should be created and next sync should be skipped ahead.
        self.assertEqual(Notification.objects.count(), 1)
        self.assertGreater(
            DropboxSettings.get_solo().latest_sync,
            timezone.now() + timezone.timedelta(
                hours=settings.DSMRREADER_DROPBOX_ERROR_INTERVAL - 1))

        # Test alternate path.
        DropboxSettings.objects.update(latest_sync=timezone.now() -
                                       timezone.timedelta(hours=24))
        upload_chunked_mock.side_effect = dropbox.exceptions.ApiError(
            12345,
            "UploadError('path', UploadWriteFailed(reason=WriteError('other_error', None), ...)",
            'x', 'y')

        with self.assertRaises(dropbox.exceptions.ApiError):
            dsmr_backup.services.dropbox.sync()

        self.assertEqual(Notification.objects.count(), 1)
Esempio n. 10
0
def upload_chunked(file_path):
    """ Uploads a file in chucks to Dropbox, allowing it to resume on (connection) failure. """
    dropbox_settings = DropboxSettings.get_solo()
    file_name = os.path.split(file_path)[-1]

    # From Dropbox docs.
    retries = 3
    client = DropboxClient(dropbox_settings.access_token)

    size = os.stat(file_path).st_size
    file_handle = open(file_path, 'rb')

    uploader = client.get_chunked_uploader(file_handle, size)

    while uploader.offset < size:
        try:
            uploader.upload_chunked(chunk_size=1 * 1024 * 1024)
        except rest.ErrorResponse:   # pragma: no cover
            retries -= 1  # pragma: no cover

            if retries == 0:  # pragma: no cover
                raise IOError("Failed to upload to dropbox")  # pragma: no cover

    # This will commit the file and persist it in Dropbox. Due to rotating backups we MUST override.
    uploader.finish(file_name, overwrite=True)
Esempio n. 11
0
def status_info():
    """ Returns the status info of the application. """
    capabilities = get_capabilities()
    status = {
        'capabilities': capabilities,
        'electricity': get_electricity_status(capabilities),
        'gas': get_gas_status(capabilities),
        'readings': get_reading_status(),
        'statistics': get_statistics_status(),
        'tools': {
            'backup': {
                'enabled': False,
                'latest_backup': None,
            },
            'dropbox': {
                'enabled': False,
                'latest_sync': None,
            },
            'pvoutput': {
                'enabled': False,
                'latest_sync': None,
            },
            'mindergas': {
                'enabled': False,
                'latest_sync': None,
            },
            'mqtt': get_mqtt_status(),
        }
    }

    # (External) tools below.
    backup_settings = BackupSettings.get_solo()

    if backup_settings.daily_backup:
        status['tools']['backup']['enabled'] = True
        status['tools']['backup'][
            'latest_backup'] = backup_settings.latest_backup

    dropbox_settings = DropboxSettings.get_solo()

    if dropbox_settings.access_token:
        status['tools']['dropbox']['enabled'] = True
        status['tools']['dropbox'][
            'latest_sync'] = dropbox_settings.latest_sync

    pvoutput_settings = PVOutputAddStatusSettings.get_solo()

    if pvoutput_settings.export:
        status['tools']['pvoutput']['enabled'] = True
        status['tools']['pvoutput'][
            'latest_sync'] = pvoutput_settings.latest_sync

    mindergas_settings = MinderGasSettings.get_solo()

    if mindergas_settings.export:
        status['tools']['mindergas']['enabled'] = True
        status['tools']['mindergas'][
            'latest_sync'] = mindergas_settings.latest_sync

    return status
Esempio n. 12
0
    def test_sync(self, now_mock, _, should_mock, sync_file_mock):
        now_mock.return_value = timezone.make_aware(
            timezone.datetime(2016, 1, 1))
        should_mock.side_effect = [
            False, True, True, True, True, True, True, True, True, True, True
        ]  # Both branches.

        old_next_sync = timezone.now() - timezone.timedelta(weeks=1)
        DropboxSettings.objects.all().update(next_sync=old_next_sync)

        self.assertFalse(sync_file_mock.called)
        self.assertIsNotNone(DropboxSettings.get_solo().access_token)

        dsmr_dropbox.services.sync()
        self.assertTrue(sync_file_mock.called)
        self.assertNotEqual(DropboxSettings.get_solo().next_sync,
                            old_next_sync)
Esempio n. 13
0
    def test_sync_disabled(self, upload_chunked_mock):
        dropbox_settings = DropboxSettings.get_solo()
        dropbox_settings.access_token = None
        dropbox_settings.save()

        self.assertFalse(upload_chunked_mock.called)

        dsmr_backup.services.dropbox.sync()
        self.assertFalse(upload_chunked_mock.called)
Esempio n. 14
0
    def test_sync_disabled(self, upload_chunked_mock):
        dropbox_settings = DropboxSettings.get_solo()
        dropbox_settings.access_token = None
        dropbox_settings.save()

        self.assertFalse(upload_chunked_mock.called)

        dsmr_backup.services.dropbox.sync()
        self.assertFalse(upload_chunked_mock.called)
Esempio n. 15
0
    def test_sync_initial(self, now_mock, upload_chunked_mock):
        now_mock.return_value = timezone.make_aware(timezone.datetime(2016, 1, 1))

        # Initial project state.
        dropbox_settings = DropboxSettings.get_solo()
        dropbox_settings.next_sync = None
        dropbox_settings.save()

        dsmr_backup.services.dropbox.sync()
        self.assertTrue(upload_chunked_mock.called)
Esempio n. 16
0
 def get_context_data(self, **kwargs):
     context_data = super(Configuration, self).get_context_data(**kwargs)
     context_data['api_settings'] = APISettings.get_solo()
     context_data['consumption_settings'] = ConsumptionSettings.get_solo()
     context_data['datalogger_settings'] = DataloggerSettings.get_solo()
     context_data['frontend_settings'] = FrontendSettings.get_solo()
     context_data['weather_settings'] = WeatherSettings.get_solo()
     context_data['backup_settings'] = BackupSettings.get_solo()
     context_data['dropbox_settings'] = DropboxSettings.get_solo()
     context_data['mindergas_settings'] = MinderGasSettings.get_solo()
     return context_data
Esempio n. 17
0
    def test_sync_latest_sync(self, now_mock, get_backup_directory_mock):
        """ Test whether syncs are limited to intervals. """
        now_mock.return_value = timezone.make_aware(timezone.datetime(2016, 1, 1))

        dropbox_settings = DropboxSettings.get_solo()
        dropbox_settings.latest_sync = timezone.now() + timezone.timedelta(minutes=1)
        dropbox_settings.save()

        self.assertFalse(get_backup_directory_mock.called)

        dsmr_backup.services.dropbox.sync()
        self.assertFalse(get_backup_directory_mock.called)
Esempio n. 18
0
    def test_sync_latest_sync(self, now_mock, get_backup_directory_mock):
        """ Test whether syncs are limited to intervals. """
        now_mock.return_value = timezone.make_aware(timezone.datetime(2016, 1, 1))

        dropbox_settings = DropboxSettings.get_solo()
        dropbox_settings.next_sync = timezone.now() + timezone.timedelta(minutes=1)
        dropbox_settings.save()

        self.assertFalse(get_backup_directory_mock.called)

        dsmr_backup.services.dropbox.sync()
        self.assertFalse(get_backup_directory_mock.called)
Esempio n. 19
0
    def test_sync_invalid_access_token(self, now_mock, _, __,
                                       upload_chunked_mock):
        now_mock.return_value = timezone.make_aware(
            timezone.datetime(2000, 1, 1))

        # Crash the party, no more space available!
        upload_chunked_mock.side_effect = dropbox.exceptions.AuthError(
            12345, "AuthError('xxx', AuthError('invalid_access_token', None))")

        Notification.objects.all().delete()
        self.assertEqual(Notification.objects.count(), 0)

        with self.assertRaises(dropbox.exceptions.AuthError):
            dsmr_dropbox.services.sync_file(
                dropbox_settings=DropboxSettings.get_solo(),
                local_root_dir='/var/tmp/',
                abs_file_path='/var/tmp/fake')

        # Warning message should be created and credentials should be wiped.
        dropbox_settings = DropboxSettings.get_solo()
        self.assertEqual(Notification.objects.count(), 1)
        self.assertIsNone(dropbox_settings.access_token)
        self.assertEqual(dropbox_settings.latest_sync, timezone.now())
        self.assertIsNone(dropbox_settings.next_sync)
Esempio n. 20
0
def upload_chunked(file_path):
    """ Uploads a file in chucks to Dropbox, allowing it to resume on (connection) failure. """
    # For backend logging in Supervisor.
    logger.info(' - Uploading file to Dropbox: %s', file_path)

    dropbox_settings = DropboxSettings.get_solo()
    file_name = os.path.split(file_path)[-1]
    dest_path = '/{}'.format(
        file_name
    )  # The slash indicates it's relative to the root of app folder.

    dbx = dropbox.Dropbox(dropbox_settings.access_token)
    write_mode = dropbox.files.WriteMode.overwrite

    file_handle = open(file_path, 'rb')
    file_size = os.path.getsize(file_path)

    # Many thanks to https://stackoverflow.com/documentation/dropbox-api/409/uploading-a-file/1927/uploading-a-file-usin
    # g-the-dropbox-python-sdk#t=201610181733061624381
    CHUNK_SIZE = 2 * 1024 * 1024

    # Small uploads should be transfers at one go.
    if file_size <= CHUNK_SIZE:
        dbx.files_upload(file_handle.read(), dest_path, mode=write_mode)

    # Large uploads can be sent in chunks, by creating a session allowing multiple separate uploads.
    else:
        upload_session_start_result = dbx.files_upload_session_start(
            file_handle.read(CHUNK_SIZE))

        cursor = dropbox.files.UploadSessionCursor(
            session_id=upload_session_start_result.session_id,
            offset=file_handle.tell())
        commit = dropbox.files.CommitInfo(path=dest_path, mode=write_mode)

        # We keep sending the data in chunks, until we reach the last one, then we instruct Dropbox to finish the upload
        # by combining all the chunks sent previously.
        while file_handle.tell() < file_size:
            if (file_size - file_handle.tell()) <= CHUNK_SIZE:
                dbx.files_upload_session_finish(file_handle.read(CHUNK_SIZE),
                                                cursor, commit)
            else:
                dbx.files_upload_session_append(file_handle.read(CHUNK_SIZE),
                                                cursor.session_id,
                                                cursor.offset)
                cursor.offset = file_handle.tell()

    file_handle.close()
Esempio n. 21
0
    def test_sync(self, now_mock, _, should_mock, sync_file_mock,
                  list_files_in_dir_mock, *mocks):
        now_mock.return_value = timezone.make_aware(
            timezone.datetime(2016, 1, 1))
        should_mock.side_effect = [False, True]  # Both branches.
        list_files_in_dir_mock.return_value = ['/tmp/fake1', '/tmp/fake2']

        self.assertFalse(sync_file_mock.called)
        self.assertIsNotNone(DropboxSettings.get_solo().refresh_token)

        dsmr_dropbox.services.run(self.schedule_process)
        self.assertTrue(sync_file_mock.called)

        self.schedule_process.refresh_from_db()
        self.assertEqual(
            self.schedule_process.planned,
            timezone.make_aware(timezone.datetime(2016, 1, 1, hour=1)))
Esempio n. 22
0
def check_dropbox_sync(**kwargs):
    from dsmr_backup.models.settings import DropboxSettings

    dropbox_settings = DropboxSettings.get_solo()

    if not dropbox_settings.access_token:
        return

    offset = timezone.now() - timezone.timedelta(
        minutes=settings.
        DSMRREADER_STATUS_ALLOWED_SCHEDULED_PROCESS_LAGG_IN_MINUTES)

    if dropbox_settings.next_sync > offset:
        return

    return MonitoringStatusIssue(
        __name__, _('Waiting for the next Dropbox sync to be executed'),
        dropbox_settings.next_sync)
Esempio n. 23
0
 def get_context_data(self, **kwargs):
     context_data = super(Configuration, self).get_context_data(**kwargs)
     # 20+ queries, we should cache this at some point.
     context_data.update(
         dict(
             api_settings=APISettings.get_solo(),
             backend_settings=BackendSettings.get_solo(),
             backup_settings=BackupSettings.get_solo(),
             consumption_settings=ConsumptionSettings.get_solo(),
             datalogger_settings=DataloggerSettings.get_solo(),
             dropbox_settings=DropboxSettings.get_solo(),
             email_settings=EmailSettings.get_solo(),
             frontend_settings=FrontendSettings.get_solo(),
             mindergas_settings=MinderGasSettings.get_solo(),
             mqtt_broker_settings=MQTTBrokerSettings.get_solo(),
             mqtt_jsondaytotals_settings=JSONDayTotalsMQTTSettings.get_solo(
             ),
             mqtt_splittopicdaytotals_settings=
             SplitTopicDayTotalsMQTTSettings.get_solo(),
             mqtt_jsoncurrentperiodtotals_settings=
             JSONCurrentPeriodTotalsMQTTSettings.get_solo(),
             mqtt_splittopiccurrentperiodtotals_settings=
             SplitTopicCurrentPeriodTotalsMQTTSettings.get_solo(),
             mqtt_jsongasconsumption_settings=JSONGasConsumptionMQTTSettings
             .get_solo(),
             mqtt_splittopicgasconsumption_settings=
             SplitTopicGasConsumptionMQTTSettings.get_solo(),
             mqtt_splittopicmeterstatistics_settings=
             SplitTopicMeterStatisticsMQTTSettings.get_solo(),
             mqtt_jsontelegram_settings=JSONTelegramMQTTSettings.get_solo(),
             mqtt_rawtelegram_settings=RawTelegramMQTTSettings.get_solo(),
             mqtt_splittopictelegram_settings=SplitTopicTelegramMQTTSettings
             .get_solo(),
             notification_settings=NotificationSetting.get_solo(),
             pvoutput_api_settings=PVOutputAPISettings.get_solo(),
             pvoutput_addstatus_settings=PVOutputAddStatusSettings.get_solo(
             ),
             retention_settings=RetentionSettings.get_solo(),
             weather_settings=WeatherSettings.get_solo(),
             influxdb_settings=InfluxdbIntegrationSettings.get_solo(),
         ))
     return context_data
Esempio n. 24
0
    def get_redirect_url(self, *args, **kwargs):
        dropbox_settings = DropboxSettings.get_solo()

        auth_flow = dropbox.DropboxOAuth2FlowNoRedirect(  # noqa: S106
            settings.DSMRREADER_DROPBOX_APP_KEY,
            use_pkce=True,
            token_access_type='offline',
            timeout=settings.DSMRREADER_CLIENT_TIMEOUT)
        authorize_url = auth_flow.start()

        # We need the data generated by the SDK (auth challenge) on oauth completion. So we'll serialize it.
        serialized_auth_flow = pickle.dumps(auth_flow)

        dropbox_settings.update(
            serialized_auth_flow=serialized_auth_flow,
            # Reset all other fields as well.
            refresh_token=None,
            one_time_authorization_code=None)

        return authorize_url
Esempio n. 25
0
    def test_sync_last_modified(self, now_mock, upload_chunked_mock, get_backup_directory_mock):
        """ Test whether syncs are skipped when file was not modified. """
        now_mock.return_value = timezone.make_aware(timezone.datetime(2016, 1, 1))

        dropbox_settings = DropboxSettings.get_solo()
        dropbox_settings.latest_sync = timezone.now() - timezone.timedelta(weeks=1)
        dropbox_settings.save()

        with tempfile.TemporaryDirectory() as temp_dir:
            get_backup_directory_mock.return_value = temp_dir
            temp_file = tempfile.NamedTemporaryFile(dir=temp_dir, delete=False)
            temp_file.write(b'Meh.')
            temp_file.flush()

            # 1420070400: 01 Jan 2015 00:00:00 GMT
            os.utime(temp_file.name, times=(1420070400, 1420070400))
            self.assertFalse(upload_chunked_mock.called)

            # File should be ignored, as its modification timestamp is before latest sync.
            dsmr_backup.services.dropbox.sync()
            self.assertFalse(upload_chunked_mock.called)
Esempio n. 26
0
    def test_sync_last_modified(self, now_mock, upload_chunked_mock, get_backup_directory_mock):
        """ Test whether syncs are skipped when file was not modified. """
        now_mock.return_value = timezone.make_aware(timezone.datetime(2016, 1, 1))

        dropbox_settings = DropboxSettings.get_solo()
        dropbox_settings.latest_sync = timezone.now() - timezone.timedelta(weeks=1)
        dropbox_settings.save()

        with tempfile.TemporaryDirectory() as temp_dir:
            get_backup_directory_mock.return_value = temp_dir
            temp_file = tempfile.NamedTemporaryFile(dir=temp_dir, delete=False)
            temp_file.write(b'Meh.')
            temp_file.flush()

            # 1420070400: 01 Jan 2015 00:00:00 GMT
            os.utime(temp_file.name, times=(1420070400, 1420070400))
            self.assertFalse(upload_chunked_mock.called)

            # File should be ignored, as it's modification timestamp is before latest sync.
            dsmr_backup.services.dropbox.sync()
            self.assertFalse(upload_chunked_mock.called)
Esempio n. 27
0
    def test_check_access_token(self, now_mock, users_get_space_usage_mock):
        now_mock.return_value = timezone.make_aware(
            timezone.datetime(2020, 1, 1))

        for current_class in (dropbox.exceptions.BadInputError,
                              dropbox.exceptions.AuthError):
            DropboxSettings.objects.all().update(next_sync=timezone.now(),
                                                 access_token='invalid-token')
            users_get_space_usage_mock.side_effect = current_class(
                12345, "Some error")

            Notification.objects.all().delete()
            self.assertEqual(Notification.objects.count(), 0)

            with self.assertRaises(current_class):
                dsmr_dropbox.services.check_access_token('dummy')

            # Warning message should be created and next sync should be skipped ahead.
            self.assertEqual(Notification.objects.count(), 1)

            self.assertIsNone(DropboxSettings.get_solo().next_sync)
Esempio n. 28
0
def sync():
    dropbox_settings = DropboxSettings.get_solo()

    # Skip when either no token was entered.
    if not dropbox_settings.access_token:
        return

    #  Or when we already synced within the last hour.
    next_sync_interval = None

    if dropbox_settings.latest_sync:
        next_sync_interval = dropbox_settings.latest_sync + timezone.timedelta(
            hours=settings.DSMR_DROPBOX_SYNC_INTERVAL
        )

    if next_sync_interval and timezone.now() < next_sync_interval:
        return

    backup_directory = dsmr_backup.services.backup.get_backup_directory()

    # Just check for modified files since the last sync.
    for (_, _, filenames) in os.walk(backup_directory):
        for current_file in filenames:
            current_file_path = os.path.join(backup_directory, current_file)
            file_stats = os.stat(current_file_path)

            # Ignore empty files.
            if file_stats.st_size == 0:
                continue

            last_modified = timezone.datetime.fromtimestamp(file_stats.st_mtime)
            last_modified = timezone.make_aware(last_modified)

            # Ignore when file was not altered since last sync.
            if dropbox_settings.latest_sync and last_modified < dropbox_settings.latest_sync:
                continue

            upload_chunked(file_path=current_file_path)

    DropboxSettings.objects.update(latest_sync=timezone.now())
Esempio n. 29
0
def sync():
    dropbox_settings = DropboxSettings.get_solo()

    # Skip when either no token was entered.
    if not dropbox_settings.access_token:
        return

    #  Or when we already synced within the last hour.
    next_sync_interval = None

    if dropbox_settings.latest_sync:
        next_sync_interval = dropbox_settings.latest_sync + timezone.timedelta(
            hours=settings.DSMRREADER_DROPBOX_SYNC_INTERVAL)

    if next_sync_interval and timezone.now() < next_sync_interval:
        return

    backup_directory = dsmr_backup.services.backup.get_backup_directory()

    # Just check for modified files since the last sync.
    for (_, _, filenames) in os.walk(backup_directory):
        for current_file in filenames:
            current_file_path = os.path.join(backup_directory, current_file)
            file_stats = os.stat(current_file_path)

            # Ignore empty files.
            if file_stats.st_size == 0:
                continue

            last_modified = timezone.datetime.fromtimestamp(
                file_stats.st_mtime)
            last_modified = timezone.make_aware(last_modified)

            # Ignore when file was not altered since last sync.
            if dropbox_settings.latest_sync and last_modified < dropbox_settings.latest_sync:
                continue

            upload_chunked(file_path=current_file_path)

    DropboxSettings.objects.update(latest_sync=timezone.now())
Esempio n. 30
0
    def test_upload_chunked(self, session_finish_mock, session_append_mock,
                            session_start_mock, files_upload_mock):
        dropbox_settings = DropboxSettings.get_solo()

        DATA = b'Lots of data.'
        session_start_result = mock.MagicMock()
        type(session_start_result).session_id = mock.PropertyMock(
            side_effect=['session-xxxxx'])
        session_start_mock.return_value = session_start_result

        self.assertFalse(files_upload_mock.called)
        self.assertFalse(session_start_mock.called)
        self.assertFalse(session_append_mock.called)
        self.assertFalse(session_finish_mock.called)

        with tempfile.NamedTemporaryFile() as temp_file:
            temp_file.write(DATA)
            temp_file.flush()

            dsmr_dropbox.services.upload_chunked(dropbox_settings,
                                                 temp_file.name,
                                                 '/remote-path.ext')

        # Only small file upload should be called.
        self.assertTrue(files_upload_mock.called)
        self.assertFalse(session_start_mock.called)
        self.assertFalse(session_append_mock.called)
        self.assertFalse(session_finish_mock.called)

        # Large file upload (> 2 MB chunks).
        with tempfile.NamedTemporaryFile() as temp_file:
            temp_file.write(DATA * 2 * 1024 * 1024)
            temp_file.flush()

            dsmr_dropbox.services.upload_chunked(dropbox_settings,
                                                 temp_file.name,
                                                 '/remote-path.ext')
        self.assertTrue(session_start_mock.called)
        self.assertTrue(session_append_mock.called)
        self.assertTrue(session_finish_mock.called)
Esempio n. 31
0
def run(scheduled_process: ScheduledProcess) -> None:
    dropbox_settings = DropboxSettings.get_solo()

    if not dropbox_settings.refresh_token:
        # Should not happen, safe fallback
        scheduled_process.disable()
        return

    dropbox_client = get_dropbox_client(scheduled_process=scheduled_process)
    backup_directory = dsmr_backup.services.backup.get_backup_directory()

    # Sync each file, recursively.
    for current_file in list_files_in_dir(directory=backup_directory):
        if not should_sync_file(current_file):
            continue

        sync_file(scheduled_process=scheduled_process,
                  dropbox_client=dropbox_client,
                  local_root_dir=backup_directory,
                  abs_file_path=current_file)

    scheduled_process.delay(hours=settings.DSMRREADER_DROPBOX_SYNC_INTERVAL)
Esempio n. 32
0
 def test_check_dropbox_sync_disabled(self):
     DropboxSettings.get_solo().update(
         access_token=None,
         next_sync=timezone.now() - timezone.timedelta(minutes=1)
     )
     self.assertIsNone(check_dropbox_sync())
Esempio n. 33
0
 def setUp(self):
     DropboxSettings.get_solo().update(
         access_token='1234',
         next_sync=timezone.now()
     )
Esempio n. 34
0
 def setUp(self):
     DropboxSettings.get_solo()
     DropboxSettings.objects.all().update(access_token='FAKE')
Esempio n. 35
0
 def setUp(self):
     dropbox_settings = DropboxSettings.get_solo()
     dropbox_settings.access_token = 'FAKE'
     dropbox_settings.save()
Esempio n. 36
0
 def setUp(self):
     dropbox_settings = DropboxSettings.get_solo()
     dropbox_settings.access_token = 'FAKE'
     dropbox_settings.save()