add more Api for Account, add recommend entity for item

Signed-off-by: Puqns67 <me@puqns67.icu>
This commit is contained in:
Puqns67 2023-09-14 23:06:49 +08:00
parent 9b89dc93e6
commit 7514842f19
Signed by: Puqns67
GPG Key ID: 9669DF042554F536
18 changed files with 219 additions and 90 deletions

View File

@ -5,7 +5,6 @@ import org.springframework.boot.runApplication
import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController import org.springframework.web.bind.annotation.RestController
@RestController @RestController
@SpringBootApplication @SpringBootApplication
class FruitableApplication { class FruitableApplication {

View File

@ -0,0 +1,7 @@
package team8.fruitable.constant
enum class UserType {
Admin,
User,
Guest
}

View File

@ -3,121 +3,128 @@ package team8.fruitable.controller.api
import jakarta.servlet.http.Cookie import jakarta.servlet.http.Cookie
import jakarta.servlet.http.HttpServletResponse import jakarta.servlet.http.HttpServletResponse
import org.springframework.web.bind.annotation.* import org.springframework.web.bind.annotation.*
import team8.fruitable.constant.UserType
import team8.fruitable.datebase.entity.User import team8.fruitable.datebase.entity.User
import team8.fruitable.datebase.repository.UserRepository import team8.fruitable.datebase.repository.UserRepository
import team8.fruitable.util.ResultBuilder import team8.fruitable.util.ResultBuilder
@RestController @RestController
class Account(private val repository: UserRepository) { class Account(private val repository: UserRepository) {
@GetMapping("/api/v1/account/info/{id}") private fun getCurrentUser(token: String?): User? {
fun info( return token?.let(repository::findByToken)
@PathVariable id: Long,
@CookieValue(value = "TOKEN", required = false) token: String?
): String {
val queryUser = repository.findById(id).orElse(null) ?: return ResultBuilder<Any>("账户不存在").toJson()
var currentUser: User? = null
if (token != null) currentUser = repository.findByToken(token)
val result = mapOf(
"id" to queryUser.id,
"name" to queryUser.name,
"gender" to queryUser.gender,
"createTime" to queryUser.createTime,
"loginTime" to queryUser.loginTime
)
if (currentUser != null && (currentUser.id == id || currentUser.isAdmin)) result + mapOf(
"address" to queryUser.address,
"admin" to queryUser.isAdmin,
"carts" to queryUser.carts,
"orders" to queryUser.orders,
"phone" to queryUser.phone
)
return ResultBuilder(result).toJson()
} }
@PostMapping("/api/v1/account/login") private fun hasAdminPermissions(token: String?): Boolean {
return this.getCurrentUser(token)?.isAdmin ?: false
}
private fun updateToken(response: HttpServletResponse, token: String, path: String = "/", age: Int = 2678400) {
val cookie = Cookie("TOKEN", token)
cookie.path = path
cookie.maxAge = age
response.addCookie(cookie)
}
@GetMapping("/api/v1/account/info", produces = ["application/json"])
fun infoMe(
@CookieValue(value = "TOKEN", required = false) token: String?
): String {
val user = this.getCurrentUser(token) ?: return ResultBuilder<Any>("账户未登录").toJson()
return ResultBuilder(user.asMap(UserType.User)).toJson()
}
@GetMapping("/api/v1/account/info/{id}", produces = ["application/json"])
fun info(
@CookieValue(value = "TOKEN", required = false) token: String?, @PathVariable id: Long
): String {
val queryUser = repository.findById(id).orElse(null) ?: return ResultBuilder<Any>("账户不存在").toJson()
val currentUser = this.getCurrentUser(token)
return ResultBuilder(
queryUser.asMap(if (currentUser != null && (currentUser.id == id || currentUser.isAdmin)) UserType.User else UserType.Guest)
).toJson()
}
//@PostMapping
@RequestMapping("/api/v1/account/login", produces = ["application/json"])
fun login( fun login(
response: HttpServletResponse, response: HttpServletResponse,
@CookieValue(value = "TOKEN", required = false) token: String?,
@RequestParam(name = "name") name: String, @RequestParam(name = "name") name: String,
@RequestParam(name = "password") password: String @RequestParam(name = "password") password: String
): String { ): String {
if (this.getCurrentUser(token) != null) return ResultBuilder<Any>("当前已登录账户").toJson()
val user = repository.findByName(name) ?: return ResultBuilder<Any>("账户不存在").toJson() val user = repository.findByName(name) ?: return ResultBuilder<Any>("账户不存在").toJson()
if (!user.testPassword(password)) { if (!user.testPassword(password)) return ResultBuilder<Any>("密码错误").toJson()
return ResultBuilder<Any>("密码错误").toJson()
}
user.updateToken() user.updateToken()
val cookie = Cookie("TOKEN", user.token) user.updateLoginTime()
cookie.maxAge = 2678400
response.addCookie(cookie)
repository.save(user) repository.save(user)
updateToken(response, user.token)
return ResultBuilder<Any>("success", "登录成功").toJson() return ResultBuilder<Any>("success", "登录成功").toJson()
} }
@PostMapping("/api/v1/account/logout") @RequestMapping("/api/v1/account/logout", produces = ["application/json"])
fun logout(response: HttpServletResponse): String { fun logout(response: HttpServletResponse): String {
val cookie = Cookie("TOKEN", "") updateToken(response, "", age = 0)
cookie.maxAge = 0
response.addCookie(cookie)
return ResultBuilder<Any>("success", "注销成功").toJson() return ResultBuilder<Any>("success", "注销成功").toJson()
} }
@PostMapping("/api/v1/account/register") @RequestMapping("/api/v1/account/register", produces = ["application/json"])
fun register( fun register(
response: HttpServletResponse, response: HttpServletResponse,
@CookieValue(value = "TOKEN", required = false) token: String?,
@RequestParam(name = "name") name: String, @RequestParam(name = "name") name: String,
@RequestParam(name = "password") password: String, @RequestParam(name = "password") password: String,
@RequestParam(name = "age", required = false) age: Int?, @RequestParam(name = "age", required = false) age: Int?,
@RequestParam(name = "gender", required = false) gender: String?, @RequestParam(name = "gender", required = false) gender: String?,
@RequestParam(name = "phone", required = false) phone: String?,
@RequestParam(name = "email", required = false) email: String?, @RequestParam(name = "email", required = false) email: String?,
@RequestParam(name = "address", required = false) address: String?, @RequestParam(name = "address", required = false) address: String?
@RequestParam(name = "phone", required = false) phone: String?
): String { ): String {
// TODO: 完成注册方法 if (this.getCurrentUser(token) != null) return ResultBuilder<Any>("当前已登录账户").toJson()
return "TODO" val user = repository.save(User(name, password, age, gender, phone, email, address))
updateToken(response, user.token)
return ResultBuilder<Any>("success", "注册成功").toJson()
} }
@PostMapping("/api/v1/account/update") @RequestMapping("/api/v1/account/update", produces = ["application/json"])
fun update( fun update(
response: HttpServletResponse, response: HttpServletResponse,
@CookieValue(name = "TOKEN", required = false) token: String, @CookieValue(name = "TOKEN", required = false) token: String?,
@RequestParam(name = "name") name: String, @RequestParam(name = "name") name: String,
@RequestParam(name = "password") password: String, @RequestParam(name = "password") password: String,
@RequestParam(name = "age", required = false) age: Int?, @RequestParam(name = "age", required = false) age: Int?,
@RequestParam(name = "gender", required = false) gender: String?, @RequestParam(name = "gender", required = false) gender: String?,
@RequestParam(name = "phone", required = false) phone: String?,
@RequestParam(name = "email", required = false) email: String?, @RequestParam(name = "email", required = false) email: String?,
@RequestParam(name = "address", required = false) address: String?, @RequestParam(name = "address", required = false) address: String?
@RequestParam(name = "phone", required = false) phone: String?
): String { ): String {
// TODO: 完成更新账户数据方法 val user = this.getCurrentUser(token) ?: return ResultBuilder<Any>("账户未登录").toJson()
return "TODO" user.update(name, password, age, gender, phone, email, address)
repository.save(user)
updateToken(response, user.token)
return ResultBuilder<Any>("success", "更新账户信息成功").toJson()
} }
@GetMapping("/api/v1/account/admin/info/{id}") @GetMapping("/api/v1/account/admin/info/{id}", produces = ["application/json"])
fun infoAdmin( fun infoAdmin(
@CookieValue(value = "TOKEN", required = false) token: String?, @CookieValue(value = "TOKEN", required = false) token: String?,
@PathVariable id: Long, @PathVariable id: Long,
): String { ): String {
var currentUser: User? = null if (this.hasAdminPermissions(token)) return ResultBuilder<Any>("无管理员权限").toJson()
if (token != null) currentUser = repository.findByToken(token)
if (currentUser == null) return ResultBuilder<Any>("账户未登录").toJson()
if (!currentUser.isAdmin) return ResultBuilder<Any>("无管理员权限").toJson()
return ResultBuilder(repository.findById(id)).toJson() return ResultBuilder(repository.findById(id)).toJson()
} }
@DeleteMapping("/api/v1/account/admin/remove/{id}") @DeleteMapping("/api/v1/account/admin/remove/{id}", produces = ["application/json"])
fun removeAdmin( fun removeAdmin(
@CookieValue(value = "TOKEN", required = false) token: String?, @CookieValue(value = "TOKEN", required = false) token: String?,
@PathVariable id: Long, @PathVariable id: Long,
): String { ): String {
var currentUser: User? = null if (this.hasAdminPermissions(token)) return ResultBuilder<Any>("无管理员权限").toJson()
if (token != null) currentUser = repository.findByToken(token)
if (currentUser == null) return ResultBuilder<Any>("账户未登录").toJson()
if (!currentUser.isAdmin) return ResultBuilder<Any>("无管理员权限").toJson()
// TODO: 完成管理员删除方法 // TODO: 完成管理员删除方法
return ResultBuilder(repository.findById(id)).toJson() return ResultBuilder(repository.findById(id)).toJson()
} }
@PostMapping("/api/v1/account/admin/update/{id}") @PostMapping("/api/v1/account/admin/update/{id}", produces = ["application/json"])
fun updateAdmin( fun updateAdmin(
@CookieValue(value = "TOKEN", required = false) token: String?, @CookieValue(value = "TOKEN", required = false) token: String?,
@PathVariable id: Long, @PathVariable id: Long,
@ -125,14 +132,11 @@ class Account(private val repository: UserRepository) {
@RequestParam(name = "password") password: String, @RequestParam(name = "password") password: String,
@RequestParam(name = "age", required = false) age: Int?, @RequestParam(name = "age", required = false) age: Int?,
@RequestParam(name = "gender", required = false) gender: String?, @RequestParam(name = "gender", required = false) gender: String?,
@RequestParam(name = "phone", required = false) phone: String?,
@RequestParam(name = "email", required = false) email: String?, @RequestParam(name = "email", required = false) email: String?,
@RequestParam(name = "address", required = false) address: String?, @RequestParam(name = "address", required = false) address: String?
@RequestParam(name = "phone", required = false) phone: String?
): String { ): String {
var currentUser: User? = null if (this.hasAdminPermissions(token)) return ResultBuilder<Any>("无管理员权限").toJson()
if (token != null) currentUser = repository.findByToken(token)
if (currentUser == null) return ResultBuilder<Any>("账户未登录").toJson()
if (!currentUser.isAdmin) return ResultBuilder<Any>("无管理员权限").toJson()
// TODO: 完成管理员更新账户数据方法 // TODO: 完成管理员更新账户数据方法
return ResultBuilder(repository.findById(id)).toJson() return ResultBuilder(repository.findById(id)).toJson()
} }

View File

@ -1,4 +1,26 @@
package team8.fruitable.controller.api package team8.fruitable.controller.api
class Item { import org.springframework.web.bind.annotation.CookieValue
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RestController
import team8.fruitable.datebase.entity.User
import team8.fruitable.datebase.repository.ItemRepository
import team8.fruitable.datebase.repository.UserRepository
import team8.fruitable.util.ResultBuilder
@RestController
class Item(private val itemRepository: ItemRepository, private val userRepository: UserRepository) {
private fun getCurrentUser(token: String?): User? {
return token?.let(userRepository::findByToken)
}
private fun hasAdminPermissions(token: String?): Boolean {
return this.getCurrentUser(token)?.isAdmin ?: false
}
@GetMapping("/api/v1/item/info/{id}", produces = ["application/json"])
fun info(@PathVariable id: Long): String {
return ResultBuilder(itemRepository.findById(id).orElse(null)).toJson()
}
} }

View File

@ -2,7 +2,6 @@ package team8.fruitable.datebase.entity
import jakarta.persistence.* import jakarta.persistence.*
@Entity @Entity
@Table(name = "items") @Table(name = "items")
class Item( class Item(
@ -17,7 +16,7 @@ class Item(
@Column(name="price", nullable = false) @Column(name="price", nullable = false)
var price: Double? = null, var price: Double? = null,
@Column(name="DESCRIPTION", length=320, nullable = true) @Column(name="description", length=320, nullable = true)
var description: String? = null, var description: String? = null,
@ManyToOne @ManyToOne
@ -29,5 +28,8 @@ class Item(
var ordered: Order? = null, var ordered: Order? = null,
@OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.LAZY, mappedBy = "tagedItem") @OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.LAZY, mappedBy = "tagedItem")
var tags: MutableList<Tag> = mutableListOf<Tag>() var tags: MutableList<Tag> = mutableListOf<Tag>(),
@OneToOne(mappedBy = "item")
var recommend: Recommend? = null,
) )

View File

@ -3,7 +3,6 @@ package team8.fruitable.datebase.entity
import jakarta.persistence.* import jakarta.persistence.*
import java.time.LocalDateTime import java.time.LocalDateTime
@Entity @Entity
@Table(name = "orders") @Table(name = "orders")
class Order( class Order(

View File

@ -2,7 +2,6 @@ package team8.fruitable.datebase.entity
import jakarta.persistence.* import jakarta.persistence.*
@Entity @Entity
@Table(name = "pay_type") @Table(name = "pay_type")
class PayType( class PayType(

View File

@ -0,0 +1,19 @@
package team8.fruitable.datebase.entity
import jakarta.persistence.*
@Entity
@Table(name = "recommends")
class Recommend (
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
var id: Long? = null,
@OneToOne
@JoinColumn(name = "item")
var item: Item,
@Column(name="description", length=32, nullable = false)
var description: String? = null,
)

View File

@ -2,7 +2,6 @@ package team8.fruitable.datebase.entity
import jakarta.persistence.* import jakarta.persistence.*
@Entity @Entity
@Table(name = "tags") @Table(name = "tags")
class Tag( class Tag(

View File

@ -1,6 +1,7 @@
package team8.fruitable.datebase.entity package team8.fruitable.datebase.entity
import jakarta.persistence.* import jakarta.persistence.*
import team8.fruitable.constant.UserType
import team8.fruitable.util.Util import team8.fruitable.util.Util
import java.time.LocalDateTime import java.time.LocalDateTime
import java.util.* import java.util.*
@ -21,7 +22,7 @@ class User(
var password: String? = null, var password: String? = null,
@Column(name = "time_create", nullable = false) @Column(name = "time_create", nullable = false)
val createTime: LocalDateTime = LocalDateTime.now(), var createTime: LocalDateTime = LocalDateTime.now(),
@Column(name = "time_login", nullable = false) @Column(name = "time_login", nullable = false)
var loginTime: LocalDateTime = LocalDateTime.now(), var loginTime: LocalDateTime = LocalDateTime.now(),
@ -53,15 +54,89 @@ class User(
@OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.LAZY, mappedBy = "user") @OneToMany(cascade = [(CascadeType.ALL)], fetch = FetchType.LAZY, mappedBy = "user")
var orders: MutableList<Order> = mutableListOf<Order>() var orders: MutableList<Order> = mutableListOf<Order>()
) { ) {
constructor(name: String, password: String) : this() {
this.name = name
this.password = this.genPassword(password)
}
constructor(
name: String,
password: String,
age: Int?,
gender: String?,
phone: String?,
email: String?,
address: String?
) : this(name, password) {
this.age = age
this.gender = gender
this.phone = phone
this.email = email
this.address = address
}
final fun genPassword(password: String): String {
return Util.hash(password)
}
fun update(
name: String,
password: String,
age: Int?,
gender: String?,
phone: String?,
email: String?,
address: String?,
isAdmin: Boolean = false
) {
this.name = name
this.updatePassword(password)
this.age = age
this.gender = gender
this.phone = phone
this.email = email
this.address = address
this.isAdmin = isAdmin
this.updateToken()
}
fun testPassword(password: String): Boolean { fun testPassword(password: String): Boolean {
return Util.hash(password) == this.password return Util.hash(password) == this.password
} }
fun updatePassword(password: String) { fun updatePassword(password: String) {
this.password = Util.hash(password) this.password = this.genPassword(password)
}
fun updateLoginTime() {
this.loginTime = LocalDateTime.now()
} }
fun updateToken() { fun updateToken() {
this.token = UUID.randomUUID().toString() this.token = UUID.randomUUID().toString()
} }
fun asMap(userType: UserType): Map<String, Any?> {
val result: MutableMap<String, Any?> = mutableMapOf(
"id" to this.id,
"name" to this.name,
"createTime" to this.createTime,
"loginTime" to this.loginTime,
"age" to this.age,
"gender" to this.gender,
"email" to this.email,
)
if (userType == UserType.User || userType == UserType.Admin) result += mapOf(
"phone" to this.phone,
"address" to this.address,
"isAdmin" to this.isAdmin,
"carts" to this.carts,
"orders" to this.orders
)
if (userType == UserType.Admin) result += mapOf(
"password" to this.password,
"token" to this.token,
)
return result
}
} }

View File

@ -0,0 +1,8 @@
package team8.fruitable.datebase.repository
import org.springframework.data.repository.CrudRepository
import team8.fruitable.datebase.entity.Item
interface ItemRepository : CrudRepository<Item, Long> {
fun findByName(name: String): Item?
}

View File

@ -3,7 +3,6 @@ package team8.fruitable.datebase.repository
import org.springframework.data.repository.CrudRepository import org.springframework.data.repository.CrudRepository
import team8.fruitable.datebase.entity.User import team8.fruitable.datebase.entity.User
interface UserRepository : CrudRepository<User, Long> { interface UserRepository : CrudRepository<User, Long> {
fun findByName(name: String): User? fun findByName(name: String): User?
fun findByToken(token: String): User? fun findByToken(token: String): User?

View File

@ -4,7 +4,6 @@ import com.alibaba.fastjson2.toJSONString
import java.time.LocalDateTime import java.time.LocalDateTime
import java.util.* import java.util.*
class ResultBuilder<T> { class ResultBuilder<T> {
var status: String = "auto" var status: String = "auto"
var message: String = "" var message: String = ""

View File

@ -2,12 +2,11 @@ package team8.fruitable.util
import java.security.MessageDigest import java.security.MessageDigest
class Util { class Util {
companion object { companion object {
fun hash(input: String, algorithm: String = "SHA-256"): String { fun hash(input: String, algorithm: String = "SHA-256"): String {
return MessageDigest.getInstance(algorithm).digest(input.toByteArray()) return MessageDigest.getInstance(algorithm).digest(input.toByteArray())
.fold("", { str, it -> str + "%02x".format(it) }) .fold("") { str, it -> str + "%02x".format(it) }
} }
} }
} }

View File

@ -1,10 +0,0 @@
spring.datasource.url=jdbc:mariadb://localhost:3306/fruitable
spring.datasource.username=root
spring.datasource.password=password
#???????updata:????????????,?????????
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
#?????????? Unable to build Hibernate SessionFactory
#spring.jpa.properties.hibernate.hbm2ddl.auto=validate

View File

@ -0,0 +1,9 @@
spring:
datasource:
url: jdbc:mariadb://localhost:3306/fruitable
username: root
password: password
jpa:
show-sql: true
hibernate:
ddl-auto: update