Add category routes
This commit is contained in:
parent
ed1dde49bf
commit
4de09a8f1c
16 changed files with 247 additions and 309 deletions
1
api/.gitignore
vendored
Normal file
1
api/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
build/
|
|
@ -23,8 +23,10 @@ fun Application.budgetRoutes(
|
|||
block: suspend (Budget) -> Unit
|
||||
) {
|
||||
val session = call.principal<Session>()!!
|
||||
val userPermission =
|
||||
permissionRepository.findAllByUserId(session.userId).firstOrNull { it.budgetId == budgetId }
|
||||
val userPermission = permissionRepository.findAll(
|
||||
userId = session.userId,
|
||||
budgetIds = listOf(budgetId)
|
||||
).firstOrNull()
|
||||
if (userPermission?.permission?.isNotAtLeast(permission) != true) {
|
||||
call.respond(HttpStatusCode.Forbidden)
|
||||
return
|
||||
|
@ -33,90 +35,87 @@ fun Application.budgetRoutes(
|
|||
}
|
||||
|
||||
routing {
|
||||
authenticate(optional = false) {
|
||||
get("/") {
|
||||
val session = call.principal<Session>()!!
|
||||
val budgetIds = permissionRepository.findAllByUserId(session.userId).map { it.budgetId }
|
||||
val budgets = budgetRepository.findAllByIds(budgetIds).map {
|
||||
BudgetResponse(it, permissionRepository.findAllByBudgetId(it.id))
|
||||
route("/api/budgets") {
|
||||
authenticate(optional = false) {
|
||||
get("/") {
|
||||
val session = call.principal<Session>()!!
|
||||
val budgetIds = permissionRepository.findAll(userId = session.userId).map { it.budgetId }
|
||||
val budgets = budgetRepository.findAllByIds(budgetIds).map {
|
||||
BudgetResponse(it, permissionRepository.findAll(budgetIds = listOf(it.id)))
|
||||
}
|
||||
call.respond(budgets)
|
||||
}
|
||||
if (call.request.contentType() == ContentType.Application.Json) {
|
||||
|
||||
} else {
|
||||
call.respondHtml()
|
||||
get("/{id}") {
|
||||
budgetWithPermission(budgetId = call.parameters["id"]!!, Permission.READ) { budget ->
|
||||
val users = permissionRepository.findAll(budgetIds = listOf(budget.id))
|
||||
call.respond(BudgetResponse(budget, users))
|
||||
}
|
||||
}
|
||||
call.respond(budgets)
|
||||
}
|
||||
|
||||
get("/{id}") {
|
||||
budgetWithPermission(budgetId = call.parameters["id"]!!, Permission.READ) { budget ->
|
||||
val users = permissionRepository.findAllByBudgetId(budget.id)
|
||||
call.respond(BudgetResponse(budget, users))
|
||||
}
|
||||
}
|
||||
|
||||
post("/{id}") {
|
||||
val session = call.principal<Session>()!!
|
||||
val request = call.receive<BudgetRequest>()
|
||||
if (request.name.isNullOrBlank()) {
|
||||
call.respond(HttpStatusCode.BadRequest, "Name cannot be empty or null")
|
||||
return@post
|
||||
}
|
||||
val budget = budgetRepository.save(
|
||||
Budget(
|
||||
name = request.name,
|
||||
description = request.description
|
||||
)
|
||||
)
|
||||
val users = request.users?.map {
|
||||
permissionRepository.save(
|
||||
UserPermission(
|
||||
budgetId = budget.id,
|
||||
userId = it.user,
|
||||
permission = it.permission
|
||||
post("/{id}") {
|
||||
val session = call.principal<Session>()!!
|
||||
val request = call.receive<BudgetRequest>()
|
||||
if (request.name.isNullOrBlank()) {
|
||||
call.respond(HttpStatusCode.BadRequest, "Name cannot be empty or null")
|
||||
return@post
|
||||
}
|
||||
val budget = budgetRepository.save(
|
||||
Budget(
|
||||
name = request.name,
|
||||
description = request.description
|
||||
)
|
||||
)
|
||||
}?.toMutableSet() ?: mutableSetOf()
|
||||
if (users.none { it.userId == session.userId }) {
|
||||
users.add(
|
||||
val users = request.users?.map {
|
||||
permissionRepository.save(
|
||||
UserPermission(
|
||||
budgetId = budget.id,
|
||||
userId = session.userId,
|
||||
permission = Permission.OWNER
|
||||
userId = it.user,
|
||||
permission = it.permission
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
call.respond(BudgetResponse(budget, users))
|
||||
}
|
||||
|
||||
put("/{id}") {
|
||||
budgetWithPermission(call.parameters["id"]!!, Permission.MANAGE) { budget ->
|
||||
val request = call.receive<BudgetRequest>()
|
||||
val name = request.name ?: budget.name
|
||||
val description = request.description ?: budget.description
|
||||
val users = request.users?.map {
|
||||
permissionRepository.save(UserPermission(budget.id, it.user, it.permission))
|
||||
} ?: permissionRepository.findAllByBudgetId(budget.id)
|
||||
permissionRepository.findAllByBudgetId(budget.id).forEach {
|
||||
if (it.permission != Permission.OWNER && users.none { userPermission -> userPermission.userId == it.userId }) {
|
||||
permissionRepository.delete(it)
|
||||
}
|
||||
}
|
||||
call.respond(
|
||||
BudgetResponse(
|
||||
budgetRepository.save(budget.copy(name = name, description = description)),
|
||||
users
|
||||
}?.toMutableSet() ?: mutableSetOf()
|
||||
if (users.none { it.userId == session.userId }) {
|
||||
users.add(
|
||||
permissionRepository.save(
|
||||
UserPermission(
|
||||
budgetId = budget.id,
|
||||
userId = session.userId,
|
||||
permission = Permission.OWNER
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
call.respond(BudgetResponse(budget, users))
|
||||
}
|
||||
}
|
||||
|
||||
delete("/{id}") {
|
||||
budgetWithPermission(budgetId = call.parameters["id"]!!, Permission.READ) { budget ->
|
||||
budgetRepository.delete(budget)
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
put("/{id}") {
|
||||
budgetWithPermission(call.parameters["id"]!!, Permission.MANAGE) { budget ->
|
||||
val request = call.receive<BudgetRequest>()
|
||||
val name = request.name ?: budget.name
|
||||
val description = request.description ?: budget.description
|
||||
val users = request.users?.map {
|
||||
permissionRepository.save(UserPermission(budget.id, it.user, it.permission))
|
||||
} ?: permissionRepository.findAll(budgetIds = listOf(budget.id))
|
||||
permissionRepository.findAll(budgetIds = listOf(budget.id)).forEach {
|
||||
if (it.permission != Permission.OWNER && users.none { userPermission -> userPermission.userId == it.userId }) {
|
||||
permissionRepository.delete(it)
|
||||
}
|
||||
}
|
||||
call.respond(
|
||||
BudgetResponse(
|
||||
budgetRepository.save(budget.copy(name = name, description = description)),
|
||||
users
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
delete("/{id}") {
|
||||
budgetWithPermission(budgetId = call.parameters["id"]!!, Permission.OWNER) { budget ->
|
||||
budgetRepository.delete(budget)
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,18 +2,11 @@ package com.wbrawner.twigs
|
|||
|
||||
import com.wbrawner.twigs.model.Category
|
||||
|
||||
data class NewCategoryRequest(
|
||||
val title: String,
|
||||
val description: String? = null,
|
||||
val amount: Long,
|
||||
val budgetId: String,
|
||||
val expense: Boolean
|
||||
)
|
||||
|
||||
data class UpdateCategoryRequest(
|
||||
data class CategoryRequest(
|
||||
val title: String? = null,
|
||||
val description: String? = null,
|
||||
val amount: Long? = null,
|
||||
val budgetId: String? = null,
|
||||
val expense: Boolean? = null,
|
||||
val archived: Boolean? = null
|
||||
)
|
||||
|
|
148
api/src/main/kotlin/com/wbrawner/twigs/CategoryRoutes.kt
Normal file
148
api/src/main/kotlin/com/wbrawner/twigs/CategoryRoutes.kt
Normal file
|
@ -0,0 +1,148 @@
|
|||
package com.wbrawner.twigs
|
||||
|
||||
import com.wbrawner.twigs.model.Category
|
||||
import com.wbrawner.twigs.model.Permission
|
||||
import com.wbrawner.twigs.storage.CategoryRepository
|
||||
import com.wbrawner.twigs.storage.PermissionRepository
|
||||
import io.ktor.application.*
|
||||
import io.ktor.auth.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.request.*
|
||||
import io.ktor.response.*
|
||||
import io.ktor.routing.*
|
||||
import io.ktor.util.pipeline.*
|
||||
|
||||
fun Application.categoryRoutes(
|
||||
categoryRepository: CategoryRepository,
|
||||
permissionRepository: PermissionRepository
|
||||
) {
|
||||
routing {
|
||||
route("/api/categories") {
|
||||
authenticate(optional = false) {
|
||||
get("/") {
|
||||
val session = call.principal<Session>()!!
|
||||
call.respond(categoryRepository.findAll(
|
||||
budgetIds = permissionRepository.findAll(
|
||||
budgetIds = call.request.queryParameters.getAll("budgetIds"),
|
||||
userId = session.userId
|
||||
).map { it.budgetId },
|
||||
expense = call.request.queryParameters["expense"]?.toBoolean(),
|
||||
archived = call.request.queryParameters["archived"]?.toBoolean()
|
||||
).map { CategoryResponse(it) })
|
||||
}
|
||||
|
||||
get("/{id}") {
|
||||
val session = call.principal<Session>()!!
|
||||
call.respond(categoryRepository.findAll(
|
||||
ids = call.parameters.getAll("id"),
|
||||
budgetIds = permissionRepository.findAll(
|
||||
userId = session.userId
|
||||
).map { it.budgetId }
|
||||
).map { CategoryResponse(it) })
|
||||
}
|
||||
|
||||
post("/{id}") {
|
||||
val session = call.principal<Session>()!!
|
||||
val request = call.receive<CategoryRequest>()
|
||||
if (request.title.isNullOrBlank()) {
|
||||
call.respond(HttpStatusCode.BadRequest, ErrorResponse("Title cannot be null or empty"))
|
||||
return@post
|
||||
}
|
||||
if (request.budgetId.isNullOrBlank()) {
|
||||
call.respond(HttpStatusCode.BadRequest, ErrorResponse("Budget ID cannot be null or empty"))
|
||||
return@post
|
||||
}
|
||||
requireBudgetWithPermission(
|
||||
permissionRepository,
|
||||
session.userId,
|
||||
request.budgetId,
|
||||
Permission.WRITE
|
||||
) {
|
||||
return@post
|
||||
}
|
||||
call.respond(
|
||||
CategoryResponse(
|
||||
categoryRepository.save(
|
||||
Category(
|
||||
title = request.title,
|
||||
description = request.description,
|
||||
amount = request.amount ?: 0L,
|
||||
expense = request.expense ?: true,
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
put("/{id}") {
|
||||
val session = call.principal<Session>()!!
|
||||
val request = call.receive<CategoryRequest>()
|
||||
val category = categoryRepository.findAll(ids = call.parameters.getAll("id"))
|
||||
.firstOrNull()
|
||||
?: run {
|
||||
call.respond(HttpStatusCode.NotFound)
|
||||
return@put
|
||||
}
|
||||
requireBudgetWithPermission(
|
||||
permissionRepository,
|
||||
session.userId,
|
||||
category.budgetId!!,
|
||||
Permission.WRITE
|
||||
) {
|
||||
return@put
|
||||
}
|
||||
call.respond(
|
||||
CategoryResponse(
|
||||
categoryRepository.save(
|
||||
Category(
|
||||
title = request.title ?: category.title,
|
||||
description = request.description ?: category.description,
|
||||
amount = request.amount ?: category.amount,
|
||||
expense = request.expense ?: category.expense,
|
||||
archived = request.archived ?: category.archived
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
delete("/{id}") {
|
||||
val session = call.principal<Session>()!!
|
||||
val category = categoryRepository.findAll(ids = call.parameters.getAll("id"))
|
||||
.firstOrNull()
|
||||
?: run {
|
||||
call.respond(HttpStatusCode.NotFound)
|
||||
return@delete
|
||||
}
|
||||
requireBudgetWithPermission(
|
||||
permissionRepository,
|
||||
session.userId,
|
||||
category.budgetId!!,
|
||||
Permission.WRITE
|
||||
) {
|
||||
return@delete
|
||||
}
|
||||
categoryRepository.delete(category)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend inline fun PipelineContext<Unit, ApplicationCall>.requireBudgetWithPermission(
|
||||
permissionRepository: PermissionRepository,
|
||||
userId: String,
|
||||
budgetId: String,
|
||||
permission: Permission,
|
||||
otherwise: () -> Unit
|
||||
) {
|
||||
permissionRepository.findAll(
|
||||
userId = userId,
|
||||
budgetIds = listOf(budgetId)
|
||||
).firstOrNull {
|
||||
it.permission.isAtLeast(permission)
|
||||
} ?: run {
|
||||
call.respond(HttpStatusCode.Forbidden, "Insufficient permissions on budget $budgetId")
|
||||
otherwise()
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package com.wbrawner.twigs.server
|
||||
|
||||
import com.wbrawner.twigs.budgetRoutes
|
||||
import com.wbrawner.twigs.categoryRoutes
|
||||
import io.ktor.application.*
|
||||
import io.ktor.auth.*
|
||||
|
||||
|
@ -10,4 +11,5 @@ fun Application.module(budgetReposi) {
|
|||
|
||||
install(Authentication)
|
||||
budgetRoutes()
|
||||
categoryRoutes()
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
package com.wbrawner.twigs.server.category
|
||||
|
||||
import com.wbrawner.twigs.ErrorResponse
|
||||
import com.wbrawner.twigs.server.currentUser
|
||||
import com.wbrawner.twigs.server.firstOfMonth
|
||||
import com.wbrawner.twigs.server.permission.Permission
|
||||
import com.wbrawner.twigs.server.permission.UserPermission
|
||||
import com.wbrawner.twigs.server.permission.UserPermissionRepository
|
||||
import com.wbrawner.twigs.server.transaction.Transaction
|
||||
import com.wbrawner.twigs.server.transaction.TransactionRepository
|
||||
import org.springframework.data.domain.PageRequest
|
||||
import org.springframework.data.domain.Sort
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import java.util.function.Consumer
|
||||
import java.util.stream.Collectors
|
||||
import javax.transaction.Transactional
|
||||
|
||||
@RestController
|
||||
@RequestMapping(path = ["/categories"])
|
||||
@Transactional
|
||||
open class CategoryController(
|
||||
private val categoryRepository: CategoryRepository,
|
||||
private val transactionRepository: TransactionRepository,
|
||||
private val userPermissionsRepository: UserPermissionRepository
|
||||
) {
|
||||
@GetMapping(path = [""], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
open fun getCategories(
|
||||
@RequestParam(name = "budgetIds", required = false) budgetIds: List<String?>?,
|
||||
@RequestParam(name = "isExpense", required = false) isExpense: Boolean?,
|
||||
@RequestParam(name = "includeArchived", required = false) includeArchived: Boolean?,
|
||||
@RequestParam(name = "count", required = false) count: Int?,
|
||||
@RequestParam(name = "page", required = false) page: Int?,
|
||||
@RequestParam(name = "false", required = false) sortBy: String?,
|
||||
@RequestParam(name = "sortOrder", required = false) sortOrder: Sort.Direction?
|
||||
): ResponseEntity<List<CategoryResponse>> {
|
||||
val userPermissions: List<UserPermission>
|
||||
userPermissions = if (budgetIds != null && !budgetIds.isEmpty()) {
|
||||
userPermissionsRepository.findAllByUserAndBudget_IdIn(
|
||||
currentUser,
|
||||
budgetIds,
|
||||
PageRequest.of(page ?: 0, count ?: 1000)
|
||||
)
|
||||
} else {
|
||||
userPermissionsRepository.findAllByUser(currentUser, null)
|
||||
}
|
||||
val budgets = userPermissions.stream()
|
||||
.map { obj: UserPermission -> obj.budget }
|
||||
.collect(Collectors.toList())
|
||||
val pageRequest = PageRequest.of(
|
||||
Math.min(0, if (page != null) page - 1 else 0),
|
||||
count ?: 1000,
|
||||
sortOrder ?: Sort.Direction.ASC,
|
||||
sortBy ?: "title"
|
||||
)
|
||||
val archived = if (includeArchived == null || includeArchived == false) false else null
|
||||
val categories = categoryRepository.findAllByBudgetIn(budgets, isExpense, archived, pageRequest)
|
||||
return ResponseEntity.ok(
|
||||
categories.stream()
|
||||
.map { category: Category -> CategoryResponse(category) }
|
||||
.collect(Collectors.toList())
|
||||
)
|
||||
}
|
||||
|
||||
@GetMapping(path = ["/{id}"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
open fun getCategory(@PathVariable id: String?): ResponseEntity<CategoryResponse> {
|
||||
val budgets = userPermissionsRepository.findAllByUser(currentUser, null)
|
||||
.stream()
|
||||
.map { obj: UserPermission -> obj.budget }
|
||||
.collect(Collectors.toList())
|
||||
val category = categoryRepository.findByBudgetInAndId(budgets, id).orElse(null)
|
||||
?: return ResponseEntity.notFound().build()
|
||||
return ResponseEntity.ok(CategoryResponse(category))
|
||||
}
|
||||
|
||||
@GetMapping(path = ["/{id}/balance"], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||
open fun getCategoryBalance(@PathVariable id: String?): ResponseEntity<CategoryBalanceResponse> {
|
||||
val budgets = userPermissionsRepository.findAllByUser(currentUser, null)
|
||||
.stream()
|
||||
.map { obj: UserPermission -> obj.budget }
|
||||
.collect(Collectors.toList())
|
||||
val category = categoryRepository.findByBudgetInAndId(budgets, id).orElse(null)
|
||||
?: return ResponseEntity.notFound().build()
|
||||
val sum = transactionRepository.sumBalanceByCategoryId(category.id, firstOfMonth)
|
||||
return ResponseEntity.ok(CategoryBalanceResponse(category.id, sum))
|
||||
}
|
||||
|
||||
@PostMapping(
|
||||
path = [""],
|
||||
consumes = [MediaType.APPLICATION_JSON_VALUE],
|
||||
produces = [MediaType.APPLICATION_JSON_VALUE]
|
||||
)
|
||||
open fun newCategory(@RequestBody request: NewCategoryRequest): ResponseEntity<Any> {
|
||||
val userResponse = userPermissionsRepository.findByUserAndBudget_Id(currentUser, request.budgetId)
|
||||
.orElse(null) ?: return ResponseEntity.badRequest().body(ErrorResponse("Invalid budget ID"))
|
||||
if (userResponse.permission.isNotAtLeast(Permission.WRITE)) {
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).build()
|
||||
}
|
||||
val budget = userResponse.budget
|
||||
return ResponseEntity.ok(
|
||||
CategoryResponse(
|
||||
categoryRepository.save(
|
||||
Category(
|
||||
title = request.title,
|
||||
description = request.description,
|
||||
amount = request.amount,
|
||||
budget = budget,
|
||||
expense = request.expense
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@PutMapping(
|
||||
path = ["/{id}"],
|
||||
consumes = [MediaType.APPLICATION_JSON_VALUE],
|
||||
produces = [MediaType.APPLICATION_JSON_VALUE]
|
||||
)
|
||||
open fun updateCategory(
|
||||
@PathVariable id: String,
|
||||
@RequestBody request: UpdateCategoryRequest
|
||||
): ResponseEntity<CategoryResponse> {
|
||||
val category = categoryRepository.findById(id).orElse(null)
|
||||
?: return ResponseEntity.notFound().build()
|
||||
val userPermission = userPermissionsRepository.findByUserAndBudget_Id(
|
||||
currentUser,
|
||||
category.budget!!.id
|
||||
).orElse(null)
|
||||
?: return ResponseEntity.notFound().build()
|
||||
if (userPermission.permission.isNotAtLeast(Permission.WRITE)) {
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).build()
|
||||
}
|
||||
if (request.title != null) {
|
||||
category.title = request.title
|
||||
}
|
||||
if (request.description != null) {
|
||||
category.description = request.description
|
||||
}
|
||||
if (request.amount != null) {
|
||||
category.amount = request.amount
|
||||
}
|
||||
if (request.expense != null) {
|
||||
category.expense = request.expense
|
||||
}
|
||||
if (request.archived != null) {
|
||||
category.archived = request.archived
|
||||
}
|
||||
return ResponseEntity.ok(CategoryResponse(categoryRepository.save(category)))
|
||||
}
|
||||
|
||||
@DeleteMapping(path = ["/{id}"], produces = [MediaType.TEXT_PLAIN_VALUE])
|
||||
open fun deleteCategory(@PathVariable id: String): ResponseEntity<Void> {
|
||||
val category = categoryRepository.findById(id).orElse(null) ?: return ResponseEntity.notFound().build()
|
||||
val userPermission =
|
||||
userPermissionsRepository.findByUserAndBudget_Id(currentUser, category.budget!!.id).orElse(null)
|
||||
?: return ResponseEntity.notFound().build()
|
||||
if (userPermission.permission.isNotAtLeast(Permission.WRITE)) {
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).build()
|
||||
}
|
||||
transactionRepository.findAllByBudgetAndCategory(userPermission.budget, category)
|
||||
.forEach(Consumer { transaction: Transaction ->
|
||||
transaction.category = null
|
||||
transactionRepository.save(transaction)
|
||||
})
|
||||
categoryRepository.delete(category)
|
||||
return ResponseEntity.ok().build()
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package com.wbrawner.twigs.server.category
|
||||
|
||||
import com.wbrawner.twigs.server.budget.Budget
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.data.jpa.repository.Query
|
||||
import org.springframework.data.repository.PagingAndSortingRepository
|
||||
import java.util.*
|
||||
|
||||
interface CategoryRepository : PagingAndSortingRepository<Category, String> {
|
||||
fun findAllByBudget(budget: Budget?, pageable: Pageable?): List<Category>
|
||||
|
||||
@Query("SELECT c FROM Category c where c.budget IN (:budgets) AND (:expense IS NULL OR c.expense = :expense) AND (:archived IS NULL OR c.archived = :archived)")
|
||||
fun findAllByBudgetIn(
|
||||
budgets: List<Budget?>?,
|
||||
expense: Boolean?,
|
||||
archived: Boolean?,
|
||||
pageable: Pageable?
|
||||
): List<Category>
|
||||
|
||||
fun findByBudgetInAndId(budgets: List<Budget?>?, id: String?): Optional<Category>
|
||||
fun findByBudgetAndId(budget: Budget?, id: String?): Optional<Category>
|
||||
fun findAllByBudgetInAndIdIn(budgets: List<Budget?>?, ids: List<String?>?, pageable: Pageable?): List<Category>
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package com.wbrawner.twigs.server.passwordresetrequest
|
||||
|
||||
import org.springframework.data.repository.PagingAndSortingRepository
|
||||
|
||||
interface PasswordResetRequestRepository : PagingAndSortingRepository<PasswordResetRequest, Long>
|
|
@ -1,15 +0,0 @@
|
|||
package com.wbrawner.twigs.server.permission
|
||||
|
||||
import com.wbrawner.twigs.server.budget.Budget
|
||||
import com.wbrawner.twigs.server.user.User
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.data.repository.PagingAndSortingRepository
|
||||
import java.util.*
|
||||
|
||||
interface UserPermissionRepository : PagingAndSortingRepository<UserPermission, UserPermissionKey> {
|
||||
fun findByUserAndBudget_Id(user: User?, budgetId: String?): Optional<UserPermission>
|
||||
fun findAllByUser(user: User?, pageable: Pageable?): List<UserPermission>
|
||||
fun findAllByBudget(budget: Budget?, pageable: Pageable?): List<UserPermission>
|
||||
fun findAllByUserAndBudget(user: User?, budget: Budget?, pageable: Pageable?): List<UserPermission>
|
||||
fun findAllByUserAndBudget_IdIn(user: User?, budgetIds: List<String?>?, pageable: Pageable?): List<UserPermission>
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package com.wbrawner.twigs.server.session
|
||||
|
||||
import org.springframework.data.repository.PagingAndSortingRepository
|
||||
import java.util.*
|
||||
|
||||
interface UserSessionRepository : PagingAndSortingRepository<Session, String> {
|
||||
fun findByUserId(userId: String?): List<Session?>?
|
||||
fun findByToken(token: String?): Optional<Session?>?
|
||||
fun findByUserIdAndToken(userId: String?, token: String?): Optional<Session?>?
|
||||
fun deleteAllByExpirationBefore(expiration: Date?)
|
||||
}
|
1
core/.gitignore
vendored
Normal file
1
core/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
build/
|
|
@ -7,7 +7,7 @@ data class Category(
|
|||
var title: String = "",
|
||||
var description: String? = null,
|
||||
var amount: Long = 0L,
|
||||
var budget: Budget? = null,
|
||||
var budgetId: String? = null,
|
||||
var expense: Boolean = true,
|
||||
var archived: Boolean = false
|
||||
)
|
||||
|
|
|
@ -30,6 +30,10 @@ enum class Permission {
|
|||
*/
|
||||
OWNER;
|
||||
|
||||
fun isAtLeast(wanted: Permission): Boolean {
|
||||
return ordinal >= wanted.ordinal
|
||||
}
|
||||
|
||||
fun isNotAtLeast(wanted: Permission): Boolean {
|
||||
return ordinal < wanted.ordinal
|
||||
}
|
||||
|
|
1
storage/.gitignore
vendored
Normal file
1
storage/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
build/
|
|
@ -0,0 +1,12 @@
|
|||
package com.wbrawner.twigs.storage
|
||||
|
||||
import com.wbrawner.twigs.model.Category
|
||||
|
||||
interface CategoryRepository : Repository<Category> {
|
||||
fun findAll(
|
||||
ids: List<String>? = null,
|
||||
budgetIds: List<String>? = null,
|
||||
expense: Boolean? = null,
|
||||
archived: Boolean? = null
|
||||
): List<Category>
|
||||
}
|
|
@ -3,6 +3,8 @@ package com.wbrawner.twigs.storage
|
|||
import com.wbrawner.twigs.model.UserPermission
|
||||
|
||||
interface PermissionRepository : Repository<UserPermission> {
|
||||
fun findAllByBudgetId(budgetId: String): List<UserPermission>
|
||||
fun findAllByUserId(userId: String): List<UserPermission>
|
||||
fun findAll(
|
||||
budgetIds: List<String>? = null,
|
||||
userId: String? = null
|
||||
): List<UserPermission>
|
||||
}
|
Loading…
Reference in a new issue