Skip to content

Commit

Permalink
Fixes codinguser#553 - Crash when adding a widget to the homescreen
Browse files Browse the repository at this point in the history
Closes codinguser#551 - Adds the book name to the export file name

Make the Exporter work on specific databases, and not only use the currently active databased. This fixes a bug where the only the default database is exported by the ScheduledActionsService, which leads to the wrong data being exported when handling scheduled actions from other books.
Update unit tests - fix some Recurrence tests
Implement #toString() for Commodity
  • Loading branch information
codinguser committed Aug 25, 2016
1 parent 19f02a4 commit e5daf4b
Show file tree
Hide file tree
Showing 17 changed files with 140 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ public void testExport(ExportFormat format){
}
}

File folder = new File(Exporter.getExportFolderPath());
File folder = new File(Exporter.getExportFolderPath(BooksDbAdapter.getInstance().getActiveBookUID()));
folder.mkdirs();
assertThat(folder).exists();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public void creatingNewAccounts_shouldCreatedNewBook(){

assertThat(mBooksDbAdapter.getRecordsCount()).isEqualTo(booksCount+1);

//// TODO: 25.08.2016 Delete all books before the start of this test
Book activeBook = mBooksDbAdapter.getRecord(mBooksDbAdapter.getActiveBookUID());
assertThat(activeBook.getDisplayName()).isEqualTo("Book " + (booksCount+1));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,7 @@ static int upgradeDbToVersion13(SQLiteDatabase db){
db.endTransaction();
}

//TODO: Move old files from old export folders into new book-specific export folders

//Migrate book-specific preferences away from shared preferences
Log.d(LOG_TAG, "Migrating shared preferences into book preferences");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,23 +123,6 @@ public boolean isActive(String bookUID){
return Integer.parseInt(isActive) > 0;
}

/**
* Returns the root account GUID of the current active book
* @return GUID of the root account
*/
public @NonNull String getActiveRootAccountUID(){
Cursor cursor = mDb.query(mTableName, new String[]{BookEntry.COLUMN_ROOT_GUID},
BookEntry.COLUMN_ACTIVE + "= 1", null, null, null, null, "1");
try{
if (cursor.moveToFirst()){
return cursor.getString(cursor.getColumnIndexOrThrow(BookEntry.COLUMN_ROOT_GUID));
}
} finally {
cursor.close();
}
return null;
}

/**
* Returns the GUID of the current active book
* @return GUID of the active book
Expand All @@ -149,7 +132,7 @@ public boolean isActive(String bookUID){
BookEntry.COLUMN_ACTIVE + "= 1", null, null, null, null, "1");
try{
if (cursor.getCount() == 0)
throw new RuntimeException("There is no active book in the app. This should NEVER happen!");
throw new RuntimeException("There is no active book in the app. This should NEVER happen, fix your bugs!");
cursor.moveToFirst();
return cursor.getString(cursor.getColumnIndexOrThrow(BookEntry.COLUMN_UID));
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,16 @@ protected Boolean doInBackground(ExportParams... params) {

switch (mExportParams.getExportFormat()) {
case QIF:
mExporter = new QifExporter(mExportParams);
mExporter = new QifExporter(mExportParams, mDb);
break;

case OFX:
mExporter = new OfxExporter(mExportParams);
mExporter = new OfxExporter(mExportParams, mDb);
break;

case XML:
default:
mExporter = new GncXmlExporter(mExportParams);
mExporter = new GncXmlExporter(mExportParams, mDb);
break;
}

Expand Down Expand Up @@ -414,11 +414,11 @@ private void moveExportToOwnCloud() {
*/
private List<String> moveExportToSDCard() {
Log.i(TAG, "Moving exported file to external storage");
new File(Exporter.getExportFolderPath());
new File(Exporter.getExportFolderPath(mExporter.mBookUID));
List<String> dstFiles = new ArrayList<>();

for (String src: mExportedFiles) {
String dst = Exporter.getExportFolderPath() + stripPathPart(src);
String dst = Exporter.getExportFolderPath(mExporter.mBookUID) + stripPathPart(src);
try {
moveFile(src, dst);
dstFiles.add(dst);
Expand Down
54 changes: 42 additions & 12 deletions app/src/main/java/org/gnucash/android/export/Exporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import org.gnucash.android.BuildConfig;
import org.gnucash.android.app.GnuCashApplication;
import org.gnucash.android.db.DatabaseSchema;
import org.gnucash.android.db.adapter.AccountsDbAdapter;
import org.gnucash.android.db.adapter.BooksDbAdapter;
import org.gnucash.android.db.adapter.BudgetAmountsDbAdapter;
Expand All @@ -37,6 +38,7 @@
import org.gnucash.android.db.adapter.ScheduledActionDbAdapter;
import org.gnucash.android.db.adapter.SplitsDbAdapter;
import org.gnucash.android.db.adapter.TransactionsDbAdapter;
import org.gnucash.android.model.Book;

import java.io.File;
import java.text.ParseException;
Expand Down Expand Up @@ -93,6 +95,16 @@ public abstract class Exporter {
protected final Context mContext;
private String mExportCacheFilePath;

/**
* Database being currently exported
*/
protected final SQLiteDatabase mDb;

/**
* GUID of the book being exported
*/
protected String mBookUID;

public Exporter(ExportParams params, SQLiteDatabase db) {
this.mExportParams = params;
mContext = GnuCashApplication.getAppContext();
Expand All @@ -104,8 +116,9 @@ public Exporter(ExportParams params, SQLiteDatabase db) {
mCommoditiesDbAdapter = CommoditiesDbAdapter.getInstance();
mBudgetsDbAdapter = BudgetsDbAdapter.getInstance();
mScheduledActionDbAdapter = ScheduledActionDbAdapter.getInstance();

mDb = GnuCashApplication.getActiveDb();
} else {
mDb = db;
mSplitsDbAdapter = new SplitsDbAdapter(db);
mTransactionsDbAdapter = new TransactionsDbAdapter(db, mSplitsDbAdapter);
mAccountsDbAdapter = new AccountsDbAdapter(db, mTransactionsDbAdapter);
Expand All @@ -116,24 +129,37 @@ public Exporter(ExportParams params, SQLiteDatabase db) {
mScheduledActionDbAdapter = new ScheduledActionDbAdapter(db, recurrenceDbAdapter);
}

mBookUID = new File(mDb.getPath()).getName(); //this depends on the database file always having the name of the book GUID
mExportCacheFilePath = null;
mCacheDir = new File(mContext.getCacheDir(), params.getExportFormat().name());
mCacheDir.mkdir();
purgeDirectory(mCacheDir);
}

/**
* Strings a string of any characters not allowed in a file name.
* All unallowed characters are replaced with an underscore
* @param inputName Raw file name input
* @return Sanitized file name
*/
public static String sanitizeFilename(String inputName) {
return inputName.replaceAll("[^a-zA-Z0-9-_\\.]", "_");
}

/**
* Builds a file name based on the current time stamp for the exported file
* @param format Format to use when exporting
* @param bookName Name of the book being exported. This name will be included in the generated file name
* @return String containing the file name
*/
public static String buildExportFilename(ExportFormat format) {
public static String buildExportFilename(ExportFormat format, String bookName) {
return EXPORT_FILENAME_DATE_FORMAT.format(new Date(System.currentTimeMillis()))
+ "_gnucash_export" + format.getExtension();
+ "_gnucash_export_" + sanitizeFilename(bookName) + format.getExtension();
}

/**
* Parses the name of an export file and returns the date of export
* @param filename Export file name generated by {@link #buildExportFilename(ExportFormat)}
* @param filename Export file name generated by {@link #buildExportFilename(ExportFormat,String)}
* @return Date in milliseconds
*/
public static long getExportTime(String filename){
Expand Down Expand Up @@ -184,31 +210,35 @@ protected String getExportCacheFilePath(){
String cachePath = mCacheDir.getAbsolutePath();
if (!cachePath.endsWith("/"))
cachePath += "/";
mExportCacheFilePath = cachePath + buildExportFilename(mExportParams.getExportFormat());
String bookName = BooksDbAdapter.getInstance().getAttribute(mBookUID, DatabaseSchema.BookEntry.COLUMN_DISPLAY_NAME);
mExportCacheFilePath = cachePath + buildExportFilename(mExportParams.getExportFormat(), bookName);
}

return mExportCacheFilePath;
}

/**
* Returns that path to the export folder for the currently active book.
* Returns that path to the export folder for the book with GUID {@code bookUID}.
* This is the folder where exports like QIF and OFX will be saved for access by external programs
* @param bookUID GUID of the book being exported. Each book has its own export path
* @return Absolute path to export folder for active book
*/
public static String getExportFolderPath(){
String path = BASE_FOLDER_PATH + "/" + BooksDbAdapter.getInstance().getActiveBookUID() + "/exports/";
public static String getExportFolderPath(String bookUID){
String path = BASE_FOLDER_PATH + "/" + bookUID + "/exports/";
File file = new File(path);
if (!file.exists())
file.mkdirs();
return path;
}

/**
* Returns the path to the backups folder for the currently active book
* @return Absolute path to backup folder for active book
* Returns the path to the backups folder for the book with GUID {@code bookUID}
* Each book has its own backup path
*
* @return Absolute path to backup folder for the book
*/
public static String getBackupFolderPath(){
String path = BASE_FOLDER_PATH + "/" + BooksDbAdapter.getInstance().getActiveBookUID() + "/backups/";
public static String getBackupFolderPath(String bookUID){
String path = BASE_FOLDER_PATH + "/" + bookUID + "/backups/";
File file = new File(path);
if (!file.exists())
file.mkdirs();
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/java/org/gnucash/android/export/ofx/OfxExporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.gnucash.android.export.ofx;

import android.database.sqlite.SQLiteDatabase;
import android.preference.PreferenceManager;
import android.util.Log;

Expand Down Expand Up @@ -76,6 +77,16 @@ public OfxExporter(ExportParams params) {
LOG_TAG = "OfxExporter";
}

/**
* Overloaded constructor. Initializes the export parameters and the database to export
* @param params Export options
* @param db SQLiteDatabase to export
*/
public OfxExporter(ExportParams params, SQLiteDatabase db){
super(params, db);
LOG_TAG = "OfxExporter";
}

/**
* Converts all expenses into OFX XML format and adds them to the XML document
* @param doc DOM document of the OFX expenses.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import org.gnucash.android.db.adapter.AccountsDbAdapter;
import org.gnucash.android.db.adapter.TransactionsDbAdapter;
Expand Down Expand Up @@ -50,9 +51,23 @@
* @author Yongxin Wang <fefe.wyx@gmail.com>
*/
public class QifExporter extends Exporter{
/**
* Initialize the exporter
* @param params Export options
*/
public QifExporter(ExportParams params){
super(params, null);
LOG_TAG = "QifExporter";
LOG_TAG = "OfxExporter";
}

/**
* Initialize the exporter
* @param params Options for export
* @param db SQLiteDatabase to export
*/
public QifExporter(ExportParams params, SQLiteDatabase db){
super(params, db);
LOG_TAG = "OfxExporter";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

import com.crashlytics.android.Crashlytics;

import org.gnucash.android.app.GnuCashApplication;
import org.gnucash.android.db.adapter.BooksDbAdapter;
import org.gnucash.android.db.adapter.CommoditiesDbAdapter;
import org.gnucash.android.db.DatabaseSchema;
import org.gnucash.android.db.adapter.RecurrenceDbAdapter;
Expand All @@ -33,6 +35,7 @@
import org.gnucash.android.model.Account;
import org.gnucash.android.model.AccountType;
import org.gnucash.android.model.BaseModel;
import org.gnucash.android.model.Book;
import org.gnucash.android.model.Commodity;
import org.gnucash.android.model.Budget;
import org.gnucash.android.model.BudgetAmount;
Expand Down Expand Up @@ -900,12 +903,13 @@ public String getExportMimeType(){
}

/**
* Creates a backup of current database contents to the directory {@link Exporter#getBackupFolderPath()}
* Creates a backup of current database contents to the directory {@link Exporter#getBackupFolderPath(String)}
* @return {@code true} if backup was successful, {@code false} otherwise
*/
public static boolean createBackup(){
try {
FileOutputStream fileOutputStream = new FileOutputStream(getBackupFilePath());
String bookUID = BooksDbAdapter.getInstance().getActiveBookUID();
FileOutputStream fileOutputStream = new FileOutputStream(getBackupFilePath(bookUID));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(bufferedOutputStream);
OutputStreamWriter writer = new OutputStreamWriter(gzipOutputStream);
Expand All @@ -922,12 +926,14 @@ public static boolean createBackup(){
}

/**
* Returns the full path of a file to make database backup.
* Returns the full path of a file to make database backup of the specified book
* Backups are done in XML format and are zipped (with ".zip" extension).
* @param bookUID GUID of the book
* @return the file path for backups of the database.
* @see #getBackupFolderPath()
* @see #getBackupFolderPath(String)
*/
private static String getBackupFilePath(){
return Exporter.getBackupFolderPath() + buildExportFilename(ExportFormat.XML) + ".zip";
private static String getBackupFilePath(String bookUID){
Book book = BooksDbAdapter.getInstance().getRecord(bookUID);
return Exporter.getBackupFolderPath(book.getUID()) + buildExportFilename(ExportFormat.XML, book.getDisplayName()) + ".zip";
}
}
9 changes: 9 additions & 0 deletions app/src/main/java/org/gnucash/android/model/Commodity.java
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,15 @@ public void setQuoteFlag(int quoteFlag) {
this.mQuoteFlag = quoteFlag;
}

@Override
/**
* Returns the full name of the currency, or the currency code if there is no full name
* @return String representation of the commodity
*/
public String toString() {
return mFullname == null || mFullname.isEmpty() ? mMnemonic : mFullname;
}

/**
* Overrides {@link BaseModel#equals(Object)} to compare only the currency codes of the commodity.
* <p>Two commodities are considered equal if they have the same currency code</p>
Expand Down
Loading

0 comments on commit e5daf4b

Please sign in to comment.