package com.kickstarter.services; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.google.gson.Gson; import com.kickstarter.libs.Config; import com.kickstarter.libs.rx.operators.ApiErrorOperator; import com.kickstarter.libs.rx.operators.Operators; import com.kickstarter.libs.utils.ObjectUtils; import com.kickstarter.models.Activity; import com.kickstarter.models.Backing; import com.kickstarter.models.Category; import com.kickstarter.models.Comment; import com.kickstarter.models.Empty; import com.kickstarter.models.Location; import com.kickstarter.models.Message; import com.kickstarter.models.MessageThread; import com.kickstarter.models.Project; import com.kickstarter.models.ProjectNotification; import com.kickstarter.models.SurveyResponse; import com.kickstarter.models.Update; import com.kickstarter.models.User; import com.kickstarter.services.apirequests.CommentBody; import com.kickstarter.services.apirequests.LoginWithFacebookBody; import com.kickstarter.services.apirequests.MessageBody; import com.kickstarter.services.apirequests.ProjectNotificationBody; import com.kickstarter.services.apirequests.PushTokenBody; import com.kickstarter.services.apirequests.RegisterWithFacebookBody; import com.kickstarter.services.apirequests.ResetPasswordBody; import com.kickstarter.services.apirequests.SettingsBody; import com.kickstarter.services.apirequests.SignupBody; import com.kickstarter.services.apirequests.XauthBody; import com.kickstarter.services.apiresponses.AccessTokenEnvelope; import com.kickstarter.services.apiresponses.ActivityEnvelope; import com.kickstarter.services.apiresponses.CategoriesEnvelope; import com.kickstarter.services.apiresponses.CommentsEnvelope; import com.kickstarter.services.apiresponses.DiscoverEnvelope; import com.kickstarter.services.apiresponses.MessageThreadEnvelope; import com.kickstarter.services.apiresponses.MessageThreadsEnvelope; import com.kickstarter.services.apiresponses.StarEnvelope; import java.util.Arrays; import java.util.List; import retrofit2.Response; import rx.Observable; import rx.schedulers.Schedulers; import static com.kickstarter.libs.utils.BooleanUtils.isTrue; public final class ApiClient implements ApiClientType { private final ApiService service; private final Gson gson; public ApiClient(final @NonNull ApiService service, final @NonNull Gson gson) { this.gson = gson; this.service = service; } @Override public @NonNull Observable<Config> config() { return service .config() .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<ActivityEnvelope> fetchActivities() { return fetchActivities(null); } @Override public @NonNull Observable<ActivityEnvelope> fetchActivities(final @Nullable Integer count) { final List<String> categories = Arrays.asList( Activity.CATEGORY_BACKING, Activity.CATEGORY_CANCELLATION, Activity.CATEGORY_FAILURE, Activity.CATEGORY_LAUNCH, Activity.CATEGORY_SUCCESS, Activity.CATEGORY_UPDATE, Activity.CATEGORY_FOLLOW ); return service .activities(categories, count) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<ActivityEnvelope> fetchActivitiesWithPaginationPath(final @NonNull String paginationPath) { return service .activities(paginationPath) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<List<Category>> fetchCategories() { return service .categories() .lift(apiErrorOperator()) .map(CategoriesEnvelope::categories) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Category> fetchCategory(final @NonNull String id) { return service .category(id) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Category> fetchCategory(final @NonNull Category category) { return fetchCategory(String.valueOf(category.id())); } @Override public @NonNull Observable<User> fetchCurrentUser() { return service .currentUser() .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Location> fetchLocation(final @NonNull String param) { return service.location(param) .subscribeOn(Schedulers.io()) .lift(apiErrorOperator()); } @Override public @NonNull Observable<List<ProjectNotification>> fetchProjectNotifications() { return service .projectNotifications() .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Project> fetchProject(final @NonNull String param) { return service .project(param) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Project> fetchProject(final @NonNull Project project) { return fetchProject(project.param()).startWith(project); } @Override public @NonNull Observable<DiscoverEnvelope> fetchProjects(final @NonNull DiscoveryParams params) { return service .projects(params.queryParams()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<DiscoverEnvelope> fetchProjects(final @NonNull String paginationUrl) { return service .projects(paginationUrl) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Backing> fetchProjectBacking(final @NonNull Project project, final @NonNull User user) { return service .projectBacking(project.param(), user.param()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<CommentsEnvelope> fetchComments(final @NonNull Project project) { return service .projectComments(project.param()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<CommentsEnvelope> fetchComments(final @NonNull Update update) { return service .updateComments(update.projectId(), update.id()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<CommentsEnvelope> fetchComments(final @NonNull String paginationPath) { return service .paginatedProjectComments(paginationPath) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<MessageThreadEnvelope> fetchMessagesForThread(final @NonNull MessageThread messageThread) { return service .messagesForThread(messageThread.id()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<MessageThreadsEnvelope> fetchMessageThreads() { return fetchMessageThreads(null); } @Override public @NonNull Observable<MessageThreadsEnvelope> fetchMessageThreads(final @Nullable Project project) { final Observable<Response<MessageThreadsEnvelope>> apiResponse = project == null ? service.messageThreads() : service.messageThreads(project.id()); return apiResponse .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<MessageThreadsEnvelope> fetchMessageThreadsWithPaginationPath(final @NonNull String paginationPath) { return service .paginatedMessageThreads(paginationPath) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<SurveyResponse> fetchSurveyResponse(final int surveyResponseId) { return service .surveyResponse(surveyResponseId) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<List<SurveyResponse>> fetchUnansweredSurveys() { return service .unansweredSurveys() .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Update> fetchUpdate(final @NonNull String projectParam, final @NonNull String updateParam) { return service .update(projectParam, updateParam) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Update> fetchUpdate(final @NonNull Update update) { final String projectParam = ObjectUtils.toString(update.projectId()); final String updateParam = ObjectUtils.toString(update.id()); return fetchUpdate(projectParam, updateParam) .startWith(update); } @Override public @NonNull Observable<AccessTokenEnvelope> loginWithFacebook(final @NonNull String accessToken) { return service .login(LoginWithFacebookBody.builder().accessToken(accessToken).build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<AccessTokenEnvelope> loginWithFacebook(final @NonNull String fbAccessToken, final @NonNull String code) { return service .login(LoginWithFacebookBody.builder().accessToken(fbAccessToken).code(code).build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<AccessTokenEnvelope> registerWithFacebook(final @NonNull String fbAccessToken, final boolean sendNewsletters) { return service .login(RegisterWithFacebookBody.builder() .accessToken(fbAccessToken) .sendNewsletters(sendNewsletters) .newsletterOptIn(sendNewsletters) .build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<AccessTokenEnvelope> login(final @NonNull String email, final @NonNull String password) { return service .login(XauthBody.builder() .email(email) .password(password) .build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<AccessTokenEnvelope> login(final @NonNull String email, final @NonNull String password, final @NonNull String code) { return service .login(XauthBody.builder() .email(email) .password(password) .code(code) .build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Comment> postComment(final @NonNull Project project, final @NonNull String body) { return service .postProjectComment(project.param(), CommentBody.builder().body(body).build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Comment> postComment(final @NonNull Update update, final @NonNull String body) { return service .postUpdateComment(update.projectId(), update.id(), CommentBody.builder().body(body).build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Empty> registerPushToken(final @NonNull String token) { return service .registerPushToken(PushTokenBody.builder().token(token).pushServer("development").build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<User> resetPassword(final @NonNull String email) { return service .resetPassword(ResetPasswordBody.builder().email(email).build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Message> sendMessageToThread(final @NonNull MessageThread messageThread, final @NonNull String body) { return service .sendMessageToThread(messageThread.id(), MessageBody.builder().body(body).build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<AccessTokenEnvelope> signup(final @NonNull String name, final @NonNull String email, final @NonNull String password, final @NonNull String passwordConfirmation, final boolean sendNewsletters) { return service .signup( SignupBody.builder() .name(name) .email(email) .password(password) .passwordConfirmation(passwordConfirmation) .sendNewsletters(sendNewsletters) .newsletterOptIn(sendNewsletters) .build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Project> starProject(final @NonNull Project project) { return service .starProject(project.param()) .lift(apiErrorOperator()) .map(StarEnvelope::project) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<Project> toggleProjectStar(final @NonNull Project project) { return service .toggleProjectStar(project.param()) .lift(apiErrorOperator()) .map(StarEnvelope::project) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<ProjectNotification> updateProjectNotifications(final @NonNull ProjectNotification projectNotification, final boolean checked) { return service .updateProjectNotifications(projectNotification.id(), ProjectNotificationBody.builder() .email(checked) .mobile(checked) .build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } @Override public @NonNull Observable<User> updateUserSettings(final @NonNull User user) { return service .updateUserSettings( SettingsBody.builder() .notifyMobileOfFollower(isTrue(user.notifyMobileOfFollower())) .notifyMobileOfFriendActivity(isTrue(user.notifyMobileOfFriendActivity())) .notifyMobileOfUpdates(isTrue(user.notifyMobileOfUpdates())) .notifyOfFollower(isTrue(user.notifyOfFollower())) .notifyOfFriendActivity(isTrue(user.notifyOfFriendActivity())) .notifyOfUpdates(isTrue(user.notifyOfUpdates())) .gamesNewsletter(isTrue(user.gamesNewsletter()) ? 1 : 0) .happeningNewsletter(isTrue(user.happeningNewsletter()) ? 1 : 0) .promoNewsletter(isTrue(user.promoNewsletter()) ? 1 : 0) .weeklyNewsletter(isTrue(user.weeklyNewsletter()) ? 1 : 0) .build()) .lift(apiErrorOperator()) .subscribeOn(Schedulers.io()); } /** * Utility to create a new {@link ApiErrorOperator}, saves us from littering references to gson throughout the client. */ private @NonNull <T> ApiErrorOperator<T> apiErrorOperator() { return Operators.apiError(gson); } }