package org.edx.mobile.user; import android.content.Context; import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.webkit.MimeTypeMap; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.inject.Inject; import com.google.inject.Singleton; import org.edx.mobile.event.AccountDataLoadedEvent; import org.edx.mobile.event.ProfilePhotoUpdatedEvent; import org.edx.mobile.http.CallTrigger; import org.edx.mobile.http.ErrorHandlingCallback; import org.edx.mobile.http.HttpResponseStatusException; import org.edx.mobile.http.cache.CacheManager; import org.edx.mobile.logger.Logger; import org.edx.mobile.model.api.EnrolledCoursesResponse; import org.edx.mobile.module.prefs.LoginPrefs; import org.edx.mobile.util.Config; import org.edx.mobile.view.common.TaskMessageCallback; import org.edx.mobile.view.common.TaskProgressCallback; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import de.greenrobot.event.EventBus; import okhttp3.MediaType; import okhttp3.RequestBody; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.Response; @Singleton public class UserAPI { private Logger logger = new Logger(UserAPI.class.getName()); @Inject private UserService userService; @Inject private Config config; @Inject private CacheManager cache; @Inject private Gson gson; public static class AccountDataUpdatedCallback extends ErrorHandlingCallback<Account> { @Inject private LoginPrefs loginPrefs; @NonNull private final String username; public AccountDataUpdatedCallback(@NonNull final Context context, @NonNull final String username, @NonNull final CallTrigger type) { super(context, type); this.username = username; } public AccountDataUpdatedCallback(@NonNull final Context context, @NonNull final String username, @NonNull final CallTrigger type, @Nullable final TaskProgressCallback progressCallback) { super(context, type, progressCallback); this.username = username; } public AccountDataUpdatedCallback(@NonNull final Context context, @NonNull final String username, @NonNull final CallTrigger type, @Nullable final TaskMessageCallback messageCallback) { super(context, type, messageCallback); this.username = username; } public AccountDataUpdatedCallback(@NonNull final Context context, @NonNull final String username, @NonNull final CallTrigger type, @Nullable final TaskProgressCallback progressCallback, @Nullable final TaskMessageCallback messageCallback) { super(context, type, progressCallback, messageCallback); this.username = username; } @Override protected void onResponse(@NonNull final Account account) { EventBus.getDefault().post(new AccountDataLoadedEvent(account)); // Store the logged in user's ProfileImage loginPrefs.setProfileImage(username, account.getProfileImage()); } } public Call<ResponseBody> setProfileImage(@NonNull String username, @NonNull final File file) { final String mimeType = "image/jpeg"; return userService.setProfileImage( username, "attachment;filename=filename." + MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType), RequestBody.create(MediaType.parse(mimeType), file)); } public static class ProfileImageUpdatedCallback extends ErrorHandlingCallback<ResponseBody> { @Inject private LoginPrefs loginPrefs; @NonNull private final String username; @Nullable private final Uri profileImageUri; public ProfileImageUpdatedCallback(@NonNull final Context context, @NonNull final String username, @Nullable final File profileImageFile, @NonNull final CallTrigger type) { super(context, type); this.username = username; profileImageUri = profileImageFile == null ? null : Uri.fromFile(profileImageFile); } public ProfileImageUpdatedCallback(@NonNull final Context context, @NonNull final String username, @Nullable final File profileImageFile, @NonNull final CallTrigger type, @Nullable final TaskProgressCallback progressCallback) { super(context, type, progressCallback); this.username = username; profileImageUri = profileImageFile == null ? null : Uri.fromFile(profileImageFile); } public ProfileImageUpdatedCallback(@NonNull final Context context, @NonNull final String username, @Nullable final File profileImageFile, @NonNull final CallTrigger type, @Nullable final TaskMessageCallback messageCallback) { super(context, type, messageCallback); this.username = username; profileImageUri = profileImageFile == null ? null : Uri.fromFile(profileImageFile); } public ProfileImageUpdatedCallback(@NonNull final Context context, @NonNull final String username, @Nullable final File profileImageFile, @NonNull final CallTrigger type, @Nullable final TaskProgressCallback progressCallback, @Nullable final TaskMessageCallback messageCallback) { super(context, type, progressCallback, messageCallback); this.username = username; profileImageUri = profileImageFile == null ? null : Uri.fromFile(profileImageFile); } @Override protected void onResponse(@NonNull final ResponseBody response) { EventBus.getDefault().post(new ProfilePhotoUpdatedEvent(username, profileImageUri)); if (profileImageUri == null) { // Delete the logged in user's ProfileImage loginPrefs.setProfileImage(username, null); } } } public @NonNull String getUserEnrolledCoursesURL(@NonNull String username) { return config.getApiHostURL() + "/api/mobile/v0.5/users/" + username + "/course_enrollments"; } public @NonNull List<EnrolledCoursesResponse> getUserEnrolledCourses(@NonNull String username, String org, boolean tryCache) throws Exception { String json = null; final String cacheKey = getUserEnrolledCoursesURL(username); // try to get from cache if we should if (tryCache) { try { json = cache.get(cacheKey); } catch (IOException e) { logger.debug(e.toString()); } } // if we don't have a json yet, get it from userService if (json == null) { Response<ResponseBody> response = userService.getUserEnrolledCourses(username, org).execute(); if (response.isSuccessful()) { json = userService.getUserEnrolledCourses(username, org).execute().body().string(); // cache result try { cache.put(cacheKey, json); } catch (IOException e) { logger.debug(e.toString()); } } else { // Cache has already been checked, and connectivity // can't be established, so throw an exception. if (tryCache) throw new HttpResponseStatusException(response.code()); // Otherwise fall back to fetching from the cache try { json = cache.get(cacheKey); } catch (IOException e) { logger.debug(e.toString()); throw new HttpResponseStatusException(response.code()); } // If the cache is empty, then throw an exception. if (json == null) throw new HttpResponseStatusException(response.code()); } } // We aren't use TypeToken here because it throws NoClassDefFoundError final JsonArray ary = gson.fromJson(json, JsonArray.class); final List<EnrolledCoursesResponse> ret = new ArrayList<>(ary.size()); for (int cnt = 0; cnt < ary.size(); ++cnt) { ret.add(gson.fromJson(ary.get(cnt), EnrolledCoursesResponse.class)); } return ret; } }