diff --git a/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt b/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt index f5ea619e403..bf8f84d52e9 100644 --- a/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt +++ b/components/browser/engine-gecko-beta/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt @@ -21,6 +21,7 @@ import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_GEOLOCATION +import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_MEDIA_KEY_SYSTEM_ACCESS import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_PERSISTENT_STORAGE import java.util.UUID @@ -59,7 +60,8 @@ sealed class GeckoPermissionRequest constructor( PERMISSION_GEOLOCATION to Permission.ContentGeoLocation(), PERMISSION_AUTOPLAY_AUDIBLE to Permission.ContentAutoPlayAudible(), PERMISSION_AUTOPLAY_INAUDIBLE to Permission.ContentAutoPlayInaudible(), - PERMISSION_PERSISTENT_STORAGE to Permission.ContentPersistentStorage() + PERMISSION_PERSISTENT_STORAGE to Permission.ContentPersistentStorage(), + PERMISSION_MEDIA_KEY_SYSTEM_ACCESS to Permission.ContentMediaKeySystemAccess() ) } } diff --git a/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt b/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt index f5ea619e403..bf8f84d52e9 100644 --- a/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt +++ b/components/browser/engine-gecko-nightly/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt @@ -21,6 +21,7 @@ import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_GEOLOCATION +import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_MEDIA_KEY_SYSTEM_ACCESS import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_PERSISTENT_STORAGE import java.util.UUID @@ -59,7 +60,8 @@ sealed class GeckoPermissionRequest constructor( PERMISSION_GEOLOCATION to Permission.ContentGeoLocation(), PERMISSION_AUTOPLAY_AUDIBLE to Permission.ContentAutoPlayAudible(), PERMISSION_AUTOPLAY_INAUDIBLE to Permission.ContentAutoPlayInaudible(), - PERMISSION_PERSISTENT_STORAGE to Permission.ContentPersistentStorage() + PERMISSION_PERSISTENT_STORAGE to Permission.ContentPersistentStorage(), + PERMISSION_MEDIA_KEY_SYSTEM_ACCESS to Permission.ContentMediaKeySystemAccess() ) } } diff --git a/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt b/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt index f5ea619e403..bf8f84d52e9 100644 --- a/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt +++ b/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/permission/GeckoPermissionRequest.kt @@ -21,6 +21,7 @@ import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_AUTOPLAY_INAUDIBLE import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_GEOLOCATION +import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_MEDIA_KEY_SYSTEM_ACCESS import org.mozilla.geckoview.GeckoSession.PermissionDelegate.PERMISSION_PERSISTENT_STORAGE import java.util.UUID @@ -59,7 +60,8 @@ sealed class GeckoPermissionRequest constructor( PERMISSION_GEOLOCATION to Permission.ContentGeoLocation(), PERMISSION_AUTOPLAY_AUDIBLE to Permission.ContentAutoPlayAudible(), PERMISSION_AUTOPLAY_INAUDIBLE to Permission.ContentAutoPlayInaudible(), - PERMISSION_PERSISTENT_STORAGE to Permission.ContentPersistentStorage() + PERMISSION_PERSISTENT_STORAGE to Permission.ContentPersistentStorage(), + PERMISSION_MEDIA_KEY_SYSTEM_ACCESS to Permission.ContentMediaKeySystemAccess() ) } } diff --git a/components/concept/engine/src/main/java/mozilla/components/concept/engine/permission/PermissionRequest.kt b/components/concept/engine/src/main/java/mozilla/components/concept/engine/permission/PermissionRequest.kt index a52af746f55..624f275ec1e 100644 --- a/components/concept/engine/src/main/java/mozilla/components/concept/engine/permission/PermissionRequest.kt +++ b/components/concept/engine/src/main/java/mozilla/components/concept/engine/permission/PermissionRequest.kt @@ -80,6 +80,8 @@ sealed class Permission { data class ContentAutoPlayAudible(override val id: String? = "", override val desc: String? = "") : Permission() data class ContentAutoPlayInaudible(override val id: String? = "", override val desc: String? = "") : Permission() data class ContentPersistentStorage(override val id: String? = "", override val desc: String? = "") : Permission() + data class ContentMediaKeySystemAccess(override val id: String? = "", override val desc: String? = "") + : Permission() data class AppCamera(override val id: String? = "", override val desc: String? = "") : Permission() data class AppAudio(override val id: String? = "", override val desc: String? = "") : Permission() diff --git a/components/feature/sitepermissions/schemas/mozilla.components.feature.sitepermissions.db.SitePermissionsDatabase/4.json b/components/feature/sitepermissions/schemas/mozilla.components.feature.sitepermissions.db.SitePermissionsDatabase/4.json new file mode 100644 index 00000000000..f91ee575159 --- /dev/null +++ b/components/feature/sitepermissions/schemas/mozilla.components.feature.sitepermissions.db.SitePermissionsDatabase/4.json @@ -0,0 +1,94 @@ +{ + "formatVersion": 1, + "database": { + "version": 4, + "identityHash": "f5379c8eb4f1519eb5994e508626ca10", + "entities": [ + { + "tableName": "site_permissions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`origin` TEXT NOT NULL, `location` INTEGER NOT NULL, `notification` INTEGER NOT NULL, `microphone` INTEGER NOT NULL, `camera` INTEGER NOT NULL, `bluetooth` INTEGER NOT NULL, `local_storage` INTEGER NOT NULL, `autoplay_audible` INTEGER NOT NULL, `autoplay_inaudible` INTEGER NOT NULL, `media_key_system_access` INTEGER NOT NULL, `saved_at` INTEGER NOT NULL, PRIMARY KEY(`origin`))", + "fields": [ + { + "fieldPath": "origin", + "columnName": "origin", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "location", + "columnName": "location", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "notification", + "columnName": "notification", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "microphone", + "columnName": "microphone", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "camera", + "columnName": "camera", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "bluetooth", + "columnName": "bluetooth", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localStorage", + "columnName": "local_storage", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "autoplayAudible", + "columnName": "autoplay_audible", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "autoplayInaudible", + "columnName": "autoplay_inaudible", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "mediaKeySystemAccess", + "columnName": "media_key_system_access", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "savedAt", + "columnName": "saved_at", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "origin" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f5379c8eb4f1519eb5994e508626ca10')" + ] + } +} \ No newline at end of file diff --git a/components/feature/sitepermissions/src/androidTest/java/mozilla/components/feature/sitepermissions/db/OnDeviceSitePermissionsStorageTest.kt b/components/feature/sitepermissions/src/androidTest/java/mozilla/components/feature/sitepermissions/db/OnDeviceSitePermissionsStorageTest.kt index cc217a2dde8..4f8f1e9eae7 100644 --- a/components/feature/sitepermissions/src/androidTest/java/mozilla/components/feature/sitepermissions/db/OnDeviceSitePermissionsStorageTest.kt +++ b/components/feature/sitepermissions/src/androidTest/java/mozilla/components/feature/sitepermissions/db/OnDeviceSitePermissionsStorageTest.kt @@ -127,4 +127,29 @@ class OnDeviceSitePermissionsStorageTest { assertEquals(Status.ALLOWED.id, cursor.getInt(cursor.getColumnIndexOrThrow("autoplay_inaudible"))) } } + + @Test + fun migrate3to4() { + helper.createDatabase(MIGRATION_TEST_DB, 3).apply { + query("SELECT * FROM site_permissions").use { cursor -> + assertEquals(10, cursor.columnCount) + } + execSQL( + "INSERT INTO " + + "site_permissions " + + "(origin, location, notification, microphone,camera,bluetooth,local_storage,autoplay_audible,autoplay_inaudible,saved_at) " + + "VALUES " + + "('mozilla.org',1,1,1,1,1,1,1,1,1)" + ) + } + + val dbVersion3 = helper.runMigrationsAndValidate(MIGRATION_TEST_DB, 4, true, Migrations.migration_3_4) + + dbVersion3.query("SELECT * FROM site_permissions").use { cursor -> + assertEquals(11, cursor.columnCount) + + cursor.moveToFirst() + assertEquals(Status.NO_DECISION.id, cursor.getInt(cursor.getColumnIndexOrThrow("media_key_system_access"))) + } + } } diff --git a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissions.kt b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissions.kt index e1ab995f68d..b68a44a65be 100644 --- a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissions.kt +++ b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissions.kt @@ -23,6 +23,7 @@ data class SitePermissions( val localStorage: Status = NO_DECISION, val autoplayAudible: Status = NO_DECISION, val autoplayInaudible: Status = NO_DECISION, + val mediaKeySystemAccess: Status = NO_DECISION, val savedAt: Long ) : Parcelable { enum class Status( @@ -53,6 +54,7 @@ data class SitePermissions( Permission.LOCATION -> location Permission.AUTOPLAY_AUDIBLE -> autoplayAudible Permission.AUTOPLAY_INAUDIBLE -> autoplayInaudible + Permission.MEDIA_KEY_SYSTEM_ACCESS -> mediaKeySystemAccess } } } diff --git a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt index 84174398a4e..9cb69cc6f1d 100644 --- a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt +++ b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsFeature.kt @@ -37,6 +37,7 @@ import mozilla.components.concept.engine.permission.Permission.ContentNotificati import mozilla.components.concept.engine.permission.Permission.ContentVideoCamera import mozilla.components.concept.engine.permission.Permission.ContentVideoCapture import mozilla.components.concept.engine.permission.Permission.ContentPersistentStorage +import mozilla.components.concept.engine.permission.Permission.ContentMediaKeySystemAccess import mozilla.components.concept.engine.permission.Permission.AppLocationCoarse import mozilla.components.concept.engine.permission.Permission.AppLocationFine import mozilla.components.concept.engine.permission.Permission.AppAudio @@ -442,6 +443,9 @@ class SitePermissionsFeature( is ContentPersistentStorage -> { permissionFromStore.localStorage.doNotAskAgain() } + is ContentMediaKeySystemAccess -> { + permissionFromStore.mediaKeySystemAccess.doNotAskAgain() + } else -> false } } @@ -503,6 +507,9 @@ class SitePermissionsFeature( is ContentPersistentStorage -> { sitePermissions.copy(localStorage = status) } + is ContentMediaKeySystemAccess -> { + sitePermissions.copy(mediaKeySystemAccess = status) + } else -> throw InvalidParameterException("$permission is not a valid permission.") } @@ -530,6 +537,7 @@ class SitePermissionsFeature( } } + @Suppress("LongMethod") @VisibleForTesting internal fun handlingSingleContentPermissions( permissionRequest: PermissionRequest, @@ -596,6 +604,17 @@ class SitePermissionsFeature( shouldSelectRememberChoice = true ) } + is ContentMediaKeySystemAccess -> { + createSinglePermissionPrompt( + context, + host, + permissionRequest, + R.string.mozac_feature_sitepermissions_media_key_system_access_title, + R.drawable.mozac_ic_video, + showDoNotAskAgainCheckBox = false, + shouldSelectRememberChoice = true + ) + } else -> throw InvalidParameterException("$permission is not a valid permission.") } @@ -731,6 +750,9 @@ internal fun isPermissionGranted( is ContentPersistentStorage -> { permissionFromStorage.localStorage.isAllowed() } + is ContentMediaKeySystemAccess -> { + permissionFromStorage.mediaKeySystemAccess.isAllowed() + } else -> throw InvalidParameterException("$permission is not a valid permission.") } @@ -743,7 +765,8 @@ private fun Permission.isSupported(): Boolean { is ContentPersistentStorage, is ContentAudioCapture, is ContentAudioMicrophone, is ContentVideoCamera, is ContentVideoCapture, - is ContentAutoPlayAudible, is ContentAutoPlayInaudible -> true + is ContentAutoPlayAudible, is ContentAutoPlayInaudible, + is ContentMediaKeySystemAccess -> true else -> false } } diff --git a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsStorage.kt b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsStorage.kt index 40ed2c2b440..5ea07f71cd6 100644 --- a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsStorage.kt +++ b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/SitePermissionsStorage.kt @@ -23,6 +23,7 @@ import mozilla.components.feature.sitepermissions.SitePermissionsStorage.Permiss import mozilla.components.feature.sitepermissions.SitePermissionsStorage.Permission.NOTIFICATION import mozilla.components.feature.sitepermissions.SitePermissionsStorage.Permission.AUTOPLAY_AUDIBLE import mozilla.components.feature.sitepermissions.SitePermissionsStorage.Permission.AUTOPLAY_INAUDIBLE +import mozilla.components.feature.sitepermissions.SitePermissionsStorage.Permission.MEDIA_KEY_SYSTEM_ACCESS import mozilla.components.feature.sitepermissions.db.SitePermissionsDatabase import mozilla.components.feature.sitepermissions.db.toSitePermissionsEntity @@ -116,6 +117,7 @@ class SitePermissionsStorage( map.putIfAllowed(LOCATION, location, permission) map.putIfAllowed(AUTOPLAY_AUDIBLE, autoplayAudible, permission) map.putIfAllowed(AUTOPLAY_INAUDIBLE, autoplayInaudible, permission) + map.putIfAllowed(MEDIA_KEY_SYSTEM_ACCESS, mediaKeySystemAccess, permission) } } return map @@ -173,6 +175,6 @@ class SitePermissionsStorage( enum class Permission { MICROPHONE, BLUETOOTH, CAMERA, LOCAL_STORAGE, NOTIFICATION, LOCATION, AUTOPLAY_AUDIBLE, - AUTOPLAY_INAUDIBLE + AUTOPLAY_INAUDIBLE, MEDIA_KEY_SYSTEM_ACCESS } } diff --git a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsDatabase.kt b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsDatabase.kt index d46e28c62e3..0d368c0e600 100644 --- a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsDatabase.kt +++ b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsDatabase.kt @@ -17,7 +17,7 @@ import mozilla.components.feature.sitepermissions.SitePermissions /** * Internal database for saving site permissions. */ -@Database(entities = [SitePermissionsEntity::class], version = 3) +@Database(entities = [SitePermissionsEntity::class], version = 4) @TypeConverters(StatusConverter::class) internal abstract class SitePermissionsDatabase : RoomDatabase() { abstract fun sitePermissionsDao(): SitePermissionsDao @@ -38,6 +38,8 @@ internal abstract class SitePermissionsDatabase : RoomDatabase() { Migrations.migration_1_2 ).addMigrations( Migrations.migration_2_3 + ).addMigrations( + Migrations.migration_3_4 ).build().also { instance = it } } } @@ -98,4 +100,17 @@ internal object Migrations { } } } + + @Suppress("MagicNumber") + val migration_3_4 = object : Migration(3, 4) { + override fun migrate(database: SupportSQLiteDatabase) { + val hasEmeColumn = database.query("SELECT * FROM site_permissions").columnCount == 11 + if (!hasEmeColumn) { + database.execSQL( + "ALTER TABLE site_permissions ADD COLUMN media_key_system_access INTEGER NOT NULL DEFAULT 0") + // default is NO_DECISION + database.execSQL("UPDATE site_permissions SET media_key_system_access = 0"); + } + } + } } diff --git a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsEntity.kt b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsEntity.kt index a244cdf8ecb..6d55c7ad5c1 100644 --- a/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsEntity.kt +++ b/components/feature/sitepermissions/src/main/java/mozilla/components/feature/sitepermissions/db/SitePermissionsEntity.kt @@ -43,6 +43,9 @@ internal data class SitePermissionsEntity( @ColumnInfo(name = "autoplay_inaudible") var autoplayInaudible: SitePermissions.Status, + @ColumnInfo(name = "media_key_system_access") + var mediaKeySystemAccess: SitePermissions.Status, + @ColumnInfo(name = "saved_at") var savedAt: Long ) { @@ -58,6 +61,7 @@ internal data class SitePermissionsEntity( localStorage, autoplayAudible, autoplayInaudible, + mediaKeySystemAccess, savedAt ) } @@ -74,6 +78,7 @@ internal fun SitePermissions.toSitePermissionsEntity(): SitePermissionsEntity { localStorage, autoplayAudible, autoplayInaudible, + mediaKeySystemAccess, savedAt ) } diff --git a/components/feature/sitepermissions/src/main/res/values/strings.xml b/components/feature/sitepermissions/src/main/res/values/strings.xml index f0bcabbc64e..de7daf31291 100644 --- a/components/feature/sitepermissions/src/main/res/values/strings.xml +++ b/components/feature/sitepermissions/src/main/res/values/strings.xml @@ -36,4 +36,6 @@ Never Allow %1$s to store data in persistent storage? - \ No newline at end of file + + Allow %1$s to use EME? + diff --git a/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsStorageTest.kt b/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsStorageTest.kt index 0cef364bfff..dfc190fefca 100644 --- a/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsStorageTest.kt +++ b/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/SitePermissionsStorageTest.kt @@ -162,6 +162,7 @@ class SitePermissionsStorageTest { bluetooth = ALLOWED, autoplayAudible = BLOCKED, autoplayInaudible = NO_DECISION, + mediaKeySystemAccess = NO_DECISION, savedAt = 0 ), SitePermissionsEntity( @@ -174,6 +175,7 @@ class SitePermissionsStorageTest { bluetooth = ALLOWED, autoplayAudible = BLOCKED, autoplayInaudible = NO_DECISION, + mediaKeySystemAccess = NO_DECISION, savedAt = 0 ) ) @@ -186,4 +188,4 @@ class SitePermissionsStorageTest { override fun createInvalidationTracker(): InvalidationTracker = mock() override fun clearAllTables() = Unit } -} \ No newline at end of file +} diff --git a/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/db/SitePermissionEntityTest.kt b/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/db/SitePermissionEntityTest.kt index 4da5b774220..25c9a37eb36 100644 --- a/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/db/SitePermissionEntityTest.kt +++ b/components/feature/sitepermissions/src/test/java/mozilla/components/feature/sitepermissions/db/SitePermissionEntityTest.kt @@ -25,6 +25,7 @@ class SitePermissionEntityTest { bluetooth = ALLOWED, autoplayInaudible = BLOCKED, autoplayAudible = NO_DECISION, + mediaKeySystemAccess = NO_DECISION, savedAt = 0 ) @@ -70,4 +71,4 @@ class SitePermissionEntityTest { assertEquals(savedAt, domainClass.savedAt) } } -} \ No newline at end of file +}