package org.softeg.slartus.forpdaapi.post;
import android.text.Html;
import android.text.TextUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.softeg.slartus.forpdaapi.IHttpClient;
import org.softeg.slartus.forpdaapi.ProgressState;
import org.softeg.slartus.forpdacommon.NotReportException;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* User: slinkin
* Date: 08.06.12
* Time: 11:04
*/
public class PostApi {
public static final String NEW_POST_ID = "0";
/**
* Удаляет пост
*
* @throws IOException
*/
public static boolean delete(IHttpClient httpClient, String forumId, String topicId, String postId, CharSequence authKey) throws IOException {
httpClient.performGet("http://4pda.ru/forum/index.php?act=zmod&auth_key=" + authKey + "&code=postchoice&tact=delete&selectedpids=" + postId);
return true;// !TODO: проверка ответа
}
/**
* Возвращает страницу с редактируемым постом
*
* @param postId NEW_POST_ID, для создания нового поста
*/
public static String getEditPage(IHttpClient httpClient, String forumId, String topicId, String postId, String authKey) throws IOException {
String res;
if (postId.equals(NEW_POST_ID))
res = httpClient.performGet("http://4pda.ru/forum/index.php?act=post&do=reply_post&f=" + forumId
+ "&t=" + topicId);
else
res = httpClient.performGet("http://4pda.ru/forum/index.php?act=post&do=edit_post&f=" + forumId
+ "&t=" + topicId
+ "&p=" + postId
+ "&auth_key=" + authKey);
return res;
}
public static String getAttachPage(IHttpClient httpClient, String postId) throws IOException {
if (postId.equals(NEW_POST_ID))
return null;
return httpClient.performGet("http://4pda.ru/forum/index.php?&act=attach&code=attach_upload_show&attach_rel_id=" + postId);
}
/**
* Проверка страницы редактирования поста на ошибки (пост удалён ранее или нет прав на редактирование и т.д. )
*/
public static String checkEditPage(String editPage) {
String startFlag = "<textarea name=\"post\" rows=\"8\" cols=\"150\" style=\"width:98%; height:160px\" tabindex=\"0\">";
int startIndex = editPage.indexOf(startFlag);
if (startIndex == -1) {
Pattern pattern = Pattern.compile("<h4>Причина:</h4>\n" +
"\\s*\n" +
"\\s*<p>(.*)</p>", Pattern.MULTILINE);
Matcher m = pattern.matcher(editPage);
if (m.find()) {
return m.group(1);
}
return "Неизвестная причина";
}
return "";
}
/**
* Отправка изменений в посте
*
* @param enablesig включить подпись
* @param enableEmo включить смайлы
* @param addedFileList список айдишек уже загруженных файлов. Например, 0,1892529,1892530,1892533
* @throws IOException
*/
public static String applyEdit(IHttpClient httpClient, String forumId, String themeId, String authKey, String postId,
Boolean enablesig,
Boolean enableEmo, String postText, String addedFileList, String post_edit_reason) throws IOException {
Map<String, String> additionalHeaders = new HashMap<>();
additionalHeaders.put("act", "post");
additionalHeaders.put("s", "");
additionalHeaders.put("f", forumId);
additionalHeaders.put("auth_key", authKey);
additionalHeaders.put("removeattachid", "0");
additionalHeaders.put("MAX_FILE_SIZE", "0");
additionalHeaders.put("CODE", "09");
additionalHeaders.put("t", themeId);
additionalHeaders.put("p", postId);
additionalHeaders.put("view", "findpost");
//if(!TextUtils.isEmpty(post_edit_reason))
additionalHeaders.put("post_edit_reason", post_edit_reason);
additionalHeaders.put("file-list", addedFileList);
additionalHeaders.put("Post", postText);
if (enablesig)
additionalHeaders.put("enablesig", "yes");
if (enableEmo)
additionalHeaders.put("enableemo", "yes");
return httpClient.performPost("http://4pda.ru/forum/index.php", additionalHeaders);
}
/**
* Быстрый ответ
*
* @param addedFileList список айдишек уже загруженных файлов. Например, 0,1892529,1892530,1892533
* @throws IOException
*/
public static String reply(IHttpClient httpClient, String forumId, String topicId, String authKey, String attachPostKey, String post,
Boolean enablesig, Boolean enableemo, String addedFileList, boolean quick) throws IOException {
Map<String, String> additionalHeaders = new HashMap<>();
if (!quick) {
additionalHeaders.put("st", "0");
additionalHeaders.put("removeattachid", "0");
additionalHeaders.put("MAX_FILE_SIZE", "0");
additionalHeaders.put("parent_id", "0");
additionalHeaders.put("ed-0_wysiwyg_used", "0");
additionalHeaders.put("editor_ids[]", "ed-0");
additionalHeaders.put("iconid", "0");
additionalHeaders.put("_upload_single_file", "1");
additionalHeaders.put("file-list", addedFileList);
} else {
additionalHeaders.put("fast_reply_used", "1");
}
return quickReply(httpClient, additionalHeaders, forumId, topicId, authKey, attachPostKey, post,
enablesig, enableemo);
}
/**
* Быстрый ответ
*/
public static String quickReply(IHttpClient httpClient, Map<String, String> additionalHeaders, String forumId,
String topicId, String authKey, String attachPostKey, String post,
Boolean enablesig, Boolean enableemo) throws IOException {
additionalHeaders.put("act", "Post");
additionalHeaders.put("CODE", "03");
additionalHeaders.put("f", forumId);
additionalHeaders.put("t", topicId);
additionalHeaders.put("auth_key", authKey);
if (!TextUtils.isEmpty(attachPostKey))
additionalHeaders.put("attach_post_key", attachPostKey);
additionalHeaders.put("Post", post);
if (enablesig)
additionalHeaders.put("enablesig", "yes");
if (enableemo)
additionalHeaders.put("enableemo", "yes");
// additionalHeaders.put("referer", "http://4pda.ru/forum/index.php?act=Post&CODE=03&f=" + forumId + "&t=" + topicId + "&st=20&auth_key=" + authKey + "&fast_reply_used=1");
return httpClient.performPost("http://4pda.ru/forum/index.php", additionalHeaders);
}
public static String checkPostErrors(String page) {
Pattern checkPattern = Pattern.compile("\t\t<h4>Причина:</h4>\n" +
"\n" +
"\t\t<p>(.*?)</p>", Pattern.MULTILINE);
Matcher m = checkPattern.matcher(page);
if (m.find()) {
return m.group(1);
}
checkPattern = Pattern.compile("<div class=\".*?\">(<b>)?ОБНАРУЖЕНЫ СЛЕДУЮЩИЕ ОШИБКИ(</b>)?</div>\n" +
"\\s*<div class=\".*?\">(.*?)</div>", Pattern.MULTILINE);
m = checkPattern.matcher(page);
if (m.find()) {
return Html.fromHtml(m.group(3)).toString();
}
return null;
}
/**
* Аттачим файл к посту.
*
* @param addedFileList список айдишек уже загруженных файлов. Например, 0,1892529,1892530,1892533
* @throws Exception
*/
public static String attachFile(IHttpClient httpClient, String forumId, String topicId, String authKey,
String attachPostKey, String postId, Boolean enablesig, Boolean enableEmo,
String post, String filePath, String addedFileList,
ProgressState progress, String post_edit_reason) throws Exception {
Map<String, String> additionalHeaders = new HashMap<>();
additionalHeaders.put("st", "0");
additionalHeaders.put("f", forumId);
additionalHeaders.put("auth_key", authKey);
additionalHeaders.put("removeattachid", "0");
additionalHeaders.put("MAX_FILE_SIZE", "0");
additionalHeaders.put("t", topicId);
if (attachPostKey != null)
additionalHeaders.put("attach_post_key", attachPostKey);
additionalHeaders.put("parent_id", "0");
additionalHeaders.put("ed-0_wysiwyg_used", "0");
additionalHeaders.put("editor_ids[]", "ed-0");
additionalHeaders.put("_upload_single_file", "1");
additionalHeaders.put("upload_process", "Закачать");
additionalHeaders.put("file-list", addedFileList);
additionalHeaders.put("post_edit_reason", post_edit_reason);
if (!postId.equals(NEW_POST_ID)) {
additionalHeaders.put("p", postId);
additionalHeaders.put("act", "attach");
additionalHeaders.put("attach_rel_id", postId);
additionalHeaders.put("code", "attach_upload_process");
} else {
additionalHeaders.put("act", "Post");
}
additionalHeaders.put("CODE", "03");
additionalHeaders.put("Post", post);
if (enablesig)
additionalHeaders.put("enablesig", "yes");
if (enableEmo)
additionalHeaders.put("enableEmo", "yes");
additionalHeaders.put("iconid", "0");
if (postId.equals(NEW_POST_ID))
return httpClient.uploadFile("http://4pda.ru/forum/index.php", filePath, additionalHeaders,
progress);
httpClient.uploadFile("http://4pda.ru/forum/index.php", filePath, additionalHeaders, progress);
progress.update("Файл загружен, получение страницы", 100);
return getEditPage(httpClient, forumId, topicId, postId, authKey);
}
/**
* Деаттачим файл
*
* @throws Exception
*/
public static String deleteAttachedFile(IHttpClient httpClient, String forumId, String themeId, String authKey,
String postId, Boolean enablesig, Boolean enableemo,
String post, String attachToDeleteId, String fileList,
String post_edit_reason) throws Exception {
Map<String, String> additionalHeaders = new HashMap<>();
additionalHeaders.put("st", "0");
additionalHeaders.put("f", forumId);
additionalHeaders.put("auth_key", authKey);
additionalHeaders.put("removeattachid", "0");
additionalHeaders.put("MAX_FILE_SIZE", "0");
additionalHeaders.put("t", themeId);
additionalHeaders.put("p", postId);
additionalHeaders.put("ed-0_wysiwyg_used", "0");
additionalHeaders.put("editor_ids[]", "ed-0");
additionalHeaders.put("Post", post);
additionalHeaders.put("_upload_single_file", "1");
additionalHeaders.put("post_edit_reason", post_edit_reason);
additionalHeaders.put("file-list", fileList);
additionalHeaders.put("removeattach[" + attachToDeleteId + "]", "Удалить!");
if (!postId.equals(NEW_POST_ID)) {
additionalHeaders.put("act", "attach");
additionalHeaders.put("code", "attach_upload_remove");
additionalHeaders.put("attach_rel_id", postId);
additionalHeaders.put("attach_id", attachToDeleteId);
} else {
additionalHeaders.put("act", "Post");
}
additionalHeaders.put("CODE", "03");
if (enablesig)
additionalHeaders.put("enablesig", "yes");
if (enableemo)
additionalHeaders.put("enableemo", "yes");
if (postId.equals(NEW_POST_ID))
return httpClient.performPost("http://4pda.ru/forum/index.php", additionalHeaders);
httpClient.performPost("http://4pda.ru/forum/index.php", additionalHeaders);
return getEditPage(httpClient, forumId, themeId, postId, authKey);
}
/**
* Жалоба на пост
*
* @return Ошибка или пустая строка в случае успеха
* @throws IOException
*/
public static String claim(IHttpClient httpClient, String topicId, String postId, String message) throws IOException {
Map<String, String> additionalHeaders = new HashMap<>();
additionalHeaders.put("act", "report");
additionalHeaders.put("send", "1");
additionalHeaders.put("t", topicId);
additionalHeaders.put("p", postId);
additionalHeaders.put("message", message);
String res = httpClient.performPost("http://4pda.ru/forum/index.php?act=report&send=1&t=" + topicId + "&p=" + postId, additionalHeaders);
Pattern p = Pattern.compile("<div class=\"errorwrap\">\n" +
"\\s*<h4>Причина:</h4>\n" +
"\\s*\n" +
"\\s*<p>(.*)</p>", Pattern.MULTILINE);
Matcher m = p.matcher(res);
if (m.find()) {
return "Ошибка отправки жалобы: " + m.group(1);
}
return null;
}
private static String getStatusMessage(String status) {
switch (status) {
case "no_items":
return "Ни одного файла не загружено";
case "uploading_file":
return "Загрузка файла...";
case "init_progress":
return "Инициализация системы...";
case "upload_ok":
return "Файл успешно загружен и доступен в меню «Управление текущими файлами»";
case "upload_failed":
return "Неудачная загрузка. Необходимо проверить настройки и права доступа. Пожалуйста, сообщите об этом администрации.";
case "upload_too_big":
return "Неудачная загрузка. Файл имеет размер больше допустимого";
case "invalid_mime_type":
return "Неудачная загрузка. Вам запрещено загружать такой тип файлов";
case "no_upload_dir":
return "Неудачная загрузка. Директория загрузок файлов не доступна. Пожалуйста, сообщите об этом администрации.";
case "no_upload_dir_perms":
return "Неудачная загрузка. Невозможно произвести запись файла в директорию загрузок. Пожалуйста, сообщите об этом администрации.";
case "upload_no_file":
return "Вы не выбрали файл для загрузки";
case "upload_banned_file":
return "Неудачная загрузка. Вам запрещено загружать этот файл";
case "ready":
return "Система готова для загрузки файлов";
case "attach_remove":
return "Удалить файл";
case "attach_insert":
return "Вставить файл в текстовый редактор";
case "remove_warn":
return "Продолжить удаление файла?";
case "attach_removed":
return "Файл успешно удален";
case "attach_removal":
return "Удаление файла...";
default:
return status;
}
}
private static void checkAttachError(String page) throws NotReportException {
Matcher m = Pattern
.compile("pipsatt.status_msg = '([^']*)';\\s*pipsatt.status_is_error = parseInt\\('(\\d+)'\\);", Pattern.CASE_INSENSITIVE)
.matcher(page);
if (m.find()) {
if ("1".equals(m.group(2)))
throw new NotReportException(getStatusMessage(m.group(1)));
}
}
public static void deleteAttachedFile(IHttpClient httpClient,
String postId,
String attachId) throws Exception {
String res = httpClient
.performGet(String.format("http://4pda.ru/forum/index.php?&act=attach&code=attach_upload_remove&attach_rel_id=%s&attach_id=%s", postId,
attachId));
checkAttachError(res);
}
public static EditAttach attachFile(IHttpClient httpClient,
String postId,
String newFilePath,
ProgressState progress) throws Exception {
String res = httpClient.uploadFile("http://4pda.ru/forum/index.php?&act=attach&code=attach_upload_process&attach_rel_id=" + postId,
newFilePath, new HashMap<String, String>(),
progress);
Matcher m = Pattern
.compile("add_current_item\\(\\s*'(\\d+)',\\s*'([^']*)',\\s*'([^']*)',\\s*'([^']*)'\\s*\\);", Pattern.CASE_INSENSITIVE)
.matcher(res);
if (m.find()) {
return new EditAttach(m.group(1), m.group(2), m.group(3), m.group(4));
}
checkAttachError(res);
return null;
}
public static String sendPost(IHttpClient httpClient, EditPostParams params,
String postBody, String postEditReason,
Boolean enablesig, Boolean enableemo) throws IOException {
List<NameValuePair> nameValuePairs = params.getListParams();
nameValuePairs.add(new BasicNameValuePair("Post", postBody));
if (postEditReason != null)
nameValuePairs.add(new BasicNameValuePair("post_edit_reason", postEditReason));
if (enableemo)
nameValuePairs.add(new BasicNameValuePair("enableemo", "yes"));
if (enablesig)
nameValuePairs.add(new BasicNameValuePair("enablesig", "yes"));
return httpClient.performPost("http://4pda.ru/forum/index.php", nameValuePairs);
}
public static EditPost editPost(IHttpClient httpClient, String forumId, String topicId, String postId, String authKey) throws IOException {
String editPage = getEditPage(httpClient, forumId, topicId, postId, authKey);
Document doc = Jsoup.parse(editPage);
EditPost editPost = new EditPost();
Element postFormElement = doc.select("#postingform").first();
if (postFormElement != null) {
for (Element el : postFormElement.select("input[type=hidden]")) {
editPost.getParams().put(el.attr("name"), el.attr("value"));
}
// название опроса
Element element = postFormElement.select("input[name=poll_question]").first();
if (element != null)
editPost.getParams().put("poll_question", element.attr("value"));
parseInterviewParams(postFormElement.html(), editPost);
// текст поста
element = postFormElement.select("textarea[name=Post]").first();
if (element != null)
editPost.setBody(element.text());
// Причина редактирования
element = postFormElement.select("input[name=post_edit_reason]").first();
if (element != null)
editPost.setPostEditReason(element.attr("value"));
// Включить смайлы?
element = postFormElement.select("input[name=enableemo]").first();
if (element != null)
editPost.setEnableEmo("checked".equals(element.attr("checked")));
// Включить подпись?
element = postFormElement.select("input[name=enablesig]").first();
if (element != null)
editPost.setEnableSign("checked".equals(element.attr("checked")));
// управление текущими файлами
editPage = getAttachPage(httpClient, postId);
if (editPage != null) {
Matcher m = Pattern
.compile("add_current_item\\( '(\\d+)', '([^']*)', '([^']*)', '([^']*)' \\)", Pattern.CASE_INSENSITIVE)
.matcher(editPage);
while (m.find()) {
editPost.addAttach(new EditAttach(m.group(1), m.group(2), m.group(3), m.group(4)));
}
}
}
if (editPost.getBody() == null) {
Pattern pattern = Pattern.compile("<h4>Причина:</h4>\n" +
"\\s*\n" +
"\\s*<p>(.*)</p>", Pattern.MULTILINE);
assert editPage != null;
Matcher m = pattern.matcher(editPage);
if (m.find()) {
editPost.setError(m.group(1));
} else {
editPost.setError("Неизвестная причина");
}
}
return editPost;
}
/*
Парсим опрос
*/
private static void parseInterviewParams(String editPage, EditPost editPost) {
Matcher m = Pattern.compile("poll_questions\\s*=\\s*\\{(.*)?'\\}", Pattern.CASE_INSENSITIVE)
.matcher(editPage);
if (m.find()) {
String s = m.group(1) + "'";
m = Pattern.compile("\\s*(\\d+)\\s*:\\s*'([^']*)'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE)
.matcher(s);
String choicesText = getChoicesText(editPage);
while (m.find()) {
String questionNum = m.group(1);
editPost.getParams().put("question[" + questionNum + "]", Html.fromHtml(m.group(2)).toString());
Matcher choiceMatcher = Pattern.compile("\\s*'(" + questionNum + "_\\d+)'\\s*:\\s*'([^']*)'",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE)
.matcher(choicesText);
while (choiceMatcher.find()) {
editPost.getParams().put("choice[" + choiceMatcher.group(1) + "]", Html.fromHtml(choiceMatcher.group(2)).toString());
}
Matcher multiMatcher = Pattern.compile("\\s*" + questionNum + "\\s*:\\s*'([^']*)'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE)
.matcher(s);
while (multiMatcher.find()) {
if ("1".equals(multiMatcher.group(1))) {
editPost.getParams().put("multi[" + questionNum + "]", "1");
}
}
}
}
}
private static String getChoicesText(String editPage) {
String choicesText = "";
Matcher choicesMatcher = Pattern.compile("poll_choices\\s*=\\s*\\{(.*)?'\\}", Pattern.CASE_INSENSITIVE)
.matcher(editPage);
if (choicesMatcher.find()) {
choicesText = choicesMatcher.group(1) + "'";
}
return choicesText;
}
private static String getMultiText(String editPage) {
Matcher m = Pattern.compile("poll_multi\\s*=\\s*\\{(.*)?'\\}", Pattern.CASE_INSENSITIVE)
.matcher(editPage);
if (m.find()) {
return m.group(1) + "'";
}
return "";
}
}