/**
* This file is part of CrashCatcher library.
* Copyright (c) 2014, Sibext Ltd. (http://www.sibext.com),
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library 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 Lesser General Public License
* for more details (http://www.gnu.org/licenses/lgpl-3.0.txt).
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.sibext.android.activity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import com.sibext.android.tools.CatchActivity;
import com.sibext.android.tools.SHA1Helper;
import com.sibext.crashcatcher.R;
import com.taskadapter.redmineapi.RedmineException;
import com.taskadapter.redmineapi.RedmineManager;
import com.taskadapter.redmineapi.RedmineManager.INCLUDE;
import com.taskadapter.redmineapi.bean.Issue;
import com.taskadapter.redmineapi.bean.User;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
public class RedmineReportActivity extends NewDesignActivity {
private static final String TAG = "[CCL] RedmineReportActivity";
private String redmineHost = null;
private String redmineKey = null;
private String redmineProject = null;
private String assigneeLogin = null;
private HandlerThread thread;
private Handler handler;
private RedmineManager manager;
private boolean founded;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tryGetArgumentsFromManifest();
if (invalidArguments()) {
tryGetArgumentsFromResources();
}
if (invalidArguments()) {
throw new RuntimeException("Please setup readmine in your manifest or in your resources!");
}
thread = new HandlerThread(TAG);
thread.start();
handler = new Handler(thread.getLooper());
manager = new RedmineManager(redmineHost, redmineKey);
}
@Override
protected boolean onReportReadyForSend(final String title, final StringBuilder body,String resultPath, final boolean isManual, ErrorType errorType) {
Log.d(TAG, "onReportReadyForSend:");
final Issue issueToCreate = new Issue();
final File logFile = new File(resultPath);
issueToCreate.setSubject(title);
issueToCreate.setPriorityId(5);
issueToCreate.setDescription(body.toString() + SHA1Helper.getSHA1(body.toString()));
if (assigneeLogin != null) {
User user = new User();
user.setLogin(assigneeLogin);
issueToCreate.setAssignee(user);
}
handler.post(new Runnable() {
@Override
public void run() {
try {
sendIssue(issueToCreate, title, body, logFile, isManual);
} catch (RedmineException e) {
Log.d(TAG, "Can't create new issue", e);
onReportUnSent();
} catch (IOException e) {
Log.d(TAG, "Can't add attach to issue", e);
onReportUnSent();
} catch (Exception e) {
Log.d(TAG, "Can't send to redmine", e);
onReportUnSent();
}
}
});
return true;
}
@Override
protected void onDestroy() {
thread.quit();
super.onDestroy();
}
protected boolean isIgnoreDuplicates() {
return true;
}
protected boolean isDuplicate() {
return founded;
}
private boolean invalidArguments() {
return redmineHost == null || redmineKey == null || redmineProject == null;
}
private void tryGetArgumentsFromManifest() {
try {
ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(),
PackageManager.GET_META_DATA);
if(ai == null) {
return;
}
redmineHost = ai.metaData.getString(getString(R.string.metadata_redmine_host));
redmineKey = ai.metaData.getString(getString(R.string.metadata_redmine_key));
redmineProject = ai.metaData.getString(getString(R.string.metadata_redmine_project));
assigneeLogin = ai.metaData.getString(getString(R.string.metadata_redmine_assignee_login));
Log.d(TAG, "tryGetArgumentsFromManifest");
} catch (NameNotFoundException e) {
Log.e(TAG, "Can't get init params", e);
}
}
private void tryGetArgumentsFromResources() {
Log.d(TAG, "tryGetArgumentsFromResources");
redmineHost = getString(R.string.redmine_host);
redmineKey = getString(R.string.redmine_access_key);
redmineProject = getString(R.string.redmine_project);
assigneeLogin = getString(R.string.redmine_assignee_login);
}
private void sendIssue(final Issue issueToCreate, final String title, final StringBuilder body, final File logFile, final boolean isManual) throws RedmineException, IOException {
Log.d(TAG, "sendIssue:");
if (isIgnoreDuplicates() && !isManual) {
HashMap<String, String> params = new HashMap<String, String>();
params.put("project_id", redmineProject);
params.put("author_id", "me");
List<Issue> foundIssues = manager.getIssues(params);
founded = false;
Issue sameIssue = null;
for (Issue issue : foundIssues) {
if (issue.getDescription().contains(SHA1Helper.getSHA1(body.toString()))) {
founded = true;
sameIssue = issue;
break;
}
}
if (founded) {
Log.d(TAG, "sendIssue: is duplicate");
onReportSent(getString(R.string.com_sibext_crashcatcher_already_exist));
// Needs reopen if already closed or resolved
if (sameIssue.getStatusName().equalsIgnoreCase("Closed") || sameIssue.getStatusName().equalsIgnoreCase("Resolved")) {
Issue loadedIssueWithJournals = manager.getIssueById(sameIssue.getId(), INCLUDE.journals);
loadedIssueWithJournals.setStatusId(4);
loadedIssueWithJournals.setStatusName("Reopen");
loadedIssueWithJournals.setNotes(title + " has been detected again!\n" + "*Comments:* " + getNotes());
manager.update(loadedIssueWithJournals);
}
return;
}
}
Issue createdIssue = manager.createIssue(redmineProject, issueToCreate);
Log.d(TAG, "id of issue = " + createdIssue.getId());
Log.d(TAG, "log file = " + logFile.getAbsolutePath());
StringBuilder log = new StringBuilder("h1. LOG FILE");
FileInputStream inputStream = new FileInputStream(logFile);
if (hasNotes()) {
log.append("<pre><code class=\"text\">").append(getNotes()).append("</code></pre>");
}
log.append("<pre><code class=\"text\">");
try {
log.append(IOUtils.toString(inputStream));
} finally {
inputStream.close();
}
createdIssue.setNotes(log.toString());
//TODO: @moskvin Please implement attachment to redmine.
//final Attachment attach = manager.uploadAttachment("log.txt", "application/octet-stream", logFile);
//createdIssue.getAttachments().add(attach);
//Log.d(TAG, "attach size = " + createdIssue.getAttachments().size());
manager.update(createdIssue);
currentReportId = "#" + createdIssue.getId();
onReportSent();
}
}