Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import com.couchbase.learningpath.data.DatabaseManager
import com.couchbase.learningpath.data.audits.AuditRepositoryDb
import com.couchbase.learningpath.data.project.ProjectRepositoryDb
import com.couchbase.learningpath.data.stockItem.StockItemRepositoryDb
import com.couchbase.learningpath.data.userprofile.UserProfileRepository
import com.couchbase.learningpath.data.userprofile.UserProfileRepositoryDb
import com.couchbase.learningpath.data.warehouse.WarehouseRepositoryDb
import com.couchbase.learningpath.models.*
import com.couchbase.learningpath.services.MockAuthenticationService
import com.couchbase.lite.CouchbaseLiteException
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.*
import org.junit.Assert.*
Expand All @@ -34,7 +35,7 @@ class DatabaseIntegrationTests {
private lateinit var warehouseRepository: WarehouseRepositoryDb
private lateinit var auditRepository: AuditRepositoryDb
private lateinit var stockItemRepository: StockItemRepositoryDb
private lateinit var userProfileRepository: UserProfileRepository
private lateinit var userProfileRepository: UserProfileRepositoryDb

//test users
private lateinit var user1: User
Expand Down Expand Up @@ -80,14 +81,16 @@ class DatabaseIntegrationTests {
databaseManager.deleteDatabases()
databaseManager.initializeDatabases(user1)

authenticationService = MockAuthenticationService()
val isAuth = authenticationService.authenticatedUser(user1.username, user1.password)
authenticationService = MockAuthenticationService(databaseManager)
val isAuth = runBlocking {
authenticationService.authenticatedUser(user1.username, user1.password)
}

//arrange repositories
auditRepository = AuditRepositoryDb(authenticationService, databaseManager)
stockItemRepository = StockItemRepositoryDb(databaseManager)
warehouseRepository = WarehouseRepositoryDb(databaseManager)
userProfileRepository = UserProfileRepository(databaseManager)
userProfileRepository = UserProfileRepositoryDb(databaseManager)
projectRepository = ProjectRepositoryDb(
authenticationService = authenticationService,
warehouseRepository = warehouseRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import org.koin.core.logger.Level
import org.koin.core.module.Module
import org.koin.dsl.module

import com.couchbase.learningpath.data.KeyValueRepository
import com.couchbase.learningpath.data.audits.AuditRepository
import com.couchbase.learningpath.data.audits.AuditRepositoryDb
import com.couchbase.learningpath.data.project.ProjectRepository
import com.couchbase.learningpath.data.project.ProjectRepositoryDb
import com.couchbase.learningpath.data.stockItem.StockItemRepository
import com.couchbase.learningpath.data.stockItem.StockItemRepositoryDb
import com.couchbase.learningpath.data.userprofile.UserProfileRepository
import com.couchbase.learningpath.data.userprofile.UserProfileRepositoryDb
import com.couchbase.learningpath.data.warehouse.WarehouseRepository
import com.couchbase.learningpath.data.warehouse.WarehouseRepositoryDb
import com.couchbase.learningpath.services.AuthenticationService
Expand Down Expand Up @@ -74,7 +74,7 @@ class InventoryApplication
singleOf(::DatabaseManager)
singleOf(::MockAuthenticationService) bind AuthenticationService::class
singleOf(::ReplicatorServiceDb) bind ReplicatorService::class
singleOf(::UserProfileRepository) bind KeyValueRepository::class
singleOf(::UserProfileRepositoryDb) bind UserProfileRepository::class
singleOf(::WarehouseRepositoryDb) bind WarehouseRepository::class
singleOf(::ProjectRepositoryDb) bind ProjectRepository::class
singleOf(::StockItemRepositoryDb) bind StockItemRepository::class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ fun InventoryNavGraph(
navController: NavHostController = rememberNavController(),
scaffoldState: ScaffoldState = rememberScaffoldState(),
scope: CoroutineScope = rememberCoroutineScope(),
userProfileViewModel: UserProfileViewModel,
startDestination: String = MainDestinations.LOGIN_ROUTE) {
val actions = remember(navController) { MainActions(navController) }
NavHost(navController = navController,
Expand Down Expand Up @@ -192,7 +193,7 @@ fun InventoryNavGraph(
UserProfileView(
openDrawer = openDrawer,
scaffoldState = scaffoldState,
viewModel = getViewModel<UserProfileViewModel>())
viewModel = userProfileViewModel)
}

composable(MainDestinations.DEVELOPER_ROUTE){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package com.couchbase.learningpath.data

interface KeyValueRepository {

fun inventoryDatabaseName(): String
fun inventoryDatabaseLocation(): String?

suspend fun count(): Int
suspend fun get(currentUser: String): Map<String, Any>
suspend fun save(data: Map<String, Any>) : Boolean
suspend fun get(key: String): Map<String, Any?>
suspend fun save(data: Map<String, Any?>) : Boolean
}
Original file line number Diff line number Diff line change
@@ -1,101 +1,10 @@
package com.couchbase.learningpath.data.userprofile

import com.couchbase.lite.CouchbaseLiteException
import com.couchbase.lite.MutableDocument

import com.couchbase.learningpath.data.DatabaseManager
import com.couchbase.learningpath.data.KeyValueRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class UserProfileRepository(
private val databaseManager: DatabaseManager
) : KeyValueRepository {
private val userProfileType = "user"

override fun inventoryDatabaseName(): String {
return databaseManager.currentInventoryDatabaseName
}

override fun inventoryDatabaseLocation(): String? {
return databaseManager.inventoryDatabase?.path
}

override suspend fun get(currentUser: String): Map<String, Any> {
return withContext(Dispatchers.IO) {
val results = HashMap<String, Any>() // <1>
results["email"] = currentUser as Any // <2>

val database = databaseManager.inventoryDatabase
database?.let { db ->
val documentId = getCurrentUserDocumentId(currentUser)
val doc = db.getDocument(documentId) // <3>
if (doc != null) {
if (doc.contains("givenName")) { // <4>
results["givenName"] = doc.getString("givenName") as Any // <4>
}
if (doc.contains("surname")) { // <4>
results["surname"] = doc.getString("surname") as Any // <4>
}
if (doc.contains("jobTitle")) { // <4>
results["jobTitle"] = doc.getString("jobTitle") as Any // <4>
}
if (doc.contains("team")) { // <4>
results["team"] = doc.getString("team") as Any // <4>
}
if (doc.contains("imageData")) { // <4>
results["imageData"] = doc.getBlob("imageData") as Any // <4>
}
}
}
return@withContext results // <5>
}
}

override suspend fun save(data: Map<String, Any>): Boolean {
return withContext(Dispatchers.IO) {
val email = data["email"] as String
val documentId = getCurrentUserDocumentId(email)
val mutableDocument = MutableDocument(documentId, data)
try {
val database = databaseManager.inventoryDatabase
database?.save(mutableDocument)
} catch (e: CouchbaseLiteException) {
android.util.Log.e(e.message, e.stackTraceToString())
return@withContext false
}
return@withContext true
}
}

override suspend fun count(): Int {
return withContext(Dispatchers.IO) {
val database = databaseManager.inventoryDatabase
database?.let { db ->
val query = "SELECT COUNT(*) AS count FROM _ WHERE documentType='$userProfileType'"
val results = db.createQuery(query).execute().allResults()
return@withContext results[0].getInt("count")
}
return@withContext 0
}
}

suspend fun delete(documentId: String): Boolean {
return withContext(Dispatchers.IO) {
var result = false
val database = databaseManager.inventoryDatabase
database?.let { db ->
val document = db.getDocument(documentId)
document?.let {
db.delete(it)
result = true
}
}
return@withContext result
}
}
interface UserProfileRepository : KeyValueRepository {

private fun getCurrentUserDocumentId(currentUser: String): String {
return "user::${currentUser}"
}
fun inventoryDatabaseName(): String
fun inventoryDatabaseLocation(): String?
suspend fun delete(documentId: String): Boolean
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package com.couchbase.learningpath.data.userprofile

import com.couchbase.lite.CouchbaseLiteException
import com.couchbase.lite.MutableDocument

import com.couchbase.learningpath.data.DatabaseManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class UserProfileRepositoryDb(
private val databaseManager: DatabaseManager
) : UserProfileRepository {
private val userProfileType = "user"

override fun inventoryDatabaseName(): String {
return databaseManager.currentInventoryDatabaseName
}

override fun inventoryDatabaseLocation(): String? {
return databaseManager.inventoryDatabase?.path
}

override suspend fun get(key: String): Map<String, Any?> {
return withContext(Dispatchers.IO) {
val results = HashMap<String, Any?>() // <1>
results["email"] = key // <2>

val database = databaseManager.inventoryDatabase
database?.let { db ->
val documentId = getCurrentUserDocumentId(key)
val doc = db.getDocument(documentId) // <3>
if (doc != null) {
results["givenName"] = doc.getString("givenName") // <4>
results["surname"] = doc.getString("surname") // <4>
results["jobTitle"] = doc.getString("jobTitle") // <4>
results["team"] = doc.getString("team") // <4>
results["imageData"] = doc.getBlob("imageData") // <4>
}
}
results // <5>
}
}

override suspend fun save(data: Map<String, Any?>): Boolean {
return withContext(Dispatchers.IO) {
val email = data["email"] as String
val documentId = getCurrentUserDocumentId(email)
val mutableDocument = MutableDocument(documentId, data)
try {
val database = databaseManager.inventoryDatabase
database?.save(mutableDocument)
} catch (e: CouchbaseLiteException) {
android.util.Log.e(e.message, e.stackTraceToString())
return@withContext false
}
return@withContext true
}
}

override suspend fun count(): Int {
return withContext(Dispatchers.IO) {
val database = databaseManager.inventoryDatabase
database?.let { db ->
val query = "SELECT COUNT(*) AS count FROM _ WHERE documentType='$userProfileType'"
val results = db.createQuery(query).execute().allResults()
return@withContext results[0].getInt("count")
}
return@withContext 0
}
}

override suspend fun delete(documentId: String): Boolean {
return withContext(Dispatchers.IO) {
var result = false
val database = databaseManager.inventoryDatabase
database?.let { db ->
val document = db.getDocument(documentId)
document?.let {
db.delete(it)
result = true
}
}
return@withContext result
}
}

private fun getCurrentUserDocumentId(currentUser: String): String {
return "user::${currentUser}"
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.couchbase.learningpath.services

import androidx.lifecycle.LiveData
import com.couchbase.learningpath.models.User

interface AuthenticationService {
val currentUser: LiveData<User?>
fun getCurrentUser() : User
fun authenticatedUser(username: String, password: String) : Boolean
suspend fun authenticatedUser(username: String, password: String) : Boolean
fun logout()
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,48 @@
package com.couchbase.learningpath.services

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.couchbase.learningpath.data.DatabaseManager
import com.couchbase.learningpath.models.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class MockAuthenticationService : AuthenticationService {
class MockAuthenticationService(
private val databaseManager: DatabaseManager
) : AuthenticationService {

private var _user: User? = null
private var _mockUsers = HashMap<String, User>()
private val _user = MutableLiveData<User?>()
private val _mockUsers = HashMap<String, User>()

override val currentUser: LiveData<User?> = _user

override fun getCurrentUser(): User {
return _user?: User("", "", "")
return _user.value ?: User("", "", "")
}

override fun authenticatedUser(username: String, password: String): Boolean {
override suspend fun authenticatedUser(username: String, password: String): Boolean {
return if (_mockUsers.containsKey(username)){
val user = _mockUsers[username]
if (user?.password == password){
_user = user
withContext(Dispatchers.IO) {
//initialize database if needed
databaseManager.initializeDatabases(user)
withContext(Dispatchers.Main) {
_user.value = user
}
}
true
} else {
false
}
} else {
_user = User(username = username, password = password, team = "team2")
_user.value = User(username = username, password = password, team = "team2")
return true
}
}

override fun logout() {
_user = null
_user.value = null
}

init {
Expand Down
Loading