From 0541aacdff5df60e39f731f7609322cb9d3531d3 Mon Sep 17 00:00:00 2001 From: Paul Hawke Date: Fri, 26 Jan 2024 08:11:44 -0600 Subject: [PATCH] Move login client out of the data-client (#5476) --- app/build.gradle | 1 + .../free/nrw/commons/CommonsAppAdapter.java | 14 +--- .../free/nrw/commons/auth/LoginActivity.java | 11 +-- .../free/nrw/commons/auth/LogoutClient.java | 36 -------- .../free/nrw/commons/auth/SessionManager.java | 3 +- .../nrw/commons/auth/csrf/CsrfTokenClient.kt | 22 +++-- .../nrw/commons/auth}/login/LoginClient.java | 16 ++-- .../nrw/commons/auth/login/LoginInterface.kt | 45 ++++++++++ .../commons/auth}/login/LoginOAuthResult.java | 2 +- .../auth}/login/LoginResetPasswordResult.java | 2 +- .../nrw/commons/auth}/login/LoginResult.java | 2 +- .../free/nrw/commons/di/NetworkingModule.java | 8 +- .../nrw/commons/CommonsAppAdapterUnitTest.kt | 9 +- .../fr/free/nrw/commons/TestAppAdapter.java | 5 -- .../commons/auth/LoginActivityUnitTests.kt | 4 +- .../free/nrw/commons/auth/LogoutClientTest.kt | 45 ---------- .../commons/auth/SessionManagerUnitTests.kt | 2 +- .../commons/auth/csrf/CsrfTokenClientTest.kt | 4 +- .../login/UserExtendedInfoClientTest.java | 84 +++++++++++++++++++ app/src/test/res/raw/user_extended_info.json | 19 +++++ .../main/java/org/wikipedia/AppAdapter.java | 2 - .../org/wikipedia/dataclient/Service.java | 49 ----------- .../login/UserExtendedInfoClientTest.java | 44 ---------- 23 files changed, 195 insertions(+), 234 deletions(-) delete mode 100644 app/src/main/java/fr/free/nrw/commons/auth/LogoutClient.java rename {data-client/src/main/java/org/wikipedia => app/src/main/java/fr/free/nrw/commons/auth}/login/LoginClient.java (93%) create mode 100644 app/src/main/java/fr/free/nrw/commons/auth/login/LoginInterface.kt rename {data-client/src/main/java/org/wikipedia => app/src/main/java/fr/free/nrw/commons/auth}/login/LoginOAuthResult.java (91%) rename {data-client/src/main/java/org/wikipedia => app/src/main/java/fr/free/nrw/commons/auth}/login/LoginResetPasswordResult.java (91%) rename {data-client/src/main/java/org/wikipedia => app/src/main/java/fr/free/nrw/commons/auth}/login/LoginResult.java (97%) delete mode 100644 app/src/test/kotlin/fr/free/nrw/commons/auth/LogoutClientTest.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/login/UserExtendedInfoClientTest.java create mode 100644 app/src/test/res/raw/user_extended_info.json delete mode 100644 data-client/src/test/java/org/wikipedia/login/UserExtendedInfoClientTest.java diff --git a/app/build.gradle b/app/build.gradle index 94a28afe8..1189a4861 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,6 +27,7 @@ dependencies { } implementation 'com.squareup.retrofit2:retrofit:2.8.1' implementation "com.squareup.retrofit2:converter-gson:2.8.1" + implementation "com.squareup.retrofit2:adapter-rxjava2:2.8.1" implementation 'com.squareup.okio:okio:2.2.2' implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' implementation 'io.reactivex.rxjava2:rxjava:2.2.3' diff --git a/app/src/main/java/fr/free/nrw/commons/CommonsAppAdapter.java b/app/src/main/java/fr/free/nrw/commons/CommonsAppAdapter.java index 8b6ca47e0..1439147ec 100644 --- a/app/src/main/java/fr/free/nrw/commons/CommonsAppAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/CommonsAppAdapter.java @@ -1,17 +1,14 @@ package fr.free.nrw.commons; import androidx.annotation.NonNull; - +import fr.free.nrw.commons.auth.SessionManager; +import fr.free.nrw.commons.kvstore.JsonKvStore; +import okhttp3.OkHttpClient; import org.wikipedia.AppAdapter; import org.wikipedia.dataclient.SharedPreferenceCookieManager; import org.wikipedia.dataclient.WikiSite; import org.wikipedia.json.GsonMarshaller; import org.wikipedia.json.GsonUnmarshaller; -import org.wikipedia.login.LoginResult; - -import fr.free.nrw.commons.auth.SessionManager; -import fr.free.nrw.commons.kvstore.JsonKvStore; -import okhttp3.OkHttpClient; public class CommonsAppAdapter extends AppAdapter { private final int DEFAULT_THUMB_SIZE = 640; @@ -60,11 +57,6 @@ public class CommonsAppAdapter extends AppAdapter { return sessionManager.getPassword(); } - @Override - public void updateAccount(@NonNull LoginResult result) { - sessionManager.updateAccount(result); - } - @Override public SharedPreferenceCookieManager getCookies() { if (!preferences.contains(COOKIE_STORE_NAME)) { diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java index e911cef4b..80b55e7dc 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java @@ -25,6 +25,9 @@ import androidx.appcompat.app.AppCompatDelegate; import androidx.core.app.NavUtils; import androidx.core.content.ContextCompat; +import fr.free.nrw.commons.auth.login.LoginClient; +import fr.free.nrw.commons.auth.login.LoginInterface; +import fr.free.nrw.commons.auth.login.LoginResult; import fr.free.nrw.commons.databinding.ActivityLoginBinding; import fr.free.nrw.commons.utils.ActivityUtils; import java.util.Locale; @@ -32,9 +35,7 @@ import org.wikipedia.AppAdapter; import org.wikipedia.dataclient.ServiceFactory; import org.wikipedia.dataclient.WikiSite; import org.wikipedia.dataclient.mwapi.MwQueryResponse; -import org.wikipedia.login.LoginClient; -import org.wikipedia.login.LoginClient.LoginCallback; -import org.wikipedia.login.LoginResult; +import fr.free.nrw.commons.auth.login.LoginClient.LoginCallback; import javax.inject.Inject; import javax.inject.Named; @@ -231,7 +232,7 @@ public class LoginActivity extends AccountAuthenticatorActivity { private void doLogin(String username, String password, String twoFactorCode) { progressDialog.show(); - loginToken = ServiceFactory.get(commonsWikiSite).getLoginToken(); + loginToken = ServiceFactory.get(commonsWikiSite, LoginInterface.class).getLoginToken(); loginToken.enqueue( new Callback() { @Override @@ -313,7 +314,7 @@ public class LoginActivity extends AccountAuthenticatorActivity { } compositeDisposable.clear(); sessionManager.setUserLoggedIn(true); - AppAdapter.get().updateAccount(loginResult); + sessionManager.updateAccount(loginResult); progressDialog.dismiss(); showSuccessAndDismissDialog(); startMainActivity(); diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LogoutClient.java b/app/src/main/java/fr/free/nrw/commons/auth/LogoutClient.java deleted file mode 100644 index 5b3ed08d7..000000000 --- a/app/src/main/java/fr/free/nrw/commons/auth/LogoutClient.java +++ /dev/null @@ -1,36 +0,0 @@ -package fr.free.nrw.commons.auth; - - -import org.wikipedia.dataclient.Service; -import org.wikipedia.dataclient.mwapi.MwPostResponse; - -import java.util.Objects; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - -import io.reactivex.Observable; - -/** - * Handler for logout - */ -@Singleton -public class LogoutClient { - - private final Service service; - - @Inject - public LogoutClient(@Named("commons-service") Service service) { - this.service = service; - } - - /** - * Fetches the CSRF token and uses that to post the logout api call - * @return - */ - public Observable postLogout() { - return service.getCsrfToken().concatMap(tokenResponse -> service.postLogout( - Objects.requireNonNull(Objects.requireNonNull(tokenResponse.query()).csrfToken()))); - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/auth/SessionManager.java b/app/src/main/java/fr/free/nrw/commons/auth/SessionManager.java index a7905f8ea..f5395ceda 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/SessionManager.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/SessionManager.java @@ -9,8 +9,7 @@ import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import org.wikipedia.login.LoginResult; - +import fr.free.nrw.commons.auth.login.LoginResult; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; diff --git a/app/src/main/java/fr/free/nrw/commons/auth/csrf/CsrfTokenClient.kt b/app/src/main/java/fr/free/nrw/commons/auth/csrf/CsrfTokenClient.kt index e3e45b642..fae982fe1 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/csrf/CsrfTokenClient.kt +++ b/app/src/main/java/fr/free/nrw/commons/auth/csrf/CsrfTokenClient.kt @@ -1,15 +1,16 @@ package fr.free.nrw.commons.auth.csrf import androidx.annotation.VisibleForTesting +import fr.free.nrw.commons.auth.SessionManager import org.wikipedia.AppAdapter import org.wikipedia.dataclient.ServiceFactory import org.wikipedia.dataclient.SharedPreferenceCookieManager import org.wikipedia.dataclient.WikiSite import org.wikipedia.dataclient.mwapi.MwQueryResponse -import org.wikipedia.login.LoginClient -import org.wikipedia.login.LoginClient.LoginCallback -import org.wikipedia.login.LoginClient.LoginFailedException -import org.wikipedia.login.LoginResult +import fr.free.nrw.commons.auth.login.LoginClient +import fr.free.nrw.commons.auth.login.LoginClient.LoginCallback +import fr.free.nrw.commons.auth.login.LoginClient.LoginFailedException +import fr.free.nrw.commons.auth.login.LoginResult import retrofit2.Call import retrofit2.Response import timber.log.Timber @@ -17,7 +18,10 @@ import java.io.IOException import java.util.concurrent.Callable import java.util.concurrent.Executors.newSingleThreadExecutor -class CsrfTokenClient(private val csrfWikiSite: WikiSite) { +class CsrfTokenClient( + private val csrfWikiSite: WikiSite, + private val sessionManager: SessionManager +) { private var retries = 0 private var csrfTokenCall: Call? = null private val loginClient = LoginClient() @@ -33,7 +37,8 @@ class CsrfTokenClient(private val csrfWikiSite: WikiSite) { try { if (retry > 0) { // Log in explicitly - LoginClient().loginBlocking(csrfWikiSite, userName, password, "") + LoginClient() + .loginBlocking(csrfWikiSite, userName, password, "") } // Get CSRFToken response off the main thread. @@ -121,10 +126,11 @@ class CsrfTokenClient(private val csrfWikiSite: WikiSite) { password: String, callback: Callback, retryCallback: () -> Unit - ) = LoginClient().request(csrfWikiSite, username, password, object : LoginCallback { + ) = LoginClient() + .request(csrfWikiSite, username, password, object : LoginCallback { override fun success(loginResult: LoginResult) { if (loginResult.pass()) { - AppAdapter.get().updateAccount(loginResult) + sessionManager.updateAccount(loginResult) retryCallback() } else { callback.failure(LoginFailedException(loginResult.message)) diff --git a/data-client/src/main/java/org/wikipedia/login/LoginClient.java b/app/src/main/java/fr/free/nrw/commons/auth/login/LoginClient.java similarity index 93% rename from data-client/src/main/java/org/wikipedia/login/LoginClient.java rename to app/src/main/java/fr/free/nrw/commons/auth/login/LoginClient.java index 08137dddd..be8661e4d 100644 --- a/data-client/src/main/java/org/wikipedia/login/LoginClient.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/login/LoginClient.java @@ -1,4 +1,4 @@ -package org.wikipedia.login; +package fr.free.nrw.commons.auth.login; import android.annotation.SuppressLint; import android.text.TextUtils; @@ -52,7 +52,7 @@ public class LoginClient { @NonNull final String password, @NonNull final LoginCallback cb) { cancel(); - tokenCall = ServiceFactory.get(wiki).getLoginToken(); + tokenCall = ServiceFactory.get(wiki, LoginInterface.class).getLoginToken(); tokenCall.enqueue(new Callback() { @Override public void onResponse(@NonNull Call call, @NonNull Response response) { @@ -75,8 +75,8 @@ public class LoginClient { @Nullable final String loginToken, @NonNull final String userLanguage, @NonNull final LoginCallback cb) { this.userLanguage = userLanguage; loginCall = TextUtils.isEmpty(twoFactorCode) && TextUtils.isEmpty(retypedPassword) - ? ServiceFactory.get(wiki).postLogIn(userName, password, loginToken, userLanguage, Service.WIKIPEDIA_URL) - : ServiceFactory.get(wiki).postLogIn(userName, password, retypedPassword, twoFactorCode, loginToken, + ? ServiceFactory.get(wiki, LoginInterface.class).postLogIn(userName, password, loginToken, userLanguage, Service.WIKIPEDIA_URL) + : ServiceFactory.get(wiki, LoginInterface.class).postLogIn(userName, password, retypedPassword, twoFactorCode, loginToken, userLanguage, true); loginCall.enqueue(new Callback() { @Override @@ -117,15 +117,15 @@ public class LoginClient { public void loginBlocking(@NonNull final WikiSite wiki, @NonNull final String userName, @NonNull final String password, @Nullable final String twoFactorCode) throws Throwable { - Response tokenResponse = ServiceFactory.get(wiki).getLoginToken().execute(); + Response tokenResponse = ServiceFactory.get(wiki, LoginInterface.class).getLoginToken().execute(); if (tokenResponse.body() == null || TextUtils.isEmpty(tokenResponse.body().query().loginToken())) { throw new IOException("Unexpected response when getting login token."); } String loginToken = tokenResponse.body().query().loginToken(); Call tempLoginCall = StringUtils.defaultIfEmpty(twoFactorCode, "").isEmpty() - ? ServiceFactory.get(wiki).postLogIn(userName, password, loginToken, userLanguage, Service.WIKIPEDIA_URL) - : ServiceFactory.get(wiki).postLogIn(userName, password, null, twoFactorCode, loginToken, + ? ServiceFactory.get(wiki, LoginInterface.class).postLogIn(userName, password, loginToken, userLanguage, Service.WIKIPEDIA_URL) + : ServiceFactory.get(wiki, LoginInterface.class).postLogIn(userName, password, null, twoFactorCode, loginToken, userLanguage, true); Response response = tempLoginCall.execute(); LoginResponse loginResponse = response.body(); @@ -153,7 +153,7 @@ public class LoginClient { @SuppressLint("CheckResult") private void getExtendedInfo(@NonNull final WikiSite wiki, @NonNull String userName, @NonNull final LoginResult loginResult, @NonNull final LoginCallback cb) { - ServiceFactory.get(wiki).getUserInfo(userName) + ServiceFactory.get(wiki, LoginInterface.class).getUserInfo(userName) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(response -> { diff --git a/app/src/main/java/fr/free/nrw/commons/auth/login/LoginInterface.kt b/app/src/main/java/fr/free/nrw/commons/auth/login/LoginInterface.kt new file mode 100644 index 000000000..49b38db3a --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/auth/login/LoginInterface.kt @@ -0,0 +1,45 @@ +package fr.free.nrw.commons.auth.login + +import io.reactivex.Observable +import org.wikipedia.dataclient.Service +import org.wikipedia.dataclient.mwapi.MwQueryResponse +import retrofit2.Call +import retrofit2.http.Field +import retrofit2.http.FormUrlEncoded +import retrofit2.http.GET +import retrofit2.http.Headers +import retrofit2.http.POST +import retrofit2.http.Query + +interface LoginInterface { + @Headers("Cache-Control: no-cache") + @GET(Service.MW_API_PREFIX + "action=query&meta=tokens&type=login") + fun getLoginToken(): Call + + @Headers("Cache-Control: no-cache") + @FormUrlEncoded + @POST(Service.MW_API_PREFIX + "action=clientlogin&rememberMe=") + fun postLogIn( + @Field("username") user: String?, + @Field("password") pass: String?, + @Field("logintoken") token: String?, + @Field("uselang") userLanguage: String?, + @Field("loginreturnurl") url: String? + ): Call + + @Headers("Cache-Control: no-cache") + @FormUrlEncoded + @POST(Service.MW_API_PREFIX + "action=clientlogin&rememberMe=") + fun postLogIn( + @Field("username") user: String?, + @Field("password") pass: String?, + @Field("retype") retypedPass: String?, + @Field("OATHToken") twoFactorCode: String?, + @Field("logintoken") token: String?, + @Field("uselang") userLanguage: String?, + @Field("logincontinue") loginContinue: Boolean + ): Call + + @GET(Service.MW_API_PREFIX + "action=query&meta=userinfo&list=users&usprop=groups|cancreate") + fun getUserInfo(@Query("ususers") userName: String): Observable +} \ No newline at end of file diff --git a/data-client/src/main/java/org/wikipedia/login/LoginOAuthResult.java b/app/src/main/java/fr/free/nrw/commons/auth/login/LoginOAuthResult.java similarity index 91% rename from data-client/src/main/java/org/wikipedia/login/LoginOAuthResult.java rename to app/src/main/java/fr/free/nrw/commons/auth/login/LoginOAuthResult.java index be24880e9..80a873925 100644 --- a/data-client/src/main/java/org/wikipedia/login/LoginOAuthResult.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/login/LoginOAuthResult.java @@ -1,4 +1,4 @@ -package org.wikipedia.login; +package fr.free.nrw.commons.auth.login; import androidx.annotation.NonNull; import androidx.annotation.Nullable; diff --git a/data-client/src/main/java/org/wikipedia/login/LoginResetPasswordResult.java b/app/src/main/java/fr/free/nrw/commons/auth/login/LoginResetPasswordResult.java similarity index 91% rename from data-client/src/main/java/org/wikipedia/login/LoginResetPasswordResult.java rename to app/src/main/java/fr/free/nrw/commons/auth/login/LoginResetPasswordResult.java index 04e931e1e..490e544a1 100644 --- a/data-client/src/main/java/org/wikipedia/login/LoginResetPasswordResult.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/login/LoginResetPasswordResult.java @@ -1,4 +1,4 @@ -package org.wikipedia.login; +package fr.free.nrw.commons.auth.login; import androidx.annotation.NonNull; import androidx.annotation.Nullable; diff --git a/data-client/src/main/java/org/wikipedia/login/LoginResult.java b/app/src/main/java/fr/free/nrw/commons/auth/login/LoginResult.java similarity index 97% rename from data-client/src/main/java/org/wikipedia/login/LoginResult.java rename to app/src/main/java/fr/free/nrw/commons/auth/login/LoginResult.java index 9cb5d542f..990067511 100644 --- a/data-client/src/main/java/org/wikipedia/login/LoginResult.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/login/LoginResult.java @@ -1,4 +1,4 @@ -package org.wikipedia.login; +package fr.free.nrw.commons.auth.login; import androidx.annotation.NonNull; import androidx.annotation.Nullable; diff --git a/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java b/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java index d5546ad18..ae505d666 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/NetworkingModule.java @@ -10,6 +10,7 @@ import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.actions.PageEditClient; import fr.free.nrw.commons.actions.PageEditInterface; import fr.free.nrw.commons.actions.ThanksInterface; +import fr.free.nrw.commons.auth.SessionManager; import fr.free.nrw.commons.category.CategoryInterface; import fr.free.nrw.commons.explore.depictions.DepictsClient; import fr.free.nrw.commons.kvstore.JsonKvStore; @@ -40,7 +41,7 @@ import org.wikipedia.dataclient.Service; import org.wikipedia.dataclient.ServiceFactory; import org.wikipedia.dataclient.WikiSite; import org.wikipedia.json.GsonUtil; -import org.wikipedia.login.LoginClient; +import fr.free.nrw.commons.auth.login.LoginClient; import timber.log.Timber; @Module @@ -105,8 +106,9 @@ public class NetworkingModule { @Named(NAMED_COMMONS_CSRF) @Provides @Singleton - public CsrfTokenClient provideCommonsCsrfTokenClient(@Named(NAMED_COMMONS_WIKI_SITE) WikiSite commonsWikiSite) { - return new CsrfTokenClient(commonsWikiSite); + public CsrfTokenClient provideCommonsCsrfTokenClient( + @Named(NAMED_COMMONS_WIKI_SITE) WikiSite commonsWikiSite, SessionManager sessionManager) { + return new CsrfTokenClient(commonsWikiSite, sessionManager); } @Provides diff --git a/app/src/test/kotlin/fr/free/nrw/commons/CommonsAppAdapterUnitTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/CommonsAppAdapterUnitTest.kt index ab295132b..442de350a 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/CommonsAppAdapterUnitTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/CommonsAppAdapterUnitTest.kt @@ -11,7 +11,7 @@ import org.mockito.Mock import org.mockito.MockitoAnnotations import org.wikipedia.dataclient.SharedPreferenceCookieManager import org.wikipedia.json.GsonMarshaller -import org.wikipedia.login.LoginResult +import fr.free.nrw.commons.auth.login.LoginResult class CommonsAppAdapterUnitTest { @@ -80,13 +80,6 @@ class CommonsAppAdapterUnitTest { Assert.assertEquals(adapter.password, "test") } - @Test - @Throws(Exception::class) - fun testUpdateAccount() { - adapter.updateAccount(result) - verify(sessionManager).updateAccount(result) - } - @Test @Throws(Exception::class) fun testSetCookies() { diff --git a/app/src/test/kotlin/fr/free/nrw/commons/TestAppAdapter.java b/app/src/test/kotlin/fr/free/nrw/commons/TestAppAdapter.java index 1b61a6fb7..835f43416 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/TestAppAdapter.java +++ b/app/src/test/kotlin/fr/free/nrw/commons/TestAppAdapter.java @@ -8,7 +8,6 @@ import org.wikipedia.dataclient.SharedPreferenceCookieManager; import org.wikipedia.dataclient.WikiSite; import org.wikipedia.dataclient.okhttp.TestStubInterceptor; import org.wikipedia.dataclient.okhttp.UnsuccessfulResponseInterceptor; -import org.wikipedia.login.LoginResult; public class TestAppAdapter extends AppAdapter { @@ -50,10 +49,6 @@ public class TestAppAdapter extends AppAdapter { return null; } - @Override - public void updateAccount(@NonNull LoginResult result) { - } - @Override public SharedPreferenceCookieManager getCookies() { return null; diff --git a/app/src/test/kotlin/fr/free/nrw/commons/auth/LoginActivityUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/auth/LoginActivityUnitTests.kt index fb3e7ce7e..a98aef12f 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/auth/LoginActivityUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/auth/LoginActivityUnitTests.kt @@ -8,13 +8,12 @@ import android.view.KeyEvent import android.view.MenuItem import android.view.View import android.view.ViewGroup -import android.view.inputmethod.EditorInfo -import android.widget.Button import android.widget.TextView import androidx.test.core.app.ApplicationProvider import fr.free.nrw.commons.R import fr.free.nrw.commons.TestAppAdapter import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.auth.login.LoginResult import fr.free.nrw.commons.kvstore.JsonKvStore import org.junit.Assert import org.junit.Before @@ -29,7 +28,6 @@ import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.robolectric.fakes.RoboMenuItem import org.wikipedia.AppAdapter -import org.wikipedia.login.LoginResult import java.lang.reflect.Method diff --git a/app/src/test/kotlin/fr/free/nrw/commons/auth/LogoutClientTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/auth/LogoutClientTest.kt deleted file mode 100644 index b9129a377..000000000 --- a/app/src/test/kotlin/fr/free/nrw/commons/auth/LogoutClientTest.kt +++ /dev/null @@ -1,45 +0,0 @@ -package fr.free.nrw.commons.auth - -import com.nhaarman.mockitokotlin2.verify -import io.reactivex.Observable -import org.junit.Before -import org.junit.Test -import org.mockito.ArgumentMatchers.anyString -import org.mockito.InjectMocks -import org.mockito.Mock -import org.mockito.Mockito.* -import org.mockito.MockitoAnnotations -import org.wikipedia.dataclient.Service -import org.wikipedia.dataclient.mwapi.MwPostResponse -import org.wikipedia.dataclient.mwapi.MwQueryResponse -import org.wikipedia.dataclient.mwapi.MwQueryResult -import javax.inject.Inject -import javax.inject.Named - -class LogoutClientTest { - - @Mock @field:[Inject Named("commons-service")] - lateinit var service: Service - - @InjectMocks - var logoutClient: LogoutClient? = null - - @Before - @Throws(Exception::class) - fun setUp() { - MockitoAnnotations.openMocks(this) - val mwQueryResponse = mock(MwQueryResponse::class.java) - val mwQueryResult = mock(MwQueryResult::class.java) - `when`(mwQueryResult!!.csrfToken()).thenReturn("test_token") - `when`(mwQueryResponse.query()).thenReturn(mwQueryResult) - `when`(service!!.csrfToken) - .thenReturn(Observable.just(mwQueryResponse)) - } - - @Test - fun postLogout() { - `when`(service!!.postLogout(anyString())).thenReturn(Observable.just(mock(MwPostResponse::class.java))) - logoutClient!!.postLogout() - verify(service, times(1))!!.csrfToken - } -} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/auth/SessionManagerUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/auth/SessionManagerUnitTests.kt index e111102be..1103978aa 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/auth/SessionManagerUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/auth/SessionManagerUnitTests.kt @@ -5,6 +5,7 @@ import android.accounts.AccountManager import android.content.Context import androidx.test.core.app.ApplicationProvider import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.auth.login.LoginResult import fr.free.nrw.commons.kvstore.JsonKvStore import org.junit.Assert import org.junit.Before @@ -17,7 +18,6 @@ import org.robolectric.RobolectricTestRunner import org.robolectric.Shadows.shadowOf import org.robolectric.annotation.Config import org.robolectric.annotation.LooperMode -import org.wikipedia.login.LoginResult import java.lang.reflect.Method diff --git a/app/src/test/kotlin/fr/free/nrw/commons/auth/csrf/CsrfTokenClientTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/auth/csrf/CsrfTokenClientTest.kt index a53de085b..ad434649a 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/auth/csrf/CsrfTokenClientTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/auth/csrf/CsrfTokenClientTest.kt @@ -2,6 +2,7 @@ package fr.free.nrw.commons.auth.csrf import com.google.gson.stream.MalformedJsonException import fr.free.nrw.commons.MockWebServerTest +import fr.free.nrw.commons.auth.SessionManager import org.junit.Test import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.eq @@ -16,8 +17,9 @@ import org.wikipedia.dataclient.okhttp.HttpStatusException class CsrfTokenClientTest : MockWebServerTest() { private val wikiSite = WikiSite("test.wikipedia.org") - private val subject = CsrfTokenClient(wikiSite) private val cb = mock(CsrfTokenClient.Callback::class.java) + private val sessionManager = mock(SessionManager::class.java) + private val subject = CsrfTokenClient(wikiSite, sessionManager) @Test @Throws(Throwable::class) diff --git a/app/src/test/kotlin/fr/free/nrw/commons/login/UserExtendedInfoClientTest.java b/app/src/test/kotlin/fr/free/nrw/commons/login/UserExtendedInfoClientTest.java new file mode 100644 index 000000000..1f2df96d8 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/login/UserExtendedInfoClientTest.java @@ -0,0 +1,84 @@ +package fr.free.nrw.commons.login; + +import android.net.Uri; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.stream.MalformedJsonException; +import fr.free.nrw.commons.MockWebServerTest; +import fr.free.nrw.commons.auth.login.LoginInterface; +import io.reactivex.observers.TestObserver; +import org.junit.Before; +import org.junit.Test; +import org.wikipedia.dataclient.WikiSite; +import org.wikipedia.dataclient.mwapi.MwQueryResponse; +import org.wikipedia.json.NamespaceTypeAdapter; +import org.wikipedia.json.PostProcessingTypeAdapter; +import org.wikipedia.json.UriTypeAdapter; +import org.wikipedia.json.WikiSiteTypeAdapter; +import org.wikipedia.page.Namespace; +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; + +public class UserExtendedInfoClientTest extends MockWebServerTest { + + private LoginInterface apiService; + + @Override + @Before + public void setUp() throws Throwable { + super.setUp(); + + apiService = new Retrofit.Builder() + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .addConverterFactory(GsonConverterFactory.create(getGson())) + .baseUrl(server().getUrl()) + .build() + .create(LoginInterface.class); + } + + @Test + public void testRequestSuccess() throws Throwable { + enqueueFromFile("user_extended_info.json"); + TestObserver observer = new TestObserver<>(); + + apiService.getUserInfo("USER").subscribe(observer); + + observer + .assertComplete() + .assertNoErrors() + .assertValue( + result -> result.query().userInfo().id() == 24531888 + && result.query().getUserResponse("USER").name().equals("USER") + ); + } + + @Test + public void testRequestResponse404() { + enqueue404(); + TestObserver observer = new TestObserver<>(); + + apiService.getUserInfo("USER").subscribe(observer); + + observer.assertError(Exception.class); + } + + @Test + public void testRequestResponseMalformed() { + enqueueMalformed(); + TestObserver observer = new TestObserver<>(); + + apiService.getUserInfo("USER").subscribe(observer); + + observer.assertError(MalformedJsonException.class); + } + + private Gson getGson() { + return new GsonBuilder() + .registerTypeHierarchyAdapter(Uri.class, new UriTypeAdapter().nullSafe()) + .registerTypeHierarchyAdapter(Namespace.class, new NamespaceTypeAdapter().nullSafe()) + .registerTypeAdapter(WikiSite.class, new WikiSiteTypeAdapter().nullSafe()) + .registerTypeAdapterFactory(new PostProcessingTypeAdapter()) + .create(); + } +} diff --git a/app/src/test/res/raw/user_extended_info.json b/app/src/test/res/raw/user_extended_info.json new file mode 100644 index 000000000..cabf18b84 --- /dev/null +++ b/app/src/test/res/raw/user_extended_info.json @@ -0,0 +1,19 @@ +{ + "batchcomplete": true, + "query": { + "users": [ + { + "userid": 24531888, + "name": "USER", + "implicitgroups": [ + "*", + "user" + ] + } + ], + "userinfo": { + "id": 24531888, + "name": "USER" + } + } +} \ No newline at end of file diff --git a/data-client/src/main/java/org/wikipedia/AppAdapter.java b/data-client/src/main/java/org/wikipedia/AppAdapter.java index aff96b2d5..aa83cf409 100644 --- a/data-client/src/main/java/org/wikipedia/AppAdapter.java +++ b/data-client/src/main/java/org/wikipedia/AppAdapter.java @@ -4,7 +4,6 @@ import androidx.annotation.NonNull; import org.wikipedia.dataclient.SharedPreferenceCookieManager; import org.wikipedia.dataclient.WikiSite; -import org.wikipedia.login.LoginResult; import okhttp3.OkHttpClient; @@ -18,7 +17,6 @@ public abstract class AppAdapter { public abstract boolean isLoggedIn(); public abstract String getUserName(); public abstract String getPassword(); - public abstract void updateAccount(@NonNull LoginResult result); public abstract SharedPreferenceCookieManager getCookies(); public abstract void setCookies(@NonNull SharedPreferenceCookieManager cookies); diff --git a/data-client/src/main/java/org/wikipedia/dataclient/Service.java b/data-client/src/main/java/org/wikipedia/dataclient/Service.java index 7e93ba055..a759524f9 100644 --- a/data-client/src/main/java/org/wikipedia/dataclient/Service.java +++ b/data-client/src/main/java/org/wikipedia/dataclient/Service.java @@ -13,7 +13,6 @@ import org.wikipedia.dataclient.mwapi.page.MwMobileViewPageRemaining; import org.wikipedia.dataclient.mwapi.page.MwQueryPageSummary; import org.wikipedia.edit.Edit; import org.wikipedia.edit.preview.EditPreview; -import org.wikipedia.login.LoginClient; import org.wikipedia.search.PrefixSearchResponse; import org.wikipedia.wikidata.Entities; @@ -190,54 +189,6 @@ public interface Service { @NonNull Observable getCategoryMembers(@NonNull @Query("cmtitle") String title, @Nullable @Query("cmcontinue") String continueStr); - // ------- CSRF, Login, and Create Account ------- - - @Headers("Cache-Control: no-cache") - @GET(MW_API_PREFIX + "action=query&meta=tokens&type=csrf") - @NonNull Observable getCsrfToken(); - - @SuppressWarnings("checkstyle:parameternumber") - @FormUrlEncoded - @POST(MW_API_PREFIX + "action=createaccount&createmessageformat=html") - @NonNull Observable postCreateAccount(@NonNull @Field("username") String user, - @NonNull @Field("password") String pass, - @NonNull @Field("retype") String retype, - @NonNull @Field("createtoken") String token, - @NonNull @Field("createreturnurl") String returnurl, - @Nullable @Field("email") String email, - @Nullable @Field("captchaId") String captchaId, - @Nullable @Field("captchaWord") String captchaWord); - - @Headers("Cache-Control: no-cache") - @GET(MW_API_PREFIX + "action=query&meta=tokens&type=login") - @NonNull Call getLoginToken(); - - @Headers("Cache-Control: no-cache") - @FormUrlEncoded - @POST(MW_API_PREFIX + "action=clientlogin&rememberMe=") - @NonNull Call postLogIn(@Field("username") String user, @Field("password") String pass, - @Field("logintoken") String token, @Field("uselang") String userLanguage, @Field("loginreturnurl") String url); - - @Headers("Cache-Control: no-cache") - @FormUrlEncoded - @POST(MW_API_PREFIX + "action=clientlogin&rememberMe=") - @NonNull Call postLogIn(@Field("username") String user, @Field("password") String pass, - @Field("retype") String retypedPass, @Field("OATHToken") String twoFactorCode, - @Field("logintoken") String token, @Field("uselang") String userLanguage, - @Field("logincontinue") boolean loginContinue); - - @Headers("Cache-Control: no-cache") - @FormUrlEncoded - @POST(MW_API_PREFIX + "action=logout") - @NonNull Observable postLogout(@NonNull @Field("token") String token); - - @GET(MW_API_PREFIX + "action=query&meta=authmanagerinfo|tokens&amirequestsfor=create&type=createaccount") - @NonNull Observable getAuthManagerInfo(); - - @GET(MW_API_PREFIX + "action=query&meta=userinfo&list=users&usprop=groups|cancreate") - @NonNull Observable getUserInfo(@Query("ususers") @NonNull String userName); - - // ------- Notifications ------- @Headers("Cache-Control: no-cache") diff --git a/data-client/src/test/java/org/wikipedia/login/UserExtendedInfoClientTest.java b/data-client/src/test/java/org/wikipedia/login/UserExtendedInfoClientTest.java deleted file mode 100644 index 2e1587708..000000000 --- a/data-client/src/test/java/org/wikipedia/login/UserExtendedInfoClientTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.wikipedia.login; - -import com.google.gson.stream.MalformedJsonException; - -import org.junit.Test; -import org.wikipedia.dataclient.mwapi.MwQueryResponse; -import org.wikipedia.test.MockRetrofitTest; - -import io.reactivex.Observable; -import io.reactivex.observers.TestObserver; - -public class UserExtendedInfoClientTest extends MockRetrofitTest { - - @Test public void testRequestSuccess() throws Throwable { - enqueueFromFile("user_extended_info.json"); - TestObserver observer = new TestObserver<>(); - getObservable().subscribe(observer); - - final int id = 24531888; - observer.assertComplete().assertNoErrors() - .assertValue(result -> result.query().userInfo().id() == id - && result.query().getUserResponse("USER").name().equals("USER")); - } - - @Test public void testRequestResponse404() { - enqueue404(); - TestObserver observer = new TestObserver<>(); - getObservable().subscribe(observer); - - observer.assertError(Exception.class); - } - - @Test public void testRequestResponseMalformed() { - enqueueMalformed(); - TestObserver observer = new TestObserver<>(); - getObservable().subscribe(observer); - - observer.assertError(MalformedJsonException.class); - } - - private Observable getObservable() { - return getApiService().getUserInfo("USER"); - } -}