Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added PVF verification routes and handlers #161

Merged
merged 9 commits into from
Jul 6, 2024
185 changes: 185 additions & 0 deletions application/admin.pvf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package application

import (
"net/http"

"github.com/gin-gonic/gin"
"github.com/spo-iitk/ras-backend/mail"
"github.com/spo-iitk/ras-backend/middleware"
"github.com/spo-iitk/ras-backend/util"
)

func getAllPvfForAdminHandler(ctx *gin.Context) {
rid, err := util.ParseUint(ctx.Param("rid"))
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var jps []PVF
err = fetchAllPvfForAdmin(ctx, rid, &jps)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

ctx.JSON(http.StatusOK, jps)

}

func getPvfForAdminHandler(ctx *gin.Context) {
rid, err := util.ParseUint(ctx.Param("rid"))
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
pid, err := util.ParseUint(ctx.Param("pid"))
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var jps PVF
err = fetchPvfForAdmin(ctx, rid, pid, &jps)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

ctx.JSON(http.StatusOK, jps)
}

func sendVerificationLinkForPvfHandler(mail_channel chan mail.Mail) gin.HandlerFunc {
return func(ctx *gin.Context) {
pid, err := util.ParseUint(ctx.Param("pid"))
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var pvf PVF

rid, err := util.ParseUint(ctx.Param("rid"))
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
err = fetchPvfForAdmin(ctx, rid, pid, &pvf)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
pvf.IsApproved.Valid = true
pvf.IsApproved.Bool = true

err = updatePVF(ctx, &pvf)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// token, err := middleware.GeneratePVFToken("[email protected]", pid, rid) // for testing
token, err := middleware.GeneratePVFToken(pvf.MentorEmail, pid, rid)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

// logrus.Infof("A Token %s with id %d", token, pid) // to be removed
message := "Dear " + pvf.MentorName + ",\n\n" +
pvf.Name + " (email: " + pvf.IITKEmail + ") has requested your verification for a project/internship they completed under your guidance.\n\n" +
"To verify the details and electronically sign the Project Verification Form (PVF), please click the link below (valid upto 3days):\n\n\n" +
"https://placement.iitk.ac.in/verify?token=" + token + "&rcid=" + util.ParseString(rid) + "\n\n" +
"Your prompt response is appreciated to ensure timely processing of " + pvf.Name + "'s placement applications.\n\n" +
"Please note:\n" +
"The PVF verifies the student's involvement and contributions to the project/internship. " +
"Only projects/internships conducted with IIT Kanpur faculty or external organizations require verification. " +
"If you have any questions regarding the PVF process, please don't hesitate to contact the Students' Placement Office at [email protected].\n\n" +
"Thank you for your time and support."

mail_channel <- mail.GenerateMail(pvf.MentorEmail,
"Project Verification Required for "+pvf.Name+"'s Internship/Project",
message,
)

// mail_channel <- mail.GenerateMail("[email protected]",
// "Registration requested on RAS",
// "Company "+pvf.Duration+" has requested to be registered on RAS. The details are as follows:\n\n"+
// "Name: "+pvf.CompanyUniversityName+"\n"+
// "Designation: "+pvf.MentorDesignation+"\n"+
// "Email: "+pvf.MentorEmail+"\n"+
// "Phone: "+pvf.FileName+"\n"+
// "Comments: "+pvf.Duration+"\n")
// ctx.JSON(http.StatusOK, gin.H{"pid": pid}) // to be removed
ctx.JSON(http.StatusOK, gin.H{"status": "Successfully Requested"})
}
}

func deletePVFHandler(ctx *gin.Context) {
pid, err := util.ParseUint(ctx.Param("pid"))
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

err = deletePVF(ctx, pid)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

ctx.JSON(http.StatusOK, gin.H{"status": "deleted PVF"})
}

func putPVFHandlerForAdmin(ctx *gin.Context) {
var jp PVF

rid, err := util.ParseUint(ctx.Param("rid"))
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

err = ctx.ShouldBindJSON(&jp)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

if jp.ID == 0 {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "id is required"})
return
}

var oldJp PVF
err = fetchPvfForAdmin(ctx, rid, jp.ID, &oldJp)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

err = updatePVF(ctx, &jp)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
ctx.JSON(http.StatusOK, gin.H{"status": "Updated PVF with id " + util.ParseString(jp.ID)})
}

func getAllStudentPvfHandler(ctx *gin.Context) {
rid, err := util.ParseUint(ctx.Param("rid"))
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

sid, err := util.ParseUint(ctx.Param("sid"))
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var pvfs []PVF
err = fetchAllPvfForStudent(ctx, sid, rid, &pvfs)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
ctx.JSON(http.StatusOK, pvfs)

}
2 changes: 1 addition & 1 deletion application/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func openConnection() {
db = database

err = db.AutoMigrate(&Proforma{}, &ApplicationQuestion{}, &ApplicationQuestionAnswer{},
&ProformaEvent{}, &EventCoordinator{}, &EventStudent{}, &ApplicationResume{})
&ProformaEvent{}, &EventCoordinator{}, &EventStudent{}, &ApplicationResume{}, &PVF{})
if err != nil {
logrus.Fatal("Failed to migrate application database: ", err)
panic(err)
Expand Down
95 changes: 95 additions & 0 deletions application/db.pvf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package application

import (
"github.com/gin-gonic/gin"
)

func createPVF(ctx *gin.Context, pvf *PVF) error {
tx := db.WithContext(ctx).Create(pvf)
return tx.Error
}

func fetchPVF(ctx *gin.Context, pid uint, jp *PVF) error {
tx := db.WithContext(ctx).Where("id = ?", pid).First(jp)
return tx.Error
}

func updatePVF(ctx *gin.Context, jp *PVF) error {
tx := db.WithContext(ctx).Where("id = ?", jp.ID).Updates(jp)
return tx.Error
}

func fetchAllPvfForStudent(ctx *gin.Context, sid uint, rid uint, jps *[]PVF) error {
tx := db.WithContext(ctx).
Where("student_recruitment_cycle_id = ? AND recruitment_cycle_id = ?", sid, rid).
Order("id DESC").
Find(jps)
return tx.Error
}
func fetchPvfForStudent(ctx *gin.Context, sid uint, rid uint, pid uint, jps *PVF) error {
tx := db.WithContext(ctx).
Where("student_recruitment_cycle_id = ? AND recruitment_cycle_id = ? AND id = ?", sid, rid, pid).
Select(
"id",
"company_university_name",
"role",
"duration",
"mentor_name",
"mentor_designation",
"mentor_email",
"is_verified",
"filename_mentor",
"filename_student",
"remarks",
).
Find(jps)
return tx.Error
}
func fetchPvfForAdmin(ctx *gin.Context, rid uint, pid uint, jps *PVF) error {
tx := db.WithContext(ctx).
Where("recruitment_cycle_id = ? AND id = ?", rid, pid).
Order("id DESC").
Find(jps)
return tx.Error
}

func fetchPvfForVerification(ctx *gin.Context, id uint, rid uint, jps *PVF) error {
tx := db.WithContext(ctx).
Where("id = ? AND recruitment_cycle_id = ?", id, rid).
Select(
"id",
"company_university_name",
"role",
"duration",
"mentor_name",
"mentor_designation",
"mentor_email",
"is_verified",
"is_approved",
"filename_student",
"filename_mentor",
"remarks",
).
Find(jps)
return tx.Error
}

func fetchAllPvfForAdmin(ctx *gin.Context, rid uint, jps *[]PVF) error {
tx := db.WithContext(ctx).
Where("recruitment_cycle_id = ?", rid).
Order("id DESC").
Find(jps)
return tx.Error
}

func deletePVF(ctx *gin.Context, pid uint) error {
tx := db.WithContext(ctx).Where("id = ?", pid).Delete(&PVF{})
return tx.Error
}

// func fetchAllStudentPvfForAdmin(ctx *gin.Context)

func updatePVFForStudent(ctx *gin.Context, sid uint, jp *PVF) (bool, error) {
tx := db.WithContext(ctx).Where("id = ? AND student_recruitment_cycle_id = ?", jp.ID, sid).Updates(jp)
return tx.RowsAffected == 1, tx.Error
}
20 changes: 20 additions & 0 deletions application/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,23 @@ type ApplicationResume struct {
ResumeID uint `json:"resume_id"`
Resume string `json:"resume"`
}

type PVF struct {
gorm.Model
RollNo string `json:"roll_no"`
Name string `json:"name"`
IITKEmail string `json:"iitk_email"`
StudentRecruitmentCycleID uint `json:"student_recruitment_cycle_id" gorm:"index;->;<-:create"`
CompanyUniversityName string `json:"company_university_name"`
Role string `json:"role"`
Duration string `json:"duration"`
Remarks string `json:"remarks"`
MentorName string `json:"mentor_name"`
MentorDesignation string `json:"mentor_designation"`
MentorEmail string `json:"mentor_email"`
IsApproved sql.NullBool `json:"is_approved" gorm:"index;default:NULL"`
IsVerified sql.NullBool `json:"is_verified" gorm:"index;default:NULL"`
RecruitmentCycleID uint `json:"recruitment_cycle_id" gorm:"index;->;<-:create"`
FilenameStudent string `json:"filename_student"`
FilenameMentor string `json:"filename_mentor"`
}
23 changes: 23 additions & 0 deletions application/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ func AdminRouter(mail_channel chan mail.Mail, r *gin.Engine) {
admin.DELETE("event/:eid/student", deleteAllStudentsFromEventHandler)
admin.DELETE("event/:eid/student/:sid", deleteStudentFromEventHandler)

admin.GET("/pvf", getAllPvfForAdminHandler)
admin.PUT("/pvf", putPVFHandlerForAdmin)
admin.GET("/pvf/:pid", getPvfForAdminHandler)
admin.GET("pvf/:pid/verification/send", sendVerificationLinkForPvfHandler(mail_channel))
admin.DELETE("pvf/:pid", deletePVFHandler)
admin.GET("pvf/student/:sid", getAllStudentPvfHandler)

admin.GET("/company/:cid/proforma", getProformaByCompanyHandler)
admin.GET("/company/:cid/stats", getCompanyRecruitStatsHandler)
admin.POST("/company/count", fetchCompanyRecruitCountHandler)
Expand Down Expand Up @@ -63,6 +70,12 @@ func StudentRouter(mail_channel chan mail.Mail, r *gin.Engine) {
student.GET("/proforma/:pid", getProformaForStudentHandler)
student.GET("/proforma/:pid/event", getEventsByProformaForStudentHandler)

student.POST("/pvf", postPvfForStudentHandler)
student.PUT("/pvf/:pid", putPVFForStudentHandler)
student.GET("/pvf", getAllPvfForStudentHandler)
student.GET("/pvf/:pid", getPvfForStudentHandler)
student.DELETE("pvf/:pid", deletePVFHandler)

student.GET("/opening", getProformasForEligibleStudentHandler)
student.GET("/opening/:pid", getApplicationHandler)
student.POST("/opening/:pid", postApplicationHandler(mail_channel))
Expand Down Expand Up @@ -98,3 +111,13 @@ func CompanyRouter(r *gin.Engine) {
company.GET("/event/:eid/student", getStudentsByEventForCompanyHandler)
}
}

func PvfVerificationRouter(r *gin.Engine) {
pvf := r.Group("/api/verification")
pvf.Use()
{
pvf.GET("/pvf", getPvfForVerificationHandler)
// pvf.PUT("pvf/:pid/verify", verifyPvfHandler)
pvf.PUT("/pvf", putPVFHandler)
}
}
Loading
Loading