Skip to content

Commit 6e4a944

Browse files
committed
catima importer: renumber IDs to merge properly
1 parent 47a0db2 commit 6e4a944

4 files changed

Lines changed: 74 additions & 25 deletions

File tree

app/src/main/java/protect/card_locker/Utils.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
import java.util.GregorianCalendar;
5959
import java.util.Locale;
6060
import java.util.Map;
61+
import java.util.regex.Matcher;
62+
import java.util.regex.Pattern;
6163

6264
import protect.card_locker.preferences.Settings;
6365

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

385+
static public String getRenamedCardImageFileName(final String fileName, final long idOffset) {
386+
Pattern pattern = Pattern.compile("^(card_)(\\d+)(_(?:front|back|icon)\\.png)$");
387+
Matcher matcher = pattern.matcher(fileName);
388+
if (matcher.matches()) {
389+
StringBuilder cardImageFileNameBuilder = new StringBuilder();
390+
cardImageFileNameBuilder.append(matcher.group(1));
391+
try {
392+
cardImageFileNameBuilder.append(Integer.parseInt(matcher.group(2)) + idOffset);
393+
} catch (NumberFormatException _e) {
394+
return null;
395+
}
396+
cardImageFileNameBuilder.append(matcher.group(3));
397+
return cardImageFileNameBuilder.toString();
398+
}
399+
return null;
400+
}
401+
383402
static public void saveCardImage(Context context, Bitmap bitmap, String fileName) throws FileNotFoundException {
384403
if (bitmap == null) {
385404
context.deleteFile(fileName);

app/src/main/java/protect/card_locker/importexport/CatimaImporter.java

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,14 @@ public void importData(Context context, SQLiteDatabase database, InputStream inp
5555

5656
String fileName = Uri.parse(localFileHeader.getFileName()).getLastPathSegment();
5757
if (fileName.equals("catima.csv")) {
58-
importCSV(context, database, zipInputStream);
58+
importCSV(context, database, zipInputStream, maxLoyaltyCardId);
5959
} else if (fileName.endsWith(".png")) {
60-
Utils.saveCardImage(context, ZipUtils.readImage(zipInputStream), fileName);
61-
newImageFiles.add(fileName);
60+
String newFileName = Utils.getRenamedCardImageFileName(fileName, maxLoyaltyCardId);
61+
if (newFileName == null) {
62+
throw new FormatException("Unexpected PNG file in import: " + fileName);
63+
}
64+
Utils.saveCardImage(context, ZipUtils.readImage(zipInputStream), newFileName);
65+
newImageFiles.add(newFileName);
6266
} else {
6367
throw new FormatException("Unexpected file in import: " + fileName);
6468
}
@@ -67,34 +71,34 @@ public void importData(Context context, SQLiteDatabase database, InputStream inp
6771
if (!isZipFile) {
6872
// This is not a zip file, try importing as bare CSV
6973
bufferedInputStream.reset();
70-
importCSV(context, database, bufferedInputStream);
74+
importCSV(context, database, bufferedInputStream, maxLoyaltyCardId);
7175
}
7276

7377
input.close();
7478
}
7579

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

7983
int version = parseVersion(bufferedReader);
8084
switch (version) {
8185
case 1:
82-
parseV1(database, bufferedReader);
86+
parseV1(database, bufferedReader, maxLoyaltyCardId);
8387
break;
8488
case 2:
85-
parseV2(context, database, bufferedReader);
89+
parseV2(context, database, bufferedReader, maxLoyaltyCardId);
8690
break;
8791
default:
8892
throw new FormatException(String.format("No code to parse version %s", version));
8993
}
9094
}
9195

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

9599
try {
96100
for (CSVRecord record : parser) {
97-
importLoyaltyCard(database, record);
101+
importLoyaltyCard(database, record, maxLoyaltyCardId);
98102

99103
if (Thread.currentThread().isInterrupted()) {
100104
throw new InterruptedException();
@@ -107,7 +111,7 @@ public void parseV1(SQLiteDatabase database, BufferedReader input) throws IOExce
107111
}
108112
}
109113

110-
public void parseV2(Context context, SQLiteDatabase database, BufferedReader input) throws IOException, FormatException, InterruptedException {
114+
public void parseV2(Context context, SQLiteDatabase database, BufferedReader input, int maxLoyaltyCardId) throws IOException, FormatException, InterruptedException {
111115
int part = 0;
112116
StringBuilder stringPart = new StringBuilder();
113117

@@ -133,15 +137,15 @@ public void parseV2(Context context, SQLiteDatabase database, BufferedReader inp
133137
break;
134138
case 2:
135139
try {
136-
parseV2Cards(context, database, stringPart.toString());
140+
parseV2Cards(context, database, stringPart.toString(), maxLoyaltyCardId);
137141
sectionParsed = true;
138142
} catch (FormatException e) {
139143
// We may have a multiline field, try again
140144
}
141145
break;
142146
case 3:
143147
try {
144-
parseV2CardGroups(database, stringPart.toString());
148+
parseV2CardGroups(database, stringPart.toString(), maxLoyaltyCardId);
145149
sectionParsed = true;
146150
} catch (FormatException e) {
147151
// We may have a multiline field, try again
@@ -195,7 +199,7 @@ public void parseV2Groups(SQLiteDatabase database, String data) throws IOExcepti
195199
}
196200
}
197201

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

@@ -216,11 +220,11 @@ public void parseV2Cards(Context context, SQLiteDatabase database, String data)
216220
}
217221

218222
for (CSVRecord record : records) {
219-
importLoyaltyCard(database, record);
223+
importLoyaltyCard(database, record, maxLoyaltyCardId);
220224
}
221225
}
222226

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

@@ -241,7 +245,7 @@ public void parseV2CardGroups(SQLiteDatabase database, String data) throws IOExc
241245
}
242246

243247
for (CSVRecord record : records) {
244-
importCardGroupMapping(database, record);
248+
importCardGroupMapping(database, record, maxLoyaltyCardId);
245249
}
246250
}
247251

@@ -278,9 +282,12 @@ private int parseVersion(BufferedReader reader) throws IOException {
278282
* Import a single loyalty card into the database using the given
279283
* session.
280284
*/
281-
private void importLoyaltyCard(SQLiteDatabase database, CSVRecord record)
285+
private void importLoyaltyCard(SQLiteDatabase database, CSVRecord record, int maxLoyaltyCardId)
282286
throws FormatException {
283287
int id = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIds.ID, record);
288+
if (id < 1) {
289+
throw new FormatException("ID must be >= 1");
290+
}
284291

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

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

382390
/**
@@ -397,16 +405,20 @@ private void importGroup(SQLiteDatabase database, CSVRecord record) throws Forma
397405
* Import a single card to group mapping into the database using the given
398406
* session.
399407
*/
400-
private void importCardGroupMapping(SQLiteDatabase database, CSVRecord record) throws FormatException {
408+
private void importCardGroupMapping(SQLiteDatabase database, CSVRecord record, int maxLoyaltyCardId) throws FormatException {
401409
int cardId = CSVHelpers.extractInt(DBHelper.LoyaltyCardDbIdsGroups.cardID, record);
402410
String groupId = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIdsGroups.groupID, record, null);
403411

412+
if (cardId < 1) {
413+
throw new FormatException("Card ID must be >= 1");
414+
}
404415
if (groupId == null) {
405416
throw new FormatException("Group has no ID: " + record);
406417
}
407418

408-
List<Group> cardGroups = DBHelper.getLoyaltyCardGroups(database, cardId);
419+
int newCardId = cardId + maxLoyaltyCardId;
420+
List<Group> cardGroups = DBHelper.getLoyaltyCardGroups(database, newCardId);
409421
cardGroups.add(DBHelper.getGroup(database, groupId));
410-
DBHelper.setLoyaltyCardGroups(database, cardId, cardGroups);
422+
DBHelper.setLoyaltyCardGroups(database, newCardId, cardGroups);
411423
}
412424
}

app/src/main/java/protect/card_locker/importexport/MultiFormatImporter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ public static ImportExportResult importData(Context context, SQLiteDatabase data
7575
Log.e(TAG, error);
7676
}
7777

78+
for (String fileName : newImageFiles) {
79+
context.deleteFile(fileName);
80+
}
81+
7882
return new ImportExportResult(ImportExportResultType.GenericFailure, error);
7983
}
8084
}

app/src/test/java/protect/card_locker/ImportExportTest.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,12 @@ private void addGroups(int groupsToAdd) {
201201
* where the smallest card's index is 1
202202
*/
203203
private void checkLoyaltyCards() {
204+
checkLoyaltyCards(false);
205+
}
206+
207+
private void checkLoyaltyCards(boolean dups) {
204208
Cursor cursor = DBHelper.getLoyaltyCardCursor(mDatabase);
209+
boolean first = true;
205210
int index = 1;
206211

207212
while (cursor.moveToNext()) {
@@ -222,7 +227,16 @@ private void checkLoyaltyCards() {
222227
assertEquals(Integer.valueOf(index), card.headerColor);
223228
assertEquals(0, card.starStatus);
224229

225-
index++;
230+
if (dups) {
231+
if (first) {
232+
first = false;
233+
} else {
234+
first = true;
235+
index++;
236+
}
237+
} else {
238+
index++;
239+
}
226240
}
227241
cursor.close();
228242
}
@@ -500,9 +514,9 @@ public void importExistingCardsNotReplace() throws IOException {
500514
result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inData, DataFormat.Catima, null);
501515
assertEquals(ImportExportResultType.Success, result.resultType());
502516

503-
assertEquals(NUM_CARDS, DBHelper.getLoyaltyCardCount(mDatabase));
517+
assertEquals(NUM_CARDS * 2, DBHelper.getLoyaltyCardCount(mDatabase));
504518

505-
checkLoyaltyCards();
519+
checkLoyaltyCards(true);
506520

507521
// Clear the database for the next format under test
508522
TestHelpers.getEmptyDb(activity);
@@ -764,7 +778,7 @@ public void importWithInvalidStarFieldV1() {
764778
// Import the CSV data
765779
result = MultiFormatImporter.importData(activity.getApplicationContext(), mDatabase, inputStream, DataFormat.Catima, null);
766780
assertEquals(ImportExportResultType.Success, result.resultType());
767-
assertEquals(1, DBHelper.getLoyaltyCardCount(mDatabase));
781+
assertEquals(2, DBHelper.getLoyaltyCardCount(mDatabase));
768782

769783
LoyaltyCard card = DBHelper.getLoyaltyCard(mDatabase, 1);
770784

0 commit comments

Comments
 (0)