package com.yaoyumeng.v2ex.api;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.PersistentCookieStore;
import com.loopj.android.http.RequestParams;
import com.loopj.android.http.TextHttpResponseHandler;
import com.yaoyumeng.v2ex.Application;
import com.yaoyumeng.v2ex.R;
import com.yaoyumeng.v2ex.model.MemberModel;
import com.yaoyumeng.v2ex.model.NodeModel;
import com.yaoyumeng.v2ex.model.NotificationListModel;
import com.yaoyumeng.v2ex.model.NotificationModel;
import com.yaoyumeng.v2ex.model.PersistenceHelper;
import com.yaoyumeng.v2ex.model.ProfileModel;
import com.yaoyumeng.v2ex.model.ReplyModel;
import com.yaoyumeng.v2ex.model.TopicListModel;
import com.yaoyumeng.v2ex.model.TopicModel;
import com.yaoyumeng.v2ex.model.TopicWithReplyListModel;
import org.apache.http.Header;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class V2EXManager {
private static Application mApp = Application.getInstance();
private static AsyncHttpClient sClient = null;
private static final String TAG = "V2EXManager";
private static final String HTTP_API_URL = "http://www.v2ex.com/api";
private static final String HTTPS_API_URL = "https://www.v2ex.com/api";
public static final String HTTP_BASE_URL = "http://www.v2ex.com";
public static final String HTTPS_BASE_URL = "https://www.v2ex.com";
private static final String API_LATEST = "/topics/latest.json";
private static final String API_HOT = "/topics/hot.json";
private static final String API_ALL_NODE = "/nodes/all.json";
private static final String API_REPLIES = "/replies/show.json";
private static final String API_TOPIC = "/topics/show.json";
private static final String API_USER = "/members/show.json";
public static final String SIGN_UP_URL = HTTPS_BASE_URL + "/signup";
public static final String SIGN_IN_URL = HTTPS_BASE_URL + "/signin";
public static String getBaseAPIUrl() {
return mApp.isHttpsFromCache() ? HTTPS_API_URL : HTTP_API_URL;
}
public static String getBaseUrl() {
return mApp.isHttpsFromCache() ? HTTPS_BASE_URL : HTTP_BASE_URL;
}
//获取最热话题
public static void getHotTopics(Context cxt, boolean refresh,
HttpRequestHandler<ArrayList<TopicModel>> handler) {
getTopics(cxt, getBaseAPIUrl() + API_HOT, refresh, handler);
}
//获取最新话题
public static void getLatestTopics(Context ctx, boolean refresh,
HttpRequestHandler<ArrayList<TopicModel>> handler) {
getTopics(ctx, getBaseAPIUrl() + API_LATEST, refresh, handler);
}
//根据节点ID获取其话题
public static void getTopicsByNodeId(Context ctx, final int nodeId, boolean refresh,
final HttpRequestHandler<ArrayList<TopicModel>> handler) {
getTopics(ctx, getBaseAPIUrl() + API_TOPIC + "?node_id=" + nodeId, refresh, handler);
}
//根据节点名获取其话题
public static void getTopicsByNodeName(Context ctx, final String nodeName,
int page, boolean refresh,
final HttpRequestHandler<ArrayList<TopicModel>> handler) {
if (mApp.isJsonAPIFromCache())
getTopics(ctx, getBaseAPIUrl() + API_TOPIC + "?node_name=" + nodeName, refresh, handler);
else
getNodeTopicsFromBrowser(ctx, nodeName, page, refresh, handler);
}
//根据话题ID获取其内容
public static void getTopicByTopicId(Context cxt, int topicId, boolean refresh,
final HttpRequestHandler<ArrayList<TopicModel>> handler) {
getTopics(cxt, getBaseAPIUrl() + API_TOPIC + "?id=" + topicId, refresh, handler);
}
//根据用户名获取其发表过的话题
public static void getTopicsByUsername(Context ctx, final String username, boolean refresh,
HttpRequestHandler<ArrayList<TopicModel>> handler) {
getTopics(ctx, getBaseAPIUrl() + API_TOPIC + "?username=" + username, refresh, handler);
}
/**
* 获取各类话题列表
*
* @param ctx
* @param urlString URL地址
* @param refresh 是否从缓存中读取
* @param handler 结果处理
*/
public static void getTopics(Context ctx, String urlString, boolean refresh,
final HttpRequestHandler<ArrayList<TopicModel>> handler) {
Uri uri = Uri.parse(urlString);
String path = uri.getLastPathSegment();
String param = uri.getEncodedQuery();
String key = path;
if (param != null)
key += param;
if (!refresh) {
//尝试从缓存中加载
ArrayList<TopicModel> topics = PersistenceHelper.loadModelList(ctx, key);
if (topics != null && topics.size() > 0) {
SafeHandler.onSuccess(handler, topics);
return;
}
}
new AsyncHttpClient().get(ctx, urlString,
new WrappedJsonHttpResponseHandler<TopicModel>(ctx, TopicModel.class, key, handler));
}
/**
* 获取首页分类话题列表
*
* @param ctx
* @param tab tab名称
* @param refresh
* @param handler
*/
public static void getTopicsByTab(Context ctx, String tab, boolean refresh,
final HttpRequestHandler<ArrayList<TopicModel>> handler) {
getCategoryTopics(ctx, getBaseUrl() + "/?tab=" + tab, refresh, handler);
}
/**
* 获取用户创建的主题列表
* @param ctx
* @param username
* @param page
* @param handler
*/
public static void getTopicsByUsernameThroughBrowser(Context ctx, String username, int page,
HttpRequestHandler<ArrayList<TopicModel>> handler){
String url = String.format("%s/member/%s/topics?p=%d", getBaseUrl(), username, page);
getCategoryTopics(ctx, url, true, handler);
}
/**
* 获取我的收藏的话题
*
* @param ctx
* @param refresh
* @param handler
*/
public static void getMyFavoriteTopics(Context ctx, int page, boolean refresh,
final HttpRequestHandler<ArrayList<TopicModel>> handler) {
getCategoryTopics(ctx, getBaseUrl() + "/my/topics?p=" + page, refresh, handler);
}
/**
* 获取我的关注者的主题列表
* @param ctx
* @param page
* @param refresh
* @param handler
*/
public static void getTopicsOfMyFollowers(Context ctx, int page, boolean refresh,
final HttpRequestHandler<ArrayList<TopicModel>> handler){
getCategoryTopics(ctx, getBaseUrl() + "/my/following?p=" + page, refresh, handler);
}
/**
* 获取首页分类话题列表 (包括技术,创意,好玩,Apple,酷工作,交易,城市,问与答,R2)
*
* @param ctx
* @param urlString
* @param refresh
* @param handler
*/
public static void getCategoryTopics(final Context ctx, final String urlString, boolean refresh,
final HttpRequestHandler<ArrayList<TopicModel>> handler) {
final String key = Uri.parse(urlString).getEncodedQuery();
if (!refresh) {
//尝试从缓存中加载
ArrayList<TopicModel> topics = PersistenceHelper.loadModelList(ctx, key);
if (topics != null && topics.size() > 0) {
SafeHandler.onSuccess(handler, topics);
return;
}
}
final AsyncHttpClient client = getClient(ctx, false);
client.addHeader("Referer", getBaseUrl());
client.addHeader("Content-Type", "application/x-www-form-urlencoded");
client.get(urlString, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(ctx, V2EXErrorType.ErrorGetTopicListFailure));
}
@Override
public void onSuccess(int statusCode, Header[] headers, final String responseBody) {
new AsyncTask<Void, Void, TopicListModel>() {
@Override
protected TopicListModel doInBackground(Void... params) {
TopicListModel topics = new TopicListModel();
try {
topics.parse(responseBody);
if (topics.size() > 0 && topics.mCurrentPage == 1)
PersistenceHelper.saveModelList(ctx, topics, key);
return topics;
} catch (Exception e) {
return null;
}
}
@Override
protected void onPostExecute(TopicListModel topics) {
if (topics != null)
SafeHandler.onSuccess(handler, topics, topics.mTotalPage, topics.mCurrentPage);
else
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(ctx, V2EXErrorType.ErrorGetTopicListFailure));
}
}.execute();
}
});
}
/**
* 根据节点名获取其话题列表
*
* @param ctx
* @param nodeName 节点名
* @param page 页码
* @param refresh 是否从缓存加载
* @param handler
*/
public static void getNodeTopicsFromBrowser(final Context ctx, final String nodeName, int page,
boolean refresh, final HttpRequestHandler<ArrayList<TopicModel>> handler) {
String urlString = String.format("%s/go/%s?p=%d", getBaseUrl(), nodeName, page);
final AsyncHttpClient client = getClient(ctx, false);
String refer = page == 1 ? getBaseUrl() : String.format("%s/go/%s?p=%d", getBaseUrl(), nodeName, page-1);
client.addHeader("Referer", refer);
client.addHeader("Content-Type", "application/x-www-form-urlencoded");
client.get(urlString, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(ctx, V2EXErrorType.ErrorGetTopicListFailure));
}
@Override
public void onSuccess(int statusCode, Header[] headers, final String responseBody) {
new AsyncTask<Void, Void, TopicListModel>() {
@Override
protected TopicListModel doInBackground(Void... params) {
TopicListModel topics = new TopicListModel();
try {
topics.parseFromNodeEntry(responseBody, nodeName);
return topics;
} catch (Exception e) {
return null;
}
}
@Override
protected void onPostExecute(TopicListModel topics) {
if (topics != null)
SafeHandler.onSuccess(handler, topics, topics.mTotalPage, topics.mCurrentPage);
else
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(ctx, V2EXErrorType.ErrorGetTopicListFailure));
}
}.execute();
}
});
}
//获取所有节点
public static void getAllNodes(Context ctx, boolean refresh,
final HttpRequestHandler<ArrayList<NodeModel>> handler) {
final String key = "allnodes";
if (!refresh) {
//尝试从缓存中加载
ArrayList<NodeModel> nodes = PersistenceHelper.loadModelList(ctx, key);
if (nodes != null && nodes.size() > 0) {
SafeHandler.onSuccess(handler, nodes);
return;
}
}
new AsyncHttpClient().get(ctx, getBaseAPIUrl() + API_ALL_NODE,
new WrappedJsonHttpResponseHandler<NodeModel>(ctx, NodeModel.class, key, handler));
}
public static void getTopicAndRepliesByTopicId(final Context ctx, final int topicId, final int page,
boolean refresh,
final HttpRequestHandler<TopicWithReplyListModel> handler) {
String urlString = String.format("%s/t/%d?p=%d", getBaseUrl(), topicId, page);
final AsyncHttpClient client = getClient(ctx, false);
client.addHeader("Referer", getBaseUrl());
client.addHeader("Content-Type", "application/x-www-form-urlencoded");
client.get(urlString, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(ctx, V2EXErrorType.ErrorGetTopicDetailsFailure));
}
@Override
public void onSuccess(int statusCode, Header[] headers, final String responseBody) {
new AsyncTask<Void, Void, TopicWithReplyListModel>() {
@Override
protected TopicWithReplyListModel doInBackground(Void... params) {
TopicWithReplyListModel model = new TopicWithReplyListModel();
try {
model.parse(responseBody, page == 1, topicId);
} catch (Exception e) {
return null;
}
return model;
}
@Override
protected void onPostExecute(TopicWithReplyListModel m) {
if (m != null)
SafeHandler.onSuccess(handler, m, m.totalPage, m.currentPage);
else
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(ctx, V2EXErrorType.ErrorGetTopicDetailsFailure));
}
}.execute();
}
});
}
//根据话题ID获取其所有回复内容
public static void getRepliesByTopicId(Context ctx, int topicId, boolean refresh,
final HttpRequestHandler<ArrayList<ReplyModel>> handler) {
final String key = "replies_id=" + topicId;
if (!refresh) {
//尝试从缓存中加载
ArrayList<ReplyModel> replies = PersistenceHelper.loadModelList(ctx, key);
if (replies != null && replies.size() > 0) {
SafeHandler.onSuccess(handler, replies);
return;
}
}
new AsyncHttpClient().get(ctx, getBaseAPIUrl() + API_REPLIES + "?topic_id=" + topicId,
new WrappedJsonHttpResponseHandler<ReplyModel>(ctx, ReplyModel.class, key, handler));
}
//获取用户基本信息
public static void getMemberInfoByUsername(Context ctx, String username, boolean refresh,
final HttpRequestHandler<ArrayList<MemberModel>> handler) {
final String key = "username=" + username;
if (!refresh) {
//尝试从缓存中加载
ArrayList<MemberModel> member = PersistenceHelper.loadModelList(ctx, key);
if (member != null && member.size() > 0) {
SafeHandler.onSuccess(handler, member);
return;
}
}
new AsyncHttpClient().get(ctx, getBaseAPIUrl() + API_USER + "?username=" + username,
new WrappedJsonHttpResponseHandler<MemberModel>(ctx, MemberModel.class, key, handler));
}
private static AsyncHttpClient getClient(Context context, boolean mobile) {
if (context == null)
context = mApp.getBaseContext();
if (sClient == null) {
sClient = new AsyncHttpClient();
sClient.setEnableRedirects(false);
sClient.setCookieStore(new PersistentCookieStore(context));
sClient.addHeader("Cache-Control", "max-age=0");
sClient.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
sClient.addHeader("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7");
sClient.addHeader("Accept-Language", "zh-CN, en-US");
sClient.addHeader("Host", "www.v2ex.com");
}
if (mobile) {
sClient.addHeader("X-Requested-With", "com.android.browser");
sClient.setUserAgent("Mozilla/5.0 (Linux; U; Android 4.2.1; en-us; M040 Build/JOP40D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30");
} else {
sClient.setUserAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");
}
return sClient;
}
private static AsyncHttpClient getClient(Context context) {
return getClient(context, true);
}
private static String getOnceStringFromHtmlResponseObject(String content) {
Pattern pattern = Pattern.compile("<input type=\"hidden\" value=\"([0-9]+)\" name=\"once\" />");
final Matcher matcher = pattern.matcher(content);
if (matcher.find())
return matcher.group(1);
return null;
}
private static void requestOnceWithURLString(final Context cxt, String url,
final HttpRequestHandler<String> handler) {
AsyncHttpClient client = getClient(cxt);
client.addHeader("Referer", getBaseUrl());
client.get(url, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
String content = new String(responseBody);
String once = getOnceStringFromHtmlResponseObject(content);
if (once != null)
SafeHandler.onSuccess(handler, once);
else
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(cxt, V2EXErrorType.ErrorNoOnceAndNext));
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(cxt, V2EXErrorType.ErrorNoOnceAndNext));
}
});
}
private static String getProblemFromHtmlResponse(Context cxt, String response) {
Pattern errorPattern = Pattern.compile("<div class=\"problem\">(.*)</div>");
Matcher errorMatcher = errorPattern.matcher(response);
String errorContent;
if (errorMatcher.find()) {
errorContent = errorMatcher.group(1).replaceAll("<[^>]+>", "");
} else {
errorContent = cxt.getString(R.string.error_unknown);
}
return errorContent;
}
/**
* 使用用户名密码登录
*
* @param cxt
* @param username 用户名
* @param password 密码
* @param handler 返回结果处理
*/
public static void loginWithUsername(final Context cxt, final String username, final String password,
final HttpRequestHandler<Integer> handler) {
getClient(cxt).get(SIGN_IN_URL, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
String content = new String(responseBody);
Element body = Jsoup.parse(content);
Elements boxes = body.getElementsByClass("box");
RequestParams params = new RequestParams();
for (Element el : boxes) {
Elements cell = el.getElementsByClass("cell");
for (Element c : cell) {
String nameVal = c.getElementsByAttributeValue("type", "text").attr("name");
String passwordVal = c.getElementsByAttributeValue("type", "password").attr("name");
String once = c.getElementsByAttributeValue("name", "once").attr("value");
if (nameVal.isEmpty() || passwordVal.isEmpty()) continue;
params.put(nameVal, username);
params.put("once", once);
params.put(passwordVal, password);
break;
}
}
AsyncHttpClient client = getClient(cxt);
client.addHeader("Origin", HTTPS_BASE_URL);
client.addHeader("Referer", SIGN_IN_URL);
client.addHeader("Content-Type", "application/x-www-form-urlencoded");
client.post(SIGN_IN_URL, params, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
if (statusCode == 302) {
SafeHandler.onSuccess(handler, 200);
} else {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(cxt, V2EXErrorType.ErrorLoginFailure));
}
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseBody) {
String errorContent = getProblemFromHtmlResponse(cxt, responseBody);
SafeHandler.onFailure(handler, errorContent);
}
});
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(cxt, V2EXErrorType.ErrorLoginFailure));
}
});
}
private static ArrayList<NodeModel> getNodeModelsFromResponse(String content) {
Pattern pattern = Pattern.compile("<a class=\"grid_item\" href=\"/go/([^\"]+)\" id=([^>]+)><div([^>]+)><img src=\"([^\"]+)([^>]+)><([^>]+)></div>([^<]+)");
Matcher matcher = pattern.matcher(content);
ArrayList<NodeModel> collections = new ArrayList<NodeModel>();
while (matcher.find()) {
NodeModel node = new NodeModel();
node.name = matcher.group(1);
node.title = matcher.group(7);
node.url = matcher.group(4);
if (node.url.startsWith("//"))
node.url = "http:" + node.url;
else
node.url = HTTP_BASE_URL + node.url;
collections.add(node);
}
return collections;
}
private static String getRedeemURLFromResponse(String response) {
Document doc = Jsoup.parse(response);
Elements elements = doc.getElementsByTag("input");
if (elements == null || elements.size() <= 0)
return "";
String url = elements.attr("onclick");
url = url.replace("location.href = '", "").replace("';", "").trim();
return getBaseUrl() + url;
}
/**
* 每日签到
*
* @param ctx
* @param handler
*/
public static void dailyCheckIn(final Context ctx,
final HttpRequestHandler<Integer> handler) {
getClient(ctx, false).get(getBaseUrl() + "/mission/daily", new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(ctx, V2EXErrorType.ErrorCheckInFailure));
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseBody) {
String url = getRedeemURLFromResponse(responseBody);
if (url.isEmpty()) {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(ctx, V2EXErrorType.ErrorCheckInFailure));
return;
}
if (url.contains("/balance")) {
SafeHandler.onFailure(handler, "每日登录奖励已领取");
return;
}
AsyncHttpClient client = getClient(ctx, false);
client.addHeader("Origin", getBaseUrl());
client.addHeader("Referer", url);
client.addHeader("Content-Type", "application/x-www-form-urlencoded");
client.get(url, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
String errorContent = getProblemFromHtmlResponse(ctx, new String(responseBody));
SafeHandler.onFailure(handler, errorContent);
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
if (statusCode == 302) {
SafeHandler.onSuccess(handler, 200);
} else {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(ctx, V2EXErrorType.ErrorCheckInFailure));
}
}
});
}
});
}
/**
* 获取自己的收藏的节点
*
* @param context
* @param handler
*/
public static void getFavoriteNodes(final Context context,
final HttpRequestHandler<ArrayList<NodeModel>> handler) {
getClient(context).get(getBaseUrl() + "/my/nodes", new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(context, V2EXErrorType.ErrorFavNodeFailure));
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseBody) {
ArrayList<NodeModel> collections = getNodeModelsFromResponse(responseBody);
SafeHandler.onSuccess(handler, collections);
}
});
}
/**
* 获取登陆用户的用户基本资料
*
* @param context
* @param handler 用户基本资料的结果处理
*/
public static void getProfile(final Context context,
final HttpRequestHandler<ProfileModel> handler, boolean direct) {
//在登录之后立即访问主页可以获取主题收藏数
//但是直接访问主页却无法获取收藏数(返回的是移动端的界面),但是访问/my/nodes或/my/topics却可以
getClient(context, false).get(getBaseUrl() + (direct ? "/my/nodes" : ""), new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(context, V2EXErrorType.ErrorGetProfileFailure));
}
@Override
public void onSuccess(int statusCode, Header[] headers, final String responseBody) {
new AsyncTask<Void, Void, ProfileModel>() {
@Override
public ProfileModel doInBackground(Void... params) {
ProfileModel profile = new ProfileModel();
try {
profile.parse(responseBody);
return profile;
} catch (Exception e) {
return null;
}
}
@Override
protected void onPostExecute(ProfileModel profile) {
if (profile != null)
SafeHandler.onSuccess(handler, profile);
else
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(context, V2EXErrorType.ErrorGetProfileFailure));
}
}.execute();
}
});
}
/**
* 回复话题
*
* @param cxt
* @param topicId 话题Id
* @param content 评论内容
* @param handler 结果处理事件
*/
public static void replyCreateWithTopicId(final Context cxt, final int topicId, final String content,
final HttpRequestHandler<Integer> handler) {
final String urlString = getBaseUrl() + "/t/" + topicId;
requestOnceWithURLString(cxt, urlString, new HttpRequestHandler<String>() {
@Override
public void onSuccess(String data, int totalPages, int currentPage) {
}
@Override
public void onSuccess(String data) {
String once = data;
AsyncHttpClient client = getClient(cxt);
client.addHeader("Origin", getBaseUrl());
client.addHeader("Referer", urlString);
client.addHeader("Content-Type", "application/x-www-form-urlencoded");
RequestParams params = new RequestParams();
params.put("content", content);
params.put("once", once);
client.post(urlString, params, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
String errorContent = getProblemFromHtmlResponse(cxt, new String(responseBody));
SafeHandler.onFailure(handler, errorContent);
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
if (statusCode == 302) {
SafeHandler.onSuccess(handler, 200);
} else {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(cxt, V2EXErrorType.ErrorCommentFailure));
}
}
});
}
@Override
public void onFailure(String error) {
SafeHandler.onFailure(handler, error);
}
});
}
/**
* 创建新的话题
*
* @param cxt
* @param nodeName 节点名称
* @param title 话题的主标题
* @param content 话题的正文内容
* @param handler 结果处理事件
*/
public static void topicCreateWithNodeName(final Context cxt, final String nodeName,
final String title, final String content,
final HttpRequestHandler<Integer> handler) {
final String urlString = getBaseUrl() + "/new/" + nodeName;
requestOnceWithURLString(cxt, urlString, new HttpRequestHandler<String>() {
@Override
public void onSuccess(String data, int totalPages, int currentPage) {
}
@Override
public void onSuccess(String once) {
AsyncHttpClient client = getClient(cxt);
client.addHeader("Origin", getBaseUrl());
client.addHeader("Referer", urlString);
client.addHeader("Content-Type", "application/x-www-form-urlencoded");
RequestParams params = new RequestParams();
params.put("once", once);
params.put("content", content);
params.put("title", title);
client.post(urlString, params, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
String errorContent = getProblemFromHtmlResponse(cxt, new String(responseBody));
SafeHandler.onFailure(handler, errorContent);
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
if (statusCode == 302) {
SafeHandler.onSuccess(handler, 200);
} else {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(cxt, V2EXErrorType.ErrorCreateNewFailure));
}
}
});
}
@Override
public void onFailure(String error) {
SafeHandler.onFailure(handler, error);
}
});
}
private static String getFavUrlStringFromEnResponse(String response) {
Pattern pattern = Pattern.compile("<a href=\"(.*)\">Favorite This Node</a>");
Matcher matcher = pattern.matcher(response);
if (matcher.find())
return matcher.group(1);
pattern = Pattern.compile("<a href=\"(.*)\">Unfavorite</a>");
matcher = pattern.matcher(response);
if (matcher.find())
return matcher.group(1);
return "";
}
private static String getFavUrlStringFromResponse(String response) {
Pattern pattern = Pattern.compile("<a href=\"(.*)\">加入收藏</a>");
Matcher matcher = pattern.matcher(response);
if (matcher.find())
return matcher.group(1);
pattern = Pattern.compile("<a href=\"(.*)\">取消收藏</a>");
matcher = pattern.matcher(response);
if (matcher.find())
return matcher.group(1);
return "";
}
/**
* 某个节点加入收藏或者取消收藏
*
* @param context
* @param nodeName 节点名称
* @param handler 结果处理事件
*/
public static void favNodeWithNodeName(final Context context, String nodeName,
final HttpRequestHandler<Integer> handler) {
String urlString = getBaseUrl() + "/go/" + nodeName;
final AsyncHttpClient client = getClient(context, false);
client.addHeader("Referer", getBaseUrl());
client.addHeader("Content-Type", "application/x-www-form-urlencoded");
client.get(urlString, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(context, V2EXErrorType.ErrorFavNodeFailure));
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseBody) {
String favUrl = getFavUrlStringFromResponse(responseBody);
if (favUrl.isEmpty()) {
favUrl = getFavUrlStringFromEnResponse(responseBody);
}
if (favUrl.isEmpty()) {
SafeHandler.onFailure(handler, context.getString(R.string.error_unknown));
return;
}
final boolean fav = !favUrl.contains("unfavorite");
client.get(context, getBaseUrl() + favUrl, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
if (statusCode == 302) {
SafeHandler.onSuccess(handler, fav ? 200 : 201);
} else {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(context, V2EXErrorType.ErrorFavNodeFailure));
}
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseString) {
SafeHandler.onFailure(handler, getProblemFromHtmlResponse(context, responseString));
}
});
}
});
}
/**
* 将某个话题加入收藏或者取消收藏
*
* @param context
* @param topicId 话题ID号
* @param handler 结果处理
*/
public static void favTopicWithTopicId(final Context context, int topicId,
final HttpRequestHandler<Integer> handler) {
String urlString = getBaseUrl() + "/t/" + topicId;
final AsyncHttpClient client = getClient(context, false);
client.addHeader("Referer", getBaseUrl());
client.addHeader("Content-Type", "application/x-www-form-urlencoded");
client.get(urlString, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(context, V2EXErrorType.ErrorFavTopicFailure));
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseBody) {
String favUrl = getFavUrlStringFromResponse(responseBody);
Log.i(TAG, favUrl);
if (favUrl.isEmpty()) {
SafeHandler.onFailure(handler, context.getString(R.string.error_unknown));
return;
}
favUrl = favUrl.replace("\" class=\"tb", "");
final boolean fav = !favUrl.contains("unfavorite");
client.get(context, getBaseUrl() + favUrl, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
if (statusCode == 302) {
SafeHandler.onSuccess(handler, fav ? 200 : 201);
} else {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(context, V2EXErrorType.ErrorFavTopicFailure));
}
}
@Override
public void onSuccess(int statusCode, Header[] headers, String responseString) {
SafeHandler.onFailure(handler, getProblemFromHtmlResponse(context, responseString));
}
});
}
});
}
/**
* 获取用户的未读提醒消息
*
* @param context
* @param handler
*/
public static void getNotifications(final Context context, int page,
final HttpRequestHandler<ArrayList<NotificationModel>> handler) {
String urlString = getBaseUrl() + "/notifications";
if (page > 1) urlString += "?p=" + page;
final AsyncHttpClient client = getClient(context, false);
client.addHeader("Referer", getBaseUrl());
client.addHeader("Content-Type", "application/x-www-form-urlencoded");
client.get(urlString, new TextHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(context, V2EXErrorType.ErrorGetNotificationFailure));
}
@Override
public void onSuccess(int statusCode, Header[] headers, final String responseBody) {
new AsyncTask<Void, Void, NotificationListModel>() {
@Override
protected NotificationListModel doInBackground(Void... params) {
NotificationListModel notifications = new NotificationListModel();
try {
notifications.parse(responseBody);
return notifications;
} catch (Exception e) {
return null;
}
}
@Override
protected void onPostExecute(NotificationListModel notifies) {
if (notifies != null)
SafeHandler.onSuccess(handler, notifies, notifies.totalPage, notifies.currentPage);
else
SafeHandler.onFailure(handler, V2EXErrorType.errorMessage(context, V2EXErrorType.ErrorGetNotificationFailure));
}
}.execute();
}
});
}
/**
* 退出登录
*
* @param context
*/
public static void logout(Context context) {
PersistentCookieStore cookieStore = new PersistentCookieStore(context);
cookieStore.clear();
}
}