申请入团

master
pan 4 years ago
parent 484ecc4ad9
commit d340be70e4
  1. 14
      build.gradle.kts
  2. 44
      module/src/main/kotlin/com/gyf/csams/module/ShareVo.kt
  3. 6
      src/main/kotlin/com/gyf/csams/Controller.kt
  4. 36
      src/main/kotlin/com/gyf/csams/Dao.kt
  5. 2
      src/main/kotlin/com/gyf/csams/MySQL.kt
  6. 121
      src/main/kotlin/com/gyf/csams/Service.kt
  7. 3
      src/main/resources/application.conf
  8. 0
      src/main/resources/logback.xml
  9. 0
      src/main/resources/static/image/.gitkeep
  10. 10
      src/test/kotlin/ApplicationTest.kt
  11. 0
      src/test/resources/static/image/.gitkeep

@ -64,9 +64,13 @@ dependencies {
testImplementation("io.ktor:ktor-server-tests:$ktor_version") testImplementation("io.ktor:ktor-server-tests:$ktor_version")
} }
//
//kotlin.sourceSets["main"].kotlin.srcDirs("src")
//kotlin.sourceSets["test"].kotlin.srcDirs("test")
kotlin.sourceSets["main"].kotlin.srcDirs("src") listOf("main","test").forEach {
kotlin.sourceSets["test"].kotlin.srcDirs("test") kotlin.sourceSets[it].apply {
kotlin.srcDirs("src/${name}/kotlin")
sourceSets["main"].resources.srcDirs("resources") resources.srcDirs("src/${name}/resources")
sourceSets["test"].resources.srcDirs("testresources") }
}

@ -626,7 +626,7 @@ data class ManagerDutySumVo(val secretariat:ManagerDutyVo,
val publicRelationsDepartment:ManagerDutyVo) val publicRelationsDepartment:ManagerDutyVo)
data class ExamVo(val questionId:Int?=null,val question:String,val optionsA:String,val optionsB:String,val optionsC:String,val optionsD:String,val answer:Int) data class ExamVo(val questionId:Int?=null,val question:String,val optionsA:String,val optionsB:String,val optionsC:String,val optionsD:String,val rightOption:Int)
/** /**
* 更新题库 * 更新题库
@ -641,32 +641,12 @@ data class AddExamVo(val questions:List<ExamVo>,
override val clientType: ClientType=ClientType.Foreground, override val clientType: ClientType=ClientType.Foreground,
val associationId:Int):ClientBaseVo() val associationId:Int):ClientBaseVo()
data class SearchExamVo(val associationId:Int, override val token: Token, override val clientType: ClientType=ClientType.Foreground):ClientBaseVo() data class SearchExamVo(val associationId:Int, override val token: Token,
override val clientType: ClientType=ClientType.Foreground):ClientBaseVo()
/**
* 试卷
*
* @property user
* @property createTime
* @property applyTime
*/
data class TestPaperVo(val user: UserInfoVo,val createTime: Long,val applyTime: Long?)
/**
* 试题
*
*/ data class ApplyAnswerVo(val examVo: ExamVo,val answer:Int)
data class AnswerVo(val examVo: ExamVo,val answer:Int?=null,val paperVo: TestPaperVo)
/**
* 答题记录
*
* @property questionId
* @property paperId
* @property answer
*/
data class ApplyAnswerVo(val questionId:Int,val paperId:Int,val answer:Int)
/** /**
* 答卷 * 答卷
* *
@ -675,21 +655,15 @@ data class ApplyAnswerVo(val questionId:Int,val paperId:Int,val answer:Int)
* @property clientType * @property clientType
*/ */
data class AddAnswerVo(val answers:List<ApplyAnswerVo>, data class AddAnswerVo(val answers:List<ApplyAnswerVo>,
val associationId:Int, override val token: Token,
override val token: Token, override val clientType: ClientType=ClientType.Foreground):ClientBaseVo() val associationId: Int,
override val clientType: ClientType=ClientType.Foreground):ClientBaseVo()
data class ShowAnswerVo(val joinId:Int, override val token: Token, data class ShowAnswerVo(val joinId:Int, override val token: Token,
override val clientType: ClientType=ClientType.Foreground):ClientBaseVo() override val clientType: ClientType=ClientType.Foreground):ClientBaseVo()
/**
* 申请入团
*
* @property associationId
* @property token
* @property clientType
*/
data class ApplyAssociationVo(val associationId:Int, override val token: Token, override val clientType: ClientType=ClientType.Foreground):ClientBaseVo()
/** /**
* 申请入团检查 * 申请入团检查
*/ */

@ -375,7 +375,7 @@ fun Application.AssociationController() {
post("/check/apply"){ post("/check/apply"){
call.withToken<ApplyAssociationVo> { call.withToken<SearchExamVo> {
try { try {
val body=AssociationService.applyAssociation(vo = it) val body=AssociationService.applyAssociation(vo = it)
call.respond(ApiResponse(message = "入团验证信息获取成功",body =body)) call.respond(ApiResponse(message = "入团验证信息获取成功",body =body))
@ -387,7 +387,7 @@ fun Application.AssociationController() {
} }
post("/create/paper"){ post("/create/paper"){
call.withToken<ApplyAssociationVo> { call.withToken<SearchExamVo> {
try { try {
call.respond(ApiResponse(message = "试卷创建成功,请开始作答",body = AssociationService.createPaper(vo=it))) call.respond(ApiResponse(message = "试卷创建成功,请开始作答",body = AssociationService.createPaper(vo=it)))
} catch (e: Exception) { } catch (e: Exception) {
@ -411,7 +411,7 @@ fun Application.AssociationController() {
post("/check/join"){ post("/check/join"){
call.withToken<ApplyAssociationVo> { call.withToken<SearchExamVo> {
try { try {
call.respond(ApiResponse(message = "入团记录查询成功",body=AssociationService.joinAssociation(vo=it))) call.respond(ApiResponse(message = "入团记录查询成功",body=AssociationService.joinAssociation(vo=it)))
} catch (e: Exception) { } catch (e: Exception) {

@ -1,7 +1,6 @@
package com.gyf.csams package com.gyf.csams
import com.gyf.csams.Notifications.defaultExpression
import com.gyf.csams.TestPapers.defaultExpression
import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.EntityID
@ -433,44 +432,23 @@ class Question(id:EntityID<Int>):IntEntity(id){
var association by Association referencedOn Questions.associationId var association by Association referencedOn Questions.associationId
} }
@TableComment("试卷")
object TestPapers:IntIdTable(){
@TableComment("答题用户")
val userId:Column<EntityID<Int>> = reference("user_id",Users)
@TableComment("生成时间")
val createTime:Column<LocalDateTime> = datetime("create_time").defaultExpression(CurrentDateTime())
@TableComment("提交时间")
val applyTime:Column<LocalDateTime?> = datetime("apply_time").nullable()
}
class TestPaper(id:EntityID<Int>):IntEntity(id){
companion object:IntEntityClass<TestPaper>(TestPapers)
var user by User referencedOn TestPapers.userId
var createTime by TestPapers.createTime
var applyTime by TestPapers.applyTime
}
@TableComment("试题") @TableComment("试题")
object Answers:IntIdTable(){ object Answers:IntIdTable(){
@TableComment("问题") @TableComment("问题")
val questionId:Column<EntityID<Int>> = reference("question_id",Questions) val questionId:Column<EntityID<Int>> = reference("question_id",Questions)
@TableComment("答案") @TableComment("答案")
val answer:Column<Int?> = integer("answer").nullable() val answer:Column<Int> = integer("answer")
@TableComment("试卷") @TableComment("入团申请记录")
val paperId:Column<EntityID<Int>> = reference("paper_id",TestPapers) val joinId:Column<EntityID<Int>> = reference("join_id",JoinAssociations)
} }
class Answer(id:EntityID<Int>):IntEntity(id){ class Answer(id:EntityID<Int>):IntEntity(id){
companion object:IntEntityClass<Answer>(Answers) companion object:IntEntityClass<Answer>(Answers)
var question by Question referencedOn Answers.questionId var question by Question referencedOn Answers.questionId
var answer by Answers.answer var answer by Answers.answer
var paper by TestPaper referencedOn Answers.paperId var join by JoinAssociation referencedOn Answers.joinId
} }
@TableComment("入团申请记录") @TableComment("入团申请记录")
@ -487,9 +465,6 @@ object JoinAssociations:IntIdTable(){
@TableComment("审核时间") @TableComment("审核时间")
val auditTime:Column<LocalDateTime?> = datetime("audit_time").nullable() val auditTime:Column<LocalDateTime?> = datetime("audit_time").nullable()
@TableComment("试卷")
val paperId:Column<EntityID<Int>?> = reference("paper_id",TestPapers).nullable()
@TableComment("申请结果") @TableComment("申请结果")
val result:Column<Boolean?> = bool("result").nullable() val result:Column<Boolean?> = bool("result").nullable()
} }
@ -498,7 +473,6 @@ class JoinAssociation(id:EntityID<Int>):IntEntity(id){
companion object:IntEntityClass<JoinAssociation>(JoinAssociations) companion object:IntEntityClass<JoinAssociation>(JoinAssociations)
var user by User referencedOn JoinAssociations.userId var user by User referencedOn JoinAssociations.userId
var association by Association referencedOn JoinAssociations.associationId var association by Association referencedOn JoinAssociations.associationId
var paper by TestPaper optionalReferencedOn JoinAssociations.paperId
var result by JoinAssociations.result var result by JoinAssociations.result
var applyTime by JoinAssociations.applyTime var applyTime by JoinAssociations.applyTime
var auditTime by JoinAssociations.auditTime var auditTime by JoinAssociations.auditTime

@ -42,7 +42,7 @@ fun initTable(){
transaction { transaction {
val tableList= arrayOf(Users,UserTokens,Managers,ManagerTokens,AuditLeggings,LeaveMessages, val tableList= arrayOf(Users,UserTokens,Managers,ManagerTokens,AuditLeggings,LeaveMessages,
ImageFiles,Associations,AssociationMembers,Notifications,Activities,PhotoAlbums,ActivityComments, ImageFiles,Associations,AssociationMembers,Notifications,Activities,PhotoAlbums,ActivityComments,
Renames,Questions,TestPapers,Answers,JoinAssociations) Renames,Questions,Answers,JoinAssociations)
SchemaUtils.createMissingTablesAndColumns(*tableList) SchemaUtils.createMissingTablesAndColumns(*tableList)
updateComment(*tableList) updateComment(*tableList)

@ -44,13 +44,19 @@ object AccountService : AbstractService() {
} }
} }
fun toUserInfo(user: User):UserInfoVo{
return UserInfoVo(name = user.name, headImg = user.headImg?.filepath, desc = user.desc)
}
/** /**
* 注册 * 注册
*/ */
fun register(userVo: UserRegVo): String? { fun register(userVo: UserRegVo): String? {
try { try {
return transaction { return transaction {
val originPassword = randomNum(8)
val originPassword = if(environment.developmentMode) (1..8).joinToString("") else randomNum(8)
log.info("密码:${originPassword}")
User.new { User.new {
studentId = userVo.studentId studentId = userVo.studentId
name = userVo.name name = userVo.name
@ -324,7 +330,7 @@ object MainService : AbstractService() {
return@transaction LeaveMessage.all().toList().map { return@transaction LeaveMessage.all().toList().map {
LeaveMessageDto( LeaveMessageDto(
message = "${it.user.name}说:${it.message}", message = "${it.user.name}说:${it.message}",
user = UserInfoVo(name = it.user.name, headImg = it.user.headImg?.filepath, desc = it.user.desc) user = AccountService.toUserInfo(user = it.user)
) )
} }
} }
@ -342,8 +348,10 @@ object FileService : AbstractService() {
super.init(environment) super.init(environment)
this.uploadDir = environment.config.property("ktor.deployment.filePath").getString() this.uploadDir = environment.config.property("ktor.deployment.filePath").getString()
log.info(this::class.java.classLoader.getResource("")?.path)
filePath = filePath =
this::class.java.classLoader.getResource(uploadDir)?.path ?: throw IllegalArgumentException("初始化资源目录失败") environment.classLoader.getResource(uploadDir)?.path ?: throw IllegalArgumentException("初始化资源目录失败")
File(filePath).let { File(filePath).let {
when { when {
it.exists() -> log.info("上传路径[${filePath}]已存在") it.exists() -> log.info("上传路径[${filePath}]已存在")
@ -690,12 +698,7 @@ abstract class AuditService<T, E, F> : AbstractService() {
return it?.let { logging -> return it?.let { logging ->
val auditLogging = AuditLoggingVo( val auditLogging = AuditLoggingVo(
id = logging.id.value, id = logging.id.value,
user = user = AccountService.toUserInfo(user = logging.user),
UserInfoVo(
name = logging.user.name,
headImg = logging.user.headImg?.filepath,
desc = logging.user.desc
),
applyTime = logging.applyTime.toLong(), applyTime = logging.applyTime.toLong(),
manager = logging.manager?.let { manager = logging.manager?.let {
ManagerInfoVo( ManagerInfoVo(
@ -775,7 +778,7 @@ object AssociationService : AuditService<AssociationRegVo, AuditAssociationVo, A
private fun toExamVo(question:Question):ExamVo{ private fun toExamVo(question:Question):ExamVo{
return ExamVo(questionId = question.id.value,question=question.question,optionsA = question.optionsA, return ExamVo(questionId = question.id.value,question=question.question,optionsA = question.optionsA,
optionsB = question.optionsB,optionsC = question.optionsC,optionsD = question.optionsD,answer = question.answer) optionsB = question.optionsB,optionsC = question.optionsC,optionsD = question.optionsD,rightOption = question.answer)
} }
/** /**
@ -798,37 +801,43 @@ object AssociationService : AuditService<AssociationRegVo, AuditAssociationVo, A
*/ */
fun applyAnswer(vo:AddAnswerVo){ fun applyAnswer(vo:AddAnswerVo){
transaction { transaction {
val association= Association.findById(vo.associationId)?:throw AssociationIdError(vo.associationId)
val user=User.findById(vo.token.id)?:throw UserIdError(vo.token.id) 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 { vo.answers.forEach {
val question=Question.findById(it.questionId)?:throw IllegalArgumentException("不存在[id=${it.questionId}]的问题") val id=it.examVo.questionId?:throw IllegalArgumentException("问题id不存在")
val paper=TestPaper.findById(it.paperId)?:throw IllegalArgumentException("不存在[id=${it.paperId}]的问题")
val question=Question.findById(id)?:throw IllegalArgumentException("不存在[id=${id}]的问题")
Answer.new { Answer.new {
this.question=question this.question=question
answer=it.answer answer= it.answer
this.paper=paper this.join=join
} }
} }
createJoin(association = association,user=user)
} }
} }
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 * @param vo
* @return * @return
*/ */
fun showAnswer(vo:ShowAnswerVo):List<AnswerVo>{ fun showAnswer(vo:ShowAnswerVo):List<ApplyAnswerVo>{
return transaction { return transaction {
val join=JoinAssociation.findById(vo.joinId)?:throw IllegalArgumentException("找不到[id=${vo.joinId}]申请记录") val join=JoinAssociation.findById(vo.joinId)?:throw IllegalArgumentException("找不到[id=${vo.joinId}]申请记录")
val paperId= join.paper?.id?:throw IllegalArgumentException("[id=${join.id}]没有关联试卷") Answer.find{ Answers.joinId eq join.id }.map {
val paper=TestPaper.findById(paperId)?:throw IllegalArgumentException("[id=${paperId}]关联的试卷不存在") ApplyAnswerVo(examVo = toExamVo(it.question),answer = it.answer)
Answer.find { Answers.paperId eq paperId}.map {
AnswerVo(examVo = toExamVo(it.question),answer = it.answer,paperVo =
TestPaperVo(user = UserInfoVo(name=join.user.name,headImg = join.user.headImg?.filepath,desc=join.user.desc),
createTime = paper.createTime.toLong(),applyTime = paper.applyTime?.toLong()))
} }
} }
} }
@ -840,21 +849,10 @@ object AssociationService : AuditService<AssociationRegVo, AuditAssociationVo, A
* @param association * @param association
* @param user * @param user
*/ */
private fun createJoin(association: Association,user:User){ private fun createJoin(association: Association,user:User):JoinAssociation{
JoinAssociation.new { return JoinAssociation.new {
this.association=association this.association=association
this.user=user this.user=user
}.apply {
//通知团长处理
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
}
}
} }
} }
@ -864,23 +862,11 @@ object AssociationService : AuditService<AssociationRegVo, AuditAssociationVo, A
* @param vo * @param vo
* @return * @return
*/ */
fun createPaper(vo:ApplyAssociationVo):List<ExamVo>{ fun createPaper(vo:SearchExamVo):List<ExamVo>{
return transaction { return transaction {
val association= Association.findById(vo.associationId)?:throw AssociationIdError(vo.associationId) val association= Association.findById(vo.associationId)?:throw AssociationIdError(vo.associationId)
val user=User.findById(vo.token.id)?:throw UserIdError(vo.token.id)
Question.find { Questions.associationId eq association.id }.let { it -> Question.find { Questions.associationId eq association.id }.let { it ->
val paper=TestPaper.new { it.shuffled().map {
this.user=user
this.applyTime= LocalDateTime.now()
}
it.shuffled().apply {
forEach {
Answer.new {
this.paper=paper
this.question=it
}
}
}.map {
toExamVo(question = it) toExamVo(question = it)
} }
} }
@ -888,11 +874,23 @@ object AssociationService : AuditService<AssociationRegVo, AuditAssociationVo, A
} }
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:ApplyAssociationVo):ApplyAssociationResultVo{ fun applyAssociation(vo:SearchExamVo):ApplyAssociationResultVo{
return transaction { return transaction {
val user=User.findById(vo.token.id)?:throw UserIdError(vo.token.id) val user=User.findById(vo.token.id)?:throw UserIdError(vo.token.id)
val association= Association.findById(vo.associationId)?:throw AssociationIdError(vo.associationId) val association= Association.findById(vo.associationId)?:throw AssociationIdError(vo.associationId)
@ -910,6 +908,7 @@ object AssociationService : AuditService<AssociationRegVo, AuditAssociationVo, A
//免试入团申请 //免试入团申请
else{ else{
createJoin(association=association,user=user) createJoin(association=association,user=user)
createJoinNotification(association=association,user=user)
ApplyAssociationResultVo(result = true,hasPaper = false) ApplyAssociationResultVo(result = true,hasPaper = false)
} }
} }
@ -920,19 +919,11 @@ object AssociationService : AuditService<AssociationRegVo, AuditAssociationVo, A
* 入团申请记录 * 入团申请记录
* *
*/ */
fun joinAssociation(vo:ApplyAssociationVo):List<JoinAssociationVo>{ fun joinAssociation(vo:SearchExamVo):List<JoinAssociationVo>{
return transaction { return transaction {
val association=Association.findById(vo.associationId)?:throw AssociationIdError(vo.associationId) val association=Association.findById(vo.associationId)?:throw AssociationIdError(vo.associationId)
val user=User.findById(vo.token.id)?:throw UserIdError(vo.token.id) JoinAssociation.find { JoinAssociations.associationId eq association.id }.sortedByDescending { it.applyTime }.map {
toJoinVo(join=it)
JoinAssociation.find { JoinAssociations.associationId eq association.id }.map {
val userInfoVo=UserInfoVo(name = user.name,headImg = user.headImg?.filepath,desc=user.desc)
JoinAssociationVo(user = userInfoVo,
associationVo = toAssociationVo(it.association),
hasPaper = it.paper!=null,result = it.result,
applyTime = it.applyTime.toLong(),
auditTime = it.auditTime?.toLong(),id = it.id.value)
} }
} }
} }
@ -1001,7 +992,7 @@ object AssociationService : AuditService<AssociationRegVo, AuditAssociationVo, A
optionsB = exam.optionsB optionsB = exam.optionsB
optionsC = exam.optionsC optionsC = exam.optionsC
optionsD = exam.optionsD optionsD = exam.optionsD
this.answer = exam.answer this.answer = exam.rightOption
this.association = association this.association = association
} }
} else { } else {
@ -1012,7 +1003,7 @@ object AssociationService : AuditService<AssociationRegVo, AuditAssociationVo, A
optionsB = exam.optionsB optionsB = exam.optionsB
optionsC = exam.optionsC optionsC = exam.optionsC
optionsD = exam.optionsD optionsD = exam.optionsD
this.answer = exam.answer this.answer = exam.rightOption
} }
} }
} }
@ -1286,7 +1277,7 @@ object ActivityService : AuditService<ActivityApplyVo, AuditActVo, ActivityCheck
return transaction { return transaction {
ActivityComment.find { ActivityComments.activityId eq vo.activityId }.map { ActivityComment.find { ActivityComments.activityId eq vo.activityId }.map {
BBSVo( BBSVo(
user = UserInfoVo(name = it.user.name, headImg = it.user.headImg?.filepath, desc = it.user.desc), user = AccountService.toUserInfo(it.user),
createTime = it.createTime.toLong(), content = it.content createTime = it.createTime.toLong(), content = it.content
) )
} }

@ -1,4 +1,6 @@
ktor { ktor {
#开发模式
development = true
deployment { deployment {
port = 8080 port = 8080
port = ${?PORT} port = ${?PORT}
@ -12,6 +14,7 @@ ktor {
maxSize = 20 maxSize = 20
} }
filePath = static/image filePath = static/image
#免重启自动重载classes目录
watch = [ classes ] watch = [ classes ]
} }

@ -132,8 +132,12 @@ class ApplicationTest {
fun testAudit(){ fun testAudit(){
initApp { initApp {
transaction { transaction {
Notification.all().sortedByDescending { it.createTime }.forEach { JoinAssociation.all().sortedBy { it.applyTime.toLong() }.forEach {
println(it.createTime) println(it.applyTime)
}
println("排序")
JoinAssociation.all().sortedByDescending { it.applyTime.toLong() }.forEach {
println(it.applyTime)
} }
} }
} }
@ -156,7 +160,7 @@ class ApplicationTest {
@Test @Test
fun testStringFormat(){ fun testStringFormat(){
println(LocalDateTime.now()) (1..8).joinToString("").let { println(it) }
} }
/** /**
* 文档生成 * 文档生成
Loading…
Cancel
Save