package org.wikipedia.notifications; import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import com.google.gson.JsonParseException; import org.wikipedia.WikipediaApp; import org.wikipedia.csrf.CsrfTokenClient; import org.wikipedia.dataclient.WikiSite; import org.wikipedia.dataclient.mwapi.MwQueryResponse; import org.wikipedia.dataclient.retrofit.RetrofitFactory; import org.wikipedia.util.log.L; import java.util.List; import retrofit2.Call; import retrofit2.Response; import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.GET; import retrofit2.http.POST; import retrofit2.http.Query; public final class NotificationClient { @NonNull private final Service service; @NonNull private final CsrfTokenClient editTokenClient; public interface Callback { void success(@NonNull List<Notification> notifications); void failure(Throwable t); } private static final NotificationClient INSTANCE = new NotificationClient(new WikiSite("www.wikidata.org", "")); public static NotificationClient instance() { return INSTANCE; } private NotificationClient(@NonNull WikiSite wiki) { service = RetrofitFactory.newInstance(wiki).create(Service.class); editTokenClient = new CsrfTokenClient(wiki, WikipediaApp.getInstance().getWikiSite()); } @VisibleForTesting static class CallbackAdapter implements retrofit2.Callback<MwQueryResponse<Notification.QueryNotifications>> { @NonNull private final Callback callback; CallbackAdapter(@NonNull Callback callback) { this.callback = callback; } @Override public void onResponse(Call<MwQueryResponse<Notification.QueryNotifications>> call, Response<MwQueryResponse<Notification.QueryNotifications>> response) { if (response.body() != null && response.body().query() != null) { callback.success(response.body().query().get()); } else { callback.failure(new JsonParseException("Notification response is malformed.")); } } @Override public void onFailure(Call<MwQueryResponse<Notification.QueryNotifications>> call, Throwable caught) { L.v(caught); callback.failure(caught); } } /** * Obrain a list of unread notifications for the user who is currently logged in. * @param callback Callback that will receive the list of notifications. * @param wikis List of wiki names for which notifications should be received. These must be * in the "DB name" format, as in "enwiki", "zhwiki", "wikidatawiki", etc. */ public void getNotifications(@NonNull final Callback callback, @NonNull String... wikis) { String wikiList = TextUtils.join("|", wikis); requestNotifications(service, wikiList).enqueue(new CallbackAdapter(callback)); } public void markRead(List<Notification> notifications) { final String idListStr = TextUtils.join("|", notifications); editTokenClient.request(new CsrfTokenClient.Callback() { @Override public void success(@NonNull String token) { requestMarkRead(service, token, idListStr).enqueue(new retrofit2.Callback<MwQueryResponse<MarkReadResponse.QueryMarkReadResponse>>() { @Override public void onResponse(Call<MwQueryResponse<MarkReadResponse.QueryMarkReadResponse>> call, Response<MwQueryResponse<MarkReadResponse.QueryMarkReadResponse>> response) { // don't care about the response for now. } @Override public void onFailure(Call<MwQueryResponse<MarkReadResponse.QueryMarkReadResponse>> call, Throwable t) { L.e(t); } }); } @Override public void failure(@NonNull Throwable t) { L.e(t); } @Override public void twoFactorPrompt() { // TODO: warn user. } }); } @VisibleForTesting @NonNull Call<MwQueryResponse<Notification.QueryNotifications>> requestNotifications(@NonNull Service service, @NonNull String wikiList) { return service.getNotifications(wikiList); } @VisibleForTesting @NonNull Call<MwQueryResponse<MarkReadResponse.QueryMarkReadResponse>> requestMarkRead(@NonNull Service service, @NonNull String token, @NonNull String idList) { return service.markRead(token, idList); } @VisibleForTesting interface Service { String ACTION = "w/api.php?format=json&formatversion=2&action="; @GET(ACTION + "query&meta=notifications¬filter=!read¬prop=list") @NonNull Call<MwQueryResponse<Notification.QueryNotifications>> getNotifications(@Query("notwikis") @NonNull String wikiList); @FormUrlEncoded @POST(ACTION + "echomarkread") @NonNull Call<MwQueryResponse<MarkReadResponse.QueryMarkReadResponse>> markRead(@Field("token") @NonNull String token, @Field("list") @NonNull String idList); } }