From 98975905d5a3fc6d8c3ca4e39cf764a59768631e Mon Sep 17 00:00:00 2001 From: jfbriere Date: Sun, 25 Feb 2024 17:09:52 -0500 Subject: [PATCH] Fix issue #226 App does not open, showing a black screen. Some db records have unexpected null fields. --- lib/database/entities.dart | 4 ++-- lib/database/repository.dart | 32 +++++++++++++++++++++++++++++++- lib/settings/_data.dart | 4 ++-- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/lib/database/entities.dart b/lib/database/entities.dart index d8567305..4ed95f6b 100644 --- a/lib/database/entities.dart +++ b/lib/database/entities.dart @@ -247,7 +247,7 @@ class TwitterTokenEntity with ToMappable { screenName: json['screen_name'] == null ? getRandomString(15) : json['screen_name'] as String, oauthToken: json['oauth_token'] == null ? '' : json['oauth_token'] as String, oauthTokenSecret: json['oauth_token_secret'] == null ? '' : json['oauth_token_secret'] as String, - createdAt: json['created_at'] == null ? DateTime.now() : DateTime.parse(json['created_at'] as String), + createdAt: json['created_at'] == null || json['created_at'] == '' ? DateTime.now() : DateTime.parse(json['created_at'] as String), profile: pProfile ); } @@ -311,7 +311,7 @@ class TwitterProfileEntity with ToMappable { return TwitterProfileEntity( username: json['username'] == null ? '' : json['username'] as String, password: pPassword, - createdAt: json['created_at'] == null ? DateTime.now() : DateTime.parse(json['created_at'] as String), + createdAt: json['created_at'] == null || json['created_at'] == '' ? DateTime.now() : DateTime.parse(json['created_at'] as String), name: json['name'] as String?, email: json['email'] as String?, phone: json['phone'] as String? diff --git a/lib/database/repository.dart b/lib/database/repository.dart index 1c038504..dbfadfc5 100644 --- a/lib/database/repository.dart +++ b/lib/database/repository.dart @@ -289,11 +289,41 @@ class Repository { await db.insert(tableTwitterProfile, {'username': screenName, 'password': password, 'name': name, 'email': email, 'phone': phone}); } })) + ], + 30: [ + Migration(Operation((db) async { + await db.delete(tableTwitterToken, where: "screen_name IS NULL OR screen_name = '' OR id_str IS NULL OR id_str = '' OR oauth_token IS NULL OR oauth_token = '' OR oauth_token_secret IS NULL OR oauth_token_secret = '' OR guest IS NULL OR created_at IS NULL OR created_at = ''"); + await db.delete(tableTwitterProfile, where: "username IS NULL OR username = '' OR password IS NULL OR password = '' OR created_at IS NULL OR created_at = ''"); + + await db.rawQuery('CREATE TABLE ${tableTwitterToken}_2 AS SELECT DISTINCT * FROM $tableTwitterToken'); + await db.rawQuery('DROP TABLE $tableTwitterToken'); + await db.rawQuery('CREATE TABLE $tableTwitterToken (oauth_token VARCHAR NON NULL PRIMARY KEY, oauth_token_secret VARCHAR NON NULL, id_str VARCHAR NON NULL, screen_name VARCHAR NON NULL, guest BOOLEAN NON NULL, created_at TIMESTAMP NON NULL DEFAULT CURRENT_TIMESTAMP)'); + await db.rawQuery('INSERT INTO $tableTwitterToken (oauth_token, oauth_token_secret, id_str, screen_name, guest, created_at) SELECT oauth_token, oauth_token_secret, id_str, screen_name, guest, created_at FROM ${tableTwitterToken}_2'); + await db.rawQuery('DROP TABLE ${tableTwitterToken}_2'); + + await db.rawQuery('CREATE TABLE ${tableTwitterProfile}_2 AS SELECT DISTINCT * FROM $tableTwitterProfile'); + await db.rawQuery('DROP TABLE $tableTwitterProfile'); + await db.rawQuery('CREATE TABLE $tableTwitterProfile (username VARCHAR NON NULL PRIMARY KEY, password VARCHAR NON NULL, created_at TIMESTAMP NON NULL DEFAULT CURRENT_TIMESTAMP, name VARCHAR, email VARCHAR, phone VARCHAR)'); + await db.rawQuery('INSERT INTO $tableTwitterProfile (username, password, created_at, name, email, phone) SELECT username, password, created_at, name, email, phone FROM ${tableTwitterProfile}_2'); + await db.rawQuery('DROP TABLE ${tableTwitterProfile}_2'); + + var tokens = await db.rawQuery('SELECT t.oauth_token, p.username FROM $tableTwitterToken t LEFT JOIN $tableTwitterProfile p ON t.screen_name = p.username WHERE t.guest = 0 AND p.username IS NULL'); + if (tokens.isNotEmpty) { + var oauthTokenLst = tokens.map((e) => e['oauth_token'] as String).toList(); + await db.delete(tableTwitterToken, where: 'oauth_token IN (${List.filled(oauthTokenLst.length, '?').join(',')})', whereArgs: oauthTokenLst); + } + + var profiles = await db.rawQuery('SELECT p.username, t.oauth_token FROM $tableTwitterProfile p LEFT JOIN $tableTwitterToken t ON p.username = t.screen_name WHERE t.oauth_token IS NULL'); + if (profiles.isNotEmpty) { + var usernameLst = profiles.map((e) => e['username'] as String).toList(); + await db.delete(tableTwitterProfile, where: 'username IN (${List.filled(usernameLst.length, '?').join(',')})', whereArgs: usernameLst); + } + })) ] }); await openDatabase( databaseName, - version: 29, + version: 30, onUpgrade: myMigrationPlan, onCreate: myMigrationPlan, onDowngrade: myMigrationPlan, diff --git a/lib/settings/_data.dart b/lib/settings/_data.dart index 50ef2f07..78d2c89a 100644 --- a/lib/settings/_data.dart +++ b/lib/settings/_data.dart @@ -40,12 +40,12 @@ class SettingsData { // guestAccounts from previous versions if (json['guestAccounts'] != null) { // make sure to filter out the badly manipulated files - twtTokens = List.from(json['guestAccounts']).map((e) => TwitterTokenEntity.fromMap(e)).where((e) => e.guest && e.profile == null).toList(); + twtTokens = List.from(json['guestAccounts']).map((e) => TwitterTokenEntity.fromMap(e)).where((e) => e.guest && e.profile == null && e.oauthToken.isNotEmpty && e.oauthTokenSecret.isNotEmpty).toList(); } if (json['twitterTokens'] != null) { // make sure to filter out the badly manipulated files twtTokens ??= (await Future.wait(List.from(json['twitterTokens']).map((e) async => TwitterTokenEntity.fromMapSecured(e)))) - .where((e) => (e.guest && e.profile == null) || (!e.guest && e.profile != null && e.profile!.username.isNotEmpty && e.profile!.password.isNotEmpty)).toList(); + .where((e) => e.oauthToken.isNotEmpty && e.oauthTokenSecret.isNotEmpty && ((e.guest && e.profile == null) || (!e.guest && e.profile != null && e.profile!.username.isNotEmpty && e.profile!.password.isNotEmpty))).toList(); } return SettingsData( settings: json['settings'],