Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added DataManager for Customer and Identifier #53

Merged
merged 1 commit into from
Jul 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.mifos.mobile.cn.data.datamanager

import io.reactivex.Observable
import org.mifos.mobile.cn.data.local.PreferencesHelper
import org.mifos.mobile.cn.data.models.Authentication
import org.mifos.mobile.cn.data.remote.BaseApiManager
import javax.inject.Inject
import javax.inject.Singleton
Expand Down Expand Up @@ -41,4 +43,7 @@ class DataManagerAuth @Inject constructor(private val baseApiManager: BaseApiMan
return@concatMap Observable.just(loginResponse)
})
}*/
fun refreshToken(): Observable<Authentication> {
return baseApiManager.getAuthApi().refreshToken()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package org.mifos.mobile.cn.data.datamanager

import io.reactivex.Completable
import io.reactivex.Observable
import io.reactivex.ObservableSource
import io.reactivex.functions.Function
import okhttp3.MultipartBody
import org.mifos.mobile.cn.data.models.customer.Command
import org.mifos.mobile.cn.data.models.customer.Customer
Expand All @@ -10,17 +12,25 @@ import org.mifos.mobile.cn.data.models.customer.identification.ScanCard

import org.mifos.mobile.cn.data.datamanager.contracts.ManagerCustomer
import org.mifos.mobile.cn.data.local.DatabaseHelperCustomer
import org.mifos.mobile.cn.data.remote.BaseApiManager
import org.mifos.mobile.cn.fakesource.FakeRemoteDataSource
import org.mifos.mobile.cn.data.datamanager.MifosBaseDataManager
import org.mifos.mobile.cn.data.local.PreferencesHelper
import javax.inject.Inject
import javax.inject.Singleton


class DataManagerCustomer @Inject constructor(var databaseHelperCustomer: DatabaseHelperCustomer) : ManagerCustomer {
@Singleton
class DataManagerCustomer @Inject constructor(private var baseApiManager: BaseApiManager, private var preferencesHelper: PreferencesHelper, dataManagerAuth: DataManagerAuth, private var databaseHelper: DatabaseHelperCustomer)
: ManagerCustomer, MifosBaseDataManager(dataManagerAuth, preferencesHelper) {


override fun fetchCustomer(identifier: String): Observable<Customer> {
return databaseHelperCustomer.fetchCustomer(identifier)

return authenticatedObservableApi(baseApiManager.getCustomerApi()
.fetchCustomer(identifier))
.onErrorResumeNext(
Function<Throwable, ObservableSource<Customer>>()
{Observable.just(FakeRemoteDataSource.getCustomerJson()) })
}

override fun updateCustomer(customerIdentifier: String, customer: Customer?): Completable? {
return null
}
Expand All @@ -31,12 +41,17 @@ class DataManagerCustomer @Inject constructor(var databaseHelperCustomer: Databa
return null
}

override fun fetchCustomerCommands(customerIdentifier: String): Observable<MutableList<Command>>? {
return null
override fun fetchCustomerCommands(customerIdentifier: String): Observable<List<Command>> {
return authenticatedObservableApi(baseApiManager.getCustomerApi()
.fetchCustomerCommands(customerIdentifier))
.onErrorResumeNext(
Function<Throwable, ObservableSource<List<Command>>> { Observable.just(FakeRemoteDataSource.getCustomerCommandJson()) })
}

override fun fetchIdentifications(customerIdentifier: String): Observable<MutableList<Identification>>? {
return null
override fun fetchIdentifications(customerIdentifier: String): Observable<List<Identification>> {
return authenticatedObservableApi(baseApiManager.getCustomerApi()
.fetchIdentification(customerIdentifier))
.onErrorResumeNext(Function<Throwable, ObservableSource<List<Identification>>> { Observable.just(FakeRemoteDataSource.getIdentificationsJson()) })
}

override fun createIdentificationCard(identifier: String, identification: Identification): Completable? {
Expand All @@ -47,8 +62,12 @@ class DataManagerCustomer @Inject constructor(var databaseHelperCustomer: Databa
return null
}

override fun fetchIdentificationScanCards(customerIdentifier: String, identificationNumber: String): Observable<MutableList<ScanCard>>? {
return null
override fun fetchIdentificationScanCards(customerIdentifier: String,
identificationNumber: String): Observable<List<ScanCard>> {
return authenticatedObservableApi(baseApiManager.getCustomerApi()
.fetchIdentificationScanCards(customerIdentifier, identificationNumber))
.onErrorResumeNext(
Function<Throwable, ObservableSource<List<ScanCard>>> { Observable.just(FakeRemoteDataSource.getScanCards()) })
}

override fun uploadIdentificationCardScan(customerIdentifier: String, identificationNumber: String, scanIdentifier: String, description: String, file: MultipartBody.Part): Completable? {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.mifos.mobile.cn.data.datamanager

import io.reactivex.Completable
import io.reactivex.CompletableSource
import io.reactivex.Observable
import io.reactivex.functions.Function
import org.mifos.mobile.cn.data.local.PreferenceKey
import org.mifos.mobile.cn.data.local.PreferencesHelper
import org.mifos.mobile.cn.exceptions.ExceptionStatusCode

open class MifosBaseDataManager(private var dataManagerAuth: DataManagerAuth, preferencesHelper: PreferencesHelper) {
private var preferencesHelper: PreferencesHelper = preferencesHelper

fun <T> authenticatedObservableApi(observable: Observable<T>): Observable<T> {
return observable.onErrorResumeNext(refreshTokenAndRetryObser<T>(observable))
}

fun authenticatedCompletableApi(completable: Completable): Completable {
return completable.onErrorResumeNext(refreshTokenAndRetryCompletable(completable))
}

fun <T> refreshTokenAndRetryObser(
toBeResumed: Observable<T>): Function<Throwable, out Observable<out T>> {
return Function { throwable ->
// Here check if the error thrown really is a 403
if (ExceptionStatusCode.isHttp403Error(throwable)) {
preferencesHelper.putBoolean(PreferenceKey.PREF_KEY_REFRESH_ACCESS_TOKEN, true)
return@Function dataManagerAuth.refreshToken().concatMap { authentication ->
preferencesHelper.putBoolean(
PreferenceKey.PREF_KEY_REFRESH_ACCESS_TOKEN, false)
preferencesHelper.putAccessToken(
authentication.accessToken)
preferencesHelper.putSignInUser(authentication)
toBeResumed
}
}
// re-throw this error because it's not recoverable from here
Observable.error(throwable)
}
}

fun refreshTokenAndRetryCompletable(
toBeResumed: Completable): Function<Throwable, out CompletableSource> {
return Function { throwable ->
// Here check if the error thrown really is a 403
if (ExceptionStatusCode.isHttp403Error(throwable)) {
preferencesHelper.putBoolean(PreferenceKey.PREF_KEY_REFRESH_ACCESS_TOKEN, true)
return@Function dataManagerAuth.refreshToken().flatMapCompletable { authentication ->
preferencesHelper.putBoolean(
PreferenceKey.PREF_KEY_REFRESH_ACCESS_TOKEN, false)
preferencesHelper.putAccessToken(
authentication.accessToken)
preferencesHelper.putSignInUser(authentication)
toBeResumed
}
}
// re-throw this error because it's not recoverable from here
Completable.error(throwable)
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ object PreferenceKey {
//TODO:remove this while implementing API
const val PREF_KEY_PASSWORD = "PREF_KEY_PASSWORD"

const val PREF_KEY_REFRESH_ACCESS_TOKEN = "PREF_KEY_REFRESH_ACCESS_TOKEN"

const val PREF_KEY_SIGNED_IN_USER = "PREF_KEY_SIGNED_IN_USER"

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import android.content.SharedPreferences
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import org.mifos.mobile.cn.data.models.Authentication
import org.mifos.mobile.cn.injection.ApplicationContext
import javax.inject.Inject
import javax.inject.Singleton
Expand Down Expand Up @@ -90,6 +91,17 @@ constructor(@ApplicationContext context: Context) {
preferences.edit().putString(PreferenceKey.PREF_KEY_USER_NAME, username).apply()
}

fun getSignedInUser(): Authentication? {
val userJson = preferences.getString(PreferenceKey.PREF_KEY_SIGNED_IN_USER, null)
?: return null
return gson.fromJson<Authentication>(userJson, Authentication::class.java!!)
}

fun putSignInUser(user: Authentication) {
preferences.edit().putString(PreferenceKey.PREF_KEY_SIGNED_IN_USER,
gson.toJson(user)).apply()
}

val username: String
get() = preferences.getString(PreferenceKey.PREF_KEY_USER_NAME, null)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.mifos.mobile.cn.data.models

import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.android.parcel.Parcelize

@Parcelize
data class Authentication(
@SerializedName("tokenType") var tokenType: String,
@SerializedName("accessToken") var accessToken: String,
@SerializedName("accessTokenExpiration") var accessTokenExpiration: String,
@SerializedName("refreshTokenExpiration") var refreshTokenExpiration: String,
@SerializedName("passwordExpiration") var passwordExpiration: String
) : Parcelable
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import org.mifos.mobile.cn.data.services.AuthService
import org.mifos.mobile.cn.data.services.CustomerService

class BaseApiManager constructor(context: Context) {

private lateinit var retrofit: Retrofit
private lateinit var anonymousRetrofit: Retrofit
private lateinit var authApi: AuthService
private lateinit var anonymousService: AnonymousService
private lateinit var customerApi: CustomerService


init {
createService(context)
Expand All @@ -23,6 +26,7 @@ class BaseApiManager constructor(context: Context) {

private fun init() {
authApi = createApi(AuthService::class.java)
customerApi = createApi(CustomerService::class.java)
}

private fun initAnonymous() {
Expand Down Expand Up @@ -72,4 +76,8 @@ class BaseApiManager constructor(context: Context) {
fun getAnonymousService(): AnonymousService {
return anonymousService
}

fun getCustomerApi(): CustomerService {
return customerApi
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package org.mifos.mobile.cn.data.services

import io.reactivex.Observable
import org.mifos.mobile.cn.data.models.Authentication
import org.mifos.mobile.cn.data.remote.EndPoints
import retrofit2.http.POST

/**
* @author Rajan Maurya
* On 22/01/18.
Expand All @@ -8,4 +13,6 @@ interface AuthService {

/*@GET("/authentication")
fun login(loginRequest: LoginRequest): Observable<LoginResponse>*/
@POST(EndPoints.API_IDENTITY_PATH + "/token?grant_type=refresh_token")
abstract fun refreshToken(): Observable<Authentication>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.mifos.mobile.cn.data.services

import io.reactivex.Completable
import io.reactivex.Observable
import okhttp3.MultipartBody
import org.mifos.mobile.cn.data.models.customer.Command
import org.mifos.mobile.cn.data.models.customer.Customer
import org.mifos.mobile.cn.data.models.customer.CustomerPage
import org.mifos.mobile.cn.data.models.customer.identification.Identification
import org.mifos.mobile.cn.data.models.customer.identification.ScanCard
import org.mifos.mobile.cn.data.remote.EndPoints
import retrofit2.http.*

interface CustomerService {
@GET(EndPoints.API_CUSTOMER_PATH + "/customers")
abstract fun fetchCustomers(
@Query("pageIndex") integer: Int?,
@Query("size") size: Int?): Observable<CustomerPage>

@GET(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}")
abstract fun fetchCustomer(@Path("identifier") identifier: String): Observable<Customer>

@PUT(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}")
abstract fun updateCustomer(
@Path("identifier") identifier: String,
@Body customer: Customer): Completable

@GET(EndPoints.API_CUSTOMER_PATH + "/customers")
abstract fun searchCustomer(
@Query("pageIndex") pageIndex: Int?,
@Query("size") size: Int?,
@Query("term") term: String): Observable<CustomerPage>

@POST(EndPoints.API_CUSTOMER_PATH + "/customers")
abstract fun createCustomer(@Body customer: Customer): Completable

@POST(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}/commands")
abstract fun customerCommand(@Path("identifier") identifier: String, @Body command: Command): Completable

@GET(EndPoints.API_CUSTOMER_PATH + "/customers/{customerIdentifier}/commands")
abstract fun fetchCustomerCommands(
@Path("customerIdentifier") customerIdentifier: String): Observable<List<Command>>

@GET(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}/identifications")
abstract fun fetchIdentification(
@Path("identifier") identifier: String): Observable<List<Identification>>

@GET(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}/identifications/{number}")
abstract fun searchIdentification(
@Path("identifier") identifier: String, @Path("number") number: String): Observable<Identification>

@POST(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}/identifications")
abstract fun createIdentificationCard(@Path("identifier") identifier: String,
@Body identification: Identification): Completable

@PUT(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}/identifications/{identificationNumber}")
abstract fun updateIdentificationCard(
@Path("identifier") identifier: String,
@Path("identificationNumber") identificationNumber: String,
@Body identification: Identification): Completable

@GET(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}/identifications/{identificationnumber}/scans")
abstract fun fetchIdentificationScanCards(
@Path("identifier") identifier: String,
@Path("identificationnumber") identificationnumber: String): Observable<List<ScanCard>>

@Multipart
@POST(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}/identifications/{identificationnumber}/scans")
abstract fun uploadIdentificationCardScan(
@Path("identifier") identifier: String,
@Path("identificationnumber") identificationnumber: String,
@Query("scanIdentifier") scanIdentifier: String,
@Query("description") description: String,
@Part file: MultipartBody.Part): Completable

@DELETE(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}/identifications/{identificationnumber}/scans/{scanIdentifier}")
abstract fun deleteIdentificationCardScan(
@Path("identifier") identifier: String,
@Path("identificationnumber") identificationnumber: String,
@Path("scanIdentifier") scanIdentifier: String): Completable

@DELETE(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}/identifications/{identificationnumber}")
abstract fun deleteIdentificationCard(
@Path("identifier") identifier: String,
@Path("identificationnumber") identificationnumber: String): Completable

@Multipart
@POST(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}/portrait")
abstract fun uploadCustomerPortrait(
@Path("identifier") customerIdentifier: String,
@Part file: MultipartBody.Part): Completable

@DELETE(EndPoints.API_CUSTOMER_PATH + "/customers/{identifier}/portrait")
abstract fun deleteCustomerPortrait(@Path("identifier") customerIdentifier: String): Completable
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ object ExceptionStatusCode {
fun isHttp500Error(throwable: Throwable): Boolean {
return (throwable as HttpException).code() == 500
}
fun isHttp403Error(throwable: Throwable): Boolean{
return (throwable as HttpException).code() == 403
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.mifos.mobile.cn.data.remote.MifosInterceptor
import org.mifos.mobile.cn.injection.ApplicationContext
import org.mifos.mobile.cn.injection.module.ApplicationModule
import org.mifos.mobile.cn.data.datamanager.DataManagerAuth
import org.mifos.mobile.cn.data.datamanager.DataManagerCustomer
import org.mifos.mobile.cn.data.datamanager.DataManagerLoan
import javax.inject.Singleton

Expand All @@ -26,6 +27,8 @@ interface ApplicationComponent {
fun dataManagerAuth(): DataManagerAuth
fun dataManagerLoan(): DataManagerLoan
fun databaseHelperLoan(): DataBaseHelperLoan
fun dataManagerCustomer(): DataManagerCustomer


fun inject(fineractInterceptor: MifosInterceptor)
fun inject(fineractApplication: MifosApplication)
Expand Down
Loading