rename remove as revoke, update order logic

Signed-off-by: Puqns67 <me@puqns67.icu>
This commit is contained in:
Puqns67 2023-09-18 21:10:21 +08:00
parent 74ebccff85
commit 906fccf619
Signed by: Puqns67
GPG Key ID: 9669DF042554F536
13 changed files with 270 additions and 58 deletions

View File

@ -38,6 +38,7 @@ class Account(private val repository: AccountRepository) {
if (this.getCurrentUser(token) != null) return error(attributes, "登录", "当前已登录账户")
val user = repository.findByName(name) ?: return error(attributes, "登录", "账户不存在", "/login")
if (!user.testPassword(password)) return error(attributes, "登录", "密码错误", "/login")
if (user.isRevoked) return error(attributes, "登录", "此账户已被吊销", "/login")
user.updateToken()
user.updateLoginTime()
repository.save(user)

View File

@ -1,4 +1,150 @@
package team8.fruitable.controller.action
class Order {
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.CookieValue
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.servlet.mvc.support.RedirectAttributes
import team8.fruitable.controller.util.error
import team8.fruitable.datebase.entity.Item
import team8.fruitable.datebase.entity.User
import team8.fruitable.datebase.entity.Order
import team8.fruitable.datebase.repository.*
@Controller
@RequestMapping("/action/order")
class Order(
private val orderRepository: OrderRepository,
private val orderedItemRepository: OrderedItemRepository,
private val payTypeRepository: PayTypeRepository,
private val accountRepository: AccountRepository,
private val itemRepository: ItemRepository
) {
private fun getCurrentUser(token: String?): User? {
return token?.let(accountRepository::findByToken)
}
@RequestMapping("/create/{item_id}/{item_number}")
fun create(
attributes: RedirectAttributes,
@CookieValue("TOKEN", required = false) token: String?,
@PathVariable("item_id") itemId: Long,
@PathVariable("item_number") itemNumber: Int,
@RequestParam("name") name: String,
@RequestParam("phone") phone: String,
@RequestParam("address") address: String,
@RequestParam("pay_type") payTypeId: Long,
@RequestParam("redirect", required = false) redirect: String?
): String {
val user = this.getCurrentUser(token) ?: return error(attributes, "创建订单", "账户未登录", "/login")
val item = itemRepository.findById(itemId).orElse(null) ?: return error(attributes, "创建订单", "商品不存在")
val payType =
payTypeRepository.findById(payTypeId).orElse(null) ?: return error(attributes, "创建订单", "未知的支付类型")
val itemPrice = item.price?.times(itemNumber) ?: return error(
attributes, "创建订单", "错误的商品价格(可能是商品未添加对应的价格)"
)
var order = Order(user, name, phone, address, payType, itemPrice, mutableListOf(item))
order = orderRepository.save(order)
// 更新 orders_to_items 表中的个数信息
val orderedItem = orderedItemRepository.findByOrder(order)[0]
orderedItem.number = itemNumber
orderedItemRepository.save(orderedItem)
redirect?.let { return "redirect:/${it}" }
return "redirect:/order/${order.id}"
}
@RequestMapping("/create")
fun createForCart(
attributes: RedirectAttributes,
@CookieValue("TOKEN", required = false) token: String?,
@RequestParam("items") itemIds: Array<Long>,
@RequestParam("item_numbers") itemNumbers: Array<Int>,
@RequestParam("name") name: String,
@RequestParam("phone") phone: String,
@RequestParam("address") address: String,
@RequestParam("pay_type") payTypeId: Long,
@RequestParam("redirect", required = false) redirect: String?
): String {
val user = this.getCurrentUser(token) ?: return error(attributes, "创建订单", "账户未登录", "/login")
val itemPairs = itemIds zip itemNumbers
val items: MutableList<Item> = mutableListOf()
var priceSum = .0
itemPairs.forEach {
items.plus(
itemRepository.findById(it.first).orElse(null) ?: return error(attributes, "创建订单", "商品不存在")
)
}
items.forEach { item ->
item.price?.let {
priceSum += it
} ?: return error(attributes, "创建订单", "错误的商品价格(可能是商品未添加对应的价格)")
}
val payType =
payTypeRepository.findById(payTypeId).orElse(null) ?: return error(attributes, "创建订单", "未知的支付类型")
val order = Order(user, name, phone, address, payType, priceSum, items)
orderRepository.save(order)
redirect?.let { return "redirect:/${it}" }
return "redirect:/order/${order.id}"
}
@RequestMapping("/update/{id}")
fun update(
attributes: RedirectAttributes,
@CookieValue("TOKEN", required = false) token: String?,
@PathVariable("id") id: Long,
@RequestParam("name", required = false) name: String?,
@RequestParam("phone", required = false) phone: String?,
@RequestParam("address", required = false) address: String?,
@RequestParam("isPaid", required = false) isPaid: Boolean?,
@RequestParam("redirect", required = false) redirect: String?
): String {
val user = this.getCurrentUser(token) ?: return error(attributes, "更新订单", "账户未登录", "/login")
val order =
orderRepository.findById(id).orElse(null) ?: return error(attributes, "更新订单", "订单不存在", "/orders")
if (order.user == null) return error(attributes, "更新订单", "此订单所指向的用户不存在", "/orders")
if (order.user!!.id != user.id) return error(attributes, "更新订单", "此订单不属于您", "/orders")
order.update(name, phone, address, isPaid)
orderRepository.save(order)
redirect?.let { return "redirect:/${it}" }
return "redirect:/order/${order.id}"
}
@RequestMapping("/paid/{id}")
fun paid(
attributes: RedirectAttributes,
@CookieValue("TOKEN", required = false) token: String?,
@PathVariable("id") id: Long,
@RequestParam("redirect", required = false) redirect: String?
): String {
val user = this.getCurrentUser(token) ?: return error(attributes, "支付订单", "账户未登录", "/login")
val order =
orderRepository.findById(id).orElse(null) ?: return error(attributes, "支付订单", "订单不存在", "/orders")
if (order.user == null) return error(attributes, "支付订单", "此订单所指向的用户不存在", "/orders")
if (order.user!!.id != user.id) return error(attributes, "支付订单", "此订单不属于您", "/orders")
order.update(isPaid = true)
orderRepository.save(order)
redirect?.let { return "redirect:/${it}" }
return "redirect:/order/${order.id}"
}
@RequestMapping("/revoke/{id}")
fun revoke(
attributes: RedirectAttributes,
@CookieValue("TOKEN", required = false) token: String?,
@PathVariable("id") id: Long,
@RequestParam("redirect", required = false) redirect: String?
): String {
val user = this.getCurrentUser(token) ?: return error(attributes, "撤销订单", "账户未登录", "/login")
val order =
orderRepository.findById(id).orElse(null) ?: return error(attributes, "撤销订单", "订单不存在", "/orders")
if (order.user == null) return error(attributes, "撤销订单", "此订单所指向的用户不存在", "/orders")
if (order.user!!.id != user.id) return error(attributes, "撤销订单", "此订单不属于您", "/orders")
order.revoke()
orderRepository.save(order)
redirect?.let { return "redirect:/${it}" }
return "redirect:/orders"
}
}

View File

@ -40,9 +40,9 @@ class Item(
return this.hasAdminPermissions(this.getCurrentUser(token))
}
private fun autoCreateTag(tags: List<String>): MutableList<Tag> {
private fun autoCreateTag(tags: List<String>?): MutableList<Tag> {
val result: MutableList<Tag> = mutableListOf()
tags.forEach {
tags?.forEach {
val oldTag = tagRepository.findByName(it)
if (oldTag != null) {
result.add(oldTag)
@ -55,12 +55,12 @@ class Item(
return result
}
private fun autoCreateTag(tags: String): MutableList<Tag> {
return this.autoCreateTag(tags.split(" "))
private fun autoCreateTag(tags: String?): MutableList<Tag> {
return this.autoCreateTag(tags?.split(" "))
}
private fun uploadPicture(file: MultipartFile): String? {
if (file.isEmpty) return null
private fun uploadPicture(file: MultipartFile?): String? {
if (file == null || file.isEmpty) return null
val hash = hash(file)
val path = Path("${uploadPath}/picture/${hash.slice(0..1)}")
if (!path.exists()) path.createDirectories()
@ -83,7 +83,11 @@ class Item(
if (name.isBlank()) return error(attributes, "创建商品", "商品名不能为空")
if (price == 0.0) return error(attributes, "创建商品", "商品价格不能为0")
if (picture.isEmpty) return error(attributes, "创建商品", "必须上传商品图片")
itemRepository.save(Item(name, price, description, uploadPicture(picture), tag?.let { this.autoCreateTag(it) }))
itemRepository.save(
Item(
name, price, description, this.uploadPicture(picture), this.autoCreateTag(tag)
)
)
redirect?.let { return "redirect:/${it}" }
return "redirect:/editor?use=item"
}
@ -105,26 +109,23 @@ class Item(
if (price == 0.0) return error(attributes, "更新商品", "商品价格不能为0")
val item = itemRepository.findById(id).orElse(null) ?: return error(attributes, "更新商品", "未找到目标商品")
item.update(
name,
price,
description,
picture?.let { this.uploadPicture(it) },
tag?.let { this.autoCreateTag(it) })
name, price, description, this.uploadPicture(picture), this.autoCreateTag(tag)
)
itemRepository.save(item)
redirect?.let { return "redirect:/${it}" }
return "redirect:/editor?use=item"
}
@PostMapping("/delete/{id}")
fun delete(
@PostMapping("/revoke/{id}")
fun revoke(
attributes: RedirectAttributes,
@CookieValue("TOKEN", required = false) token: String?,
@PathVariable("id") id: Long,
@RequestParam("redirect", required = false) redirect: String?
): String {
if (!this.hasAdminPermissions(token)) return error(attributes, "删除商品", "账户无权限")
val item = itemRepository.findById(id).orElse(null) ?: return error(attributes, "删除商品", "未找到目标商品")
item.update(isRemoved = true)
if (!this.hasAdminPermissions(token)) return error(attributes, "撤销商品", "账户无权限")
val item = itemRepository.findById(id).orElse(null) ?: return error(attributes, "撤销商品", "未找到目标商品")
item.revoke()
itemRepository.save(item)
redirect?.let { return "redirect:/${it}" }
return "redirect:/editor?use=item"

View File

@ -65,10 +65,7 @@ class User(private val accountRepository: AccountRepository) {
val currentUser = this.getCurrentUser(token) ?: return error(attributes, "更新用户", "账户未登录")
if (!this.hasAdminPermissions(currentUser)) return error(attributes, "更新用户", "账户无权限")
val user = accountRepository.findById(id).orElse(null) ?: return error(
attributes,
"更新用户",
"未找到此用户",
"/editor?use=user"
attributes, "更新用户", "未找到此用户", "/editor?use=user"
)
user.update(name, password, age, gender, phone, email, address, isAdmin)
accountRepository.save(user)
@ -82,22 +79,20 @@ class User(private val accountRepository: AccountRepository) {
return "redirect:/editor?use=user"
}
@PostMapping("/delete/{id}")
fun delete(
@PostMapping("/revoke/{id}")
fun revoke(
attributes: RedirectAttributes,
@CookieValue("TOKEN", required = false) token: String?,
@PathVariable("id") id: Long,
@RequestParam("redirect", required = false) redirect: String?
): String {
val currentUser = this.getCurrentUser(token) ?: return error(attributes, "删除用户", "账户未登录")
if (!this.hasAdminPermissions(currentUser)) return error(attributes, "删除用户", "账户无权限")
if (currentUser.id == id) return error(attributes, "删除用户", "无法删除当前使用的账户", "/editor?use=user")
val currentUser = this.getCurrentUser(token) ?: return error(attributes, "禁用用户", "账户未登录")
if (!this.hasAdminPermissions(currentUser)) return error(attributes, "禁用用户", "账户无权限")
if (currentUser.id == id) return error(attributes, "禁用用户", "无法删除当前使用的账户", "/editor?use=user")
val user = accountRepository.findById(id).orElse(null) ?: return error(
attributes,
"删除用户",
"未找到此用户",
"/editor?use=user"
attributes, "禁用用户", "未找到此用户", "/editor?use=user"
)
user.revoke()
accountRepository.delete(user)
redirect?.let { return "redirect:/${it}" }
return "redirect:/editor?use=user"

View File

@ -75,12 +75,12 @@ class Editor(
@RequestParam("page", required = false) page: Int?,
): String {
val user = this.getCurrentUser(token) ?: return error(attributes, "编辑", "账户未登录", "/login")
if (!this.hasAdminPermissions(user)) return error(attributes, "编辑", "账户无权限编辑网站")
if (!this.hasAdminPermissions(user)) return error(attributes, "编辑", "普通账户无权限编辑网站")
model["isEditor"] = true
model["user"] = user
model["using"] = use
model["tabs"] = editorTabs
if (searchContent != null) model["searching"] = searchContent
searchContent?.let { model["searching"] = it }
val pageRequested = PageRequest.of(page ?: 0, 15)
val data = when (use) {
"item" -> pagingItemRepository.findAll(pageRequested)
@ -116,15 +116,17 @@ class Editor(
model["target"] = when (use) {
"item" -> {
target?.let {
itemRepository.findById(it)
.orElse(null) ?: return error(attributes, "编辑", "无法找到目标商品")
itemRepository.findById(it).orElse(null) ?: return error(attributes, "编辑", "无法找到目标商品")
} ?: return error(attributes, "编辑", "目标商品为空")
}
else -> {
val targetUser = target?.let {
accountRepository.findById(it)
.orElse(null) ?: return error(attributes, "编辑", "无法找到目标用户")
accountRepository.findById(it).orElse(null) ?: return error(
attributes,
"编辑",
"无法找到目标用户"
)
} ?: return error(attributes, "编辑", "目标用户为空")
if (action == "updating") when (targetUser.gender) {
"M" -> model["isGenderAsMale"] = true

View File

@ -30,8 +30,8 @@ class Item(
@Column(name = "picture", length = 64, nullable = true)
var picture: String? = null,
@Column(name = "is_removed", nullable = false)
var isRemoved: Boolean? = false,
@Column(name = "is_revoked", nullable = false)
var isRevoked: Boolean = false,
@ManyToMany(cascade = [CascadeType.ALL], fetch = FetchType.LAZY)
@JoinTable(
@ -67,13 +67,11 @@ class Item(
price: Double,
description: String? = null,
picture: String? = null,
tags: MutableList<Tag>? = null,
isRemoved: Boolean? = null
tags: MutableList<Tag>? = null
) : this(name, price) {
if (!description.isNullOrBlank()) this.description = description
if (!picture.isNullOrBlank()) this.picture = picture
tags?.let { this.tags.addAll(it) }
isRemoved?.let { this.isRemoved = it }
}
fun update(
@ -81,15 +79,13 @@ class Item(
price: Double? = null,
description: String? = null,
picture: String? = null,
tags: MutableList<Tag>? = null,
isRemoved: Boolean? = null
tags: MutableList<Tag>? = null
) {
if (!name.isNullOrBlank()) this.name = name
this.price = price?.let { if (it <= 0) null else it }
if (!description.isNullOrBlank()) this.description = description
if (!picture.isNullOrBlank()) this.picture = picture
tags?.let { this.tags = it }
isRemoved?.let { this.isRemoved = it }
this.updateEditTime()
}
@ -97,6 +93,10 @@ class Item(
this.editTime = LocalDateTime.now()
}
fun revoke() {
this.isRevoked = true
}
@Bean
fun getTagPretty(): String {
return this.tags.joinToString(", ")

View File

@ -17,6 +17,9 @@ class Order(
@Column(name = "time_create", nullable = false)
var createTime: LocalDateTime = LocalDateTime.now(),
@Column(name = "time_edit", nullable = false)
var editTime: LocalDateTime = LocalDateTime.now(),
@Column(name = "name", length = 16, nullable = false)
var name: String? = null,
@ -26,16 +29,19 @@ class Order(
@Column(name = "address", length = 64, nullable = false)
var address: String? = null,
@ManyToOne
@JoinColumn(name = "order_id")
@ManyToOne(optional = false)
@JoinColumn(name = "pay_type", nullable = false)
var payType: PayType? = null,
@Column(name = "pay_status", nullable = false)
var payStatus: Int = 1,
@Column(name = "price", nullable = false)
var priceSum: Double = .0,
@Column(name = "is_paid", nullable = false)
var isPaid: Boolean = false,
@Column(name = "is_revoked", nullable = false)
var isRevoked: Boolean = false,
@ManyToMany(cascade = [CascadeType.ALL], fetch = FetchType.LAZY)
@JoinTable(
name = "orders_to_items",
@ -43,4 +49,41 @@ class Order(
inverseJoinColumns = [JoinColumn(name = "item_id", nullable = false)]
)
var items: MutableList<Item> = mutableListOf()
)
) {
constructor(user: User) : this() {
this.user = user
}
constructor(
user: User,
name: String,
phone: String,
address: String,
payType: PayType,
priceSum: Double,
items: MutableList<Item>
) : this(user) {
this.name = name
this.phone = phone
this.address = address
this.payType = payType
this.priceSum = priceSum
this.items = items
}
fun update(name: String? = null, phone: String? = null, address: String? = null, isPaid: Boolean? = null) {
if (!name.isNullOrBlank()) this.name = name
if (!phone.isNullOrBlank()) this.phone = phone
if (!address.isNullOrBlank()) this.address = address
isPaid?.let { this.isPaid = it }
this.updateEditTime()
}
fun updateEditTime() {
this.editTime = LocalDateTime.now()
}
fun revoke() {
this.isRevoked = true
}
}

View File

@ -11,13 +11,13 @@ class OrderedItem(
var id: Long? = null,
@ManyToOne
@JoinColumn(name = "order_id")
@JoinColumn(name = "order_id", nullable = false)
var order: Order? = null,
@ManyToOne
@JoinColumn(name = "item_id")
@JoinColumn(name = "item_id", nullable = false)
var item: Item? = null,
@Column(name = "number", nullable = false)
@Column(name = "number")
var number: Int? = 0
)

View File

@ -12,8 +12,4 @@ class PayType(
@Column(name = "NAME", length = 16, nullable = false)
var name: String? = null,
@OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.LAZY)
@JoinColumn(name = "pay_type", nullable = false)
var orders: MutableList<Order> = mutableListOf()
)

View File

@ -47,6 +47,9 @@ class User(
@Column(name = "is_admin", nullable = false)
var isAdmin: Boolean = false,
@Column(name = "is_revoked", nullable = false)
var isRevoked: Boolean = false,
@ManyToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.LAZY)
@JoinTable(
name = "carts",
@ -124,6 +127,10 @@ class User(
this.token = UUID.randomUUID().toString()
}
fun revoke() {
this.isRevoked = true
}
@Bean
fun getGenderPretty(): String {
return when (this.gender) {

View File

@ -0,0 +1,6 @@
package team8.fruitable.datebase.repository
import org.springframework.data.repository.CrudRepository
import team8.fruitable.datebase.entity.Order
interface OrderRepository : CrudRepository<Order, Long>

View File

@ -0,0 +1,9 @@
package team8.fruitable.datebase.repository
import org.springframework.data.repository.CrudRepository
import team8.fruitable.datebase.entity.Order
import team8.fruitable.datebase.entity.OrderedItem
interface OrderedItemRepository : CrudRepository<OrderedItem, Long> {
fun findByOrder(order: Order): List<OrderedItem>
}

View File

@ -0,0 +1,6 @@
package team8.fruitable.datebase.repository
import org.springframework.data.repository.CrudRepository
import team8.fruitable.datebase.entity.PayType
interface PayTypeRepository : CrudRepository<PayType, Long>