/*
Copyright (C) 2014 Prasanna Thirumalai
This file is part of StackX.
StackX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
StackX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with StackX. If not, see <http://www.gnu.org/licenses/>.
*/
package com.prasanna.android.stacknetwork.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.prasanna.android.stacknetwork.model.Account;
import com.prasanna.android.stacknetwork.model.Answer;
import com.prasanna.android.stacknetwork.model.InboxItem;
import com.prasanna.android.stacknetwork.model.InboxItem.ItemType;
import com.prasanna.android.stacknetwork.model.Post;
import com.prasanna.android.stacknetwork.model.Question;
import com.prasanna.android.stacknetwork.model.Reputation;
import com.prasanna.android.stacknetwork.model.Site;
import com.prasanna.android.stacknetwork.model.StackExchangeHttpError;
import com.prasanna.android.stacknetwork.model.StackXPage;
import com.prasanna.android.stacknetwork.model.Tag;
import com.prasanna.android.stacknetwork.model.User;
import com.prasanna.android.stacknetwork.model.User.UserType;
import com.prasanna.android.stacknetwork.model.WritePermission;
import com.prasanna.android.stacknetwork.model.WritePermission.ObjectType;
import com.prasanna.android.stacknetwork.utils.AppUtils;
import com.prasanna.android.stacknetwork.utils.JSONObjectWrapper;
import com.prasanna.android.stacknetwork.utils.JsonFields;
import com.prasanna.android.stacknetwork.utils.OperatingSite;
import com.prasanna.android.stacknetwork.utils.StackUri;
import com.prasanna.android.stacknetwork.utils.StackUri.Order;
import com.prasanna.android.stacknetwork.utils.StackUri.Sort;
import com.prasanna.android.stacknetwork.utils.StringConstants;
import com.prasanna.android.utils.LogWrapper;
public class UserServiceHelper extends AbstractBaseServiceHelper {
private final String TAG = UserServiceHelper.class.getSimpleName();
private static final UserServiceHelper userService = new UserServiceHelper();
public static UserServiceHelper getInstance() {
return userService;
}
@Override
protected String getLogTag() {
return TAG;
}
public LinkedHashMap<String, Site> getAllSitesInNetwork() {
String restEndPoint = StringConstants.SITES;
LinkedHashMap<String, Site> sites = new LinkedHashMap<String, Site>();
boolean hasMore = true;
int page = 1;
final int PAGE_SIZE = 100;
Map<String, String> queryParams = AppUtils.getDefaultQueryParams();
queryParams.put(StackUri.QueryParams.PAGE_SIZE, String.valueOf(PAGE_SIZE));
while (hasMore) {
queryParams.put(StackUri.QueryParams.PAGE, String.valueOf(page++));
JSONObjectWrapper jsonObject = executeHttpGetRequest(restEndPoint, queryParams);
try {
hasMore = addSites(sites, jsonObject);
} catch (JSONException e) {
LogWrapper.d(getLogTag(), e.getMessage());
hasMore = false;
}
}
return sites;
}
private boolean addSites(LinkedHashMap<String, Site> sites, JSONObjectWrapper jsonObject) throws JSONException {
if (jsonObject != null) {
JSONArray jsonArray = jsonObject.getJSONArray(JsonFields.ITEMS);
if (jsonArray != null) {
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject siteJsonObject = jsonArray.getJSONObject(i);
Site site = getSerializedSiteObject(new JSONObjectWrapper(siteJsonObject));
if (site != null) sites.put(site.link, site);
}
}
return jsonObject.getBoolean(JsonFields.HAS_MORE);
}
return false;
}
private Site getSerializedSiteObject(JSONObjectWrapper siteJsonObject) {
if (siteJsonObject == null) return null;
Site site = new Site();
site.apiSiteParameter = siteJsonObject.getString(JsonFields.Site.API_SITE_PARAMETER);
site.logoUrl = siteJsonObject.getString(JsonFields.Site.LOGO_URL);
site.name = siteJsonObject.getString(JsonFields.Site.NAME);
site.audience = siteJsonObject.getString(JsonFields.Site.AUDIENCE);
site.link = siteJsonObject.getString(JsonFields.Site.SITE_URL);
site.faviconUrl = siteJsonObject.getString(JsonFields.Site.FAVICON_URL);
site.iconUrl = siteJsonObject.getString(JsonFields.Site.ICON_URL);
return site;
}
private StackXPage<Question> getQuestions(String restEndPoint, Map<String, String> queryParams) {
JSONObjectWrapper questionsJsonResponse = executeHttpGetRequest(restEndPoint, queryParams);
if (questionsJsonResponse != null) { return getQuestionModel(questionsJsonResponse); }
return null;
}
public StackXPage<Question> getMyQuestions(int page) {
return getQuestions("/me/questions", getQueryParams(page));
}
public StackXPage<Question> getQuestionsByUser(long userId, int page) {
return getQuestions("/users/" + userId + "/questions", getQueryParams(page));
}
public StackXPage<Question> getMyFavorites(int page) {
return getQuestions("/me/favorites", getQueryParams(page));
}
public StackXPage<Question> getFavoritesByUser(long userId, int page) {
return getQuestions("/users/" + userId + "/favorites", getQueryParams(page));
}
private Map<String, String> getQueryParams(int page) {
Map<String, String> queryParams = AppUtils.getDefaultQueryParams();
queryParams.put(StackUri.QueryParams.ORDER, StackUri.QueryParamDefaultValues.ORDER);
queryParams.put(StackUri.QueryParams.SORT, StackUri.Sort.ACTIVITY);
queryParams.put(StackUri.QueryParams.SITE, OperatingSite.getSite().apiSiteParameter);
queryParams.put(StackUri.QueryParams.PAGE, String.valueOf(page));
queryParams.put(StackUri.QueryParams.PAGE_SIZE, String.valueOf(StackUri.QueryParamDefaultValues.PAGE_SIZE));
return queryParams;
}
public StackXPage<User> getMe(String site) {
Map<String, String> queryParams = AppUtils.getDefaultQueryParams();
queryParams.put(StackUri.QueryParams.SITE, site);
queryParams.put(StackUri.QueryParams.FILTER, StackUri.QueryParamDefaultValues.USER_DETAIL_FILTER);
return getSerializedUserObject(executeHttpGetRequest("/me", queryParams));
}
public StackXPage<User> getUserById(long userId, String site) {
StackXPage<User> page = null;
Map<String, String> queryParams = AppUtils.getDefaultQueryParams();
queryParams.put(StackUri.QueryParams.SITE, site);
queryParams.put(StackUri.QueryParams.FILTER, StackUri.QueryParamDefaultValues.USER_DETAIL_FILTER);
if (userId != -1) page = getSerializedUserObject(executeHttpGetRequest("/users/" + userId, queryParams));
return page;
}
private StackXPage<Answer> getAnswers(String restEndPoint, Map<String, String> queryParams) {
StackXPage<Answer> page = new StackXPage<Answer>();
JSONObjectWrapper answersJsonObject = executeHttpGetRequest(restEndPoint, queryParams);
if (answersJsonObject != null) {
getPageInfo(answersJsonObject, page);
page.items = new ArrayList<Answer>();
JSONArray jsonArray = answersJsonObject.getJSONArray(JsonFields.ITEMS);
if (jsonArray != null) {
try {
for (int i = 0; i < jsonArray.length(); i++) {
JSONObjectWrapper jsonObject = JSONObjectWrapper.wrap(jsonArray.getJSONObject(i));
page.items.add(getSerializedAnswerObject(jsonObject));
}
} catch (JSONException e) {
LogWrapper.d(getLogTag(), e.getMessage());
}
}
}
return page;
}
public StackXPage<Answer> getMyAnswers(int page) {
return answers("/me/answers", page);
}
public StackXPage<Answer> getAnswersByUser(long userId, int page) {
return answers("/users/" + userId + "/answers", page);
}
private StackXPage<Answer> answers(String restEndPoint, int page) {
Map<String, String> queryParams = getQueryParams(page);
queryParams.put(StackUri.QueryParams.FILTER, StackUri.QueryParamDefaultValues.ITEM_DETAIL_FILTER);
return getAnswers(restEndPoint, queryParams);
}
public ArrayList<WritePermission> getWritePermissions(String site) {
ArrayList<WritePermission> permissions = new ArrayList<WritePermission>();
String restEndPoint = "me/write-permissions";
Map<String, String> queryParams = AppUtils.getDefaultQueryParams();
queryParams.put(StackUri.QueryParams.SITE, site);
JSONObjectWrapper jsonObjectWrapper = executeHttpGetRequest(restEndPoint, queryParams);
if (jsonObjectWrapper != null) {
JSONArray jsonArray = jsonObjectWrapper.getJSONArray(JsonFields.ITEMS);
if (jsonArray != null && jsonArray.length() > 0) {
try {
for (int i = 0; i < jsonArray.length(); i++) {
JSONObjectWrapper permissionJsonObject = JSONObjectWrapper.wrap(jsonArray.getJSONObject(i));
WritePermission permission = new WritePermission();
permission.canAdd = permissionJsonObject.getBoolean(JsonFields.Permission.CAN_ADD);
permission.canDelete = permissionJsonObject.getBoolean(JsonFields.Permission.CAN_DELETE);
permission.canEdit = permissionJsonObject.getBoolean(JsonFields.Permission.CAN_EDIT);
permission.maxDailyActions = permissionJsonObject.getInt(JsonFields.Permission.MAX_DAILY_ACTIONS);
permission.minSecondsBetweenActions =
permissionJsonObject.getInt(JsonFields.Permission.MIN_SECONDS_BETWEEN_ACTIONS);
permission.objectType =
ObjectType.getEnum(permissionJsonObject.getString(JsonFields.Permission.OBJECT_TYPE));
permission.userId = permissionJsonObject.getLong(JsonFields.Permission.USER_ID);
permissions.add(permission);
}
} catch (JSONException e) {
LogWrapper.d(getLogTag(), e.getMessage());
}
}
}
return permissions;
}
public StackXPage<InboxItem> getInbox(int page, int pageSize) {
String restEndPoint = "inbox";
Map<String, String> queryParams = AppUtils.getDefaultQueryParams();
queryParams.put(StackUri.QueryParams.ORDER, StackUri.QueryParamDefaultValues.ORDER);
queryParams.put(StackUri.QueryParams.SORT, StackUri.Sort.ACTIVITY);
queryParams.put(StackUri.QueryParams.PAGE, String.valueOf(page));
queryParams.put(StackUri.QueryParams.PAGE_SIZE, String.valueOf(pageSize));
queryParams.put(StackUri.QueryParams.FILTER, StackUri.QueryParamDefaultValues.USER_INBOX_FILTER);
return getInboxItems(restEndPoint, queryParams);
}
public StackXPage<InboxItem> getUnreadItemsInInbox(int page) {
String restEndPoint = "/inbox/unread";
Map<String, String> queryParams = AppUtils.getDefaultQueryParams();
queryParams.put(StackUri.QueryParams.PAGE, String.valueOf(page));
queryParams.put(StackUri.QueryParams.PAGE_SIZE, String.valueOf(StackUri.QueryParamDefaultValues.PAGE_SIZE));
queryParams.put(StackUri.QueryParams.FILTER, StackUri.QueryParamDefaultValues.USER_INBOX_FILTER);
return getInboxItems(restEndPoint, queryParams);
}
private StackXPage<InboxItem> getInboxItems(String restEndPoint, Map<String, String> queryParams) {
StackXPage<InboxItem> page = null;
JSONObjectWrapper jsonOfInboxItems = executeHttpGetRequest(restEndPoint, queryParams);
if (jsonOfInboxItems != null) {
JSONArray itemsArray = jsonOfInboxItems.getJSONArray(JsonFields.ITEMS);
if (itemsArray != null) {
page = new StackXPage<InboxItem>();
getPageInfo(jsonOfInboxItems, page);
page.items = new ArrayList<InboxItem>();
for (int i = 0; i < itemsArray.length(); i++) {
try {
JSONObjectWrapper itemJsonObject = JSONObjectWrapper.wrap(itemsArray.getJSONObject(i));
if (itemJsonObject != null) page.items.add(getSerializedInboxItem(itemJsonObject));
} catch (JSONException e) {
LogWrapper.d(getLogTag(), e.getMessage());
}
}
}
}
return page;
}
private InboxItem getSerializedInboxItem(JSONObjectWrapper itemJsonObject) {
InboxItem inboxItem = new InboxItem();
inboxItem.questionId = itemJsonObject.getLong(JsonFields.InboxItem.QUESTION_ID);
inboxItem.answerId = itemJsonObject.getLong(JsonFields.InboxItem.ANSWER_ID);
inboxItem.commentId = itemJsonObject.getLong(JsonFields.InboxItem.COMMENT_ID);
inboxItem.itemType = ItemType.getValue(itemJsonObject.getString(JsonFields.InboxItem.ITEM_TYPE));
inboxItem.title = itemJsonObject.getString(JsonFields.InboxItem.TITLE);
inboxItem.creationDate = itemJsonObject.getLong(JsonFields.InboxItem.CREATION_DATE);
inboxItem.body = itemJsonObject.getString(JsonFields.InboxItem.BODY);
inboxItem.unread = itemJsonObject.getBoolean(JsonFields.InboxItem.IS_UNREAD);
inboxItem.site = getSerializedSiteObject(itemJsonObject.getJSONObject(JsonFields.InboxItem.SITE));
return inboxItem;
}
public HashMap<String, Account> getMyAccount() {
Map<String, String> queryParams = AppUtils.getDefaultQueryParams();
queryParams.put(StackUri.QueryParams.FILTER, StackUri.QueryParamDefaultValues.NETWORK_USER_TYPE_FILTER);
return getAccounts("/me/associated", 1, queryParams);
}
public HashMap<String, Account> getAccount(long accountId) {
return getAccounts("/users/" + accountId + "/associated", 1, AppUtils.getDefaultQueryParams());
}
private HashMap<String, Account> getAccounts(String restEndPoint, int page, Map<String, String> queryParams) {
final int PAGE_SIZE = 100;
boolean hasMore = true;
HashMap<String, Account> accounts = new HashMap<String, Account>();
queryParams.put(StackUri.QueryParams.PAGE_SIZE, String.valueOf(PAGE_SIZE));
while (hasMore) {
queryParams.put(StackUri.QueryParams.PAGE, String.valueOf(page++));
hasMore = addAccountsToMap(accounts, executeHttpGetRequest(restEndPoint, queryParams));
}
return accounts;
}
private boolean addAccountsToMap(HashMap<String, Account> accounts, JSONObjectWrapper accountsJsonObject) {
if (accountsJsonObject != null) {
JSONArray jsonArray = accountsJsonObject.getJSONArray(JsonFields.ITEMS);
if (jsonArray != null) {
for (int i = 0; i < jsonArray.length(); i++) {
try {
JSONObjectWrapper accountJsonObject = JSONObjectWrapper.wrap(jsonArray.getJSONObject(i));
Account account = new Account();
account.id = accountJsonObject.getLong(JsonFields.Account.ACCOUNT_ID);
account.userId = accountJsonObject.getLong(JsonFields.Account.USER_ID);
account.siteName = accountJsonObject.getString(JsonFields.Account.SITE_NAME);
account.siteUrl = accountJsonObject.getString(JsonFields.Account.SITE_URL);
account.userType = UserType.toEnum(accountJsonObject.getString(JsonFields.Account.USER_TYPE));
accounts.put(account.siteUrl, account);
} catch (JSONException e) {
LogWrapper.d(getLogTag(), e.getMessage());
}
}
}
return accountsJsonObject.getBoolean(JsonFields.HAS_MORE);
}
return false;
}
public StackExchangeHttpError logout(String accessToken) {
StackExchangeHttpError error = new StackExchangeHttpError();
error.id = -1;
String restEndPoint = "/apps/" + accessToken + "/de-authenticate";
JSONObjectWrapper jsonObject = executeHttpGetRequest(restEndPoint, null);
if (jsonObject != null) {
String deauthenticatedAccessToken = jsonObject.getString(JsonFields.AccessToken.ACCESS_TOKEN);
if (deauthenticatedAccessToken == null || !accessToken.equals(deauthenticatedAccessToken)) {
error.id = jsonObject.getInt(JsonFields.Error.ERROR_ID);
error.name = jsonObject.getString(JsonFields.Error.ERROR_NAME);
error.message = jsonObject.getString(JsonFields.Error.ERROR_MESSAGE);
}
}
return error;
}
public LinkedHashSet<Tag> getTags(String site, int pageSize, boolean meTags) {
int page = 1;
LinkedHashSet<Tag> tags = null;
String restEndPoint = meTags ? "/me/tags" : "/tags";
boolean hasMore = true;
Map<String, String> queryParams = AppUtils.getDefaultQueryParams();
queryParams.put(StackUri.QueryParams.SORT, StackUri.Sort.ACTIVITY);
queryParams.put(StackUri.QueryParams.SITE, OperatingSite.getSite().apiSiteParameter);
queryParams.put(StackUri.QueryParams.PAGE_SIZE, String.valueOf(pageSize));
queryParams.put(StackUri.QueryParams.SORT, meTags ? Sort.NAME : Sort.POPULAR);
queryParams.put(StackUri.QueryParams.ORDER, meTags ? Order.ASC : Order.DESC);
while (hasMore) {
queryParams.put(StackUri.QueryParams.PAGE, String.valueOf(page++));
JSONObjectWrapper jsonObjectWrapper = executeHttpGetRequest(restEndPoint, queryParams);
if (jsonObjectWrapper != null) {
JSONArray jsonArray = jsonObjectWrapper.getJSONArray(JsonFields.ITEMS);
if (jsonArray != null && jsonArray.length() > 0) {
if (tags == null) tags = new LinkedHashSet<Tag>();
for (int i = 0; i < jsonArray.length(); i++) {
try {
JSONObjectWrapper tagJson = JSONObjectWrapper.wrap(jsonArray.getJSONObject(i));
tags.add(new Tag(tagJson.getString(JsonFields.Tag.NAME)));
} catch (JSONException e) {
LogWrapper.d(getLogTag(), e.getMessage());
}
}
}
/* Get all the tags only for a registered user */
hasMore = meTags ? jsonObjectWrapper.getBoolean(JsonFields.HAS_MORE) : false;
/*
* Dont bombard the server if the user has like 10-15 pages of tags,
* delay each request by 100ms
*/
sleep(100);
}
}
return tags;
}
public StackXPage<Reputation> reputationHistoryFull(int pageNum) {
final StackXPage<Reputation> page = new StackXPage<Reputation>();
final String restEndPoint = "me/reputation-history/full";
Map<String, String> queryParams = AppUtils.getDefaultQueryParams();
queryParams.put(StackUri.QueryParams.FILTER, StackUri.QueryParamDefaultValues.POST_TITLE_FILTER);
queryParams.put(StackUri.QueryParams.SITE, OperatingSite.getSite().apiSiteParameter);
queryParams.put(StackUri.QueryParams.PAGE, String.valueOf(pageNum));
queryParams.put(StackUri.QueryParams.PAGE_SIZE, String.valueOf("50"));
JSONObjectWrapper repHistory = executeHttpGetRequest(restEndPoint, queryParams);
getPageInfo(repHistory, page);
page.items = Reputation.parseCollection(repHistory);
final Map<Long, List<Reputation>> postIdToRepMap = new HashMap<Long, List<Reputation>>();
for (Reputation reputation : page.items) {
if (!postIdToRepMap.containsKey(reputation.postId)) {
postIdToRepMap.put(reputation.postId, new ArrayList<Reputation>());
}
postIdToRepMap.get(reputation.postId).add(reputation);
}
for (Post post : PostServiceHelper.getInstance().getPosts(postIdToRepMap.keySet(),
OperatingSite.getSite().apiSiteParameter)) {
for (Reputation reputation : postIdToRepMap.get(post.id)) {
reputation.postTitle = new String(post.title);
}
}
return page;
}
}