Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LEIP-206] Add draft for webdav upload #299

Merged
merged 5 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ class CustomApplication : Application() {
// Initialize DataStore once for all settings
appSettings = lazyAppSettings
TrackingSettings.initialize(this) // energy_settings
CyfaceAuthenticator.settings = SynchronizationSettings( // synchronization
CyfaceAuthenticator.settings = DefaultSynchronizationSettings( // synchronization
this,
"https://example.com/api/v4", // Set the Data Collector URL
// Movebis variant can replace oauth config with `JsonObject()`
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ ext {
// When `android-app` is checkout out, `rootProject.uploaderVersion` in the submodules will point
// to `android-app/build.gradle` instead of `submodule/build.gradle`.
cyfaceSerializationVersion = "3.2.0"
cyfaceUploaderVersion = "1.2.0"
cyfaceUploaderVersion = "1.3.0"

// Android SDK versions
minSdkVersion = 21 // device support
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
Expand All @@ -46,6 +48,7 @@
import de.cyface.datacapturing.ui.UIListener;
import de.cyface.persistence.model.Modality;
import de.cyface.synchronization.CyfaceAuthenticator;
import de.cyface.synchronization.settings.DefaultSynchronizationSettings;

/**
* Checks if missing permissions are correctly detected before starting a service.
Expand Down Expand Up @@ -82,18 +85,26 @@ public class DataCapturingServiceWithoutPermissionTest {
* Initializes the object of class under test.
*/
@Before
public void setUp() {
public void setUp() throws JSONException {
context = InstrumentationRegistry.getInstrumentation().getTargetContext();

// The LOGIN_ACTIVITY is normally set to the LoginActivity of the SDK implementing app
CyfaceAuthenticator.LOGIN_ACTIVITY = AccountAuthenticatorActivity.class;
CyfaceAuthenticator.settings = new MockSynchronizationSettings();

//final String dataUploadServerAddress = "https://localhost:8080/api/v3";
final DataCapturingListener listener = new TestListener();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
try {
oocut = new CyfaceDataCapturingService(context, TestUtils.AUTHORITY, TestUtils.ACCOUNT_TYPE,
/*dataUploadServerAddress, TestUtils.oauthConfig(),*/ new IgnoreEventsStrategy(), listener, 100);
oocut = new CyfaceDataCapturingService(
context,
TestUtils.AUTHORITY,
TestUtils.ACCOUNT_TYPE,
/*dataUploadServerAddress, TestUtils.oauthConfig(),*/ new IgnoreEventsStrategy(),
listener,
100,
new CyfaceAuthenticator(context)
);
} catch (SetupException e) {
throw new IllegalStateException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ import de.cyface.persistence.model.Measurement
import de.cyface.persistence.model.MeasurementStatus
import de.cyface.persistence.model.Modality
import de.cyface.synchronization.CyfaceAuthenticator
import de.cyface.synchronization.settings.DefaultSynchronizationSettings
import de.cyface.testutils.SharedTestUtils.clearPersistenceLayer
import de.cyface.utils.Validate
import kotlinx.coroutines.runBlocking
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert.assertThat
import org.json.JSONObject
import org.junit.After
import org.junit.Before
import org.junit.Ignore
Expand Down Expand Up @@ -120,6 +122,7 @@ class DataCapturingServiceTest {

// The LOGIN_ACTIVITY is normally set to the LoginActivity of the SDK implementing app
CyfaceAuthenticator.LOGIN_ACTIVITY = Activity::class.java
CyfaceAuthenticator.settings = MockSynchronizationSettings()

// Add test account
val requestAccount = Account(TestUtils.DEFAULT_USERNAME, TestUtils.ACCOUNT_TYPE)
Expand All @@ -138,7 +141,8 @@ class DataCapturingServiceTest {
//TestUtils.oauthConfig(),
IgnoreEventsStrategy(),
testListener!!,
100
100,
CyfaceAuthenticator(context!!)
)
} catch (e: SetupException) {
throw IllegalStateException(e)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package de.cyface.datacapturing

import de.cyface.synchronization.settings.SynchronizationSettings
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import org.json.JSONObject

class MockSynchronizationSettings : SynchronizationSettings {

private var _collectorUrl = MutableStateFlow("https://TEST_URL/")
private var _oAuthConfig = MutableStateFlow(JSONObject().put("discovery_uri", "https://TEST_URL/").toString())

override suspend fun setCollectorUrl(value: String) {
_collectorUrl.value = value
}

override val collectorUrlFlow: Flow<String>
get() = _collectorUrl.asStateFlow()

override suspend fun setOAuthConfiguration(value: String) {
_oAuthConfig.value = value
}

override val oAuthConfigurationFlow: Flow<String>
get() = _oAuthConfig.asStateFlow()
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ import de.cyface.persistence.SetupException
import de.cyface.persistence.exception.NoSuchMeasurementException
import de.cyface.persistence.model.Modality
import de.cyface.synchronization.CyfaceAuthenticator
import de.cyface.synchronization.settings.DefaultSynchronizationSettings
import de.cyface.testutils.SharedTestUtils.clearPersistenceLayer
import kotlinx.coroutines.runBlocking
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert
import org.json.JSONObject
import org.junit.After
import org.junit.Before
import org.junit.Rule
Expand Down Expand Up @@ -140,6 +142,7 @@ class PingPongTest {
val testListener: DataCapturingListener = TestListener()
// The LOGIN_ACTIVITY is normally set to the LoginActivity of the SDK implementing app
CyfaceAuthenticator.LOGIN_ACTIVITY = Activity::class.java
CyfaceAuthenticator.settings = MockSynchronizationSettings()
InstrumentationRegistry.getInstrumentation().runOnMainSync {
dcs = try {
CyfaceDataCapturingService(
Expand All @@ -150,7 +153,8 @@ class PingPongTest {
//TestUtils.oauthConfig(),
IgnoreEventsStrategy(),
testListener,
100
100,
CyfaceAuthenticator(context!!)
)
} catch (e: SetupException) {
throw IllegalStateException(e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
package de.cyface.datacapturing;

import static de.cyface.datacapturing.Constants.TAG;
import static de.cyface.synchronization.CyfaceAuthenticator.LOGIN_ACTIVITY;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -30,8 +29,6 @@

import androidx.annotation.NonNull;

import org.json.JSONObject;

import de.cyface.datacapturing.backend.DataCapturingBackgroundService;
import de.cyface.datacapturing.exception.CorruptedMeasurementException;
import de.cyface.datacapturing.exception.DataCapturingException;
Expand All @@ -49,6 +46,7 @@
import de.cyface.persistence.strategy.DefaultLocationCleaning;
import de.cyface.persistence.strategy.DistanceCalculationStrategy;
import de.cyface.persistence.strategy.LocationCleaningStrategy;
import de.cyface.synchronization.LoginActivityProvider;
import de.cyface.synchronization.WiFiSurveyor;
import de.cyface.uploader.exception.SynchronisationException;
import de.cyface.utils.Validate;
Expand Down Expand Up @@ -85,15 +83,16 @@ public final class CyfaceDataCapturingService extends DataCapturingService {
* usually uses a frequency sightly higher than this value, e.g.: 101-103/s for 100 Hz.
*/
private CyfaceDataCapturingService(@NonNull final Context context,
@NonNull final String authority, @NonNull final String accountType,
@NonNull final EventHandlingStrategy eventHandlingStrategy,
@NonNull final DistanceCalculationStrategy distanceCalculationStrategy,
@NonNull final LocationCleaningStrategy locationCleaningStrategy,
@NonNull final DataCapturingListener capturingListener, final int sensorFrequency) {
@NonNull final String authority, @NonNull final String accountType,
@NonNull final EventHandlingStrategy eventHandlingStrategy,
@NonNull final DistanceCalculationStrategy distanceCalculationStrategy,
@NonNull final LocationCleaningStrategy locationCleaningStrategy,
@NonNull final DataCapturingListener capturingListener, final int sensorFrequency,
@NonNull final LoginActivityProvider loginActivityProvider) {
super(context, authority, accountType, eventHandlingStrategy,
new DefaultPersistenceLayer<>(context, new CapturingPersistenceBehaviour()),
distanceCalculationStrategy, locationCleaningStrategy, capturingListener, sensorFrequency);
if (LOGIN_ACTIVITY == null) {
if (loginActivityProvider.getLoginActivity() == null) {
throw new IllegalStateException("No LOGIN_ACTIVITY was set from the SDK using app.");
}
}
Expand All @@ -119,11 +118,12 @@ private CyfaceDataCapturingService(@NonNull final Context context,
public CyfaceDataCapturingService(@NonNull final Context context,
@NonNull final String authority, @NonNull final String accountType,
@NonNull final EventHandlingStrategy eventHandlingStrategy,
@NonNull final DataCapturingListener capturingListener, final int sensorFrequency)
@NonNull final DataCapturingListener capturingListener, final int sensorFrequency,
@NonNull final LoginActivityProvider loginActivityProvider)
throws SetupException {
this(context, authority, accountType, eventHandlingStrategy,
new DefaultDistanceCalculation(), new DefaultLocationCleaning(), capturingListener,
sensorFrequency);
sensorFrequency, loginActivityProvider);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ internal class MockedUploader : Uploader {
metaData: RequestMetaData,
measurementId: Long,
file: File,
fileName: String,
progressListener: UploadProgressListener
): Result {
progressListener.updatedProgress(1.0f) // 100%
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ class SyncPerformerTest {
metaData: RequestMetaData,
measurementId: Long,
file: File,
fileName: String,
progressListener: UploadProgressListener
): Result {
throw UploadFailed(ConflictException("Test ConflictException"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import org.junit.Before
import org.junit.Test

/**
* Test the inner workings of the [SynchronizationSettings].
* Test the inner workings of the [DefaultSynchronizationSettings].
*
* @author Armin Schnabel
* @version 1.0.0
Expand All @@ -42,7 +42,7 @@ class SynchronizationSettingsTest {
}

/**
* Test that checks that the [SynchronizationSettings] constructor only accepts API URls with
* Test that checks that the [DefaultSynchronizationSettings] constructor only accepts API URls with
* "https://" as protocol.
*
* We had twice the problem that SDK implementors used no or a false protocol. This test ensures
Expand All @@ -52,7 +52,7 @@ class SynchronizationSettingsTest {
@Test(expected = SetupException::class)
@Throws(SetupException::class)
fun testConstructor_doesNotAcceptUrlWithoutProtocol() {
SynchronizationSettings(
DefaultSynchronizationSettings(
context!!,
"localhost:8080/api/v3",
JSONObject()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ package de.cyface.synchronization

interface Auth {

/**
* Makes sure that a valid access token is available before executing the provided action.
*
* @param action The method which will be executed.
*/
fun performActionWithFreshTokens(
action: (
accessToken: String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ import kotlinx.coroutines.runBlocking
* against the Cyface server.
*
* **ATTENTION:** The [.getAuthToken] method is only
* called by the system if no token is cached. As our logic to invalidate token currently is in this method, we call it
* directly where we need a fresh token.
* called by the system if no token is cached. As our logic to invalidate tokens is in this method,
* we call it directly where we need a fresh token.
*
* @author Klemens Muthmann
* @author Armin Schnabel
* @version 5.1.1
* @since 2.0.0
*/
class CyfaceAuthenticator(private val context: Context) :
AbstractAccountAuthenticator(context) {
AbstractAccountAuthenticator(context), LoginActivityProvider {

private var auth: OAuth2 = OAuth2(context, settings)

Expand Down Expand Up @@ -171,4 +171,8 @@ class CyfaceAuthenticator(private val context: Context) :
*/
lateinit var settings: SynchronizationSettings
}

override fun getLoginActivity(): Class<out Activity?>? {
return LOGIN_ACTIVITY
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,10 @@ class CyfaceAuthenticatorService : Service() {
private var authenticator: CyfaceAuthenticator? = null

override fun onCreate() {
Log.d(TAG, "authenticator service on create!")

authenticator = CyfaceAuthenticator(this)
}

override fun onBind(intent: Intent): IBinder? {
Log.d(TAG, "authenticator service on bind")
return authenticator!!.iBinder
}

companion object {
/**
* Logging TAG to identify logs associated with the [WiFiSurveyor].
*/
@Suppress("unused") // we add and move logs often, so keep it

val TAG = Constants.TAG + ".authSvc"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2024 Cyface GmbH
*
* This file is part of the Cyface SDK for Android.
*
* The Cyface SDK for Android is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Cyface SDK for Android is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Cyface SDK for Android. If not, see <http://www.gnu.org/licenses/>.
*/
package de.cyface.synchronization

import android.app.Activity

interface LoginActivityProvider {
fun getLoginActivity(): Class<out Activity?>?
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ internal class SyncPerformer(private val context: Context, private val fromBackg
metaData,
measurementId,
file,
fileName,
progressListener
)

Expand Down
Loading
Loading