From f53812b04466401518f46731732f25c4a949c034 Mon Sep 17 00:00:00 2001 From: Tamas Kozmer Date: Wed, 12 Feb 2025 18:10:14 +0100 Subject: [PATCH 1/7] Added webview authentication in activities onResume. --- .../parentapp/features/main/MainActivity.kt | 23 ++------ .../parentapp/util/FlutterAppMigration.kt | 1 - .../student/activity/NavigationActivity.kt | 25 ++------- .../teacher/activities/InitActivity.kt | 25 ++------- .../instructure/canvasapi2/utils/ApiPrefs.kt | 2 + .../canvasapi2/utils/MasqueradeHelper.kt | 2 +- .../pandautils/di/ApplicationModule.kt | 10 ++++ .../pandautils/utils/WebViewAuthenticator.kt | 44 +++++++++++++++ .../utils/WebViewAuthenticatorTest.kt | 55 +++++++++++++++++++ 9 files changed, 128 insertions(+), 59 deletions(-) create mode 100644 libs/pandautils/src/main/java/com/instructure/pandautils/utils/WebViewAuthenticator.kt create mode 100644 libs/pandautils/src/test/java/com/instructure/pandautils/utils/WebViewAuthenticatorTest.kt diff --git a/apps/parent/src/main/java/com/instructure/parentapp/features/main/MainActivity.kt b/apps/parent/src/main/java/com/instructure/parentapp/features/main/MainActivity.kt index 0423f3228e..950bf931c4 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/features/main/MainActivity.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/features/main/MainActivity.kt @@ -27,8 +27,6 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.NavController import androidx.navigation.fragment.NavHostFragment import com.google.android.material.snackbar.Snackbar -import com.instructure.canvasapi2.apis.OAuthAPI -import com.instructure.canvasapi2.builders.RestParams import com.instructure.canvasapi2.utils.ApiPrefs import com.instructure.canvasapi2.utils.MasqueradeHelper import com.instructure.loginapi.login.dialog.MasqueradingDialog @@ -42,7 +40,7 @@ import com.instructure.pandautils.utils.AppType import com.instructure.pandautils.utils.ColorKeeper import com.instructure.pandautils.utils.Const import com.instructure.pandautils.utils.ThemePrefs -import com.instructure.pandautils.utils.loadUrlIntoHeadlessWebView +import com.instructure.pandautils.utils.WebViewAuthenticator import com.instructure.parentapp.R import com.instructure.parentapp.databinding.ActivityMainBinding import com.instructure.parentapp.features.dashboard.InboxCountUpdater @@ -68,7 +66,7 @@ class MainActivity : BaseCanvasActivity(), OnUnreadCountInvalidated, Masqueradin lateinit var alarmScheduler: AlarmScheduler @Inject - lateinit var oAuthApi: OAuthAPI.OAuthInterface + lateinit var webViewAuthenticator: WebViewAuthenticator private lateinit var navController: NavController @@ -80,23 +78,12 @@ class MainActivity : BaseCanvasActivity(), OnUnreadCountInvalidated, Masqueradin handleQrMasquerading() scheduleAlarms() - if (ApiPrefs.isFirstMasqueradingStart) { - loadAuthenticatedSession() - ApiPrefs.isFirstMasqueradingStart = false - } - RatingDialog.showRatingDialog(this, AppType.PARENT) } - private fun loadAuthenticatedSession() { - lifecycleScope.launch { - oAuthApi.getAuthenticatedSession( - ApiPrefs.fullDomain, - RestParams(isForceReadFromNetwork = true) - ).dataOrNull?.sessionUrl?.let { - loadUrlIntoHeadlessWebView(this@MainActivity, it) - } - } + override fun onResume() { + super.onResume() + webViewAuthenticator.authenticateWebViews(lifecycleScope, this) } private fun handleQrMasquerading() { diff --git a/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt b/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt index 2c86ad1cb6..adee092bea 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt @@ -205,7 +205,6 @@ class FlutterAppMigration( isMasquerading = flutterSignedInUser.masqueradeUser != null isMasqueradingFromQRCode = flutterSignedInUser.isMasqueradingFromQRCode.orDefault() masqueradeId = flutterSignedInUser.masqueradeUser?.id ?: -1 - isFirstMasqueradingStart = true domain = if (isMasquerading) Uri.parse(flutterSignedInUser.masqueradeDomain).host.orEmpty() else signedInUser.domain user = if (isMasquerading) flutterSignedInUser.masqueradeUser else signedInUser.user } diff --git a/apps/student/src/main/java/com/instructure/student/activity/NavigationActivity.kt b/apps/student/src/main/java/com/instructure/student/activity/NavigationActivity.kt index 32f10de8dd..621c063ce9 100644 --- a/apps/student/src/main/java/com/instructure/student/activity/NavigationActivity.kt +++ b/apps/student/src/main/java/com/instructure/student/activity/NavigationActivity.kt @@ -112,11 +112,11 @@ import com.instructure.pandautils.utils.RequestCodes.PICK_FILE_FROM_DEVICE import com.instructure.pandautils.utils.RequestCodes.PICK_IMAGE_GALLERY import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.ViewStyler +import com.instructure.pandautils.utils.WebViewAuthenticator import com.instructure.pandautils.utils.applyTheme import com.instructure.pandautils.utils.hideKeyboard import com.instructure.pandautils.utils.isAccessibilityEnabled import com.instructure.pandautils.utils.items -import com.instructure.pandautils.utils.loadUrlIntoHeadlessWebView import com.instructure.pandautils.utils.onClickWithRequireNetwork import com.instructure.pandautils.utils.post import com.instructure.pandautils.utils.postSticky @@ -212,15 +212,15 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. @Inject lateinit var alarmScheduler: AlarmScheduler - @Inject - lateinit var oAuthApi: OAuthAPI.OAuthInterface - @Inject lateinit var offlineAnalyticsManager: OfflineAnalyticsManager @Inject lateinit var enabledCourseTabs: EnabledTabs + @Inject + lateinit var webViewAuthenticator: WebViewAuthenticator + private var routeJob: WeaveJob? = null private var debounceJob: Job? = null private var drawerItemSelectedJob: Job? = null @@ -329,6 +329,7 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. override fun onResume() { super.onResume() applyCurrentFragmentTheme() + webViewAuthenticator.authenticateWebViews(lifecycleScope, this) } private fun checkAppUpdates() { @@ -406,11 +407,6 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. } scheduleAlarms() - - if (ApiPrefs.isFirstMasqueradingStart) { - loadAuthenticatedSession() - ApiPrefs.isFirstMasqueradingStart = false - } } private fun logOfflineEvents(isOnline: Boolean) { @@ -423,17 +419,6 @@ class NavigationActivity : BaseRouterActivity(), Navigation, MasqueradingDialog. } } - private fun loadAuthenticatedSession() { - lifecycleScope.launch { - oAuthApi.getAuthenticatedSession( - ApiPrefs.fullDomain, - RestParams(isForceReadFromNetwork = true) - ).dataOrNull?.sessionUrl?.let { - loadUrlIntoHeadlessWebView(this@NavigationActivity, it) - } - } - } - private fun handleTokenCheck(online: Boolean?) { val checkToken = ApiPrefs.checkTokenAfterOfflineLogin if (checkToken && online == true) { diff --git a/apps/teacher/src/main/java/com/instructure/teacher/activities/InitActivity.kt b/apps/teacher/src/main/java/com/instructure/teacher/activities/InitActivity.kt index b4d48263d2..1ad27ff4d8 100644 --- a/apps/teacher/src/main/java/com/instructure/teacher/activities/InitActivity.kt +++ b/apps/teacher/src/main/java/com/instructure/teacher/activities/InitActivity.kt @@ -40,8 +40,6 @@ import androidx.fragment.app.FragmentManager import androidx.lifecycle.lifecycleScope import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.google.android.material.bottomnavigation.BottomNavigationView -import com.instructure.canvasapi2.apis.OAuthAPI -import com.instructure.canvasapi2.builders.RestParams import com.instructure.canvasapi2.managers.CourseNicknameManager import com.instructure.canvasapi2.managers.ThemeManager import com.instructure.canvasapi2.managers.UserManager @@ -94,10 +92,10 @@ import com.instructure.pandautils.utils.LocaleUtils import com.instructure.pandautils.utils.ProfileUtils import com.instructure.pandautils.utils.ThemePrefs import com.instructure.pandautils.utils.ViewStyler +import com.instructure.pandautils.utils.WebViewAuthenticator import com.instructure.pandautils.utils.applyTheme import com.instructure.pandautils.utils.isAccessibilityEnabled import com.instructure.pandautils.utils.items -import com.instructure.pandautils.utils.loadUrlIntoHeadlessWebView import com.instructure.pandautils.utils.setGone import com.instructure.pandautils.utils.setVisible import com.instructure.pandautils.utils.toast @@ -150,10 +148,10 @@ class InitActivity : BasePresenterActivity HOUR_IN_MILLIS) { + coroutineScope.launch { + oAuthApi.getAuthenticatedSession( + apiPrefs.fullDomain, + RestParams(isForceReadFromNetwork = true) + ).dataOrNull?.sessionUrl?.let { + loadUrlIntoHeadlessWebView(context, it) + apiPrefs.webViewAuthenticationTimestamp = currentTime + } + } + } + } +} \ No newline at end of file diff --git a/libs/pandautils/src/test/java/com/instructure/pandautils/utils/WebViewAuthenticatorTest.kt b/libs/pandautils/src/test/java/com/instructure/pandautils/utils/WebViewAuthenticatorTest.kt new file mode 100644 index 0000000000..3c2ee7aa9e --- /dev/null +++ b/libs/pandautils/src/test/java/com/instructure/pandautils/utils/WebViewAuthenticatorTest.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2025 - present Instructure, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.instructure.pandautils.utils + +import com.instructure.canvasapi2.apis.OAuthAPI +import com.instructure.canvasapi2.utils.ApiPrefs +import com.instructure.canvasapi2.utils.DataResult +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class WebViewAuthenticatorTest { + + private val oAuthApi: OAuthAPI.OAuthInterface = mockk(relaxed = true) + private val apiPrefs: ApiPrefs = mockk(relaxed = true) + + private val webViewAuthenticator = WebViewAuthenticator(oAuthApi, apiPrefs) + + @Test + fun `Authenticate webviews when timestamp is older than an hour`() = runTest { + every { apiPrefs.webViewAuthenticationTimestamp } returns System.currentTimeMillis() - 1000 * 60 * 61 + coEvery { oAuthApi.getAuthenticatedSession(any(), any()) } returns DataResult.Fail() + + webViewAuthenticator.authenticateWebViews(this, mockk()) + this.testScheduler.advanceUntilIdle() + + coVerify { oAuthApi.getAuthenticatedSession(any(), any()) } + } + + @Test + fun `Do not authenticate webviews when timestamp is not older than an hour`() = runTest { + every { apiPrefs.webViewAuthenticationTimestamp } returns System.currentTimeMillis() + coEvery { oAuthApi.getAuthenticatedSession(any(), any()) } returns DataResult.Fail() + + webViewAuthenticator.authenticateWebViews(this, mockk()) + + coVerify(exactly = 0) { oAuthApi.getAuthenticatedSession(any(), any()) } + } +} \ No newline at end of file From 9af5c219af2cae9d5ede0b406e232c1393086b30 Mon Sep 17 00:00:00 2001 From: Tamas Kozmer Date: Thu, 13 Feb 2025 09:32:54 +0100 Subject: [PATCH 2/7] Fixed Parent unit tests. --- .../com/instructure/parentapp/util/FlutterAppMigrationTest.kt | 1 - .../src/main/java/com/instructure/canvasapi2/utils/ApiPrefs.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/apps/parent/src/test/java/com/instructure/parentapp/util/FlutterAppMigrationTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/util/FlutterAppMigrationTest.kt index 00514fe491..525d499f88 100644 --- a/apps/parent/src/test/java/com/instructure/parentapp/util/FlutterAppMigrationTest.kt +++ b/apps/parent/src/test/java/com/instructure/parentapp/util/FlutterAppMigrationTest.kt @@ -246,7 +246,6 @@ class FlutterAppMigrationTest { apiPrefs.isMasquerading = false apiPrefs.isMasqueradingFromQRCode = false apiPrefs.masqueradeId = -1 - apiPrefs.isFirstMasqueradingStart = true apiPrefs.domain = "domain2.com" apiPrefs.user = expectedUsers[1] } diff --git a/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/utils/ApiPrefs.kt b/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/utils/ApiPrefs.kt index 1e789e64e7..cf2724b90f 100644 --- a/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/utils/ApiPrefs.kt +++ b/libs/canvas-api-2/src/main/java/com/instructure/canvasapi2/utils/ApiPrefs.kt @@ -83,7 +83,6 @@ object ApiPrefs : PrefManager(PREFERENCE_FILE_NAME) { var isStudentView by BooleanPref() var isMasqueradingFromQRCode by BooleanPref() var masqueradeId by LongPref(-1L) - var isFirstMasqueradingStart by BooleanPref() internal var masqueradeDomain by StringPref() internal var masqueradeUser: User? by GsonPref(User::class.java, null, "masq-user", false) From b9453e1f207212f40ef107cb7f551c8f8a7a0bfc Mon Sep 17 00:00:00 2001 From: Tamas Kozmer Date: Thu, 13 Feb 2025 13:44:24 +0100 Subject: [PATCH 3/7] Removed try-catch to see where FlutterAppMigration tests are failing. --- .../parentapp/util/FlutterAppMigration.kt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt b/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt index adee092bea..2b67a24fd4 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt @@ -114,17 +114,15 @@ class FlutterAppMigration( } } - private fun migratePrefs() = try { + private fun migratePrefs() { val prefs = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE) val isDarkMode = prefs.getBoolean(KEY_DARK_MODE, false) themePrefs.appTheme = if (isDarkMode) 1 else 0 - } catch (e: Exception) { - e.printStackTrace() } - private fun migrateEncryptedSharedPrefs() = try { + private fun migrateEncryptedSharedPrefs() { val masterKey = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC) val encryptedPrefs = EncryptedSharedPreferences.create( @@ -165,8 +163,6 @@ class FlutterAppMigration( val currentStudent: User = it.toString().fromJson() parentPrefs.currentStudent = currentStudent } - } catch (e: Exception) { - e.printStackTrace() } private fun getAllPrefs(allPrefs: Map) = allPrefs @@ -209,7 +205,7 @@ class FlutterAppMigration( user = if (isMasquerading) flutterSignedInUser.masqueradeUser else signedInUser.user } - private fun migrateDatabase() = try { + private fun migrateDatabase() { val database = SQLiteDatabase.openDatabase( context.getDatabasePath("canvas_parent.db").path, null, @@ -222,8 +218,6 @@ class FlutterAppMigration( migrateReminders(it) } } - } catch (e: Exception) { - e.printStackTrace() } private suspend fun migrateCalendarFilters(database: SQLiteDatabase) { From c1c034dabcc5fc553a50f0c201f1f01252f9c19a Mon Sep 17 00:00:00 2001 From: Tamas Kozmer Date: Thu, 13 Feb 2025 14:38:43 +0100 Subject: [PATCH 4/7] Add log and test with different timezone --- .../com/instructure/parentapp/util/FlutterAppMigration.kt | 2 ++ .../com/instructure/parentapp/util/FlutterAppMigrationTest.kt | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt b/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt index 2b67a24fd4..e3420b586f 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt @@ -21,6 +21,7 @@ import android.content.Context import android.database.sqlite.SQLiteDatabase import android.net.Uri import android.util.Base64 +import android.util.Log import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.MasterKeys import com.google.common.reflect.TypeToken @@ -269,6 +270,7 @@ class FlutterAppMigration( val messageParam = context.getString(if (type == "assignment") R.string.assignment else R.string.a11y_calendar_event) val message = context.getString(R.string.reminderNotificationTitleFor, messageParam) + println("FlutterAppMigration date: $date, now: ${Instant.now(clock)}") if (date.isAfter(Instant.now(clock))) { reminderRepository.createReminder( userId = userId, diff --git a/apps/parent/src/test/java/com/instructure/parentapp/util/FlutterAppMigrationTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/util/FlutterAppMigrationTest.kt index 525d499f88..d0bd743da2 100644 --- a/apps/parent/src/test/java/com/instructure/parentapp/util/FlutterAppMigrationTest.kt +++ b/apps/parent/src/test/java/com/instructure/parentapp/util/FlutterAppMigrationTest.kt @@ -42,6 +42,8 @@ import io.mockk.every import io.mockk.mockk import io.mockk.mockkStatic import io.mockk.unmockkAll +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Before import org.junit.Test @@ -61,7 +63,7 @@ class FlutterAppMigrationTest { private val ratingDialogPrefs: RatingDialog.Prefs = mockk(relaxed = true) private val reminderRepository: ReminderRepository = mockk(relaxed = true) private val calendarFilterDao: CalendarFilterDao = mockk(relaxed = true) - private val clock = Clock.fixed(Instant.parse("2024-01-05T00:00:00.00Z"), ZoneId.systemDefault()) + private val clock = Clock.fixed(Instant.parse("2024-01-05T00:00:00.00Z"), ZoneId.of("UTC")) private val mockUri: Uri = mockk(relaxed = true) private lateinit var mockSharedPreferences: SharedPreferences From fa98d9356065213e52d6d997dd636fa3f43d5c07 Mon Sep 17 00:00:00 2001 From: Tamas Kozmer Date: Thu, 13 Feb 2025 15:17:17 +0100 Subject: [PATCH 5/7] More logs --- .../java/com/instructure/parentapp/util/FlutterAppMigration.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt b/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt index e3420b586f..7e3d04d995 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt @@ -272,6 +272,7 @@ class FlutterAppMigration( println("FlutterAppMigration date: $date, now: ${Instant.now(clock)}") if (date.isAfter(Instant.now(clock))) { + println("FlutterAppMigration date is after now, creating reminder") reminderRepository.createReminder( userId = userId, contentId = itemId, From 0b544fc50749203478dcf670fac6102480121fa6 Mon Sep 17 00:00:00 2001 From: Tamas Kozmer Date: Thu, 13 Feb 2025 15:45:34 +0100 Subject: [PATCH 6/7] More logs --- .../java/com/instructure/parentapp/util/FlutterAppMigration.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt b/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt index 7e3d04d995..a99a54120b 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt @@ -273,6 +273,7 @@ class FlutterAppMigration( println("FlutterAppMigration date: $date, now: ${Instant.now(clock)}") if (date.isAfter(Instant.now(clock))) { println("FlutterAppMigration date is after now, creating reminder") + println("Calling this with: userId: $userId, itemId: $itemId, contentHtmlUrl: $contentHtmlUrl, message: $message, date: ${date.toEpochMilli()}") reminderRepository.createReminder( userId = userId, contentId = itemId, From 7b2546f9a650cb52530b3ff9e1f2379548e630c9 Mon Sep 17 00:00:00 2001 From: Tamas Kozmer Date: Thu, 13 Feb 2025 16:09:41 +0100 Subject: [PATCH 7/7] Revert test changes. --- .../parentapp/util/FlutterAppMigration.kt | 16 +++++++++------- .../parentapp/util/FlutterAppMigrationTest.kt | 4 +--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt b/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt index a99a54120b..adee092bea 100644 --- a/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt +++ b/apps/parent/src/main/java/com/instructure/parentapp/util/FlutterAppMigration.kt @@ -21,7 +21,6 @@ import android.content.Context import android.database.sqlite.SQLiteDatabase import android.net.Uri import android.util.Base64 -import android.util.Log import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.MasterKeys import com.google.common.reflect.TypeToken @@ -115,15 +114,17 @@ class FlutterAppMigration( } } - private fun migratePrefs() { + private fun migratePrefs() = try { val prefs = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE) val isDarkMode = prefs.getBoolean(KEY_DARK_MODE, false) themePrefs.appTheme = if (isDarkMode) 1 else 0 + } catch (e: Exception) { + e.printStackTrace() } - private fun migrateEncryptedSharedPrefs() { + private fun migrateEncryptedSharedPrefs() = try { val masterKey = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC) val encryptedPrefs = EncryptedSharedPreferences.create( @@ -164,6 +165,8 @@ class FlutterAppMigration( val currentStudent: User = it.toString().fromJson() parentPrefs.currentStudent = currentStudent } + } catch (e: Exception) { + e.printStackTrace() } private fun getAllPrefs(allPrefs: Map) = allPrefs @@ -206,7 +209,7 @@ class FlutterAppMigration( user = if (isMasquerading) flutterSignedInUser.masqueradeUser else signedInUser.user } - private fun migrateDatabase() { + private fun migrateDatabase() = try { val database = SQLiteDatabase.openDatabase( context.getDatabasePath("canvas_parent.db").path, null, @@ -219,6 +222,8 @@ class FlutterAppMigration( migrateReminders(it) } } + } catch (e: Exception) { + e.printStackTrace() } private suspend fun migrateCalendarFilters(database: SQLiteDatabase) { @@ -270,10 +275,7 @@ class FlutterAppMigration( val messageParam = context.getString(if (type == "assignment") R.string.assignment else R.string.a11y_calendar_event) val message = context.getString(R.string.reminderNotificationTitleFor, messageParam) - println("FlutterAppMigration date: $date, now: ${Instant.now(clock)}") if (date.isAfter(Instant.now(clock))) { - println("FlutterAppMigration date is after now, creating reminder") - println("Calling this with: userId: $userId, itemId: $itemId, contentHtmlUrl: $contentHtmlUrl, message: $message, date: ${date.toEpochMilli()}") reminderRepository.createReminder( userId = userId, contentId = itemId, diff --git a/apps/parent/src/test/java/com/instructure/parentapp/util/FlutterAppMigrationTest.kt b/apps/parent/src/test/java/com/instructure/parentapp/util/FlutterAppMigrationTest.kt index d0bd743da2..525d499f88 100644 --- a/apps/parent/src/test/java/com/instructure/parentapp/util/FlutterAppMigrationTest.kt +++ b/apps/parent/src/test/java/com/instructure/parentapp/util/FlutterAppMigrationTest.kt @@ -42,8 +42,6 @@ import io.mockk.every import io.mockk.mockk import io.mockk.mockkStatic import io.mockk.unmockkAll -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Before import org.junit.Test @@ -63,7 +61,7 @@ class FlutterAppMigrationTest { private val ratingDialogPrefs: RatingDialog.Prefs = mockk(relaxed = true) private val reminderRepository: ReminderRepository = mockk(relaxed = true) private val calendarFilterDao: CalendarFilterDao = mockk(relaxed = true) - private val clock = Clock.fixed(Instant.parse("2024-01-05T00:00:00.00Z"), ZoneId.of("UTC")) + private val clock = Clock.fixed(Instant.parse("2024-01-05T00:00:00.00Z"), ZoneId.systemDefault()) private val mockUri: Uri = mockk(relaxed = true) private lateinit var mockSharedPreferences: SharedPreferences