Fix - No Precise Error Message After Error Due to Password Change (#5643)

* initial commit

* Fix No Precise Message After Clicking Review Buttons

* Fix For ThanksClient

* Fix For Depictions

* Fix For Categories

* Fix For Description & Coordinates

* Fix For Description & Coordinates

* Fix For Description & Coordinates

* Fix For Mark as Read notifications

* resolve conflicts

* fix merge conflicts
This commit is contained in:
Shashank Kumar 2024-04-01 13:53:00 +05:30 committed by GitHub
parent e56de2c343
commit 3d1efecb55
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 361 additions and 110 deletions

View file

@ -30,9 +30,13 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import fr.free.nrw.commons.CameraPosition;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient;
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException;
import fr.free.nrw.commons.coordinates.CoordinateEditHelper;
import fr.free.nrw.commons.filepicker.Constants;
import fr.free.nrw.commons.kvstore.JsonKvStore;
@ -141,6 +145,8 @@ public class LocationPickerActivity extends BaseActivity implements
@Inject
LocationServiceManager locationManager;
@Inject
SessionManager sessionManager;
/**
* Constants
@ -404,13 +410,29 @@ public class LocationPickerActivity extends BaseActivity implements
if (media == null) {
return;
}
compositeDisposable.add(coordinateEditHelper.makeCoordinatesEdit(getApplicationContext(),media,
Latitude, Longitude, Accuracy)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
Timber.d("Coordinates are added.");
}));
try {
compositeDisposable.add(
coordinateEditHelper.makeCoordinatesEdit(getApplicationContext(), media,
Latitude, Longitude, Accuracy)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
Timber.d("Coordinates are added.");
}));
} catch (Exception e) {
if (e.getLocalizedMessage().equals(CsrfTokenClient.ANONYMOUS_TOKEN_MESSAGE)) {
final String username = sessionManager.getUserName();
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
this,
getString(R.string.invalid_login_message),
username
);
CommonsApplication.getInstance().clearApplicationData(
this, logoutListener);
}
}
}
/**

View file

@ -1,5 +1,6 @@
package fr.free.nrw.commons.actions
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
import io.reactivex.Observable
import io.reactivex.Single
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient
@ -28,7 +29,11 @@ class PageEditClient(
pageEditInterface.postEdit(pageTitle, summary, text, csrfTokenClient.getTokenBlocking())
.map { editResponse -> editResponse.edit()!!.editSucceeded() }
} catch (throwable: Throwable) {
Observable.just(false)
if (throwable is InvalidLoginTokenException) {
throw throwable
} else {
Observable.just(false)
}
}
}
@ -44,7 +49,11 @@ class PageEditClient(
pageEditInterface.postAppendEdit(pageTitle, summary, appendText, csrfTokenClient.getTokenBlocking())
.map { editResponse -> editResponse.edit()!!.editSucceeded() }
} catch (throwable: Throwable) {
Observable.just(false)
if (throwable is InvalidLoginTokenException) {
throw throwable
} else {
Observable.just(false)
}
}
}
@ -58,12 +67,17 @@ class PageEditClient(
fun prependEdit(pageTitle: String, prependText: String, summary: String): Observable<Boolean> {
return try {
pageEditInterface.postPrependEdit(pageTitle, summary, prependText, csrfTokenClient.getTokenBlocking())
.map { editResponse -> editResponse.edit()!!.editSucceeded() }
.map { editResponse -> editResponse.edit()?.editSucceeded() ?: false }
} catch (throwable: Throwable) {
Observable.just(false)
if (throwable is InvalidLoginTokenException) {
throw throwable
} else {
Observable.just(false)
}
}
}
/**
* Set new labels to Wikibase server of commons
* @param summary Edit summary
@ -79,7 +93,11 @@ class PageEditClient(
value, csrfTokenClient.getTokenBlocking()
).map { it.success }
} catch (throwable: Throwable) {
Observable.just(0)
if (throwable is InvalidLoginTokenException) {
throw throwable
} else {
Observable.just(0)
}
}
}
@ -93,4 +111,4 @@ class PageEditClient(
it.query()?.pages()?.get(0)?.revisions()?.get(0)?.content()
}
}
}
}

View file

@ -4,6 +4,8 @@ import fr.free.nrw.commons.CommonsApplication
import fr.free.nrw.commons.di.NetworkingModule.NAMED_COMMONS_CSRF
import io.reactivex.Observable
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
import fr.free.nrw.commons.auth.login.LoginFailedException
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
@ -32,8 +34,15 @@ class ThanksClient @Inject constructor(
).map {
mwThankPostResponse -> mwThankPostResponse.result?.success == 1
}
} catch (throwable: Throwable) {
Observable.just(false)
}
catch (throwable: Throwable) {
if (throwable is InvalidLoginTokenException) {
Observable.error(throwable)
}
else {
Observable.just(false)
}
}
}
}
}

View file

@ -48,16 +48,19 @@ class CsrfTokenClient(
token = response.body()!!.query()!!.csrfToken()!!
if (sessionManager.isUserLoggedIn && token == ANON_TOKEN) {
throw RuntimeException("App believes we're logged in, but got anonymous token.")
throw InvalidLoginTokenException(ANONYMOUS_TOKEN_MESSAGE)
}
break
} catch (t: Throwable) {
} catch (e: LoginFailedException) {
throw InvalidLoginTokenException(ANONYMOUS_TOKEN_MESSAGE)
}
catch (t: Throwable) {
Timber.w(t)
}
}
if (token.isEmpty() || token == ANON_TOKEN) {
throw IOException(INVALID_TOKEN_ERROR_MESSAGE)
throw InvalidLoginTokenException(ANONYMOUS_TOKEN_MESSAGE)
}
return token
}
@ -68,7 +71,7 @@ class CsrfTokenClient(
override fun success(token: String?) {
if (sessionManager.isUserLoggedIn && token == ANON_TOKEN) {
retryWithLogin(cb) {
RuntimeException("App believes we're logged in, but got anonymous token.")
InvalidLoginTokenException(ANONYMOUS_TOKEN_MESSAGE)
}
} else {
cb.success(token)
@ -161,5 +164,8 @@ class CsrfTokenClient(
private const val MAX_RETRIES = 1
private const val MAX_RETRIES_OF_LOGIN_BLOCKING = 2
const val INVALID_TOKEN_ERROR_MESSAGE = "Invalid token, or login failure."
const val ANONYMOUS_TOKEN_MESSAGE = "App believes we're logged in, but got anonymous token."
}
}
class InvalidLoginTokenException(message: String) : Exception(message)

View file

@ -13,6 +13,7 @@ import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.actions.PageEditClient;
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException;
import fr.free.nrw.commons.notification.NotificationHelper;
import fr.free.nrw.commons.review.ReviewController;
import fr.free.nrw.commons.utils.ViewUtilWrapper;
@ -66,7 +67,13 @@ public class DeleteHelper {
return delete(media, reason)
.flatMapSingle(result -> Single.just(showDeletionNotification(context, media, result)))
.firstOrError();
.firstOrError()
.onErrorResumeNext(throwable -> {
if (throwable instanceof InvalidLoginTokenException) {
return Single.error(throwable);
}
return Single.error(throwable);
});
}
/**
@ -104,22 +111,30 @@ public class DeleteHelper {
}
return pageEditClient.prependEdit(media.getFilename(), fileDeleteString + "\n", summary)
.flatMap(result -> {
if (result) {
return pageEditClient.edit("Commons:Deletion_requests/" + media.getFilename(), subpageString + "\n", summary);
}
throw new RuntimeException("Failed to nominate for deletion");
}).flatMap(result -> {
if (result) {
return pageEditClient.appendEdit("Commons:Deletion_requests/" + date, logPageString + "\n", summary);
}
throw new RuntimeException("Failed to nominate for deletion");
}).flatMap(result -> {
if (result) {
return pageEditClient.appendEdit("User_Talk:" + creator, userPageString + "\n", summary);
}
throw new RuntimeException("Failed to nominate for deletion");
});
.onErrorResumeNext(throwable -> {
if (throwable instanceof InvalidLoginTokenException) {
return Observable.error(throwable);
}
return Observable.error(throwable);
})
.flatMap(result -> {
if (result) {
return pageEditClient.edit("Commons:Deletion_requests/" + media.getFilename(), subpageString + "\n", summary);
}
return Observable.error(new RuntimeException("Failed to nominate for deletion"));
})
.flatMap(result -> {
if (result) {
return pageEditClient.appendEdit("Commons:Deletion_requests/" + date, logPageString + "\n", summary);
}
return Observable.error(new RuntimeException("Failed to nominate for deletion"));
})
.flatMap(result -> {
if (result) {
return pageEditClient.appendEdit("User_Talk:" + creator, userPageString + "\n", summary);
}
return Observable.error(new RuntimeException("Failed to nominate for deletion"));
});
}
private boolean showDeletionNotification(Context context, Media media, boolean result) {
@ -226,14 +241,15 @@ public class DeleteHelper {
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aBoolean -> {
if (aBoolean) {
reviewCallback.onSuccess();
reviewCallback.onSuccess();
}, throwable -> {
if (throwable instanceof InvalidLoginTokenException) {
reviewCallback.onTokenException((InvalidLoginTokenException) throwable);
} else {
reviewCallback.onFailure();
}
reviewCallback.enableButtons();
});
});
alert.setNegativeButton(context.getString(R.string.cancel), (dialog, which) -> reviewCallback.onFailure());
d = alert.create();

View file

@ -49,6 +49,7 @@ import com.facebook.imagepipeline.image.ImageInfo;
import com.facebook.imagepipeline.request.ImageRequest;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.CameraPosition;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.LocationPicker.LocationPicker;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.MediaDataExtractor;
@ -57,6 +58,8 @@ import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.actions.ThanksClient;
import fr.free.nrw.commons.auth.AccountUtil;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient;
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException;
import fr.free.nrw.commons.category.CategoryClient;
import fr.free.nrw.commons.category.CategoryDetailsActivity;
import fr.free.nrw.commons.category.CategoryEditHelper;
@ -780,9 +783,23 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
firstRevision.getRevisionId()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe((result) -> {
displayThanksToast(context, result);
}, Timber::e);
.subscribe(result -> {
displayThanksToast(getContext(), result);
}, throwable -> {
if (throwable instanceof InvalidLoginTokenException) {
final String username = sessionManager.getUserName();
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
getActivity(),
requireActivity().getString(R.string.invalid_login_message),
username
);
CommonsApplication.getInstance().clearApplicationData(
requireActivity(), logoutListener);
} else {
Timber.e(throwable);
}
});
}
/**
@ -1056,13 +1073,28 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
if (requestCode == REQUEST_CODE_EDIT_DESCRIPTION && resultCode == RESULT_OK) {
final String updatedWikiText = data.getStringExtra(UPDATED_WIKITEXT);
compositeDisposable.add(descriptionEditHelper.addDescription(getContext(), media,
updatedWikiText)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
Timber.d("Descriptions are added.");
}));
try {
compositeDisposable.add(descriptionEditHelper.addDescription(getContext(), media,
updatedWikiText)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
Timber.d("Descriptions are added.");
}));
} catch (Exception e) {
if (e.getLocalizedMessage().equals(CsrfTokenClient.ANONYMOUS_TOKEN_MESSAGE)) {
final String username = sessionManager.getUserName();
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
getActivity(),
requireActivity().getString(R.string.invalid_login_message),
username
);
CommonsApplication.getInstance().clearApplicationData(
requireActivity(), logoutListener);
}
}
final ArrayList<UploadMediaDetail> uploadMediaDetails
= data.getParcelableArrayListExtra(LIST_OF_DESCRIPTION_AND_CAPTION);
@ -1070,14 +1102,29 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
LinkedHashMap<String, String> updatedCaptions = new LinkedHashMap<>();
for (UploadMediaDetail mediaDetail:
uploadMediaDetails) {
compositeDisposable.add(descriptionEditHelper.addCaption(getContext(), media,
mediaDetail.getLanguageCode(), mediaDetail.getCaptionText())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
updateCaptions(mediaDetail, updatedCaptions);
Timber.d("Caption is added.");
}));
try {
compositeDisposable.add(descriptionEditHelper.addCaption(getContext(), media,
mediaDetail.getLanguageCode(), mediaDetail.getCaptionText())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
updateCaptions(mediaDetail, updatedCaptions);
Timber.d("Caption is added.");
}));
} catch (Exception e) {
if (e.getLocalizedMessage().equals(CsrfTokenClient.ANONYMOUS_TOKEN_MESSAGE)) {
final String username = sessionManager.getUserName();
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
getActivity(),
requireActivity().getString(R.string.invalid_login_message),
username
);
CommonsApplication.getInstance().clearApplicationData(
requireActivity(), logoutListener);
}
}
}
binding.progressBarEdit.setVisibility(GONE);
binding.descriptionEdit.setVisibility(VISIBLE);

View file

@ -12,9 +12,12 @@ import android.view.View;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.google.android.material.snackbar.Snackbar;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.databinding.ActivityNotificationBinding;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException;
import fr.free.nrw.commons.notification.models.Notification;
import fr.free.nrw.commons.theme.BaseActivity;
import fr.free.nrw.commons.utils.NetworkUtils;
@ -41,6 +44,9 @@ public class NotificationActivity extends BaseActivity {
@Inject
NotificationController controller;
@Inject
SessionManager sessionManager;
private static final String TAG_NOTIFICATION_WORKER_FRAGMENT = "NotificationWorkerFragment";
private NotificationWorkerFragment mNotificationWorkerFragment;
private NotificatinAdapter adapter;
@ -107,10 +113,23 @@ public class NotificationActivity extends BaseActivity {
ViewUtil.showLongToast(this,getString(R.string.some_error));
}
}, throwable -> {
if (throwable instanceof InvalidLoginTokenException) {
final String username = sessionManager.getUserName();
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
this,
getString(R.string.invalid_login_message),
username
);
Timber.e(throwable, "Error occurred while loading notifications");
throwable.printStackTrace();
CommonsApplication.getInstance().clearApplicationData(
this, logoutListener);
} else {
Timber.e(throwable, "Error occurred while loading notifications");
throwable.printStackTrace();
ViewUtil.showShortSnackbar(binding.container, R.string.error_notifications);
binding.progressBar.setVisibility(View.GONE);
ViewUtil.showShortSnackbar(binding.container, R.string.error_notifications);
}
binding.progressBar.setVisibility(View.GONE);
});
compositeDisposable.add(disposable);
@ -170,7 +189,7 @@ public class NotificationActivity extends BaseActivity {
}
binding.progressBar.setVisibility(View.GONE);
}, throwable -> {
Timber.e(throwable, "Error occurred while loading notifications");
Timber.e(throwable, "Error occurred while loading notifications ");
ViewUtil.showShortSnackbar(binding.container, R.string.error_notifications);
binding.progressBar.setVisibility(View.GONE);
}));

View file

@ -6,6 +6,7 @@ import fr.free.nrw.commons.notification.models.NotificationType
import io.reactivex.Observable
import io.reactivex.Single
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
import fr.free.nrw.commons.utils.DateUtil
import javax.inject.Inject
@ -39,7 +40,11 @@ class NotificationClient @Inject constructor(
unreadList = ""
).map(MwQueryResponse::success)
} catch (throwable: Throwable) {
Observable.just(false)
if (throwable is InvalidLoginTokenException) {
Observable.error(throwable)
} else {
Observable.just(false)
}
}
}

View file

@ -9,6 +9,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException;
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage;
import java.util.ArrayList;
@ -39,6 +41,9 @@ public class ReviewController {
protected static ArrayList<String> categories;
@Inject
ThanksClient thanksClient;
@Inject
SessionManager sessionManager;
private final DeleteHelper deleteHelper;
@Nullable
MwQueryPage.Revision firstRevision; // TODO: maybe we can expand this class to include fileName
@ -155,9 +160,23 @@ public class ReviewController {
Observable.defer((Callable<ObservableSource<Boolean>>) () -> thanksClient.thank(firstRevision.getRevisionId()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe((result) -> {
displayThanksToast(context,result);
}, Timber::e);
.subscribe(result -> {
displayThanksToast(context, result);
}, throwable -> {
if (throwable instanceof InvalidLoginTokenException) {
final String username = sessionManager.getUserName();
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
activity,
activity.getString(R.string.invalid_login_message),
username
);
CommonsApplication.getInstance().clearApplicationData(
activity, logoutListener);
} else {
Timber.e(throwable);
}
});
}
@SuppressLint("StringFormatInvalid")
@ -192,6 +211,8 @@ public class ReviewController {
void onFailure();
void onTokenException(Exception e);
void disableButtons();
void enableButtons();

View file

@ -7,15 +7,17 @@ import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException;
import fr.free.nrw.commons.databinding.FragmentReviewImageBinding;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
public class ReviewImageFragment extends CommonsDaggerSupportFragment {
@ -28,7 +30,8 @@ public class ReviewImageFragment extends CommonsDaggerSupportFragment {
private FragmentReviewImageBinding binding;
@Inject
SessionManager sessionManager;
// Constant variable used to store user's key name for onSaveInstanceState method
@ -37,20 +40,20 @@ public class ReviewImageFragment extends CommonsDaggerSupportFragment {
// Variable that stores the value of user
private String user;
public void update(int position) {
public void update(final int position) {
this.position = position;
}
private String updateCategoriesQuestion() {
Media media = getReviewActivity().getMedia();
final Media media = getReviewActivity().getMedia();
if (media != null && media.getCategoriesHiddenStatus() != null && isAdded()) {
// Filter category name attribute from all categories
List<String> categories = new ArrayList<>();
for(String key : media.getCategoriesHiddenStatus().keySet()) {
final List<String> categories = new ArrayList<>();
for(final String key : media.getCategoriesHiddenStatus().keySet()) {
String value = String.valueOf(key);
// Each category returned has a format like "Category:<some-category-name>"
// so remove the prefix "Category:"
int index = key.indexOf("Category:");
final int index = key.indexOf("Category:");
if(index == 0) {
value = key.substring(9);
}
@ -59,7 +62,7 @@ public class ReviewImageFragment extends CommonsDaggerSupportFragment {
String catString = TextUtils.join(", ", categories);
if (catString != null && !catString.equals("") && binding.tvReviewQuestionContext != null) {
catString = "<b>" + catString + "</b>";
String stringToConvertHtml = String.format(getResources().getString(R.string.review_category_explanation), catString);
final String stringToConvertHtml = String.format(getResources().getString(R.string.review_category_explanation), catString);
return Html.fromHtml(stringToConvertHtml).toString();
}
}
@ -67,17 +70,20 @@ public class ReviewImageFragment extends CommonsDaggerSupportFragment {
}
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
final Bundle savedInstanceState) {
position = getArguments().getInt("position");
binding = FragmentReviewImageBinding.inflate(inflater, container, false);
String question, explanation=null, yesButtonText, noButtonText;
final String question;
String explanation=null;
String yesButtonText;
final String noButtonText;
binding.buttonYes.setOnClickListener(view -> onYesButtonClicked());
@ -182,6 +188,22 @@ public class ReviewImageFragment extends CommonsDaggerSupportFragment {
//do nothing
}
@Override
public void onTokenException(final Exception e) {
if (e instanceof InvalidLoginTokenException){
final String username = sessionManager.getUserName();
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
getActivity(),
requireActivity().getString(R.string.invalid_login_message),
username
);
CommonsApplication.getInstance().clearApplicationData(
requireActivity(), logoutListener);
}
}
/**
* This function is called when an image is being loaded
* to disable the review buttons

View file

@ -56,6 +56,12 @@ public interface CategoriesContract {
* Refreshes the categories
*/
void refreshCategories();
/**
* Navigate the user to Login Activity
*/
void navigateToLoginScreen();
}
interface UserActionListener extends BasePresenter<View> {

View file

@ -5,6 +5,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
import fr.free.nrw.commons.category.CategoryEditHelper
import fr.free.nrw.commons.category.CategoryItem
import fr.free.nrw.commons.di.CommonsApplicationModule
@ -211,25 +212,31 @@ class CategoriesPresenter @Inject constructor(
if (selectedCategories.isNotEmpty()) {
view.showProgressDialog()
compositeDisposable.add(
categoryEditHelper.makeCategoryEdit(view.fragmentContext, media,
selectedCategories, wikiText)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
Timber.d("Categories are added.")
media.addedCategories = selectedCategories
repository.cleanup()
view.dismissProgressDialog()
view.refreshCategories()
view.goBackToPreviousScreen()
})
{
Timber.e(
"Failed to update categories"
)
}
)
try {
compositeDisposable.add(
categoryEditHelper.makeCategoryEdit(
view.fragmentContext, media,
selectedCategories, wikiText
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
Timber.d("Categories are added.")
media.addedCategories = selectedCategories
repository.cleanup()
view.dismissProgressDialog()
view.refreshCategories()
view.goBackToPreviousScreen()
}, {
Timber.e(
"Failed to update categories"
)
})
)
} catch (e: InvalidLoginTokenException) {
view.navigateToLoginScreen();
}
}
} else {

View file

@ -19,8 +19,10 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.jakewharton.rxbinding2.view.RxView;
import com.jakewharton.rxbinding2.widget.RxTextView;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.category.CategoryItem;
import fr.free.nrw.commons.contributions.ContributionsFragment;
import fr.free.nrw.commons.databinding.UploadCategoriesFragmentBinding;
@ -41,6 +43,8 @@ public class UploadCategoriesFragment extends UploadBaseFragment implements Cate
@Inject
CategoriesContract.UserActionListener presenter;
@Inject
SessionManager sessionManager;
private UploadCategoryAdapter adapter;
private Disposable subscribe;
/**
@ -295,6 +299,22 @@ public class UploadCategoriesFragment extends UploadBaseFragment implements Cate
mediaDetailFragment.updateCategories();
}
/**
*
*/
@Override
public void navigateToLoginScreen() {
final String username = sessionManager.getUserName();
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
getActivity(),
requireActivity().getString(R.string.invalid_login_message),
username
);
CommonsApplication.getInstance().clearApplicationData(
requireActivity(), logoutListener);
}
public void onNextButtonClicked() {
if (media != null) {
presenter.updateCategories(media, wikiText);

View file

@ -73,6 +73,11 @@ public interface DepictsContract {
* Update the depictions
*/
void updateDepicts();
/**
* Navigate the user to Login Activity
*/
void navigateToLoginScreen();
}
interface UserActionListener extends BasePresenter<View> {

View file

@ -17,8 +17,10 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.jakewharton.rxbinding2.view.RxView;
import com.jakewharton.rxbinding2.widget.RxTextView;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.contributions.ContributionsFragment;
import fr.free.nrw.commons.databinding.UploadDepictsFragmentBinding;
import fr.free.nrw.commons.kvstore.JsonKvStore;
@ -63,6 +65,9 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
private UploadDepictsFragmentBinding binding;
@Inject
SessionManager sessionManager;
@Nullable
@Override
public android.view.View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@ -311,6 +316,22 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
mediaDetailFragment.onResume();
}
/**
* Navigates to the login Activity
*/
@Override
public void navigateToLoginScreen() {
final String username = sessionManager.getUserName();
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
getActivity(),
requireActivity().getString(R.string.invalid_login_message),
username
);
CommonsApplication.getInstance().clearApplicationData(
requireActivity(), logoutListener);
}
/**
* Determines the calling fragment by media nullability and act accordingly
*/

View file

@ -5,6 +5,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsController
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
import fr.free.nrw.commons.di.CommonsApplicationModule
import fr.free.nrw.commons.repository.UploadRepository
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
@ -218,13 +219,18 @@ class DepictsPresenter @Inject constructor(
view.dismissProgressDialog()
view.updateDepicts()
view.goBackToPreviousScreen()
}, { error ->
if (error is InvalidLoginTokenException) {
view.navigateToLoginScreen();
} else {
Timber.e(
"Failed to update depictions"
)
}
})
{
Timber.e(
"Failed to update depictions"
)
}
)
}
} else {
repository.cleanup()

View file

@ -59,11 +59,6 @@ class WikiBaseClient @Inject constructor(
}
private fun csrfToken(): Observable<String> = Observable.fromCallable {
try {
csrfTokenClient.getTokenBlocking()
} catch (throwable: Throwable) {
Timber.e(throwable)
""
}
csrfTokenClient.getTokenBlocking()
}
}

View file

@ -8,6 +8,7 @@ import android.content.Context;
import androidx.annotation.Nullable;
import com.google.gson.Gson;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException;
import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.upload.UploadResult;
@ -123,8 +124,13 @@ public class WikidataEditService {
}
})
.doOnError(throwable -> {
Timber.e(throwable, "Error occurred while setting DEPICTS property");
ViewUtil.showLongToast(context, throwable.toString());
if (throwable instanceof InvalidLoginTokenException) {
Observable.error(throwable);
} else {
Timber.e(throwable, "Error occurred while setting DEPICTS property");
ViewUtil.showLongToast(context, throwable.toString());
}
})
.subscribeOn(Schedulers.io());
}