Fixes for new Ktor API

This commit is contained in:
William Brawner 2021-08-16 15:38:38 -06:00
parent b65edb31c6
commit ed6babe09f
11 changed files with 85 additions and 82 deletions

View file

@ -14,7 +14,7 @@ android {
}
defaultConfig {
applicationId "com.wbrawner.budget"
minSdkVersion 23
minSdkVersion 26
targetSdkVersion 30
versionCode 1
versionName "1.0"

View file

@ -50,21 +50,16 @@ class SplashViewModel : ViewModel(), AsyncViewModel<AuthenticationState> {
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 {

View file

@ -7,7 +7,7 @@ android {
compileSdkVersion 30
defaultConfig {
minSdkVersion 21
minSdkVersion 26
targetSdkVersion 30
versionCode 1
versionName "1.0"

View file

@ -1,3 +1,3 @@
package com.wbrawner.budget.lib.network
data class BudgetBalanceResponse(val id: String, val balance: Long)
data class BalanceResponse(val balance: Long)

View file

@ -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<Budget>
@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<String>? = null,
@Query("count") count: Int? = null,
@Query("page") page: Int? = null
@Query("budgetIds") budgetIds: Array<String>? = null,
@Query("archived") archived: Boolean? = false,
@Query("count") count: Int? = null,
@Query("page") page: Int? = null,
): List<Category>
@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<String>? = null,
@Query("categoryIds") categoryIds: List<String>? = 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<String>? = null,
@Query("categoryIds") categoryIds: List<String>? = null,
@Query("from") from: String? = null,
@Query("to") to: String? = null,
@Query("count") count: Int? = null,
@Query("page") page: Int? = null
): List<Transaction>
@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<User>
@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<User>
@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)
}

View file

@ -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(

View file

@ -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
}

View file

@ -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<String>?,
categoryIds: List<String>?,
start: Calendar?,
end: Calendar?
budgetIds: List<String>?,
categoryIds: List<String>?,
start: Calendar?,
end: Calendar?
): List<Transaction> = 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<Transaction> = 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)
}

View file

@ -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)

View file

@ -8,7 +8,7 @@ android {
defaultConfig {
minSdkVersion 21
minSdkVersion 26
targetSdkVersion 30
versionCode 1
versionName "1.0"

View file

@ -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
)