blob: b59174ab5dd973cf04c46ca33d46d6da38bd8a59 [file] [log] [blame]
package org.wordpress.android.ui.prefs;
import android.app.Activity;
import com.android.volley.VolleyError;
import com.wordpress.rest.RestRequest;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.wordpress.android.WordPress;
import org.wordpress.android.analytics.AnalyticsTracker;
import org.wordpress.android.datasets.SiteSettingsTable;
import org.wordpress.android.models.Blog;
import org.wordpress.android.models.CategoryModel;
import org.wordpress.android.util.AnalyticsUtils;
import org.wordpress.android.util.AppLog;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
class DotComSiteSettings extends SiteSettingsInterface {
// WP.com REST keys used in response to a settings GET and POST request
public static final String LANGUAGE_ID_KEY = "lang_id";
public static final String PRIVACY_KEY = "blog_public";
public static final String URL_KEY = "URL";
public static final String DEF_CATEGORY_KEY = "default_category";
public static final String DEF_POST_FORMAT_KEY = "default_post_format";
public static final String RELATED_POSTS_ALLOWED_KEY = "jetpack_relatedposts_allowed";
public static final String RELATED_POSTS_ENABLED_KEY = "jetpack_relatedposts_enabled";
public static final String RELATED_POSTS_HEADER_KEY = "jetpack_relatedposts_show_headline";
public static final String RELATED_POSTS_IMAGES_KEY = "jetpack_relatedposts_show_thumbnails";
public static final String ALLOW_COMMENTS_KEY = "default_comment_status";
public static final String SEND_PINGBACKS_KEY = "default_pingback_flag";
public static final String RECEIVE_PINGBACKS_KEY = "default_ping_status";
public static final String CLOSE_OLD_COMMENTS_KEY = "close_comments_for_old_posts";
public static final String CLOSE_OLD_COMMENTS_DAYS_KEY = "close_comments_days_old";
public static final String THREAD_COMMENTS_KEY = "thread_comments";
public static final String THREAD_COMMENTS_DEPTH_KEY = "thread_comments_depth";
public static final String PAGE_COMMENTS_KEY = "page_comments";
public static final String PAGE_COMMENT_COUNT_KEY = "comments_per_page";
public static final String COMMENT_SORT_ORDER_KEY = "comment_order";
public static final String COMMENT_MODERATION_KEY = "comment_moderation";
public static final String REQUIRE_IDENTITY_KEY = "require_name_email";
public static final String REQUIRE_USER_ACCOUNT_KEY = "comment_registration";
public static final String WHITELIST_KNOWN_USERS_KEY = "comment_whitelist";
public static final String MAX_LINKS_KEY = "comment_max_links";
public static final String MODERATION_KEYS_KEY = "moderation_keys";
public static final String BLACKLIST_KEYS_KEY = "blacklist_keys";
// WP.com REST keys used to GET certain site settings
public static final String GET_TITLE_KEY = "name";
public static final String GET_DESC_KEY = "description";
// WP.com REST keys used to POST updates to site settings
private static final String SET_TITLE_KEY = "blogname";
private static final String SET_DESC_KEY = "blogdescription";
// JSON response keys
private static final String SETTINGS_KEY = "settings";
private static final String UPDATED_KEY = "updated";
// WP.com REST keys used in response to a categories GET request
private static final String CAT_ID_KEY = "ID";
private static final String CAT_NAME_KEY = "name";
private static final String CAT_SLUG_KEY = "slug";
private static final String CAT_DESC_KEY = "description";
private static final String CAT_PARENT_ID_KEY = "parent";
private static final String CAT_POST_COUNT_KEY = "post_count";
private static final String CAT_NUM_POSTS_KEY = "found";
private static final String CATEGORIES_KEY = "categories";
/**
* Only instantiated by {@link SiteSettingsInterface}.
*/
DotComSiteSettings(Activity host, Blog blog, SiteSettingsListener listener) {
super(host, blog, listener);
}
@Override
public void saveSettings() {
super.saveSettings();
final Map<String, String> params = serializeDotComParams();
if (params == null || params.isEmpty()) return;
WordPress.getRestClientUtils().setGeneralSiteSettings(
String.valueOf(mBlog.getRemoteBlogId()), new RestRequest.Listener() {
@Override
public void onResponse(JSONObject response) {
AppLog.d(AppLog.T.API, "Site Settings saved remotely");
notifySavedOnUiThread(null);
mRemoteSettings.copyFrom(mSettings);
if (response != null) {
JSONObject updated = response.optJSONObject(UPDATED_KEY);
if (updated == null) return;
HashMap<String, Object> properties = new HashMap<>();
Iterator<String> keys = updated.keys();
while (keys.hasNext()) {
String currentKey = keys.next();
Object currentValue = updated.opt(currentKey);
if (currentValue != null) {
properties.put(SAVED_ITEM_PREFIX + currentKey, currentValue);
}
}
AnalyticsUtils.trackWithCurrentBlogDetails(
AnalyticsTracker.Stat.SITE_SETTINGS_SAVED_REMOTELY, properties);
}
}
}, new RestRequest.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
AppLog.w(AppLog.T.API, "Error POSTing site settings changes: " + error);
notifySavedOnUiThread(error);
}
}, params);
}
/**
* Request remote site data via the WordPress REST API.
*/
@Override
protected void fetchRemoteData() {
fetchCategories();
WordPress.getRestClientUtils().getGeneralSettings(
String.valueOf(mBlog.getRemoteBlogId()), new RestRequest.Listener() {
@Override
public void onResponse(JSONObject response) {
AppLog.d(AppLog.T.API, "Received response to Settings REST request.");
credentialsVerified(true);
mRemoteSettings.localTableId = mBlog.getRemoteBlogId();
deserializeDotComRestResponse(mBlog, response);
if (!mRemoteSettings.equals(mSettings)) {
// postFormats setting is not returned by this api call so copy it over
final Map<String, String> currentPostFormats = mSettings.postFormats;
mSettings.copyFrom(mRemoteSettings);
mSettings.postFormats = currentPostFormats;
SiteSettingsTable.saveSettings(mSettings);
notifyUpdatedOnUiThread(null);
}
}
}, new RestRequest.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
AppLog.w(AppLog.T.API, "Error response to Settings REST request: " + error);
notifyUpdatedOnUiThread(error);
}
});
}
/**
* Sets values from a .com REST response object.
*/
public void deserializeDotComRestResponse(Blog blog, JSONObject response) {
if (blog == null || response == null) return;
JSONObject settingsObject = response.optJSONObject(SETTINGS_KEY);
mRemoteSettings.username = blog.getUsername();
mRemoteSettings.password = blog.getPassword();
mRemoteSettings.address = response.optString(URL_KEY, "");
mRemoteSettings.title = response.optString(GET_TITLE_KEY, "");
mRemoteSettings.tagline = response.optString(GET_DESC_KEY, "");
mRemoteSettings.languageId = settingsObject.optInt(LANGUAGE_ID_KEY, -1);
mRemoteSettings.privacy = settingsObject.optInt(PRIVACY_KEY, -2);
mRemoteSettings.defaultCategory = settingsObject.optInt(DEF_CATEGORY_KEY, 0);
mRemoteSettings.defaultPostFormat = settingsObject.optString(DEF_POST_FORMAT_KEY, "0");
mRemoteSettings.language = languageIdToLanguageCode(Integer.toString(mRemoteSettings.languageId));
mRemoteSettings.allowComments = settingsObject.optBoolean(ALLOW_COMMENTS_KEY, true);
mRemoteSettings.sendPingbacks = settingsObject.optBoolean(SEND_PINGBACKS_KEY, false);
mRemoteSettings.receivePingbacks = settingsObject.optBoolean(RECEIVE_PINGBACKS_KEY, true);
mRemoteSettings.shouldCloseAfter = settingsObject.optBoolean(CLOSE_OLD_COMMENTS_KEY, false);
mRemoteSettings.closeCommentAfter = settingsObject.optInt(CLOSE_OLD_COMMENTS_DAYS_KEY, 0);
mRemoteSettings.shouldThreadComments = settingsObject.optBoolean(THREAD_COMMENTS_KEY, false);
mRemoteSettings.threadingLevels = settingsObject.optInt(THREAD_COMMENTS_DEPTH_KEY, 0);
mRemoteSettings.shouldPageComments = settingsObject.optBoolean(PAGE_COMMENTS_KEY, false);
mRemoteSettings.commentsPerPage = settingsObject.optInt(PAGE_COMMENT_COUNT_KEY, 0);
mRemoteSettings.commentApprovalRequired = settingsObject.optBoolean(COMMENT_MODERATION_KEY, false);
mRemoteSettings.commentsRequireIdentity = settingsObject.optBoolean(REQUIRE_IDENTITY_KEY, false);
mRemoteSettings.commentsRequireUserAccount = settingsObject.optBoolean(REQUIRE_USER_ACCOUNT_KEY, true);
mRemoteSettings.commentAutoApprovalKnownUsers = settingsObject.optBoolean(WHITELIST_KNOWN_USERS_KEY, false);
mRemoteSettings.maxLinks = settingsObject.optInt(MAX_LINKS_KEY, 0);
mRemoteSettings.holdForModeration = new ArrayList<>();
mRemoteSettings.blacklist = new ArrayList<>();
String modKeys = settingsObject.optString(MODERATION_KEYS_KEY, "");
if (modKeys.length() > 0) {
Collections.addAll(mRemoteSettings.holdForModeration, modKeys.split("\n"));
}
String blacklistKeys = settingsObject.optString(BLACKLIST_KEYS_KEY, "");
if (blacklistKeys.length() > 0) {
Collections.addAll(mRemoteSettings.blacklist, blacklistKeys.split("\n"));
}
if (settingsObject.optString(COMMENT_SORT_ORDER_KEY, "").equals("asc")) {
mRemoteSettings.sortCommentsBy = ASCENDING_SORT;
} else {
mRemoteSettings.sortCommentsBy = DESCENDING_SORT;
}
if (settingsObject.optBoolean(RELATED_POSTS_ALLOWED_KEY, false)) {
mRemoteSettings.showRelatedPosts = settingsObject.optBoolean(RELATED_POSTS_ENABLED_KEY, false);
mRemoteSettings.showRelatedPostHeader = settingsObject.optBoolean(RELATED_POSTS_HEADER_KEY, false);
mRemoteSettings.showRelatedPostImages = settingsObject.optBoolean(RELATED_POSTS_IMAGES_KEY, false);
}
}
/**
* Helper method to create the parameters for the site settings POST request
*
* Using undocumented endpoint WPCOM_JSON_API_Site_Settings_Endpoint
* https://wpcom.trac.automattic.com/browser/trunk/public.api/rest/json-endpoints.php#L1903
*/
public Map<String, String> serializeDotComParams() {
Map<String, String> params = new HashMap<>();
if (mSettings.title!= null && !mSettings.title.equals(mRemoteSettings.title)) {
params.put(SET_TITLE_KEY, mSettings.title);
}
if (mSettings.tagline != null && !mSettings.tagline.equals(mRemoteSettings.tagline)) {
params.put(SET_DESC_KEY, mSettings.tagline);
}
if (mSettings.languageId != mRemoteSettings.languageId) {
params.put(LANGUAGE_ID_KEY, String.valueOf((mSettings.languageId)));
}
if (mSettings.privacy != mRemoteSettings.privacy) {
params.put(PRIVACY_KEY, String.valueOf((mSettings.privacy)));
}
if (mSettings.defaultCategory != mRemoteSettings.defaultCategory) {
params.put(DEF_CATEGORY_KEY, String.valueOf(mSettings.defaultCategory));
}
if (mSettings.defaultPostFormat != null && !mSettings.defaultPostFormat.equals(mRemoteSettings.defaultPostFormat)) {
params.put(DEF_POST_FORMAT_KEY, mSettings.defaultPostFormat);
}
if (mSettings.showRelatedPosts != mRemoteSettings.showRelatedPosts ||
mSettings.showRelatedPostHeader != mRemoteSettings.showRelatedPostHeader ||
mSettings.showRelatedPostImages != mRemoteSettings.showRelatedPostImages) {
params.put(RELATED_POSTS_ENABLED_KEY, String.valueOf(mSettings.showRelatedPosts));
params.put(RELATED_POSTS_HEADER_KEY, String.valueOf(mSettings.showRelatedPostHeader));
params.put(RELATED_POSTS_IMAGES_KEY, String.valueOf(mSettings.showRelatedPostImages));
}
if (mSettings.allowComments != mRemoteSettings.allowComments) {
params.put(ALLOW_COMMENTS_KEY, String.valueOf(mSettings.allowComments));
}
if (mSettings.sendPingbacks != mRemoteSettings.sendPingbacks) {
params.put(SEND_PINGBACKS_KEY, String.valueOf(mSettings.sendPingbacks));
}
if (mSettings.receivePingbacks != mRemoteSettings.receivePingbacks) {
params.put(RECEIVE_PINGBACKS_KEY, String.valueOf(mSettings.receivePingbacks));
}
if (mSettings.commentApprovalRequired != mRemoteSettings.commentApprovalRequired) {
params.put(COMMENT_MODERATION_KEY, String.valueOf(mSettings.commentApprovalRequired));
}
if (mSettings.closeCommentAfter != mRemoteSettings.closeCommentAfter
|| mSettings.shouldCloseAfter != mRemoteSettings.shouldCloseAfter) {
params.put(CLOSE_OLD_COMMENTS_KEY, String.valueOf(mSettings.shouldCloseAfter));
params.put(CLOSE_OLD_COMMENTS_DAYS_KEY, String.valueOf(mSettings.closeCommentAfter));
}
if (mSettings.sortCommentsBy != mRemoteSettings.sortCommentsBy) {
if (mSettings.sortCommentsBy == ASCENDING_SORT) {
params.put(COMMENT_SORT_ORDER_KEY, "asc");
} else if (mSettings.sortCommentsBy == DESCENDING_SORT) {
params.put(COMMENT_SORT_ORDER_KEY, "desc");
}
}
if (mSettings.threadingLevels != mRemoteSettings.threadingLevels
|| mSettings.shouldThreadComments != mRemoteSettings.shouldThreadComments) {
params.put(THREAD_COMMENTS_KEY, String.valueOf(mSettings.shouldThreadComments));
params.put(THREAD_COMMENTS_DEPTH_KEY, String.valueOf(mSettings.threadingLevels));
}
if (mSettings.commentsPerPage != mRemoteSettings.commentsPerPage
|| mSettings.shouldPageComments != mRemoteSettings.shouldPageComments) {
params.put(PAGE_COMMENTS_KEY, String.valueOf(mSettings.shouldPageComments));
params.put(PAGE_COMMENT_COUNT_KEY, String.valueOf(mSettings.commentsPerPage));
}
if (mSettings.commentsRequireIdentity != mRemoteSettings.commentsRequireIdentity) {
params.put(REQUIRE_IDENTITY_KEY, String.valueOf(mSettings.commentsRequireIdentity));
}
if (mSettings.commentsRequireUserAccount != mRemoteSettings.commentsRequireUserAccount) {
params.put(REQUIRE_USER_ACCOUNT_KEY, String.valueOf(mSettings.commentsRequireUserAccount));
}
if (mSettings.commentAutoApprovalKnownUsers != mRemoteSettings.commentAutoApprovalKnownUsers) {
params.put(WHITELIST_KNOWN_USERS_KEY, String.valueOf(mSettings.commentAutoApprovalKnownUsers));
}
if (mSettings.maxLinks != mRemoteSettings.maxLinks) {
params.put(MAX_LINKS_KEY, String.valueOf(mSettings.maxLinks));
}
if (mSettings.holdForModeration != null && !mSettings.holdForModeration.equals(mRemoteSettings.holdForModeration)) {
StringBuilder builder = new StringBuilder();
for (String key : mSettings.holdForModeration) {
builder.append(key);
builder.append("\n");
}
if (builder.length() > 1) {
params.put(MODERATION_KEYS_KEY, builder.substring(0, builder.length() - 1));
} else {
params.put(MODERATION_KEYS_KEY, "");
}
}
if (mSettings.blacklist != null && !mSettings.blacklist.equals(mRemoteSettings.blacklist)) {
StringBuilder builder = new StringBuilder();
for (String key : mSettings.blacklist) {
builder.append(key);
builder.append("\n");
}
if (builder.length() > 1) {
params.put(BLACKLIST_KEYS_KEY, builder.substring(0, builder.length() - 1));
} else {
params.put(BLACKLIST_KEYS_KEY, "");
}
}
return params;
}
/**
* Request a list of post categories for a site via the WordPress REST API.
*/
private void fetchCategories() {
WordPress.getRestClientUtilsV1_1().getCategories(String.valueOf(mBlog.getRemoteBlogId()),
new RestRequest.Listener() {
@Override
public void onResponse(JSONObject response) {
AppLog.d(AppLog.T.API, "Received response to Categories REST request.");
credentialsVerified(true);
CategoryModel[] models = deserializeJsonRestResponse(response);
if (models == null) return;
SiteSettingsTable.saveCategories(models);
mRemoteSettings.categories = models;
mSettings.categories = models;
notifyUpdatedOnUiThread(null);
}
}, new RestRequest.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
AppLog.d(AppLog.T.API, "Error fetching WP.com categories:" + error);
}
});
}
private CategoryModel deserializeCategoryFromJson(JSONObject category) throws JSONException {
if (category == null) return null;
CategoryModel model = new CategoryModel();
model.id = category.getInt(CAT_ID_KEY);
model.name = category.getString(CAT_NAME_KEY);
model.slug = category.getString(CAT_SLUG_KEY);
model.description = category.getString(CAT_DESC_KEY);
model.parentId = category.getInt(CAT_PARENT_ID_KEY);
model.postCount = category.getInt(CAT_POST_COUNT_KEY);
return model;
}
private CategoryModel[] deserializeJsonRestResponse(JSONObject response) {
try {
int num = response.getInt(CAT_NUM_POSTS_KEY);
JSONArray categories = response.getJSONArray(CATEGORIES_KEY);
CategoryModel[] models = new CategoryModel[num];
for (int i = 0; i < num; ++i) {
JSONObject category = categories.getJSONObject(i);
models[i] = deserializeCategoryFromJson(category);
}
AppLog.d(AppLog.T.API, "Successfully fetched WP.com categories");
return models;
} catch (JSONException exception) {
AppLog.d(AppLog.T.API, "Error parsing WP.com categories response:" + response);
return null;
}
}
}