You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1786 lines
63 KiB
1786 lines
63 KiB
package com.gyf.csams
|
|
|
|
|
|
import com.gyf.csams.FileService.getFormParam
|
|
import com.gyf.csams.module.*
|
|
import io.ktor.application.*
|
|
import io.ktor.http.content.*
|
|
import io.ktor.util.*
|
|
import org.jetbrains.exposed.dao.IntEntityClass
|
|
import org.jetbrains.exposed.dao.id.EntityID
|
|
import org.jetbrains.exposed.dao.id.IntIdTable
|
|
import org.jetbrains.exposed.sql.*
|
|
import org.jetbrains.exposed.sql.transactions.transaction
|
|
import org.slf4j.Logger
|
|
import java.io.File
|
|
import java.time.LocalDateTime
|
|
import kotlin.properties.Delegates
|
|
import kotlin.system.exitProcess
|
|
|
|
interface BaseService {
|
|
fun init(environment: ApplicationEnvironment)
|
|
}
|
|
|
|
|
|
abstract class AbstractService : BaseService {
|
|
protected lateinit var log: Logger
|
|
protected lateinit var environment: ApplicationEnvironment
|
|
override fun init(environment: ApplicationEnvironment) {
|
|
this.environment = environment
|
|
this.log = environment.log
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 账号服务
|
|
*/
|
|
object AccountService : AbstractService() {
|
|
/**
|
|
* 检查学号是否已注册,true=已注册
|
|
*/
|
|
fun registered(selectId: String): Boolean {
|
|
return transaction {
|
|
return@transaction !User.find { Users.studentId eq selectId }.empty()
|
|
}
|
|
}
|
|
|
|
fun toUserInfo(user: User): UserInfoVo {
|
|
return UserInfoVo(name = user.name, headImg = user.headImg?.filepath, desc = user.desc)
|
|
}
|
|
|
|
/**
|
|
* 注册
|
|
*/
|
|
fun register(userVo: UserRegVo): String? {
|
|
try {
|
|
return transaction {
|
|
|
|
val originPassword = if (environment.developmentMode) (1..8).joinToString("") else randomNum(8)
|
|
log.info("密码:${originPassword}")
|
|
User.new {
|
|
studentId = userVo.studentId
|
|
name = userVo.name
|
|
password = originPassword.md5()
|
|
}
|
|
return@transaction originPassword
|
|
}
|
|
} catch (e: Exception) {
|
|
log.error("注册失败,发生异常:$e")
|
|
return null
|
|
}
|
|
}
|
|
|
|
fun login(vo: BaseLoginVo, ip: String): OwnInfoVo {
|
|
return when (vo) {
|
|
is UserLoginVo -> login(vo, ip)
|
|
is ManagerLoginVo -> login(vo, ip)
|
|
else -> throw IllegalArgumentException("vo:${vo::class.java}类型不合法")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 前台登录
|
|
*
|
|
*/
|
|
private fun login(userLoginVo: UserLoginVo, _ip: String): UserVo {
|
|
return transaction {
|
|
val matchUser = User.find { Users.studentId eq userLoginVo.studentId }.firstOrNull()
|
|
when {
|
|
matchUser == null -> {
|
|
log.warn("学号:${userLoginVo.studentId}不存在")
|
|
throw StudentIdError(userLoginVo.studentId)
|
|
}
|
|
userLoginVo.password.md5() != matchUser.password -> {
|
|
log.warn("密码:${userLoginVo.password}错误")
|
|
throw PasswordError(id = userLoginVo.studentId, password = userLoginVo.password)
|
|
}
|
|
else -> {
|
|
val token = UserToken.new {
|
|
user = matchUser
|
|
ip = _ip
|
|
device = userLoginVo.device
|
|
token =
|
|
listOf(matchUser.id, ip, device).joinToString(separator = ('a'..'z').random().toString())
|
|
.md5()
|
|
}
|
|
token.flush()
|
|
val associationMember =
|
|
AssociationMember.find { AssociationMembers.userId eq matchUser.id }.firstOrNull()
|
|
return@transaction UserVo(
|
|
studentId = matchUser.studentId, token =
|
|
Token(
|
|
id = matchUser.id.value, token = token.token,
|
|
createTime = token.createTime.toLong()
|
|
), name = matchUser.name,
|
|
headImg = matchUser.headImg?.filepath,
|
|
desc = matchUser.desc,
|
|
associationVo = associationMember?.let { AssociationService.toAssociationVo(it.association) },
|
|
isHead = associationMember?.isHead
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 后台登陆
|
|
*
|
|
* @return
|
|
*/
|
|
private fun login(managerLoginVo: ManagerLoginVo, _ip: String): ManagerVo {
|
|
return transaction {
|
|
val matchManager = Manager.find { Managers.account eq managerLoginVo.account }.firstOrNull()
|
|
when {
|
|
matchManager == null -> {
|
|
log.warn("账号:${managerLoginVo.account}不存在")
|
|
throw AccountError(managerLoginVo.account)
|
|
}
|
|
managerLoginVo.password.md5() != matchManager.password -> {
|
|
log.warn("密码:${managerLoginVo.password}错误")
|
|
throw PasswordError(id = managerLoginVo.account, password = managerLoginVo.password)
|
|
}
|
|
else -> {
|
|
val token = ManagerToken.new {
|
|
manager = matchManager
|
|
ip = _ip
|
|
device = managerLoginVo.device
|
|
token =
|
|
listOf(matchManager.id, ip, device).joinToString(separator = ('a'..'z').random().toString())
|
|
.md5()
|
|
}
|
|
token.flush()
|
|
|
|
return@transaction tokenRes(token, matchManager)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun uploadHeadImg(data: List<PartData>) {
|
|
val userId = data.getFormParam("id").toInt()
|
|
transaction {
|
|
val fileIds = FileService.storeFile(data)
|
|
if (fileIds?.isNotEmpty() == true) {
|
|
val fileId = fileIds.first()
|
|
val user = User.findById(userId) ?: throw UserIdError(userId)
|
|
user.apply {
|
|
headImg = ImageFile.findById(fileId) ?: throw FileIdError(fileId)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun refreshInfo(vo: InfoUpdateVo): PersonInfoVo {
|
|
return transaction {
|
|
when (vo.clientType) {
|
|
ClientType.Foreground -> {
|
|
val matchUser = User.findById(vo.token.id) ?: throw UserIdError(vo.token.id)
|
|
matchUser.apply {
|
|
vo.name?.let {
|
|
matchUser.name = it
|
|
}
|
|
vo.desc?.let {
|
|
matchUser.desc = it
|
|
}
|
|
}
|
|
val token = UserToken.find { UserTokens.userId eq matchUser.id }.firstOrNull()
|
|
?: throw IllegalArgumentException("无法根据[userId=${matchUser.id}]找到token")
|
|
tokenRes(token = token, matchUser = matchUser)
|
|
}
|
|
ClientType.Background -> {
|
|
val matchManager = Manager.findById(vo.token.id) ?: throw ManagerIdError(vo.token.id)
|
|
matchManager.apply {
|
|
vo.name?.let {
|
|
matchManager.name = it
|
|
}
|
|
vo.desc?.let {
|
|
matchManager.desc = it
|
|
}
|
|
}
|
|
val token = ManagerToken.find { ManagerTokens.managerId eq matchManager.id }.firstOrNull()
|
|
?: throw IllegalArgumentException("无法根据[matchId=${matchManager.id}]找到token")
|
|
tokenRes(token = token, matchManager = matchManager)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun tokenRes(token: ManagerToken, matchManager: Manager): ManagerVo {
|
|
return ManagerVo(
|
|
account = matchManager.account,
|
|
token = Token(
|
|
id = matchManager.id.value, token = token.token,
|
|
createTime = token.createTime.toLong()
|
|
),
|
|
desc = matchManager.desc,
|
|
duty = Duty.valueOf(matchManager.duty),
|
|
headImg = matchManager.headImg?.filepath, name = matchManager.name
|
|
)
|
|
}
|
|
|
|
private fun tokenRes(token: UserToken, matchUser: User): UserVo {
|
|
val associationMember = AssociationMember.find { AssociationMembers.userId eq matchUser.id }.firstOrNull()
|
|
return UserVo(
|
|
studentId = matchUser.studentId, token =
|
|
Token(
|
|
id = matchUser.id.value, token = token.token,
|
|
createTime = token.createTime.toLong()
|
|
), name = matchUser.name,
|
|
headImg = matchUser.headImg?.filepath, desc = matchUser.desc,
|
|
associationVo = associationMember?.let { AssociationService.toAssociationVo(it.association) },
|
|
isHead = associationMember?.isHead
|
|
)
|
|
}
|
|
|
|
|
|
fun getManagerVo(token: Token): ManagerVo {
|
|
return transaction {
|
|
val c = ManagerToken.find {
|
|
ManagerTokens.managerId eq token.id
|
|
ManagerTokens.token eq token.token
|
|
}
|
|
if (!c.empty()) {
|
|
val manager = Manager.findById(token.id)
|
|
return@transaction tokenRes(token = c.first(), matchManager = manager!!)
|
|
} else {
|
|
throw IllegalArgumentException("token校验失败")
|
|
}
|
|
}
|
|
}
|
|
|
|
fun getUserVo(token: Token): UserVo {
|
|
return transaction {
|
|
val c = UserToken.find {
|
|
UserTokens.userId eq token.id
|
|
UserTokens.token eq token.token
|
|
}
|
|
if (!c.empty()) {
|
|
val user = User.findById(token.id)
|
|
return@transaction tokenRes(token = c.first(), matchUser = user!!)
|
|
} else {
|
|
throw IllegalArgumentException("token校验失败")
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun validManagerToken(token: Token): Boolean {
|
|
return transaction {
|
|
!ManagerToken.find {
|
|
ManagerTokens.managerId eq token.id
|
|
ManagerTokens.token eq token.token
|
|
}.empty()
|
|
}
|
|
}
|
|
|
|
fun validUserToken(token: Token): Boolean {
|
|
return transaction {
|
|
!UserToken.find {
|
|
UserTokens.userId eq token.id
|
|
UserTokens.token eq token.token
|
|
}.empty()
|
|
}
|
|
}
|
|
|
|
fun <T : ClientBaseVo> validToken(vo: T): Boolean {
|
|
return when (vo.clientType) {
|
|
ClientType.Foreground -> validUserToken(vo.token)
|
|
ClientType.Background -> validManagerToken(vo.token)
|
|
else -> throw IllegalArgumentException("不清楚是来自哪个平台的token信息")
|
|
}
|
|
}
|
|
|
|
fun logout(vo: OnlyToken): Boolean {
|
|
return transaction {
|
|
if (vo.clientType == ClientType.Foreground)
|
|
UserTokens.deleteWhere { UserTokens.userId eq vo.token.id } > 0
|
|
else
|
|
ManagerTokens.deleteWhere { ManagerTokens.managerId eq vo.token.id } > 0
|
|
}
|
|
}
|
|
|
|
fun test() {
|
|
log.info("开始测试")
|
|
transaction {
|
|
log.info("查询到个${User.count()}用户")
|
|
}
|
|
log.info("结束测试")
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* 主页服务
|
|
*/
|
|
object MainService : AbstractService() {
|
|
private var maxSize by Delegates.notNull<Int>()
|
|
|
|
override fun init(environment: ApplicationEnvironment) {
|
|
super.init(environment)
|
|
this.maxSize = environment.config.property("ktor.deployment.leaveMessage.maxSize").getString().toInt()
|
|
}
|
|
|
|
|
|
/**
|
|
* 创建留言信息
|
|
*
|
|
* @param leaveMessageVo
|
|
* @return
|
|
*/
|
|
fun createMessage(leaveMessageVo: LeaveMessageVo): Boolean {
|
|
return if (leaveMessageVo.message.isNotEmpty()) {
|
|
return transaction {
|
|
val count = LeaveMessage.count().toInt()
|
|
log.info("系统留言数:$count,限制数:$maxSize")
|
|
if (count >= maxSize) {
|
|
LeaveMessage.all().sortedBy { it.createTime }.subList(0, count - maxSize).forEach {
|
|
it.delete()
|
|
}
|
|
|
|
}
|
|
log.info("保存留言:${leaveMessageVo.message}")
|
|
LeaveMessage.new {
|
|
user = User.findById(leaveMessageVo.token.id) ?: throw IllegalArgumentException("非法id")
|
|
message = leaveMessageVo.message
|
|
}
|
|
log.info("留言保存成功")
|
|
return@transaction true
|
|
}
|
|
} else {
|
|
log.info("留言不能为空")
|
|
false
|
|
}
|
|
}
|
|
|
|
fun getAllLeaveMessage(): List<LeaveMessageDto> {
|
|
return transaction {
|
|
log.info("获取所有留言")
|
|
|
|
return@transaction LeaveMessage.all().toList().map {
|
|
LeaveMessageDto(
|
|
message = "${it.user.name}说:${it.message}",
|
|
user = AccountService.toUserInfo(user = it.user)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 文件管理服务
|
|
*/
|
|
object FileService : AbstractService() {
|
|
private lateinit var uploadDir: String
|
|
private lateinit var filePath: String
|
|
|
|
override fun init(environment: ApplicationEnvironment) {
|
|
super.init(environment)
|
|
this.uploadDir = environment.config.property("ktor.deployment.filePath").getString()
|
|
|
|
log.info(this::class.java.classLoader.getResource("")?.path)
|
|
|
|
filePath =
|
|
environment.classLoader.getResource(uploadDir)?.path ?: throw IllegalArgumentException("初始化资源目录失败")
|
|
File(filePath).let {
|
|
when {
|
|
it.exists() -> log.info("上传路径[${filePath}]已存在")
|
|
!it.mkdirs() -> throw IllegalArgumentException("上传路径[${filePath}]创建失败")
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun save(id: String, path: String, file: File): Int {
|
|
return transaction {
|
|
return@transaction ImageFile.new {
|
|
userId = id
|
|
filepath = path
|
|
md5 = file.readBytes().md5()
|
|
}
|
|
}.id.value
|
|
}
|
|
|
|
|
|
private inline fun <reified T : PartData> getPartData(map: Map<String?, PartData>, key: String): T {
|
|
if (map.containsKey(key)) {
|
|
val obj = map[key]
|
|
if (obj is T) {
|
|
return obj
|
|
} else {
|
|
throw IllegalArgumentException("类型错误")
|
|
}
|
|
}
|
|
throw IllegalArgumentException("找不到key:${key}")
|
|
}
|
|
|
|
fun List<PartData>.getFormParam(key: String): String {
|
|
forEach {
|
|
if (it.name == key && it is PartData.FormItem) {
|
|
return it.value
|
|
}
|
|
}
|
|
throw IllegalArgumentException("没有找到[key=${key}]的表单参数")
|
|
}
|
|
|
|
fun storeFile(data: List<PartData>): List<Int>? {
|
|
val userId = data.getFormParam(key = "id")
|
|
val token = data.getFormParam(key = "token")
|
|
val createTime = data.getFormParam(key = "createTime")
|
|
val tokenVo = Token(token = token, id = userId.toInt(), createTime = createTime.toLong())
|
|
if (AccountService.validUserToken(tokenVo)) {
|
|
val fileIds = mutableListOf<Int>()
|
|
data.forEach {
|
|
if (it is PartData.FileItem) {
|
|
val fileBytes = it.streamProvider().readBytes()
|
|
val fileName = it.originalFileName ?: throw IllegalArgumentException("参数异常")
|
|
val format = fileBytes.getFormat()
|
|
val fullFileName = "${fileName}.${format.format}"
|
|
log.info("fullFileName=$fullFileName")
|
|
val file = File(filePath, fullFileName).apply {
|
|
writeBytes(fileBytes)
|
|
}
|
|
log.info("文件成功保存到${file.absolutePath}")
|
|
val fileId = save(id = userId, "/${uploadDir}/${fullFileName}", file = file)
|
|
fileIds.add(fileId)
|
|
}
|
|
}
|
|
return fileIds
|
|
} else {
|
|
return null
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 审核资料
|
|
*
|
|
* @param T 注册实体类型
|
|
* @param E 后台注册实体类型
|
|
* @param F 前台审核进度类型
|
|
*/
|
|
abstract class AuditService<T, E, F> : AbstractService() {
|
|
|
|
abstract val dataType: String
|
|
|
|
/**
|
|
* 注册资料
|
|
*
|
|
* @param vo
|
|
*/
|
|
abstract fun register(vo: T)
|
|
|
|
// protected abstract fun load
|
|
|
|
/**
|
|
* 通知用户审核进度
|
|
*
|
|
* @param receiverId
|
|
* @param content
|
|
*/
|
|
private fun foreground(receiverId: Int, content: String) {
|
|
Notification.new {
|
|
this.title = dataType
|
|
this.content = content
|
|
this.receiverId = receiverId
|
|
receiverClient = ClientType.Foreground.name
|
|
}.apply {
|
|
log.info("通知前台用户${dataType}处理进度")
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 前台任务通知管理员处理
|
|
*
|
|
*/
|
|
private fun background(content: String, duty: Duty) {
|
|
Manager.find { Managers.duty eq duty.name }.apply {
|
|
if (count() == 0L) {
|
|
log.warn("找不到适当的${duty.desc}处理此任务")
|
|
} else {
|
|
forEach {
|
|
Notification.new {
|
|
this.title = dataType
|
|
this.content = content
|
|
receiverId = it.id.value
|
|
receiverClient = ClientType.Background.name
|
|
}.apply {
|
|
log.info("通知${duty.desc}处理${dataType}")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 查找审核资料
|
|
*
|
|
* @param auditId
|
|
* @return
|
|
*/
|
|
abstract fun findEntity(auditId: Int): AbstractAudit
|
|
|
|
protected inline fun <reified E : AbstractAudit, reified Row : IntEntityClass<E>, reified Table : AbstractAudits> testFind(
|
|
table: Table,
|
|
row: Row,
|
|
auditId: Int
|
|
): E {
|
|
return row.find { table.auditId eq auditId }.firstOrNull() ?: throw AuditIdError(auditId)
|
|
}
|
|
|
|
/**
|
|
* 更新审核结果
|
|
*
|
|
* @param vo
|
|
*/
|
|
private fun AuditLogging.update(vo: CheckVo) {
|
|
apply {
|
|
if (nextAudit != null) {
|
|
nextAudit?.apply {
|
|
cause = vo.cause
|
|
result = vo.result
|
|
auditTime = LocalDateTime.now()
|
|
}
|
|
} else {
|
|
cause = vo.cause
|
|
result = vo.result
|
|
auditTime = LocalDateTime.now()
|
|
}
|
|
}.apply {
|
|
log.info("更新审核结果")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 通过审核后
|
|
*
|
|
*/
|
|
protected open fun afterAudit(entity: AbstractAudit) {}
|
|
|
|
/**
|
|
* 资料受理
|
|
*
|
|
* @param vo
|
|
*/
|
|
fun accept(vo: AcceptVo) {
|
|
transaction {
|
|
val association = findEntity(vo.auditId)
|
|
when (val manager = Manager.findById(vo.token.id)) {
|
|
null -> throw ManagerIdError(vo.token.id)
|
|
else -> {
|
|
association.apply {
|
|
val nextAudit = audit.nextAudit
|
|
if (nextAudit == null) {
|
|
audit.manager = manager
|
|
audit.acceptTime = LocalDateTime.now()
|
|
} else {
|
|
nextAudit.manager = manager
|
|
nextAudit.acceptTime = LocalDateTime.now()
|
|
}
|
|
}
|
|
|
|
log.info("[${association.notificationName()}]${this@AuditService.dataType}已受理")
|
|
Notification.new {
|
|
title = this@AuditService.dataType
|
|
content = "您提交的[${association.notificationName()}]${this@AuditService.dataType}已受理"
|
|
receiverId = vo.token.id
|
|
receiverClient = ClientType.Foreground.name
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 资料审核
|
|
*
|
|
* @param vo
|
|
*/
|
|
fun check(vo: CheckVo) {
|
|
transaction {
|
|
try {
|
|
val entity = findEntity(vo.auditId)
|
|
val matchUser = entity.audit.user
|
|
entity.audit.update(vo)
|
|
when {
|
|
entity.audit.nextAudit == null && vo.result -> {
|
|
entity.audit.nextAudit = AuditLogging.new {
|
|
this.user = matchUser
|
|
}.apply {
|
|
log.info("构造${this@AuditService.dataType}复审记录")
|
|
}
|
|
background(
|
|
content = "总部长上报了一份${this@AuditService.dataType}需要您进行受理",
|
|
duty = Duty.Teacher
|
|
)
|
|
foreground(
|
|
receiverId = matchUser.id.value,
|
|
content = "您提交的【${entity.notificationName()}】${this@AuditService.dataType}初审通过,请耐心等待复审"
|
|
)
|
|
}
|
|
entity.audit.nextAudit == null && !vo.result -> {
|
|
foreground(
|
|
receiverId = matchUser.id.value,
|
|
content = "您提交的【${entity.notificationName()}】${this@AuditService.dataType}初审不通过,可根据初审意见,重新申请\n" +
|
|
"【初审意见:${vo.cause},审核人:${entity.audit.manager?.duty ?: ""}】"
|
|
)
|
|
}
|
|
entity.audit.nextAudit != null && vo.result -> {
|
|
afterAudit(entity)
|
|
foreground(
|
|
receiverId = matchUser.id.value,
|
|
content = "您提交的【${entity.notificationName()}】${this@AuditService.dataType}复审通过"
|
|
)
|
|
}
|
|
else -> {
|
|
foreground(
|
|
receiverId = matchUser.id.value,
|
|
content = "您提交的【${entity.notificationName()}】${this@AuditService.dataType}复审不通过,可根据复审意见,重新申请\n" +
|
|
"【复审意见:${vo.cause},审核人:${entity.audit.nextAudit?.manager?.duty ?: ""}】"
|
|
)
|
|
}
|
|
}
|
|
log.info("【${entity.notificationName()}】${this@AuditService.dataType}审核完成")
|
|
} catch (e: Exception) {
|
|
rollback()
|
|
throw e
|
|
}
|
|
}
|
|
}
|
|
|
|
//过滤完成的审核记录?(可多次提交的资料)
|
|
open val isFilter: Boolean = true
|
|
|
|
/**
|
|
* TODO 审核进度查询
|
|
*
|
|
*/
|
|
fun read(vo: OnlyToken, table: IntIdTable): F? {
|
|
return transaction {
|
|
if (isFilter) {
|
|
// val nextAudit = AuditLeggings.alias("nextAudit")
|
|
val c = table.innerJoin(AuditLeggings)
|
|
// .innerJoin(nextAudit, { AuditLeggings.nextAudit }, { nextAudit[AuditLeggings.id] })
|
|
.innerJoin(Users)
|
|
.slice(listOf(table.id, AuditLeggings.result, AuditLeggings.nextAudit))
|
|
.select { Users.id eq vo.token.id }
|
|
.filter {
|
|
log.info("it[AuditLeggings.result]=${it[AuditLeggings.result]},it[AuditLeggings.nextAudit]=${it[AuditLeggings.nextAudit]}")
|
|
it[AuditLeggings.result] == null || it[AuditLeggings.nextAudit]?.let { it1 ->
|
|
AuditLogging.findById(
|
|
it1
|
|
)?.result
|
|
} == null
|
|
}
|
|
log.info("size:${c.size}")
|
|
if (c.size == 1) {
|
|
getCheckVo(c.first()[table.id])
|
|
} else {
|
|
null
|
|
}
|
|
} else {
|
|
table.innerJoin(AuditLeggings).innerJoin(Users)
|
|
.slice(listOf(table.id))
|
|
.select { Users.id eq vo.token.id }
|
|
.firstOrNull()
|
|
?.let { it ->
|
|
getCheckVo(id = it[table.id])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
abstract fun getCheckVo(id: EntityID<Int>): F
|
|
|
|
|
|
protected fun toCheckVo(audit: AuditLogging): AuditCheckVo {
|
|
return AuditCheckVo(
|
|
checkStatus = when {
|
|
audit.nextAudit == null && audit.manager == null -> CheckStatus.WaitFirst
|
|
audit.nextAudit == null && audit.manager != null && audit.result == null -> CheckStatus.AcceptFirst
|
|
audit.nextAudit != null && audit.nextAudit?.manager == null -> CheckStatus.WaitLast
|
|
audit.nextAudit != null && audit.nextAudit?.result == null -> CheckStatus.AcceptLast
|
|
else -> CheckStatus.Finish
|
|
},
|
|
applyTime = audit.applyTime.toLong(),
|
|
firstCause = audit.cause ?: "",
|
|
lastCause = audit.nextAudit?.cause,
|
|
result = audit.nextAudit?.result == true
|
|
)
|
|
}
|
|
|
|
|
|
/**
|
|
* 查看审核记录
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
abstract fun audit(vo: OnlyToken): List<E>
|
|
|
|
|
|
protected fun <T : AbstractAudit> createSortedBy(table: IntEntityClass<T>): List<T> {
|
|
return table.all().sortedBy {
|
|
//按初审受理>等待复审>复审受理>完成审核 排序
|
|
when {
|
|
it.audit.nextAudit == null && it.audit.manager == null -> 1
|
|
it.audit.nextAudit == null && it.audit.manager != null -> 2
|
|
it.audit.nextAudit != null && it.audit.nextAudit?.manager == null -> 3
|
|
it.audit.nextAudit != null && it.audit.nextAudit?.result == null -> 4
|
|
else -> 5
|
|
}
|
|
}
|
|
}
|
|
|
|
protected fun toAuditLoggingVo(it: AuditLogging?): AuditLoggingVo? {
|
|
return it?.let { logging ->
|
|
val auditLogging = AuditLoggingVo(
|
|
id = logging.id.value,
|
|
user = AccountService.toUserInfo(user = logging.user),
|
|
applyTime = logging.applyTime.toLong(),
|
|
manager = logging.manager?.let {
|
|
ManagerInfoVo(
|
|
duty = Duty.valueOf(it.duty),
|
|
name = it.name,
|
|
headImg = it.headImg?.filepath,
|
|
desc = it.desc
|
|
)
|
|
},
|
|
acceptTime = logging.acceptTime?.toLong(),
|
|
cause = logging.cause,
|
|
result = logging.result,
|
|
auditTime = logging.auditTime?.toLong(),
|
|
nextAudit = toAuditLoggingVo(logging.nextAudit)
|
|
)
|
|
auditLogging
|
|
}
|
|
}
|
|
|
|
protected fun createNotifications(vo: ClientBaseVo, user: User) {
|
|
foreground(
|
|
receiverId = vo.token.id,
|
|
content = "您成功提交了一份${dataType},请耐心等待后台受理"
|
|
)
|
|
background(
|
|
content = "用户${user.name}提交了一份${dataType}需要您进行受理",
|
|
duty = Duty.PamphaBhusal
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 社团服务
|
|
*/
|
|
object AssociationService : AuditService<AssociationRegVo, AuditAssociationVo, AssociationCheckVo>() {
|
|
|
|
override val dataType: String = "社团注册资料"
|
|
|
|
override fun findEntity(auditId: Int): AbstractAudit {
|
|
return testFind(Associations, Association, auditId)
|
|
}
|
|
|
|
override val isFilter: Boolean = false
|
|
|
|
override fun afterAudit(entity: AbstractAudit) {
|
|
AssociationMember.new {
|
|
user = entity.audit.user
|
|
this.association = Association.find { Associations.auditId eq entity.audit.id }.firstOrNull()
|
|
?: throw IllegalArgumentException("无法根据[audit=${entity.audit.id}]找到社团信息")
|
|
isHead = true
|
|
}.apply {
|
|
this@AssociationService.log.info("初始化社团团长")
|
|
}
|
|
}
|
|
|
|
fun Association.set(vo: AssociationRegVo, user: User) {
|
|
name = vo.name
|
|
desc = vo.desc
|
|
logo = ImageFile.findById(vo.fileId) ?: throw FileIdError(vo.fileId)
|
|
this.audit = AuditLogging.new {
|
|
this.user = user
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 加载所有社团
|
|
*
|
|
* @return
|
|
*/
|
|
fun loadAll(): List<AssociationVo> {
|
|
return transaction {
|
|
Association.all().map {
|
|
toAssociationVo(it)
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun toExamVo(question: Question): ExamVo {
|
|
return ExamVo(
|
|
questionId = question.id.value,
|
|
question = question.question,
|
|
optionsA = question.optionsA,
|
|
optionsB = question.optionsB,
|
|
optionsC = question.optionsC,
|
|
optionsD = question.optionsD,
|
|
rightOption = question.answer
|
|
)
|
|
}
|
|
|
|
/**
|
|
* 加载题库
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
fun loadExam(vo: SearchExamVo): List<ExamVo> {
|
|
return transaction {
|
|
Question.find { Questions.associationId eq vo.associationId }.map {
|
|
toExamVo(question = it)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 提交答卷
|
|
*
|
|
*/
|
|
fun applyAnswer(vo: AddAnswerVo) {
|
|
transaction {
|
|
val user = User.findById(vo.token.id) ?: throw UserIdError(vo.token.id)
|
|
|
|
val association = Association.findById(vo.associationId) ?: throw AssociationIdError(vo.associationId)
|
|
val join = createJoin(association = association, user = user)
|
|
|
|
vo.answers.forEach {
|
|
val id = it.examVo.questionId ?: throw IllegalArgumentException("问题id不存在")
|
|
|
|
val question = Question.findById(id) ?: throw IllegalArgumentException("不存在[id=${id}]的问题")
|
|
|
|
Answer.new {
|
|
this.question = question
|
|
answer = it.answer
|
|
this.join = join
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun toJoinVo(join: JoinAssociation): JoinAssociationVo {
|
|
val hasPaper = Answer.find { Answers.joinId eq join.id.value }.count() > 0
|
|
return JoinAssociationVo(
|
|
id = join.id.value, user = AccountService.toUserInfo(join.user),
|
|
associationVo = toAssociationVo(join.association), hasPaper = hasPaper, result = join.result,
|
|
applyTime = join.applyTime.toLong(), auditTime = join.auditTime?.toLong()
|
|
)
|
|
}
|
|
|
|
/**
|
|
* 显示答卷
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
fun showAnswer(vo: ShowAnswerVo): List<ApplyAnswerVo> {
|
|
return transaction {
|
|
val join = JoinAssociation.findById(vo.joinId) ?: throw IllegalArgumentException("找不到[id=${vo.joinId}]申请记录")
|
|
Answer.find { Answers.joinId eq join.id }.map {
|
|
ApplyAnswerVo(examVo = toExamVo(it.question), answer = it.answer)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 创建申请记录
|
|
*
|
|
* @param association
|
|
* @param user
|
|
*/
|
|
private fun createJoin(association: Association, user: User): JoinAssociation {
|
|
return JoinAssociation.new {
|
|
this.association = association
|
|
this.user = user
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 生成试卷
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
fun createPaper(vo: SearchExamVo): List<ExamVo> {
|
|
return transaction {
|
|
val association = Association.findById(vo.associationId) ?: throw AssociationIdError(vo.associationId)
|
|
Question.find { Questions.associationId eq association.id }.let { it ->
|
|
it.shuffled().map {
|
|
toExamVo(question = it)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private fun createJoinNotification(user: User, association: Association) {
|
|
AssociationMember.find {
|
|
AssociationMembers.associationId eq association.id and
|
|
(AssociationMembers.isHead eq true)
|
|
}.firstOrNull()?.apply {
|
|
Notification.new {
|
|
this.title = "入团申请通知"
|
|
this.content = "用户${user.name}申请加入社团"
|
|
this.receiverId = user.id.value
|
|
receiverClient = ClientType.Foreground.name
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 申请入团
|
|
*
|
|
*/
|
|
fun applyAssociation(vo: SearchExamVo): ApplyAssociationResultVo {
|
|
return transaction {
|
|
val user = User.findById(vo.token.id) ?: throw UserIdError(vo.token.id)
|
|
val association = Association.findById(vo.associationId) ?: throw AssociationIdError(vo.associationId)
|
|
JoinAssociation.find { JoinAssociations.userId eq vo.token.id and (JoinAssociations.result eq null) }
|
|
.firstOrNull().let {
|
|
if (it != null) {
|
|
return@transaction ApplyAssociationResultVo(associationVo = toAssociationVo(it.association))
|
|
}
|
|
}
|
|
|
|
Question.find { Questions.associationId eq association.id }.let { it ->
|
|
//题库需要满足最少题目数才能生成试卷
|
|
if (it.count() >= QUESTION_MIN_SIZE) {
|
|
ApplyAssociationResultVo(result = true, hasPaper = true)
|
|
}
|
|
//免试入团申请
|
|
else {
|
|
createJoin(association = association, user = user)
|
|
createJoinNotification(association = association, user = user)
|
|
ApplyAssociationResultVo(result = true, hasPaper = false)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 入团申请记录
|
|
*
|
|
*/
|
|
fun joinAssociation(vo: SearchExamVo): List<JoinAssociationVo> {
|
|
return transaction {
|
|
val association = Association.findById(vo.associationId) ?: throw AssociationIdError(vo.associationId)
|
|
JoinAssociation.find { JoinAssociations.associationId eq association.id }
|
|
.sortedByDescending { it.applyTime }.map {
|
|
toJoinVo(join = it)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 审核入团申请
|
|
* @param vo
|
|
*/
|
|
fun auditJoin(vo: AuditJoinVo) {
|
|
transaction {
|
|
val join = JoinAssociation.findById(vo.joinId) ?: throw IllegalArgumentException("审核记录不存在")
|
|
join.result = vo.result
|
|
join.auditTime = LocalDateTime.now()
|
|
if (vo.result) {
|
|
AssociationMember.new {
|
|
user = join.user
|
|
association = join.association
|
|
isHead = false
|
|
}
|
|
//入团申请通过,通知社团其他人
|
|
AssociationMember.find { AssociationMembers.associationId eq join.association.id }.forEach {
|
|
Notification.new {
|
|
this.title = "入团通知"
|
|
this.content = "欢迎新人${join.user.name}加入社团"
|
|
this.receiverId = it.user.id.value
|
|
receiverClient = ClientType.Foreground.name
|
|
}.apply {
|
|
log.info("通知前台用户${dataType}处理进度")
|
|
}
|
|
}
|
|
}
|
|
//把审核结果发送给申请人
|
|
Notification.new {
|
|
this.title = "入团审核结果"
|
|
this.content = "您申请加入${join.association.name}社团审核${if (vo.result) "通过" else "不通过"}"
|
|
this.receiverId = join.user.id.value
|
|
receiverClient = ClientType.Foreground.name
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 更新题库
|
|
*
|
|
* @param vo
|
|
*/
|
|
fun updateExam(vo: AddExamVo) {
|
|
transaction {
|
|
val association = Association.findById(vo.associationId) ?: throw IllegalArgumentException("找不到社团信息")
|
|
|
|
vo.deleteIds?.let {
|
|
//删除社团题目
|
|
Question.find { Questions.associationId eq association.id and (Questions.id inList it) }.forEach {
|
|
log.info("删除[id=${it.id}]题目")
|
|
it.delete()
|
|
}
|
|
}
|
|
|
|
vo.questions.forEach { exam ->
|
|
exam.questionId.let {
|
|
if (it == null) {
|
|
Question.new {
|
|
question = exam.question
|
|
optionsA = exam.optionsA
|
|
optionsB = exam.optionsB
|
|
optionsC = exam.optionsC
|
|
optionsD = exam.optionsD
|
|
this.answer = exam.rightOption
|
|
this.association = association
|
|
}
|
|
} else {
|
|
log.info("更新[id=${it}]的题目")
|
|
Question.findById(it)?.apply {
|
|
question = exam.question
|
|
optionsA = exam.optionsA
|
|
optionsB = exam.optionsB
|
|
optionsC = exam.optionsC
|
|
optionsD = exam.optionsD
|
|
this.answer = exam.rightOption
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 更新社团信息
|
|
*
|
|
* @param vo
|
|
*/
|
|
fun update(vo: AssociationVo) {
|
|
transaction {
|
|
Association.findById(vo.associationId).let {
|
|
if (it == null) {
|
|
throw AssociationIdError(vo.associationId)
|
|
} else {
|
|
it.level = vo.level?.name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 注册社团
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
override fun register(vo: AssociationRegVo) {
|
|
return transaction {
|
|
//再次申请
|
|
val user = User.findById(vo.token.id) ?: throw UserIdError(vo.token.id)
|
|
if (vo.associationId != null) {
|
|
log.info("再次提交【${vo.name}】注册资料")
|
|
(Association.findById(vo.associationId!!) ?: throw AuditIdError(vo.associationId!!))
|
|
.set(vo = vo, user = user)
|
|
} else {
|
|
val associationMember = AssociationMember.find { AssociationMembers.userId eq user.id }.firstOrNull()
|
|
val association: Association? = associationMember?.association
|
|
when {
|
|
association != null && association.audit.result == true -> throw IllegalArgumentException("您是社团团长不能再创建其他社团")
|
|
association != null && association.audit.result == null -> throw IllegalArgumentException("您已经提交过${dataType},请耐心等待后台管理员处理")
|
|
association == null -> {
|
|
Association.new {
|
|
set(vo = vo, user = user)
|
|
faculty = faculty(user.studentId).name
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
createNotifications(vo = vo, user = user)
|
|
log.info("未审核社团:${vo.name}创建成功")
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 社团列表加载
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
fun load(vo: SearchAssociationVo): List<AssociationVo> {
|
|
return transaction {
|
|
log.info("社团搜索条件[name=${vo.name},desc=${vo.desc}]")
|
|
|
|
val nextAudit = AuditLeggings.alias("nextAudit")
|
|
return@transaction Associations.innerJoin(otherTable = AuditLeggings)
|
|
.innerJoin(nextAudit, { AuditLeggings.nextAudit }, { nextAudit[AuditLeggings.id] })
|
|
.slice(listOf(Associations.id))
|
|
.select {
|
|
nextAudit[AuditLeggings.result] eq true and (Associations.name like "%${vo.name}%") and (Associations.desc like "%${vo.desc}%")
|
|
}.map {
|
|
val association =
|
|
Association.findById(it[Associations.id]) ?: throw AssociationIdError(it[Associations.id].value)
|
|
toAssociationVo(association)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 前台读取社团注册资料
|
|
*
|
|
*/
|
|
override fun getCheckVo(id: EntityID<Int>): AssociationCheckVo {
|
|
return (Association.findById(id) ?: throw AssociationIdError(id.value)).let {
|
|
AssociationCheckVo(
|
|
associationVo = toAssociationVo(it),
|
|
auditCheckVo = toCheckVo(it.audit),
|
|
fileId = it.logo.id.value
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 后台读取社团注册资料
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
override fun audit(vo: OnlyToken): List<AuditAssociationVo> {
|
|
return transaction {
|
|
return@transaction createSortedBy(Association).map {
|
|
val audit = toAuditLoggingVo(it.audit) ?: throw IllegalArgumentException("转换审核记录出错!!!!")
|
|
AuditAssociationVo(name = it.name, desc = it.desc, logo = it.logo.filepath, audit = audit)
|
|
}.apply {
|
|
log.info("找到${this.size}份${dataType}")
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
fun toAssociationVo(it: Association): AssociationVo {
|
|
return AssociationVo(associationId = it.id.value, name = it.name, desc = it.desc,
|
|
logo = it.logo.filepath, faculty = AssociationFaculty.valueOf(it.faculty),
|
|
level = it.level?.let { AssociationLevel.valueOf(it) })
|
|
}
|
|
|
|
/**
|
|
*
|
|
* 查询社团详情
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
fun load(vo: ShowAssociationVo): AssociationMainVo {
|
|
return transaction {
|
|
val associationVo = (Association.findById(vo.id) ?: throw AssociationIdError(vo.id)).let { it ->
|
|
AssociationVo(associationId = it.id.value, name = it.name, desc = it.desc,
|
|
logo = it.logo.filepath, faculty = AssociationFaculty.valueOf(it.faculty),
|
|
level = it.level?.let { AssociationLevel.valueOf(it) })
|
|
}
|
|
val head = Users.innerJoin(AssociationMembers)
|
|
.slice(Users.columns)
|
|
.select { AssociationMembers.isHead eq true and (AssociationMembers.associationId eq vo.id) }
|
|
.firstOrNull()?.let { it ->
|
|
UserInfoVo(
|
|
name = it[Users.name],
|
|
headImg = it[Users.imgId]?.let {
|
|
ImageFile.findById(it) ?: throw FileIdError(it.value)
|
|
}?.filepath,
|
|
desc = it[Users.desc]
|
|
)
|
|
|
|
} ?: throw IllegalArgumentException("无法找到社团[${vo.id}]")
|
|
AssociationMainVo(associationVo = associationVo, head = head)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 加载社团成员
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
fun load(vo: QueryAssociationMembers): List<UserInfoVo> {
|
|
return transaction {
|
|
Users.innerJoin(AssociationMembers).innerJoin(Associations)
|
|
.slice(Users.columns)
|
|
.select {
|
|
vo.name.let {
|
|
if (it == null || it.isEmpty())
|
|
Associations.id eq vo.id
|
|
else
|
|
Associations.id eq vo.id and (Users.name like "%${vo.name}%")
|
|
}
|
|
}.map { it ->
|
|
UserInfoVo(
|
|
name = it[Users.name], headImg = it[Users.imgId]?.let { ImageFile.findById(it) }?.filepath,
|
|
desc = it[Users.desc]
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 活动服务
|
|
*/
|
|
object ActivityService : AuditService<ActivityApplyVo, AuditActVo, ActivityCheckVo>() {
|
|
|
|
|
|
override val dataType: String = "活动申请书"
|
|
|
|
override fun findEntity(auditId: Int): AbstractAudit {
|
|
return testFind(Activities, Activity, auditId)
|
|
}
|
|
|
|
private fun checkTendency(userId:Int, activityId:Int, type:TendencyType): SizedIterable<Tendency> {
|
|
val user=User.findById(userId)?:throw UserIdError(userId)
|
|
val activity=Activity.findById(activityId)?:throw ActivityIdError(activityId)
|
|
return Tendency.find { Tendencies.userId eq user.id and (Tendencies.activityId eq activity.id) and
|
|
(Tendencies.type eq type.ordinal) }
|
|
}
|
|
|
|
|
|
|
|
fun checkTendency(vo: CheckTendencyVo):CheckTendencyResVo{
|
|
return transaction {
|
|
val hasLike= checkTendency(userId = vo.token.id,activityId = vo.activityId,type = TendencyType.Like).count()==1L
|
|
val hasCollect=checkTendency(userId = vo.token.id,activityId = vo.activityId,type = TendencyType.Collect).count()==1L
|
|
CheckTendencyResVo(hasLike=hasLike,hasCollect=hasCollect)
|
|
}
|
|
}
|
|
|
|
fun findTendency(vo:FindTendencyVo):List<ActivityVo>{
|
|
return transaction {
|
|
val user=User.findById(vo.token.id)?:throw UserIdError(vo.token.id)
|
|
Tendency.find { Tendencies.userId eq user.id and (Tendencies.type eq vo.type.ordinal) }.map {
|
|
toActivityVo(activity = it.activity)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 活动倾向
|
|
*
|
|
*/
|
|
fun tendency(vo: TendencyVo) {
|
|
transaction {
|
|
checkTendency(userId = vo.token.id,activityId = vo.activityId,type = vo.type).apply {
|
|
if (count() == 1L) {
|
|
first().delete()
|
|
} else {
|
|
Tendency.new {
|
|
this.user= User[vo.token.id]
|
|
this.activity= Activity[vo.activityId]
|
|
this.type=vo.type.ordinal
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 查看活动信息
|
|
*
|
|
*/
|
|
fun listAll(): List<ManagerActVo> {
|
|
return transaction {
|
|
Activity.all().map {
|
|
ManagerActVo(
|
|
association = AssociationService.toAssociationVo(it.association),
|
|
score = (1..5).random(), activityVo = toActivityVo(it)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 主页活动图片
|
|
*
|
|
* @return
|
|
*/
|
|
fun random(): List<MainActivityPhotoVo> {
|
|
return transaction {
|
|
PhotoAlbum.all().shuffled().map {
|
|
MainActivityPhotoVo(
|
|
url = it.photo.filepath,
|
|
activityVo = toActivityVo(it.activity),
|
|
associationVo = AssociationService.toAssociationVo(it.activity.association)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 上传照片
|
|
*
|
|
* @param data
|
|
*/
|
|
fun upload(data: List<PartData>) {
|
|
val activityId = data.getFormParam("activityId")
|
|
val name = data.getFormParam("name")
|
|
transaction {
|
|
(Activity.findById(activityId.toInt()) ?: throw IllegalArgumentException("活动id参数有误:${activityId}")).apply {
|
|
val fileId = FileService.storeFile(data)
|
|
//保存到相册
|
|
fileId?.forEach {
|
|
PhotoAlbum.new {
|
|
activity = this@apply
|
|
photo = ImageFile.findById(it) ?: throw FileIdError(it)
|
|
this.name = name
|
|
}.let {
|
|
log.info("保存照片:${it.name}")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 发送评论
|
|
*
|
|
* @param vo
|
|
*/
|
|
fun sendComment(vo: SendBBSVo) {
|
|
transaction {
|
|
ActivityComment.new {
|
|
content = vo.content
|
|
user = User.findById(vo.token.id) ?: throw UserIdError(vo.token.id)
|
|
activity = Activity.findById(vo.activityId) ?: throw ActivityIdError(vo.activityId)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 加载评论
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
fun loadComment(vo: SearchCommentVo): List<BBSVo> {
|
|
return transaction {
|
|
ActivityComment.find { ActivityComments.activityId eq vo.activityId }.map {
|
|
BBSVo(
|
|
user = AccountService.toUserInfo(it.user),
|
|
createTime = it.createTime.toLong(), content = it.content
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 加载活动照片
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
fun load(vo: SearchActivityPhotoVo): List<ActivityPhotoVo> {
|
|
return transaction {
|
|
PhotoAlbum.find { PhotoAlbums.activityId eq vo.activityId }.map {
|
|
ActivityPhotoVo(name = it.name, url = it.photo.filepath)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 活动列表
|
|
*
|
|
*/
|
|
fun load(vo: SearchActivityVo): List<ActivityVo> {
|
|
return transaction {
|
|
val nextAudit = AuditLeggings.alias("nextAudit")
|
|
return@transaction Activities.innerJoin(otherTable = AuditLeggings)
|
|
.innerJoin(nextAudit, { AuditLeggings.nextAudit }, { nextAudit[AuditLeggings.id] })
|
|
.slice(listOf(Activities.id))
|
|
.select {
|
|
nextAudit[AuditLeggings.result] eq true and (Activities.associationId eq vo.associationId)
|
|
}.map {
|
|
val activity =
|
|
Activity.findById(it[Activities.id]) ?: throw ActivityIdError(it[Activities.id].value)
|
|
toActivityVo(activity = activity)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 活动详情
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
fun show(vo: ShowActivityVo): ActivityDetailVo {
|
|
return transaction {
|
|
(Activity.findById(vo.activityId) ?: throw ActivityIdError(vo.activityId)).let {
|
|
ActivityDetailVo(
|
|
activityVo = toActivityVo(it),
|
|
associationVo = AssociationService.toAssociationVo(it.association)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
fun Activity.set(activityVo: ActivityVo, user: User) {
|
|
activityName = activityVo.activityName
|
|
activityTime = activityVo.activityTime.toLocalDateTime()
|
|
activityAddress = activityVo.activityAddress
|
|
activityDesc = activityVo.activityDesc
|
|
activitySize = activityVo.activitySize
|
|
audit = AuditLogging.new {
|
|
this.user = user
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 申请活动
|
|
*
|
|
*/
|
|
override fun register(vo: ActivityApplyVo) {
|
|
transaction {
|
|
val user = User.findById(vo.token.id) ?: throw UserIdError(vo.token.id)
|
|
|
|
if (vo.activityVo.activityId != null) {
|
|
//再次提交
|
|
log.info("再次提交【${vo.activityVo.activityName}】${dataType}")
|
|
(Activity.findById(vo.activityVo.activityId!!) ?: throw ActivityIdError(vo.activityVo.activityId!!))
|
|
.set(activityVo = vo.activityVo, user = user)
|
|
} else {
|
|
//首次提交
|
|
//申请活动的限制
|
|
val activityMember = AssociationMember.find { AssociationMembers.userId eq user.id }.firstOrNull()
|
|
when {
|
|
activityMember == null -> throw IllegalArgumentException("非社团成员无法申请活动")
|
|
!activityMember.isHead -> throw IllegalArgumentException("不是社团团长无法申请活动")
|
|
else -> {
|
|
Activity.new {
|
|
set(vo.activityVo, user = user)
|
|
association =
|
|
Association.findById(vo.associationId) ?: throw AssociationIdError(vo.associationId)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
createNotifications(vo = vo, user = user)
|
|
}
|
|
}
|
|
|
|
private fun toActivityVo(activity: Activity): ActivityVo {
|
|
return ActivityVo(
|
|
activityName = activity.activityName, activityTime = activity.activityTime.toLong(),
|
|
activityAddress = activity.activityAddress, activityDesc = activity.activityDesc,
|
|
activitySize = activity.activitySize,
|
|
activityId = activity.id.value
|
|
)
|
|
}
|
|
|
|
override fun audit(vo: OnlyToken): List<AuditActVo> {
|
|
return transaction {
|
|
return@transaction createSortedBy(Activity).map {
|
|
val audit = toAuditLoggingVo(it.audit) ?: throw IllegalArgumentException("转换审核记录出错!!!!")
|
|
AuditActVo(activityVo = toActivityVo(activity = it), audit = audit)
|
|
}.apply {
|
|
log.info("找到${this.size}份${dataType}")
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun getCheckVo(id: EntityID<Int>): ActivityCheckVo {
|
|
return (Activity.findById(id) ?: throw ActivityIdError(id.value)).let {
|
|
ActivityCheckVo(
|
|
activityVo = toActivityVo(activity = it),
|
|
auditCheckVo = toCheckVo(it.audit)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 重命名服务
|
|
*/
|
|
object RenameService : AuditService<RenameApplyVo, AuditRenameVo, RenameCheckVo>() {
|
|
override val dataType: String = "换名申请表"
|
|
|
|
fun Rename.set(vo: RenameVo, user: User) {
|
|
newName = vo.newName
|
|
cause = vo.cause
|
|
audit = AuditLogging.new {
|
|
this.user = user
|
|
}
|
|
}
|
|
|
|
|
|
//TODO 类型自动转换
|
|
override fun afterAudit(entity: AbstractAudit) {
|
|
if (entity is Rename) {
|
|
entity.association.name = entity.newName
|
|
}
|
|
}
|
|
|
|
override fun register(vo: RenameApplyVo) {
|
|
transaction {
|
|
vo.rename.renameId.also {
|
|
val user = User.findById(vo.token.id) ?: throw UserIdError(vo.token.id)
|
|
if (it != null) {
|
|
//再次提交
|
|
(Rename.findById(it) ?: throw IllegalArgumentException("无法根据[id=${it}]找到${dataType}")).set(
|
|
vo = vo.rename,
|
|
user = user
|
|
)
|
|
} else {
|
|
//重新提交
|
|
val activityMember = AssociationMember.find { AssociationMembers.userId eq user.id }.firstOrNull()
|
|
when {
|
|
activityMember == null -> throw IllegalArgumentException("非社团成员无法申请社团换名")
|
|
!activityMember.isHead -> throw IllegalArgumentException("非社团团长无法申请社团换名")
|
|
else -> {
|
|
Rename.new {
|
|
set(vo = vo.rename, user = user)
|
|
association =
|
|
Association.findById(vo.associationId) ?: throw AssociationIdError(vo.associationId)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
createNotifications(vo = vo, user = user)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
override fun findEntity(auditId: Int): AbstractAudit {
|
|
return testFind(Renames, Rename, auditId)
|
|
}
|
|
|
|
private fun toRenameVo(rename: Rename): RenameVo {
|
|
return RenameVo(renameId = rename.id.value, newName = rename.newName, cause = rename.cause)
|
|
}
|
|
|
|
override fun getCheckVo(id: EntityID<Int>): RenameCheckVo {
|
|
return (Rename.findById(id) ?: throw IllegalArgumentException("找不到[id=${id}]${dataType}")).let {
|
|
RenameCheckVo(renameVo = toRenameVo(it), auditCheckVo = toCheckVo(it.audit))
|
|
}
|
|
}
|
|
|
|
override fun audit(vo: OnlyToken): List<AuditRenameVo> {
|
|
return transaction {
|
|
return@transaction createSortedBy(Rename).map {
|
|
val audit = toAuditLoggingVo(it.audit) ?: throw IllegalArgumentException("转换审核记录出错!!!!")
|
|
AuditRenameVo(
|
|
renameVo = toRenameVo(rename = it),
|
|
audit = audit,
|
|
associationVo = AssociationService.toAssociationVo(it.association)
|
|
)
|
|
}.apply {
|
|
log.info("找到${this.size}份${ActivityService.dataType}")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 通知服务
|
|
*/
|
|
object NotificationService : AbstractService() {
|
|
|
|
/**
|
|
* 拉取最新通知
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
fun pull(vo: NotificationDto): List<NotificationVo> {
|
|
return transaction {
|
|
log.info("通知查询条件[receiverId=${vo.receiverId},receiverClient=${vo.receiverClient.name},pull=false]")
|
|
val notifications = Notification.find {
|
|
Notifications.pull eq false and
|
|
(Notifications.receiverId eq vo.receiverId) and
|
|
(Notifications.receiverClient eq vo.receiverClient.name)
|
|
}
|
|
log.info("获取${notifications.count()}条最新通知")
|
|
return@transaction notifications.map {
|
|
it.pull = true
|
|
NotificationVo(
|
|
title = it.title, id = it.id.value, content = it.content,
|
|
createTime = it.createTime.toLong()
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 未读通知计数
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
fun count(vo: NotificationDto): Long {
|
|
return transaction {
|
|
return@transaction Notification.find {
|
|
Notifications.read eq false and
|
|
(Notifications.receiverId eq vo.receiverId) and
|
|
(Notifications.receiverClient eq vo.receiverClient.name)
|
|
}.count().apply {
|
|
log.info("未读通知${this}条")
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param vo
|
|
* @return
|
|
*/
|
|
fun list(vo: NotificationDto): List<NotificationVo> {
|
|
return transaction {
|
|
return@transaction Notification.find {
|
|
(Notifications.receiverId eq vo.receiverId) and
|
|
(Notifications.receiverClient eq vo.receiverClient.name)
|
|
}.sortedByDescending { it.createTime }.map {
|
|
NotificationVo(
|
|
title = it.title,
|
|
id = it.id.value,
|
|
content = it.content,
|
|
createTime = it.createTime.toLong()
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 后台服务
|
|
*/
|
|
object BackgroundService : AbstractService() {
|
|
|
|
|
|
override fun init(environment: ApplicationEnvironment) {
|
|
super.init(environment)
|
|
initManager()
|
|
}
|
|
|
|
|
|
fun toManagerVo(manager: Manager): ManagerInfoVo {
|
|
return ManagerInfoVo(
|
|
duty = manager.duty.let { Duty.valueOf(it) }, name = manager.name,
|
|
headImg = manager.headImg?.filepath, desc = manager.desc
|
|
)
|
|
}
|
|
|
|
|
|
/**
|
|
* 加载部门部长,和总人数
|
|
*
|
|
*/
|
|
fun load(): ManagerDutySumVo {
|
|
return transaction {
|
|
val secretariat = Manager.find { Managers.duty eq Duty.SecretaryOfTheMinister.name }.first()
|
|
val secretariatCount = Manager.find { Managers.duty eq Duty.SecretaryDepartmentOfficer.name }.count()
|
|
val propaganda = Manager.find { Managers.duty eq Duty.PropagandaDepartment.name }.first()
|
|
val propagandaCount = Manager.find { Managers.duty eq Duty.PublicityDepartmentOfficer.name }.count()
|
|
val publicRelationsDepartment = Manager.find { Managers.duty eq Duty.LiaisonMinister.name }.first()
|
|
val publicRelationsDepartmentCount = Manager.find { Managers.duty eq Duty.LiaisonOfficer.name }.count()
|
|
ManagerDutySumVo(
|
|
secretariat = ManagerDutyVo(manager = toManagerVo(secretariat), people = secretariatCount.toInt()),
|
|
propaganda = ManagerDutyVo(manager = toManagerVo(propaganda), people = propagandaCount.toInt()),
|
|
publicRelationsDepartment = ManagerDutyVo(
|
|
manager = toManagerVo(publicRelationsDepartment),
|
|
people = publicRelationsDepartmentCount.toInt()
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 加载部门详细信息
|
|
*
|
|
* @return
|
|
*/
|
|
fun loadDetail(): AllOfficerVo {
|
|
return transaction {
|
|
val secretariat = Manager.find { Managers.duty eq Duty.SecretaryDepartmentOfficer.name }.map {
|
|
toManagerVo(it)
|
|
}
|
|
val propaganda = Manager.find { Managers.duty eq Duty.PublicityDepartmentOfficer.name }.map {
|
|
toManagerVo(it)
|
|
}
|
|
val publicRelationsDepartment = Manager.find { Managers.duty eq Duty.LiaisonOfficer.name }.map {
|
|
toManagerVo(it)
|
|
}
|
|
AllOfficerVo(
|
|
secretariat = secretariat,
|
|
propaganda = propaganda,
|
|
publicRelationsDepartment = publicRelationsDepartment
|
|
)
|
|
}
|
|
}
|
|
|
|
private fun createManager(duty: Duty, num: Int = 1): MutableList<InitManagerDto> {
|
|
val managerList = mutableListOf<InitManagerDto>()
|
|
repeat(num) {
|
|
val originPassword = randomNum()
|
|
Manager.new {
|
|
account = randomNum()
|
|
password = originPassword.md5()
|
|
this.duty = duty.name
|
|
this.name = duty.desc
|
|
}.apply {
|
|
managerList.add(InitManagerDto(account = account, originPassword = originPassword, duty = duty))
|
|
}
|
|
}
|
|
return managerList
|
|
}
|
|
|
|
//初始化管理员
|
|
private fun initManager() {
|
|
transaction {
|
|
val resourcePath =
|
|
this::class.java.classLoader.getResource("")?.path ?: throw IllegalArgumentException("初始化资源目录失败")
|
|
val file = File(resourcePath, "管理员账号.txt")
|
|
try {
|
|
if (!file.exists()) {
|
|
Manager.count().let { it ->
|
|
if (it.toInt() == 0) {
|
|
val allManager = mutableListOf<InitManagerDto>()
|
|
allManager.addAll(createManager(Duty.Teacher, 1))
|
|
allManager.addAll(createManager(Duty.PamphaBhusal, 1))
|
|
allManager.addAll(createManager(Duty.SecretaryOfTheMinister, 1))
|
|
allManager.addAll(createManager(Duty.PropagandaDepartment, 1))
|
|
allManager.addAll(createManager(Duty.LiaisonMinister, 1))
|
|
arrayOf(
|
|
Duty.SecretaryDepartmentOfficer,
|
|
Duty.PublicityDepartmentOfficer,
|
|
Duty.LiaisonOfficer
|
|
).forEach {
|
|
allManager.addAll(createManager(it, 3))
|
|
}
|
|
allManager.forEach {
|
|
file.appendText("${it.account}------${it.originPassword}------${it.duty.desc}\n")
|
|
}
|
|
log.info("共生成${allManager.size}个管理员账号")
|
|
} else {
|
|
log.info("不需要生成管理员")
|
|
}
|
|
}
|
|
}
|
|
} catch (e: Exception) {
|
|
log.error(e)
|
|
exitProcess(0)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|