Skip to content

Commit

Permalink
Merge pull request #1697 from wordpress-mobile/feature/add-stock-medi…
Browse files Browse the repository at this point in the history
…a-methods-to-media-store

Add stock media upload methods to media store
  • Loading branch information
planarvoid authored Oct 7, 2020
2 parents 32a6af7 + 2770fe0 commit b3b554c
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken;
import org.wordpress.android.fluxc.network.rest.wpcom.auth.AppSecrets;
import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator;
import org.wordpress.android.fluxc.network.rest.wpcom.media.MediaResponseUtils;
import org.wordpress.android.fluxc.network.rest.wpcom.media.MediaRestClient;
import org.wordpress.android.fluxc.network.rest.wpcom.notifications.NotificationRestClient;
import org.wordpress.android.fluxc.network.rest.wpcom.plugin.PluginRestClient;
Expand Down Expand Up @@ -105,8 +106,10 @@ public SiteRestClient provideSiteRestClient(Context appContext, Dispatcher dispa
public MediaRestClient provideMediaRestClient(Dispatcher dispatcher, Context appContext,
RequestQueue requestQueue,
OkHttpClient okHttpClient,
AccessToken token, UserAgent userAgent) {
return new MediaRestClient(appContext, dispatcher, requestQueue, okHttpClient, token, userAgent);
AccessToken token, UserAgent userAgent,
MediaResponseUtils mediaResponseUtils) {
return new MediaRestClient(appContext, dispatcher, requestQueue, okHttpClient, token, userAgent,
mediaResponseUtils);
}

@Singleton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class StockMediaStoreTest {
@Mock lateinit var dispatcher: Dispatcher
@Mock lateinit var restClient: StockMediaRestClient
@Mock lateinit var sqlUtils: StockMediaSqlUtils
@Mock lateinit var mediaStore: MediaStore
private lateinit var store: StockMediaStore
private val stockMediaModel = StockMediaModel()
private lateinit var stockMediaItem: StockMediaItem
Expand All @@ -39,7 +40,8 @@ class StockMediaStoreTest {
dispatcher,
restClient,
initCoroutineEngine(),
sqlUtils
sqlUtils,
mediaStore
)
stockMediaModel.id = id
stockMediaModel.name = name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.wordpress.android.fluxc.network.rest.wpcom.comment.CommentRestClient;
import org.wordpress.android.fluxc.network.rest.wpcom.encryptedlog.EncryptedLogRestClient;
import org.wordpress.android.fluxc.network.rest.wpcom.jetpacktunnel.JetpackRestClient;
import org.wordpress.android.fluxc.network.rest.wpcom.media.MediaResponseUtils;
import org.wordpress.android.fluxc.network.rest.wpcom.media.MediaRestClient;
import org.wordpress.android.fluxc.network.rest.wpcom.notifications.NotificationRestClient;
import org.wordpress.android.fluxc.network.rest.wpcom.planoffers.PlanOffersRestClient;
Expand Down Expand Up @@ -128,8 +129,10 @@ public SiteXMLRPCClient provideSiteXMLRPCClient(Dispatcher dispatcher,
public MediaRestClient provideMediaRestClient(Context appContext, Dispatcher dispatcher,
@Named("regular") RequestQueue requestQueue,
@Named("regular") OkHttpClient okHttpClient,
AccessToken token, UserAgent userAgent) {
return new MediaRestClient(appContext, dispatcher, requestQueue, okHttpClient, token, userAgent);
AccessToken token, UserAgent userAgent,
MediaResponseUtils mediaResponseUtils) {
return new MediaRestClient(appContext, dispatcher, requestQueue, okHttpClient, token, userAgent,
mediaResponseUtils);
}

@Singleton
Expand Down Expand Up @@ -442,12 +445,13 @@ public EncryptedLogRestClient provideEncryptedLogRestClient(@Named("regular") Re

@Singleton
@Provides
public StockMediaRestClient provideStockMediaRestClient(Context appContext, Dispatcher dispatcher,
public StockMediaRestClient provideStockMediaRestClient(Context appContext, MediaResponseUtils mediaResponseUtils,
Dispatcher dispatcher,
@Named("regular") RequestQueue requestQueue,
AccessToken token, UserAgent userAgent,
WPComGsonRequestBuilder wpComGsonRequestBuilder) {
return new StockMediaRestClient(wpComGsonRequestBuilder, dispatcher, appContext, requestQueue, token,
userAgent);
return new StockMediaRestClient(wpComGsonRequestBuilder, mediaResponseUtils, dispatcher, appContext,
requestQueue, token, userAgent);
}

@Singleton
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.wordpress.android.fluxc.network.rest.wpcom.media

import android.text.TextUtils
import org.apache.commons.text.StringEscapeUtils
import org.wordpress.android.fluxc.model.MediaModel
import org.wordpress.android.fluxc.model.MediaModel.MediaUploadState.DELETED
import org.wordpress.android.fluxc.model.MediaModel.MediaUploadState.UPLOADED
import org.wordpress.android.fluxc.network.rest.wpcom.media.MediaWPComRestResponse.MultipleMediaResponse
import javax.inject.Inject

class MediaResponseUtils
@Inject constructor() {
/**
* Creates a [MediaModel] list from a WP.com REST response to a request for all media.
*/
fun getMediaListFromRestResponse(from: MultipleMediaResponse?, localSiteId: Int): List<MediaModel>? {
return from?.media?.mapNotNull { getMediaFromRestResponse(it)?.apply { this.localSiteId = localSiteId } }
}

/**
* Creates a [MediaModel] from a WP.com REST response to a fetch request.
*/
fun getMediaFromRestResponse(from: MediaWPComRestResponse?): MediaModel? {
if (from == null) return null
val media = MediaModel()
media.mediaId = from.ID
media.uploadDate = from.date
media.postId = from.post_ID
media.authorId = from.author_ID
media.url = from.URL
media.guid = from.guid
media.fileName = from.file
media.fileExtension = from.extension
media.mimeType = from.mime_type
media.title = StringEscapeUtils.unescapeHtml4(from.title)
media.caption = StringEscapeUtils.unescapeHtml4(from.caption)
media.description = StringEscapeUtils.unescapeHtml4(from.description)
media.alt = StringEscapeUtils.unescapeHtml4(from.alt)
if (from.thumbnails != null) {
if (!TextUtils.isEmpty(from.thumbnails.fmt_std)) {
media.thumbnailUrl = from.thumbnails.fmt_std
} else {
media.thumbnailUrl = from.thumbnails.thumbnail
}
}
media.height = from.height
media.width = from.width
media.length = from.length
media.videoPressGuid = from.videopress_guid
media.videoPressProcessingDone = from.videopress_processing_done
media.deleted = MediaWPComRestResponse.DELETED_STATUS == from.status
if (!media.deleted) {
media.setUploadState(UPLOADED)
} else {
media.setUploadState(DELETED)
}
return media
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.google.gson.JsonObject;
import com.google.gson.stream.JsonReader;

import org.apache.commons.text.StringEscapeUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
Expand Down Expand Up @@ -48,7 +47,6 @@

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -83,14 +81,17 @@
@Singleton
public class MediaRestClient extends BaseWPComRestClient implements ProgressListener {
private OkHttpClient mOkHttpClient;
private MediaResponseUtils mMediaResponseUtils;
// this will hold which media is being uploaded by which call, in order to be able
// to monitor multiple uploads
private ConcurrentHashMap<Integer, Call> mCurrentUploadCalls = new ConcurrentHashMap<>();

public MediaRestClient(Context appContext, Dispatcher dispatcher, RequestQueue requestQueue,
OkHttpClient okHttpClient, AccessToken accessToken, UserAgent userAgent) {
OkHttpClient okHttpClient, AccessToken accessToken, UserAgent userAgent,
MediaResponseUtils mediaResponseUtils) {
super(appContext, dispatcher, requestQueue, accessToken, userAgent);
mOkHttpClient = okHttpClient;
mMediaResponseUtils = mediaResponseUtils;
}

@Override
Expand All @@ -114,7 +115,7 @@ public void pushMedia(final SiteModel site, final MediaModel media) {
new Listener<MediaWPComRestResponse>() {
@Override
public void onResponse(MediaWPComRestResponse response) {
MediaModel responseMedia = getMediaFromRestResponse(response);
MediaModel responseMedia = mMediaResponseUtils.getMediaFromRestResponse(response);
if (responseMedia != null) {
AppLog.v(T.MEDIA, "media changes pushed for " + responseMedia.getTitle());
responseMedia.setLocalSiteId(site.getId());
Expand Down Expand Up @@ -226,7 +227,8 @@ public void onResponse(@NonNull Call call, @NonNull Response response) throws IO
reader.setLenient(true);
MultipleMediaResponse mediaResponse = gson.fromJson(reader, MultipleMediaResponse.class);

List<MediaModel> responseMedia = getMediaListFromRestResponse(mediaResponse, site.getId());
List<MediaModel> responseMedia =
mMediaResponseUtils.getMediaListFromRestResponse(mediaResponse, site.getId());
if (responseMedia != null && !responseMedia.isEmpty()) {
MediaModel uploadedMedia = responseMedia.get(0);
uploadedMedia.setId(media.getId());
Expand Down Expand Up @@ -286,7 +288,8 @@ public void fetchMediaList(final SiteModel site, final int number, final int off
new Listener<MultipleMediaResponse>() {
@Override
public void onResponse(MultipleMediaResponse response) {
List<MediaModel> mediaList = getMediaListFromRestResponse(response, site.getId());
List<MediaModel> mediaList =
mMediaResponseUtils.getMediaListFromRestResponse(response, site.getId());
if (mediaList != null) {
AppLog.v(T.MEDIA, "Fetched media list for site with size: " + mediaList.size());
boolean canLoadMore = mediaList.size() == number;
Expand Down Expand Up @@ -324,7 +327,7 @@ public void fetchMedia(final SiteModel site, final MediaModel media) {
new Listener<MediaWPComRestResponse>() {
@Override
public void onResponse(MediaWPComRestResponse response) {
MediaModel responseMedia = getMediaFromRestResponse(response);
MediaModel responseMedia = mMediaResponseUtils.getMediaFromRestResponse(response);
if (responseMedia != null) {
responseMedia.setLocalSiteId(site.getId());
AppLog.v(T.MEDIA, "Fetched media with ID: " + media.getMediaId());
Expand Down Expand Up @@ -362,7 +365,7 @@ public void deleteMedia(final SiteModel site, final MediaModel media) {
new Listener<MediaWPComRestResponse>() {
@Override
public void onResponse(MediaWPComRestResponse response) {
MediaModel deletedMedia = getMediaFromRestResponse(response);
MediaModel deletedMedia = mMediaResponseUtils.getMediaFromRestResponse(response);
if (deletedMedia != null) {
AppLog.v(T.MEDIA, "deleted media: " + media.getTitle());
notifyMediaDeleted(site, media, null);
Expand Down Expand Up @@ -433,7 +436,8 @@ public void uploadStockMedia(@NonNull final SiteModel site,
@Override
public void onResponse(MultipleMediaResponse response) {
// response is a list of media, exactly like that of MediaRestClient.fetchMediaList()
List<MediaModel> mediaList = getMediaListFromRestResponse(response, site.getId());
List<MediaModel> mediaList =
mMediaResponseUtils.getMediaListFromRestResponse(response, site.getId());
UploadedStockMediaPayload payload = new UploadedStockMediaPayload(site, mediaList);
mDispatcher.dispatch(MediaActionBuilder.newUploadedStockMediaAction(payload));
}
Expand Down Expand Up @@ -558,62 +562,6 @@ private void notifyMediaUploadCanceled(MediaModel media) {
// Utility methods
//

/**
* Creates a {@link MediaModel} list from a WP.com REST response to a request for all media.
*/
private List<MediaModel> getMediaListFromRestResponse(final MultipleMediaResponse from, int localSiteId) {
if (from == null || from.media == null) return null;

final List<MediaModel> mediaList = new ArrayList<>();
for (MediaWPComRestResponse mediaItem : from.media) {
MediaModel mediaModel = getMediaFromRestResponse(mediaItem);
mediaModel.setLocalSiteId(localSiteId);
mediaList.add(mediaModel);
}
return mediaList;
}

/**
* Creates a {@link MediaModel} from a WP.com REST response to a fetch request.
*/
private MediaModel getMediaFromRestResponse(final MediaWPComRestResponse from) {
if (from == null) return null;

final MediaModel media = new MediaModel();
media.setMediaId(from.ID);
media.setUploadDate(from.date);
media.setPostId(from.post_ID);
media.setAuthorId(from.author_ID);
media.setUrl(from.URL);
media.setGuid(from.guid);
media.setFileName(from.file);
media.setFileExtension(from.extension);
media.setMimeType(from.mime_type);
media.setTitle(StringEscapeUtils.unescapeHtml4(from.title));
media.setCaption(StringEscapeUtils.unescapeHtml4(from.caption));
media.setDescription(StringEscapeUtils.unescapeHtml4(from.description));
media.setAlt(StringEscapeUtils.unescapeHtml4(from.alt));
if (from.thumbnails != null) {
if (!TextUtils.isEmpty(from.thumbnails.fmt_std)) {
media.setThumbnailUrl(from.thumbnails.fmt_std);
} else {
media.setThumbnailUrl(from.thumbnails.thumbnail);
}
}
media.setHeight(from.height);
media.setWidth(from.width);
media.setLength(from.length);
media.setVideoPressGuid(from.videopress_guid);
media.setVideoPressProcessingDone(from.videopress_processing_done);
media.setDeleted(MediaWPComRestResponse.DELETED_STATUS.equals(from.status));
if (!media.getDeleted()) {
media.setUploadState(MediaUploadState.UPLOADED);
} else {
media.setUploadState(MediaUploadState.DELETED);
}
return media;
}

/**
* The current REST API call (v1.1) accepts 'title', 'description', 'caption', 'alt',
* and 'parent_id' for all media. Audio media also accepts 'artist' and 'album' attributes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,40 @@ package org.wordpress.android.fluxc.network.rest.wpcom.stockmedia

import android.content.Context
import com.android.volley.RequestQueue
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import org.wordpress.android.fluxc.Dispatcher
import org.wordpress.android.fluxc.generated.endpoint.WPCOMREST
import org.wordpress.android.fluxc.model.MediaModel
import org.wordpress.android.fluxc.model.SiteModel
import org.wordpress.android.fluxc.network.UserAgent
import org.wordpress.android.fluxc.network.rest.wpcom.BaseWPComRestClient
import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequestBuilder
import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequestBuilder.Response.Error
import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequestBuilder.Response.Success
import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken
import org.wordpress.android.fluxc.network.rest.wpcom.media.MediaResponseUtils
import org.wordpress.android.fluxc.network.rest.wpcom.media.MediaWPComRestResponse.MultipleMediaResponse
import org.wordpress.android.fluxc.store.MediaStore.UploadStockMediaError
import org.wordpress.android.fluxc.store.MediaStore.UploadStockMediaErrorType
import org.wordpress.android.fluxc.store.MediaStore.UploadedStockMediaPayload
import org.wordpress.android.fluxc.store.StockMediaStore.FetchedStockMediaListPayload
import org.wordpress.android.fluxc.store.StockMediaStore.StockMediaError
import org.wordpress.android.fluxc.store.StockMediaStore.StockMediaErrorType
import org.wordpress.android.fluxc.store.StockMediaUploadItem
import org.wordpress.android.util.AppLog
import org.wordpress.android.util.AppLog.T.MEDIA
import org.wordpress.android.util.StringUtils
import org.wordpress.android.util.UrlUtils
import java.util.HashMap
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class StockMediaRestClient
@Inject constructor(
private val wpComGsonRequestBuilder: WPComGsonRequestBuilder,
private val mediaResponseUtils: MediaResponseUtils,
dispatcher: Dispatcher,
appContext: Context?,
requestQueue: RequestQueue,
Expand Down Expand Up @@ -66,4 +79,49 @@ class StockMediaRestClient
}
}
}
/**
* Gets a list of stock media items matching a query string
*/

suspend fun uploadStockMedia(
site: SiteModel,
stockMediaList: List<StockMediaUploadItem>
): UploadedStockMediaPayload {
val url = WPCOMREST.sites.site(site.siteId).external_media_upload.urlV1_1
val jsonBody = JsonArray()
for (stockMedia in stockMediaList) {
val json = JsonObject()
json.addProperty("url", StringUtils.notNullStr(stockMedia.url))
json.addProperty("name", StringUtils.notNullStr(stockMedia.name))
json.addProperty("title", StringUtils.notNullStr(stockMedia.title))
jsonBody.add(json.toString())
}
val body: MutableMap<String, Any> = HashMap()
body["service"] = "pexels"
body["external_ids"] = jsonBody

val response = wpComGsonRequestBuilder.syncPostRequest(
this,
url,
body,
MultipleMediaResponse::class.java
)
return when (response) {
is Success -> {
val mediaList: List<MediaModel> = mediaResponseUtils.getMediaListFromRestResponse(
response.data,
site.id
) ?: listOf()
UploadedStockMediaPayload(site, mediaList)
}
is Error -> {
val error = response.error
AppLog.e(MEDIA, "VolleyError uploading stock media: $error")
val mediaError = UploadStockMediaError(
UploadStockMediaErrorType.fromNetworkError(error), error.message
)
UploadedStockMediaPayload(site, mediaError)
}
}
}
}
Loading

0 comments on commit b3b554c

Please sign in to comment.