Merge pull request #1434 from obfusk/refactor-importer-part-2

refactor importer part 2
This commit is contained in:
Sylvia van Os
2023-07-19 21:17:22 +02:00
committed by GitHub
3 changed files with 139 additions and 23 deletions

View File

@@ -19,10 +19,13 @@ import java.io.StringReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import protect.card_locker.CatimaBarcode;
import protect.card_locker.DBHelper;
import protect.card_locker.FormatException;
import protect.card_locker.LoyaltyCard;
import protect.card_locker.Utils;
/**
@@ -33,6 +36,14 @@ import protect.card_locker.Utils;
* A header is expected for the each table showing the names of the columns.
*/
public class FidmeImporter implements Importer {
public static class ImportedData {
public final List<LoyaltyCard> cards;
ImportedData(final List<LoyaltyCard> cards) {
this.cards = cards;
}
}
public void importData(Context context, SQLiteDatabase database, File inputFile, char[] password) throws IOException, FormatException, JSONException, ParseException {
InputStream input = new FileInputStream(inputFile);
// We actually retrieve a .zip file
@@ -57,10 +68,14 @@ public class FidmeImporter implements Importer {
}
final CSVParser fidmeParser = new CSVParser(new StringReader(loyaltyCards.toString()), CSVFormat.RFC4180.builder().setDelimiter(';').setHeader().build());
ImportedData importedData = new ImportedData(new ArrayList<>());
try {
for (CSVRecord record : fidmeParser) {
importLoyaltyCard(context, database, record);
LoyaltyCard card = importLoyaltyCard(context, record);
if (card != null) {
importedData.cards.add(card);
}
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
@@ -74,14 +89,15 @@ public class FidmeImporter implements Importer {
zipInputStream.close();
input.close();
saveAndDeduplicate(database, importedData);
}
/**
* Import a single loyalty card into the database using the given
* session.
*/
private void importLoyaltyCard(Context context, SQLiteDatabase database, CSVRecord record)
throws FormatException {
private LoyaltyCard importLoyaltyCard(Context context, CSVRecord record) throws FormatException {
// A loyalty card export from Fidme contains the following fields:
// Retailer (store name)
// Program (program name)
@@ -117,7 +133,7 @@ public class FidmeImporter implements Importer {
// Fidme deletes the card id if a card is expired
// Because Catima considers the card id a required field, we ignore these expired cards
// https://github.com/CatimaLoyalty/Android/issues/1005
return;
return null;
}
// Sadly, Fidme exports don't contain the card type
@@ -132,6 +148,17 @@ public class FidmeImporter implements Importer {
// TODO: Front and back image
DBHelper.insertLoyaltyCard(database, store, note, null, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, headerColor, starStatus, null,archiveStatus);
// use -1 for the ID, it will be ignored when inserting the card into the DB
return new LoyaltyCard(-1, store, note, null, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, headerColor, starStatus, Utils.getUnixTime(), DBHelper.DEFAULT_ZOOM_LEVEL, archiveStatus);
}
public void saveAndDeduplicate(SQLiteDatabase database, final ImportedData data) {
// This format does not have IDs that can cause conflicts
// Proper deduplication for all formats will be implemented later
for (LoyaltyCard card : data.cards) {
// Do not use card.id which is set to -1
DBHelper.insertLoyaltyCard(database, card.store, card.note, card.validFrom, card.expiry, card.balance, card.balanceType,
card.cardId, card.barcodeId, card.barcodeType, card.headerColor, card.starStatus, card.lastUsed, card.archiveStatus);
}
}
}

View File

@@ -24,12 +24,16 @@ import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import protect.card_locker.CatimaBarcode;
import protect.card_locker.DBHelper;
import protect.card_locker.FormatException;
import protect.card_locker.ImageLocationType;
import protect.card_locker.LoyaltyCard;
import protect.card_locker.R;
import protect.card_locker.Utils;
import protect.card_locker.ZipUtils;
@@ -42,11 +46,30 @@ import protect.card_locker.ZipUtils;
* A header is expected for the each table showing the names of the columns.
*/
public class StocardImporter implements Importer {
public static class ZIPData {
public final HashMap<String, HashMap<String, Object>> loyaltyCardHashMap;
public final HashMap<String, HashMap<String, Object>> providers;
ZIPData(final HashMap<String, HashMap<String, Object>> loyaltyCardHashMap, final HashMap<String, HashMap<String, Object>> providers) {
this.loyaltyCardHashMap = loyaltyCardHashMap;
this.providers = providers;
}
}
public static class ImportedData {
public final List<LoyaltyCard> cards;
public final Map<Integer, Map<ImageLocationType, Bitmap>> images;
ImportedData(final List<LoyaltyCard> cards, final Map<Integer, Map<ImageLocationType, Bitmap>> images) {
this.cards = cards;
this.images = images;
}
}
private static final String TAG = "Catima";
public void importData(Context context, SQLiteDatabase database, File inputFile, char[] password) throws IOException, FormatException, JSONException, ParseException {
HashMap<String, HashMap<String, Object>> loyaltyCardHashMap = new HashMap<>();
HashMap<String, HashMap<String, Object>> providers = new HashMap<>();
ZIPData zipData = new ZIPData(new HashMap<>(), new HashMap<>());
final CSVParser parser = new CSVParser(new InputStreamReader(context.getResources().openRawResource(R.raw.stocard_stores), StandardCharsets.UTF_8), CSVFormat.RFC4180.builder().setHeader().build());
@@ -56,7 +79,7 @@ public class StocardImporter implements Importer {
recordData.put("name", record.get("name"));
recordData.put("barcodeFormat", record.get("barcodeFormat"));
providers.put(record.get("_id"), recordData);
zipData.providers.put(record.get("_id"), recordData);
}
parser.close();
@@ -66,6 +89,21 @@ public class StocardImporter implements Importer {
InputStream input = new FileInputStream(inputFile);
ZipInputStream zipInputStream = new ZipInputStream(input, password);
zipData = importZIP(zipInputStream, zipData);
zipInputStream.close();
input.close();
if (zipData.loyaltyCardHashMap.keySet().size() == 0) {
throw new FormatException("Couldn't find any loyalty cards in this Stocard export.");
}
ImportedData importedData = importLoyaltyCardHashMap(context, zipData);
saveAndDeduplicate(context, database, importedData);
}
public ZIPData importZIP(ZipInputStream zipInputStream, final ZIPData zipData) throws IOException, JSONException {
HashMap<String, HashMap<String, Object>> loyaltyCardHashMap = zipData.loyaltyCardHashMap;
HashMap<String, HashMap<String, Object>> providers = zipData.providers;
String[] providersFileName = null;
String[] customProvidersBaseName = null;
@@ -197,11 +235,14 @@ public class StocardImporter implements Importer {
}
}
if (loyaltyCardHashMap.keySet().size() == 0) {
throw new FormatException("Couldn't find any loyalty cards in this Stocard export.");
}
return new ZIPData(loyaltyCardHashMap, providers);
}
for (HashMap<String, Object> loyaltyCardData : loyaltyCardHashMap.values()) {
public ImportedData importLoyaltyCardHashMap(Context context, final ZIPData zipData) {
ImportedData importedData = new ImportedData(new ArrayList<>(), new HashMap<>());
int tempID = 0;
for (Map<String, Object> loyaltyCardData : zipData.loyaltyCardHashMap.values()) {
String providerId = (String) loyaltyCardData.get("_providerId");
if (providerId == null) {
@@ -209,7 +250,7 @@ public class StocardImporter implements Importer {
continue;
}
HashMap<String, Object> providerData = providers.get(providerId);
HashMap<String, Object> providerData = zipData.providers.get(providerId);
String store = providerData != null ? providerData.get("name").toString() : providerId;
String note = (String) Utils.mapGetOrDefault(loyaltyCardData, "note", "");
@@ -233,22 +274,39 @@ public class StocardImporter implements Importer {
headerColor = Utils.getHeaderColorFromImage(cardIcon, headerColor);
}
long loyaltyCardInternalId = DBHelper.insertLoyaltyCard(database, store, note, null, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, headerColor, 0, null,0);
LoyaltyCard card = new LoyaltyCard(tempID, store, note, null, null, BigDecimal.valueOf(0), null, cardId, null, barcodeType, headerColor, 0, Utils.getUnixTime(), DBHelper.DEFAULT_ZOOM_LEVEL, 0);
importedData.cards.add(card);
Map<ImageLocationType, Bitmap> images = new HashMap<>();
if (cardIcon != null) {
Utils.saveCardImage(context, cardIcon, (int) loyaltyCardInternalId, ImageLocationType.icon);
images.put(ImageLocationType.icon, cardIcon);
}
if (loyaltyCardData.containsKey("frontImage")) {
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("frontImage"), (int) loyaltyCardInternalId, ImageLocationType.front);
images.put(ImageLocationType.front, (Bitmap) loyaltyCardData.get("frontImage"));
}
if (loyaltyCardData.containsKey("backImage")) {
Utils.saveCardImage(context, (Bitmap) loyaltyCardData.get("backImage"), (int) loyaltyCardInternalId, ImageLocationType.back);
images.put(ImageLocationType.back, (Bitmap) loyaltyCardData.get("backImage"));
}
importedData.images.put(tempID, images);
tempID++;
}
zipInputStream.close();
input.close();
return importedData;
}
public void saveAndDeduplicate(Context context, SQLiteDatabase database, final ImportedData data) throws IOException {
// This format does not have IDs that can cause conflicts
// Proper deduplication for all formats will be implemented later
for (LoyaltyCard card : data.cards) {
// card.id is temporary and only used to index the images Map
long id = DBHelper.insertLoyaltyCard(database, card.store, card.note, card.validFrom, card.expiry, card.balance, card.balanceType,
card.cardId, card.barcodeId, card.barcodeType, card.headerColor, card.starStatus, card.lastUsed, card.archiveStatus);
for (Map.Entry<ImageLocationType, Bitmap> entry : data.images.get(card.id).entrySet()) {
Utils.saveCardImage(context, entry.getValue(), (int) id, entry.getKey());
}
}
}
private boolean startsWith(String[] full, String[] start, int minExtraLength) {

View File

@@ -21,13 +21,16 @@ import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Currency;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import protect.card_locker.CatimaBarcode;
import protect.card_locker.DBHelper;
import protect.card_locker.FormatException;
import protect.card_locker.LoyaltyCard;
import protect.card_locker.Utils;
/**
@@ -38,6 +41,14 @@ import protect.card_locker.Utils;
* A header is expected for the each table showing the names of the columns.
*/
public class VoucherVaultImporter implements Importer {
public static class ImportedData {
public final List<LoyaltyCard> cards;
ImportedData(final List<LoyaltyCard> cards) {
this.cards = cards;
}
}
public void importData(Context context, SQLiteDatabase database, File inputFile, char[] password) throws IOException, FormatException, JSONException, ParseException {
InputStream input = new FileInputStream(inputFile);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
@@ -49,6 +60,16 @@ public class VoucherVaultImporter implements Importer {
}
JSONArray jsonArray = new JSONArray(sb.toString());
bufferedReader.close();
input.close();
ImportedData importedData = importJSON(jsonArray);
saveAndDeduplicate(database, importedData);
}
public ImportedData importJSON(JSONArray jsonArray) throws FormatException, JSONException, ParseException {
ImportedData importedData = new ImportedData(new ArrayList<>());
// See https://github.com/tim-smart/vouchervault/issues/4#issuecomment-788226503 for more info
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonCard = jsonArray.getJSONObject(i);
@@ -129,10 +150,20 @@ public class VoucherVaultImporter implements Importer {
throw new FormatException("Unknown colour type found: " + colorFromJSON);
}
DBHelper.insertLoyaltyCard(database, store, "", null, expiry, balance, balanceType, cardId, null, barcodeType, headerColor, 0, Utils.getUnixTime(),0);
// use -1 for the ID, it will be ignored when inserting the card into the DB
importedData.cards.add(new LoyaltyCard(-1, store, "", null, expiry, balance, balanceType, cardId, null, barcodeType, headerColor, 0, Utils.getUnixTime(), DBHelper.DEFAULT_ZOOM_LEVEL, 0));
}
bufferedReader.close();
input.close();
return importedData;
}
public void saveAndDeduplicate(SQLiteDatabase database, final ImportedData data) {
// This format does not have IDs that can cause conflicts
// Proper deduplication for all formats will be implemented later
for (LoyaltyCard card : data.cards) {
// Do not use card.id which is set to -1
DBHelper.insertLoyaltyCard(database, card.store, card.note, card.validFrom, card.expiry, card.balance, card.balanceType,
card.cardId, card.barcodeId, card.barcodeType, card.headerColor, card.starStatus, card.lastUsed, card.archiveStatus);
}
}
}