From ed6babe09fde283f86abc6b29d2fce86dca23530 Mon Sep 17 00:00:00 2001 From: William Brawner Date: Mon, 16 Aug 2021 15:38:38 -0600 Subject: [PATCH] Fixes for new Ktor API --- android/build.gradle | 2 +- .../com/wbrawner/budget/ui/SplashViewModel.kt | 7 +- budgetlib/build.gradle | 2 +- .../com/wbrawner/budget/lib/network/Budget.kt | 2 +- .../budget/lib/network/TwigsApiService.kt | 82 +++++++++---------- .../lib/repository/NetworkBudgetRepository.kt | 3 +- .../repository/NetworkCategoryRepository.kt | 5 +- .../NetworkTransactionRepository.kt | 30 +++---- .../lib/repository/NetworkUserRepository.kt | 29 +++++-- common/build.gradle | 2 +- .../com/wbrawner/budget/common/Session.kt | 3 +- 11 files changed, 85 insertions(+), 82 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 79be2d0..8e0eff6 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -14,7 +14,7 @@ android { } defaultConfig { applicationId "com.wbrawner.budget" - minSdkVersion 23 + minSdkVersion 26 targetSdkVersion 30 versionCode 1 versionName "1.0" diff --git a/android/src/main/java/com/wbrawner/budget/ui/SplashViewModel.kt b/android/src/main/java/com/wbrawner/budget/ui/SplashViewModel.kt index 7d291d4..6a58881 100644 --- a/android/src/main/java/com/wbrawner/budget/ui/SplashViewModel.kt +++ b/android/src/main/java/com/wbrawner/budget/ui/SplashViewModel.kt @@ -50,21 +50,16 @@ class SplashViewModel : ViewModel(), AsyncViewModel { else "https://$server" baseUrlHelper.url = correctServer userRepository.login(username, password).also { - loadBudgetData() + budgetRepository.prefetchData() } sharedPreferences.edit { putString(PREF_KEY_BASE_URL, correctServer) } AuthenticationState.Authenticated } catch (e: Exception) { - // TODO: Return error message here AuthenticationState.Unauthenticated(server, username, password, e.message) } } - - private suspend fun loadBudgetData() { - budgetRepository.prefetchData() - } } sealed class AuthenticationState { diff --git a/budgetlib/build.gradle b/budgetlib/build.gradle index 25acbfb..416e4b5 100644 --- a/budgetlib/build.gradle +++ b/budgetlib/build.gradle @@ -7,7 +7,7 @@ android { compileSdkVersion 30 defaultConfig { - minSdkVersion 21 + minSdkVersion 26 targetSdkVersion 30 versionCode 1 versionName "1.0" diff --git a/budgetlib/src/main/java/com/wbrawner/budget/lib/network/Budget.kt b/budgetlib/src/main/java/com/wbrawner/budget/lib/network/Budget.kt index 8a1bac5..2af1dda 100644 --- a/budgetlib/src/main/java/com/wbrawner/budget/lib/network/Budget.kt +++ b/budgetlib/src/main/java/com/wbrawner/budget/lib/network/Budget.kt @@ -1,3 +1,3 @@ package com.wbrawner.budget.lib.network -data class BudgetBalanceResponse(val id: String, val balance: Long) \ No newline at end of file +data class BalanceResponse(val balance: Long) \ No newline at end of file diff --git a/budgetlib/src/main/java/com/wbrawner/budget/lib/network/TwigsApiService.kt b/budgetlib/src/main/java/com/wbrawner/budget/lib/network/TwigsApiService.kt index f3da7ad..67d6a75 100644 --- a/budgetlib/src/main/java/com/wbrawner/budget/lib/network/TwigsApiService.kt +++ b/budgetlib/src/main/java/com/wbrawner/budget/lib/network/TwigsApiService.kt @@ -11,111 +11,109 @@ import retrofit2.http.* interface TwigsApiService { // Budgets - @GET("budgets") + @GET("api/budgets") suspend fun getBudgets( @Query("count") count: Int? = null, @Query("page") page: Int? = null ): List - @GET("budgets/{id}") + @GET("api/budgets/{id}") suspend fun getBudget(@Path("id") id: String): Budget - @GET("budgets/{id}/balance") - suspend fun getBudgetBalance(@Path("id") id: String): BudgetBalanceResponse - - @POST("budgets") + @POST("api/budgets") suspend fun newBudget(@Body budget: NewBudgetRequest): Budget - @PUT("budgets/{id}") + @PUT("api/budgets/{id}") suspend fun updateBudget( @Path("id") id: String, @Body budget: Budget ): Budget - @DELETE("budgets/{id}") + @DELETE("api/budgets/{id}") suspend fun deleteBudget(@Path("id") id: String) // Categories - @GET("categories") + @GET("api/categories") suspend fun getCategories( - @Query("budgetIds") budgetIds: Array? = null, - @Query("count") count: Int? = null, - @Query("page") page: Int? = null + @Query("budgetIds") budgetIds: Array? = null, + @Query("archived") archived: Boolean? = false, + @Query("count") count: Int? = null, + @Query("page") page: Int? = null, ): List - @GET("categories/{id}") + @GET("api/categories/{id}") suspend fun getCategory(@Path("id") id: String): Category - @GET("categories/{id}/balance") - suspend fun getCategoryBalance(@Path("id") id: String): CategoryBalanceResponse - - @POST("categories") + @POST("api/categories") suspend fun newCategory(@Body category: Category): Category - @PUT("categories/{id}") + @PUT("api/categories/{id}") suspend fun updateCategory( @Path("id") id: String, @Body category: Category ): Category - @DELETE("categories/{id}") + @DELETE("api/categories/{id}") suspend fun deleteCategory(@Path("id") id: String) // Transactions - @GET("transactions") + @GET("api/transactions") suspend fun getTransactions( - @Query("budgetIds") budgetIds: List? = null, - @Query("categoryIds") categoryIds: List? = null, - @Query("from") from: String? = null, - @Query("to") to: String? = null, - @Query("count") count: Int? = null, - @Query("page") page: Int? = null + @Query("budgetIds") budgetIds: List? = null, + @Query("categoryIds") categoryIds: List? = null, + @Query("from") from: String? = null, + @Query("to") to: String? = null, + @Query("count") count: Int? = null, + @Query("page") page: Int? = null ): List - @GET("transactions/{id}") + @GET("api/transactions/{id}") suspend fun getTransaction(@Path("id") id: String): Transaction - @POST("transactions") + @GET("api/transactions/sum") + suspend fun sumTransactions( + @Query("budgetId") budgetId: String? = null, + @Query("categoryId") categoryId: String? = null + ): BalanceResponse + + @POST("api/transactions") suspend fun newTransaction(@Body transaction: Transaction): Transaction - @PUT("transactions/{id}") + @PUT("api/transactions/{id}") suspend fun updateTransaction( - @Path("id") id: String, - @Body transaction: Transaction + @Path("id") id: String, + @Body transaction: Transaction ): Transaction - @DELETE("transactions/{id}") + @DELETE("api/transactions/{id}") suspend fun deleteTransaction(@Path("id") id: String) // Users - @GET("users") + @GET("api/users") suspend fun getUsers( @Query("budgetId") budgetid: String? = null, @Query("count") count: Int? = null, @Query("page") page: Int? = null ): List - @POST("users/login") + @POST("api/users/login") suspend fun login(@Body request: LoginRequest): Session - @GET("users/me") - suspend fun getProfile(): User - - @GET("users/search") + @GET("api/users/search") suspend fun searchUsers(@Query("query") query: String): List - @GET("users/{id}") + @GET("api/users/{id}") suspend fun getUser(@Path("id") id: String): User - @POST("users") + @POST("api/users") suspend fun newUser(@Body user: User): User - @PUT("users/{id}") + @PUT("api/users/{id}") suspend fun updateUser( @Path("id") id: String, @Body user: User ): User - @DELETE("users/{id}") + @DELETE("api/users/{id}") suspend fun deleteUser(@Path("id") id: String) } \ No newline at end of file diff --git a/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkBudgetRepository.kt b/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkBudgetRepository.kt index 72a160f..45b3ccc 100644 --- a/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkBudgetRepository.kt +++ b/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkBudgetRepository.kt @@ -93,7 +93,8 @@ class NetworkBudgetRepository( } } - override suspend fun getBalance(id: String): Long = apiService.getBudgetBalance(id).balance + override suspend fun getBalance(id: String): Long = + apiService.sumTransactions(budgetId = id).balance } data class NewBudgetRequest( diff --git a/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkCategoryRepository.kt b/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkCategoryRepository.kt index 9afa793..69b4e96 100644 --- a/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkCategoryRepository.kt +++ b/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkCategoryRepository.kt @@ -19,7 +19,6 @@ class NetworkCategoryRepository @Inject constructor(private val apiService: Twig override suspend fun delete(id: String) = apiService.deleteCategory(id) - // TODO: Implement this method server-side and then here - override suspend fun getBalance(id: String): Long = apiService.getCategoryBalance(id).balance + override suspend fun getBalance(id: String): Long = + apiService.sumTransactions(categoryId = id).balance } - diff --git a/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkTransactionRepository.kt b/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkTransactionRepository.kt index 180c8ff..4e36305 100644 --- a/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkTransactionRepository.kt +++ b/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkTransactionRepository.kt @@ -3,29 +3,25 @@ package com.wbrawner.budget.lib.repository import com.wbrawner.budget.common.transaction.Transaction import com.wbrawner.budget.common.transaction.TransactionRepository import com.wbrawner.budget.lib.network.TwigsApiService -import java.text.SimpleDateFormat import java.util.* import javax.inject.Inject -class NetworkTransactionRepository @Inject constructor(private val apiService: TwigsApiService) : TransactionRepository { - private val dateFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ENGLISH) +class NetworkTransactionRepository @Inject constructor(private val apiService: TwigsApiService) : + TransactionRepository { - override suspend fun create(newItem: Transaction): Transaction = apiService.newTransaction(newItem) + override suspend fun create(newItem: Transaction): Transaction = + apiService.newTransaction(newItem) override suspend fun findAll( - budgetIds: List?, - categoryIds: List?, - start: Calendar?, - end: Calendar? + budgetIds: List?, + categoryIds: List?, + start: Calendar?, + end: Calendar? ): List = apiService.getTransactions( - budgetIds, - categoryIds, - start?.let { - dateFormatter.format(it.time) - }, - end?.let { - dateFormatter.format(it.time) - } + budgetIds, + categoryIds, + start?.toInstant()?.toString(), + end?.toInstant()?.toString() ) override suspend fun findAll(): List = findAll(null) @@ -33,7 +29,7 @@ class NetworkTransactionRepository @Inject constructor(private val apiService: T override suspend fun findById(id: String): Transaction = apiService.getTransaction(id) override suspend fun update(updatedItem: Transaction): Transaction = - apiService.updateTransaction(updatedItem.id!!, updatedItem) + apiService.updateTransaction(updatedItem.id!!, updatedItem) override suspend fun delete(id: String) = apiService.deleteTransaction(id) } diff --git a/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkUserRepository.kt b/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkUserRepository.kt index 7b5f627..61572bf 100644 --- a/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkUserRepository.kt +++ b/budgetlib/src/main/java/com/wbrawner/budget/lib/repository/NetworkUserRepository.kt @@ -4,6 +4,7 @@ import android.content.SharedPreferences import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.wbrawner.budget.common.PREF_KEY_TOKEN +import com.wbrawner.budget.common.PREF_KEY_USER_ID import com.wbrawner.budget.common.user.LoginRequest import com.wbrawner.budget.common.user.User import com.wbrawner.budget.common.user.UserRepository @@ -21,24 +22,36 @@ class NetworkUserRepository @Inject constructor( init { GlobalScope.launch { - try { - getProfile() - } catch (ignored: Exception) { - } + sharedPreferences.getString(PREF_KEY_USER_ID, null) + ?.let { + try { + getProfile() + } catch (ignored: Exception) { + sharedPreferences.edit() + .remove(PREF_KEY_USER_ID) + .remove(PREF_KEY_TOKEN) + .apply() + } + } } } override suspend fun login(username: String, password: String): User { apiService.login(LoginRequest(username, password)).also { sharedPreferences.edit() - .putString(PREF_KEY_TOKEN, it.token) - .apply() + .putString(PREF_KEY_USER_ID, it.userId) + .putString(PREF_KEY_TOKEN, it.token) + .apply() } return getProfile() } - override suspend fun getProfile(): User = apiService.getProfile().also { - (currentUser as MutableLiveData).postValue(it) + override suspend fun getProfile(): User { + val userId = sharedPreferences.getString(PREF_KEY_USER_ID, null) + ?: throw RuntimeException("Not authenticated") + return apiService.getUser(userId).also { + (currentUser as MutableLiveData).postValue(it) + } } override suspend fun create(newItem: User): User = apiService.newUser(newItem) diff --git a/common/build.gradle b/common/build.gradle index 259f3ff..8b56c16 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -8,7 +8,7 @@ android { defaultConfig { - minSdkVersion 21 + minSdkVersion 26 targetSdkVersion 30 versionCode 1 versionName "1.0" diff --git a/common/src/main/java/com/wbrawner/budget/common/Session.kt b/common/src/main/java/com/wbrawner/budget/common/Session.kt index dccbc89..2a8bbda 100644 --- a/common/src/main/java/com/wbrawner/budget/common/Session.kt +++ b/common/src/main/java/com/wbrawner/budget/common/Session.kt @@ -2,10 +2,11 @@ package com.wbrawner.budget.common import java.util.* +const val PREF_KEY_USER_ID = "userId" const val PREF_KEY_TOKEN = "sessionToken" data class Session( - val id: String, + val userId: String, val token: String, val expiration: Date ) \ No newline at end of file