Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge imports #1394

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/src/main/java/protect/card_locker/DBHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,14 @@ private static void updateFTS(final SQLiteDatabase db, final int id, final Strin
whereAttrs(LoyaltyCardDbFTS.ID), withArgs(id));
}

public static int getMaxLoyaltyCardId(final SQLiteDatabase database) {
Cursor data = database.rawQuery("SELECT IFNULL(MAX(" + LoyaltyCardDbIds.ID + "), 0) FROM " + LoyaltyCardDbIds.TABLE, null, null);
data.moveToFirst();
int maxId = data.getInt(0);
data.close();
return maxId;
}

public static long insertLoyaltyCard(
final SQLiteDatabase database, final String store, final String note, final Date validFrom,
final Date expiry, final BigDecimal balance, final Currency balanceType, final String cardId,
Expand Down
19 changes: 19 additions & 0 deletions app/src/main/java/protect/card_locker/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import protect.card_locker.preferences.Settings;

Expand Down Expand Up @@ -380,6 +382,23 @@ static public String getCardImageFileName(int loyaltyCardId, ImageLocationType t
return cardImageFileNameBuilder.toString();
}

static public String getRenamedCardImageFileName(final String fileName, final long idOffset) {
Pattern pattern = Pattern.compile("^(card_)(\\d+)(_(?:front|back|icon)\\.png)$");
Matcher matcher = pattern.matcher(fileName);
if (matcher.matches()) {
StringBuilder cardImageFileNameBuilder = new StringBuilder();
cardImageFileNameBuilder.append(matcher.group(1));
try {
cardImageFileNameBuilder.append(Integer.parseInt(matcher.group(2)) + idOffset);
} catch (NumberFormatException _e) {
return null;
}
cardImageFileNameBuilder.append(matcher.group(3));
return cardImageFileNameBuilder.toString();
}
return null;
}

static public void saveCardImage(Context context, Bitmap bitmap, String fileName) throws FileNotFoundException {
if (bitmap == null) {
context.deleteFile(fileName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Currency;
import java.util.Date;
import java.util.List;
import java.util.Set;

import protect.card_locker.CatimaBarcode;
import protect.card_locker.DBHelper;
Expand All @@ -39,7 +40,7 @@
* A header is expected for the each table showing the names of the columns.
*/
public class CatimaImporter implements Importer {
public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password) throws IOException, FormatException, InterruptedException {
public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password, Set<String> newImageFiles, int maxLoyaltyCardId) throws IOException, FormatException, InterruptedException {
InputStream bufferedInputStream = new BufferedInputStream(input);
bufferedInputStream.mark(100);

Expand All @@ -54,9 +55,14 @@ public void importData(Context context, SQLiteDatabase database, InputStream inp

String fileName = Uri.parse(localFileHeader.getFileName()).getLastPathSegment();
if (fileName.equals("catima.csv")) {
importCSV(context, database, zipInputStream);
importCSV(context, database, zipInputStream, maxLoyaltyCardId);
} else if (fileName.endsWith(".png")) {
Utils.saveCardImage(context, ZipUtils.readImage(zipInputStream), fileName);
String newFileName = Utils.getRenamedCardImageFileName(fileName, maxLoyaltyCardId);
if (newFileName == null) {
throw new FormatException("Unexpected PNG file in import: " + fileName);
}
Utils.saveCardImage(context, ZipUtils.readImage(zipInputStream), newFileName);
newImageFiles.add(newFileName);
} else {
throw new FormatException("Unexpected file in import: " + fileName);
}
Expand All @@ -65,34 +71,34 @@ public void importData(Context context, SQLiteDatabase database, InputStream inp
if (!isZipFile) {
// This is not a zip file, try importing as bare CSV
bufferedInputStream.reset();
importCSV(context, database, bufferedInputStream);
importCSV(context, database, bufferedInputStream, maxLoyaltyCardId);
}

input.close();
}

public void importCSV(Context context, SQLiteDatabase database, InputStream input) throws IOException, FormatException, InterruptedException {
public void importCSV(Context context, SQLiteDatabase database, InputStream input, int maxLoyaltyCardId) throws IOException, FormatException, InterruptedException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));

int version = parseVersion(bufferedReader);
switch (version) {
case 1:
parseV1(database, bufferedReader);
parseV1(database, bufferedReader, maxLoyaltyCardId);
break;
case 2:
parseV2(context, database, bufferedReader);
parseV2(context, database, bufferedReader, maxLoyaltyCardId);
break;
default:
throw new FormatException(String.format("No code to parse version %s", version));
}
}

public void parseV1(SQLiteDatabase database, BufferedReader input) throws IOException, FormatException, InterruptedException {
public void parseV1(SQLiteDatabase database, BufferedReader input, int maxLoyaltyCardId) throws IOException, FormatException, InterruptedException {
final CSVParser parser = new CSVParser(input, CSVFormat.RFC4180.builder().setHeader().build());

try {
for (CSVRecord record : parser) {
importLoyaltyCard(database, record);
importLoyaltyCard(database, record, maxLoyaltyCardId);

if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
Expand All @@ -105,7 +111,7 @@ public void parseV1(SQLiteDatabase database, BufferedReader input) throws IOExce
}
}

public void parseV2(Context context, SQLiteDatabase database, BufferedReader input) throws IOException, FormatException, InterruptedException {
public void parseV2(Context context, SQLiteDatabase database, BufferedReader input, int maxLoyaltyCardId) throws IOException, FormatException, InterruptedException {
int part = 0;
StringBuilder stringPart = new StringBuilder();

Expand All @@ -131,15 +137,15 @@ public void parseV2(Context context, SQLiteDatabase database, BufferedReader inp
break;
case 2:
try {
parseV2Cards(context, database, stringPart.toString());
parseV2Cards(context, database, stringPart.toString(), maxLoyaltyCardId);
sectionParsed = true;
} catch (FormatException e) {
// We may have a multiline field, try again
}
break;
case 3:
try {
parseV2CardGroups(database, stringPart.toString());
parseV2CardGroups(database, stringPart.toString(), maxLoyaltyCardId);
sectionParsed = true;
} catch (FormatException e) {
// We may have a multiline field, try again
Expand Down Expand Up @@ -193,7 +199,7 @@ public void parseV2Groups(SQLiteDatabase database, String data) throws IOExcepti
}
}

public void parseV2Cards(Context context, SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException {
public void parseV2Cards(Context context, SQLiteDatabase database, String data, int maxLoyaltyCardId) throws IOException, FormatException, InterruptedException {
// Parse cards
final CSVParser cardParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());

Expand All @@ -214,11 +220,11 @@ public void parseV2Cards(Context context, SQLiteDatabase database, String data)
}

for (CSVRecord record : records) {
importLoyaltyCard(database, record);
importLoyaltyCard(database, record, maxLoyaltyCardId);
}
}

public void parseV2CardGroups(SQLiteDatabase database, String data) throws IOException, FormatException, InterruptedException {
public void parseV2CardGroups(SQLiteDatabase database, String data, int maxLoyaltyCardId) throws IOException, FormatException, InterruptedException {
// Parse card group mappings
final CSVParser cardGroupParser = new CSVParser(new StringReader(data), CSVFormat.RFC4180.builder().setHeader().build());

Expand All @@ -239,7 +245,7 @@ public void parseV2CardGroups(SQLiteDatabase database, String data) throws IOExc
}

for (CSVRecord record : records) {
importCardGroupMapping(database, record);
importCardGroupMapping(database, record, maxLoyaltyCardId);
}
}

Expand Down Expand Up @@ -276,9 +282,12 @@ private int parseVersion(BufferedReader reader) throws IOException {
* Import a single loyalty card into the database using the given
* session.
*/
private void importLoyaltyCard(SQLiteDatabase database, CSVRecord record)
private void importLoyaltyCard(SQLiteDatabase database, CSVRecord record, int maxLoyaltyCardId)
throws FormatException {
int id = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.ID, record);
if (id < 1) {
throw new FormatException("ID must be >= 1");
}

String store = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.STORE, record, "");
if (store.isEmpty()) {
Expand Down Expand Up @@ -374,7 +383,8 @@ private void importLoyaltyCard(SQLiteDatabase database, CSVRecord record)
// We catch this exception so we can still import old backups
}

DBHelper.insertLoyaltyCard(database, id, store, note, validFrom, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starStatus, lastUsed, archiveStatus);
int newId = id + maxLoyaltyCardId;
DBHelper.insertLoyaltyCard(database, newId, store, note, validFrom, expiry, balance, balanceType, cardId, barcodeId, barcodeType, headerColor, starStatus, lastUsed, archiveStatus);
}

/**
Expand All @@ -395,16 +405,20 @@ private void importGroup(SQLiteDatabase database, CSVRecord record) throws Forma
* Import a single card to group mapping into the database using the given
* session.
*/
private void importCardGroupMapping(SQLiteDatabase database, CSVRecord record) throws FormatException {
private void importCardGroupMapping(SQLiteDatabase database, CSVRecord record, int maxLoyaltyCardId) throws FormatException {
int cardId = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIdsGroups.cardID, record);
String groupId = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIdsGroups.groupID, record, null);

if (cardId < 1) {
throw new FormatException("Card ID must be >= 1");
}
if (groupId == null) {
throw new FormatException("Group has no ID: " + record);
}

List<Group> cardGroups = DBHelper.getLoyaltyCardGroups(database, cardId);
int newCardId = cardId + maxLoyaltyCardId;
List<Group> cardGroups = DBHelper.getLoyaltyCardGroups(database, newCardId);
cardGroups.add(DBHelper.getGroup(database, groupId));
DBHelper.setLoyaltyCardGroups(database, cardId, cardGroups);
DBHelper.setLoyaltyCardGroups(database, newCardId, cardGroups);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.Set;

import protect.card_locker.CatimaBarcode;
import protect.card_locker.DBHelper;
Expand All @@ -31,7 +32,7 @@
* A header is expected for the each table showing the names of the columns.
*/
public class FidmeImporter implements Importer {
public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password, Set<String> newImageFiles, int maxLoyaltyCardId) throws IOException, FormatException, JSONException, ParseException {
// We actually retrieve a .zip file
ZipInputStream zipInputStream = new ZipInputStream(input, password);

Expand Down Expand Up @@ -130,4 +131,4 @@ private void importLoyaltyCard(Context context, SQLiteDatabase database, CSVReco

DBHelper.insertLoyaltyCard(database, store, note, null, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, headerColor, starStatus, null,archiveStatus);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.Set;

import protect.card_locker.FormatException;

Expand All @@ -23,5 +24,5 @@ public interface Importer {
* @throws IOException
* @throws FormatException
*/
void importData(Context context, SQLiteDatabase database, InputStream input, char[] password) throws IOException, FormatException, InterruptedException, JSONException, ParseException;
void importData(Context context, SQLiteDatabase database, InputStream input, char[] password, Set<String> newImageFiles, int maxLoyaltyCardId) throws IOException, FormatException, InterruptedException, JSONException, ParseException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
import net.lingala.zip4j.exception.ZipException;

import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;

import protect.card_locker.DBHelper;

public class MultiFormatImporter {
private static final String TAG = "Catima";
Expand Down Expand Up @@ -41,11 +45,17 @@ public static ImportExportResult importData(Context context, SQLiteDatabase data
}

String error = null;
Set<String> newImageFiles = new HashSet<>();
if (importer != null) {
database.beginTransaction();
try {
importer.importData(context, database, input, password);
int maxLoyaltyCardId = DBHelper.getMaxLoyaltyCardId(database);
Log.d(TAG, "Current max loyalty card id: " + maxLoyaltyCardId);
importer.importData(context, database, input, password, newImageFiles, maxLoyaltyCardId);
database.setTransactionSuccessful();
for (String fileName : newImageFiles) {
Log.d(TAG, "New image file: " + fileName);
}
return new ImportExportResult(ImportExportResultType.Success);
} catch (ZipException e) {
if (e.getType().equals(ZipException.Type.WRONG_PASSWORD)) {
Expand All @@ -65,6 +75,10 @@ public static ImportExportResult importData(Context context, SQLiteDatabase data
Log.e(TAG, error);
}

for (String fileName : newImageFiles) {
context.deleteFile(fileName);
}

return new ImportExportResult(ImportExportResultType.GenericFailure, error);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Set;

import protect.card_locker.CatimaBarcode;
import protect.card_locker.DBHelper;
Expand All @@ -42,7 +43,7 @@
public class StocardImporter implements Importer {
private static final String TAG = "Catima";

public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password, Set<String> newImageFiles, int maxLoyaltyCardId) throws IOException, FormatException, JSONException, ParseException {
HashMap<String, HashMap<String, Object>> loyaltyCardHashMap = new HashMap<>();
HashMap<String, HashMap<String, Object>> providers = new HashMap<>();

Expand Down Expand Up @@ -233,14 +234,20 @@ public void importData(Context context, SQLiteDatabase database, InputStream inp
long loyaltyCardInternalId = DBHelper.insertLoyaltyCard(database, store, note, null, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, headerColor, 0, null,0);

if (cardIcon != null) {
Utils.saveCardImage(context, cardIcon, (int) loyaltyCardInternalId, ImageLocationType.icon);
String fileName = Utils.getCardImageFileName((int) loyaltyCardInternalId, ImageLocationType.icon);
Utils.saveCardImage(context, cardIcon, fileName);
newImageFiles.add(fileName);
}

if (loyaltyCardData.containsKey("frontImage")) {
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("frontImage"), (int) loyaltyCardInternalId, ImageLocationType.front);
String fileName = Utils.getCardImageFileName((int) loyaltyCardInternalId, ImageLocationType.front);
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("frontImage"), fileName);
newImageFiles.add(fileName);
}
if (loyaltyCardData.containsKey("backImage")) {
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("backImage"), (int) loyaltyCardInternalId, ImageLocationType.back);
String fileName = Utils.getCardImageFileName((int) loyaltyCardInternalId, ImageLocationType.back);
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("backImage"), fileName);
newImageFiles.add(fileName);
}
}

Expand Down Expand Up @@ -272,4 +279,4 @@ private HashMap<String, HashMap<String, Object>> appendToHashMap(HashMap<String,

return loyaltyCardHashMap;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.text.SimpleDateFormat;
import java.util.Currency;
import java.util.Date;
import java.util.Set;
import java.util.TimeZone;

import protect.card_locker.CatimaBarcode;
Expand All @@ -36,7 +37,7 @@
* A header is expected for the each table showing the names of the columns.
*/
public class VoucherVaultImporter implements Importer {
public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password) throws IOException, FormatException, JSONException, ParseException {
public void importData(Context context, SQLiteDatabase database, InputStream input, char[] password, Set<String> newImageFiles, int maxLoyaltyCardId) throws IOException, FormatException, JSONException, ParseException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));

StringBuilder sb = new StringBuilder();
Expand Down Expand Up @@ -131,4 +132,4 @@ public void importData(Context context, SQLiteDatabase database, InputStream inp

bufferedReader.close();
}
}
}
Loading