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.
 
csamsserver/src/Service.kt

496 lines
17 KiB

package com.gyf.csams
import io.ktor.application.*
import io.ktor.http.content.*
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.transactions.transaction
import org.slf4j.Logger
import java.io.File
import java.time.ZoneOffset
import kotlin.properties.Delegates
interface BaseService{
fun init(environment:ApplicationEnvironment)
}
abstract class AbstractService:BaseService{
protected lateinit var log:Logger
override fun init(environment: ApplicationEnvironment) {
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 register(userVo: UserVo): UserResDto? {
try {
return transaction {
val originPassword = randomNum(8)
User.new {
studentId=userVo.studentId
name=userVo.name
password=originPassword.md5()
}
return@transaction UserResDto(password=originPassword)
}
} catch (e: Exception) {
log.error("注册失败,发生异常:$e")
return null
}
}
/**
* 前台登录
*
*/
fun login(userLoginVo: UserLoginVo,_ip:String):Token?{
return transaction {
val matchUser=User.find { Users.studentId eq userLoginVo.studentId }.firstOrNull()
when {
matchUser==null -> {
log.warn("学号:${userLoginVo.studentId}不存在")
return@transaction null
}
userLoginVo.password.md5() != matchUser.password -> {
log.warn("密码:${userLoginVo.password}错误")
return@transaction null
}
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()
return@transaction Token(id = matchUser.id.value,token = token.token,
createTime = token.createTime.toEpochSecond(
ZoneOffset.of("+8")))
}
}
}
}
fun login(managerLoginVo: ManagerLoginVo, _ip:String):Token?{
return transaction {
val matchUser=Manager.find { Managers.account eq managerLoginVo.account }.firstOrNull()
when {
matchUser==null -> {
log.warn("学号:${managerLoginVo.account}不存在")
return@transaction null
}
managerLoginVo.password.md5() != matchUser.password -> {
log.warn("密码:${managerLoginVo.password}错误")
return@transaction null
}
else -> {
val token=ManagerToken.new{
manager=matchUser
ip=_ip
device=managerLoginVo.device
token=listOf(matchUser.id,ip,device).joinToString(separator = ('a' .. 'z').random().toString()).md5()
}
token.flush()
return@transaction Token(id = matchUser.id.value,token = token.token,
createTime = token.createTime.toEpochSecond(
ZoneOffset.of("+8")))
}
}
}
}
fun validManagerToken(token:Token):Boolean{
return transaction {
!ManagerToken.find {
ManagerTokens.managerId eq token.id
ManagerTokens.token eq token.token
}.empty()
}
}
fun validToken(token: Token):Boolean{
return transaction {
!UserToken.find {
UserTokens.userId eq token.id
UserTokens.token eq token.token
}.empty()
}
}
fun logout(userId:Int):Boolean{
return transaction {
UserTokens.deleteWhere { UserTokens.userId eq userId }>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 = UserVo(studentId = it.user.studentId, name = it.user.name)
)
}
}
}
}
/**
* 文件管理服务
*/
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()
val resourcePath =this::class.java.classLoader.getResource("")?.path ?: throw IllegalArgumentException("初始化资源目录失败")
File(resourcePath, uploadDir).apply {
when{
!exists()&&mkdir()-> {
log.info("图片上传路径[${absolutePath}]初始化成功")
this@FileService.filePath=absolutePath
}
exists()->{
log.info("图片上传路径[${absolutePath}]已存在")
this@FileService.filePath=absolutePath
}
else->throw IllegalArgumentException("图片上传路径[${absolutePath}]初始化失败")
}
}
}
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 storeFile(data:List<PartData>):List<Int>?{
val map=data.associateBy {
it.name
}.toMutableMap()
log.info("map=${map}")
val userId=getPartData<PartData.FormItem>(map,"id").value
val token= getPartData<PartData.FormItem>(map,"token").value
val createTime= getPartData<PartData.FormItem>(map,"createTime").value
val tokenVo=Token(token=token,id=userId.toInt(),createTime=createTime.toLong())
if(AccountService.validToken(tokenVo)){
map.remove("id")
map.remove("token")
val fileIds= mutableListOf<Int>()
map.forEach{
val value=it.value
if(value is PartData.FileItem){
val fileBytes = value.streamProvider().readBytes()
val fileName=value.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
}
}
}
/**
* 社团服务
*/
object AssociationService: AbstractService() {
/**
* 注册社团
*
* @param vo
* @return
*/
fun register(vo:RegAssociationVo):Boolean{
return try {
transaction {
Association.new {
name=vo.name
desc=vo.desc
logo=ImageFile.findById(vo.fileId) ?: throw IllegalArgumentException("文件id不存在!")
}
Notification.new {
title="注册社团"
content="您成功提交了一份社团注册资料,请耐心等待后台受理"
receiverId=vo.token.id
receiverClient=ReceiverType.Foreground.name
}
val user=User.findById(vo.token.id)
if(user!=null) {
BackgroundService.createBackgroundNotification(title = "审核注册社团",content = "用户${user.name}提交了一份社团资料需要您进行受理",
duty = Duty.PamphaBhusal)
}else{
log.warn("无法根据token id:${vo.token.id}查找到用户名")
}
return@transaction true
}
log.info("未审核社团创建成功")
true
} catch (e: Exception) {
log.error(e.stackTraceToString())
false
}
}
}
enum class Duty(val desc:String, val level:Int){
Teacher("老师",1),
PamphaBhusal("总部长",2),
SecretaryOfTheMinister("秘书部部长",3),
PropagandaDepartment("宣传部部长",3),
LiaisonMinister("外联部部长",3),
SecretaryDepartmentOfficer("秘书部干事",4),
PublicityDepartmentOfficer("宣传部干事",4),
LiaisonOfficer("外联部干事",4)
}
/**
* 通知服务
*/
object NotificationService:AbstractService(){
/**
* 拉取最新通知
*
* @param vo
* @return
*/
fun pull(vo:NotificationDto):List<NotificationVo>{
return transaction {
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.toEpochSecond(
ZoneOffset.of("+8")))
}
}
}
/**
* 未读通知计数
*
* @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 vo.page?.let {
transaction {
log.info("page:${it}")
return@transaction Notification.find{
(Notifications.receiverId eq vo.receiverId) and
(Notifications.receiverClient eq vo.receiverClient.name) }.
limit(n=it.pageSize,offset = (it.currentPage-1)*it.pageSize).map {
NotificationVo(title=it.title,id=it.id.value,content = it.content,createTime = it.createTime.toEpochSecond(
ZoneOffset.of("+8"))*1000)
}
}
}
}
}
/**
* 后台服务
*/
object BackgroundService:AbstractService(){
override fun init(environment: ApplicationEnvironment) {
super.init(environment)
initManager()
}
/**
* 前台任务通知管理员处理
*
*/
fun createBackgroundNotification(content:String,title:String,duty: Duty){
Manager.find { Managers.duty eq duty.name }.apply {
if(count()==0L){
log.warn("找不到适当的${duty.desc}处理此任务")
}else{
forEach {
Notification.new {
this.title = title
this.content = content
receiverId= it.id.value
receiverClient=ReceiverType.Background.name
}
}
}
}
}
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
level=duty.level
}.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")
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("不需要生成管理员")
}
}
}
}
}
}