Skip to content

Commit

Permalink
Merge pull request #93 from metakgp/approve_paper
Browse files Browse the repository at this point in the history
Admin DashBoard Endpoint: Approve Paper
  • Loading branch information
rajivharlalka authored Sep 24, 2024
2 parents 0053555 + b2f36cc commit 5ae618e
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 5 deletions.
59 changes: 58 additions & 1 deletion backend/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/metakgp/iqps/backend/pkg/config"
"github.com/metakgp/iqps/backend/pkg/db"
"github.com/metakgp/iqps/backend/pkg/models"
"github.com/metakgp/iqps/backend/pkg/utils"
"github.com/metakgp/iqps/backend/query"
)

Expand Down Expand Up @@ -57,6 +58,62 @@ func HandleQPYear(w http.ResponseWriter, r *http.Request) {
sendResponse(w, http.StatusOK, map[string]int{"min": minYear, "max": maxYear})
}

func HandleApprovePaper(w http.ResponseWriter, r *http.Request) {
approverUsername := r.Context().Value(CLAIMS_KEY).(*Claims).Username

db := db.GetDB()
var qpDetails models.QuestionPaper
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&qpDetails); err != nil {
sendErrorResponse(w, http.StatusInternalServerError, "Could not find Question Paper, Try Later!", nil)
config.Get().Logger.Errorf("HandleApprovePaper: could not approve paper, invalid Body: %+v", err.Error())
return
}

destFileLink := fmt.Sprintf("peqp/qp/%s_%s_%v_%v_%v.pdf", qpDetails.CourseCode, qpDetails.CourseName, qpDetails.Year, qpDetails.Semester, qpDetails.Exam)
srcFile := filepath.Join(config.Get().StaticFilesStorageLocation, qpDetails.FileLink)
destFile := utils.SanitizeFileLink(filepath.Join(config.Get().StaticFilesStorageLocation, destFileLink))

err := utils.CopyFile(srcFile, destFile)
if err != nil {
sendErrorResponse(w, http.StatusInternalServerError, "Could not move Question Paper, Try Later!", nil)
config.Get().Logger.Errorf("HandleApprovePaper: could not approve paper, could not move question paper: %+v", err.Error())
return
}

newQPDetails := models.QuestionPaper{
CourseCode: qpDetails.CourseCode,
CourseName: qpDetails.CourseName,
Year: qpDetails.Year,
Exam: qpDetails.Exam,
FileLink: destFileLink,
ApproveStatus: true,
Semester: qpDetails.Semester,
FromLibrary: false,
ApprovedBy: approverUsername,
}

id, err := db.InsertNewPaper(&newQPDetails)
if err != nil {
// undelete file
utils.DeleteFile(destFile)
sendErrorResponse(w, http.StatusInternalServerError, "could not update file details, try again later", nil)
config.Get().Logger.Errorf("HandleApprovePaper: Could not approve paper: %+v", err.Error())
return
}
// log line to help which entry was made by deleting which paper for recovery
config.Get().Logger.Infof("HandleApprovePaper: Id %d added against Id %d", id, qpDetails.ID)

err = db.MarkPaperAsSoftDeletedAndUnApprove(qpDetails.ID)
if err != nil {
utils.DeleteFile(destFile)
sendErrorResponse(w, http.StatusInternalServerError, "error updating paper details!", nil)
config.Get().Logger.Errorf("HandleApprovePaper: error soft-deleting paper: %+v PaperDetails: %d", err.Error(), qpDetails.ID)
return
}
sendResponse(w, http.StatusOK, httpResp{Message: "File Approved successfully"})
}

func HandleLibraryPapers(w http.ResponseWriter, r *http.Request) {
db := db.GetDB()
rows, err := db.Db.Query(context.Background(), "SELECT id, course_code, course_name, year, exam, filelink, from_library FROM iqps WHERE from_library = 'true'")
Expand Down Expand Up @@ -114,7 +171,7 @@ func HandleQPSearch(w http.ResponseWriter, r *http.Request) {
var qps []models.QuestionPaper = make([]models.QuestionPaper, 0)
for rows.Next() {
qp := models.QuestionPaper{}
err := rows.Scan(&qp.ID, &qp.CourseCode, &qp.CourseName, &qp.Year, &qp.Exam, &qp.FileLink, &qp.FromLibrary, &qp.UploadTimestamp, &qp.ApproveStatus)
err := rows.Scan(&qp.ID, &qp.CourseCode, &qp.CourseName, &qp.Year, &qp.Exam, &qp.FileLink, &qp.FromLibrary, &qp.UploadTimestamp, &qp.ApproveStatus, &qp.Semester)
if err != nil {
config.Get().Logger.Error("HandleQPSearch: Error parsing question paper details")
sendErrorResponse(w, http.StatusInternalServerError, err.Error(), nil)
Expand Down
1 change: 1 addition & 0 deletions backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func main() {
http.HandleFunc("POST /oauth", GhAuth)
http.Handle("GET /unapproved", JWTMiddleware(http.HandlerFunc(ListUnapprovedPapers)))
http.Handle("GET /all", JWTMiddleware(http.HandlerFunc(ListAllPapers)))
http.Handle("POST /approve", JWTMiddleware(http.HandlerFunc(HandleApprovePaper)))

logger := config.Get().Logger
c := cors.New(cors.Options{
Expand Down
39 changes: 39 additions & 0 deletions backend/pkg/db/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"

"github.com/jackc/pgx/v5"
"github.com/metakgp/iqps/backend/pkg/config"
"github.com/metakgp/iqps/backend/pkg/models"
)
Expand All @@ -31,3 +32,41 @@ func (db *db) FetchAllQuestionPapers() ([]models.QuestionPaper, error) {

return qps, nil
}

func (db *db) InsertNewPaper(qpDetails *models.QuestionPaper) (int, error) {
query := "INSERT INTO iqps (course_code, course_name, year, exam, filelink, semester, approve_status, from_library, approved_by) VALUES (@course_code, @course_name, @year, @exam, @filelink, @semester, @approve_status, @from_library, @approved_by) RETURNING id"
params := pgx.NamedArgs{
"course_code": qpDetails.CourseCode,
"course_name": qpDetails.CourseName,
"year": qpDetails.Year,
"exam": qpDetails.Exam,
"semester": qpDetails.Semester,
"filelink": qpDetails.FileLink,
"from_library": qpDetails.FromLibrary,
"approve_status": qpDetails.ApproveStatus,
"approved_by": qpDetails.ApprovedBy,
}
var id int
err := db.Db.QueryRow(context.Background(), query, params).Scan(&id)
if err != nil {
return 0, err
}
return id, nil
}

func (db *db) MarkPaperAsSoftDeletedAndUnApprove(qpID int) error {
query := "UPDATE iqps set approve_status=false, is_deleted = true where id=@qpID and is_deleted=false"
params := pgx.NamedArgs{
"qpID": qpID,
}

ct, err := db.Db.Exec(context.Background(), query, params)
if err != nil {
return err
}

if ct.RowsAffected() == 0 {
return fmt.Errorf("no such paper found to be approved")
}
return nil
}
8 changes: 5 additions & 3 deletions backend/pkg/models/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ import (
)

type QuestionPaper struct {
ID int `json:"id"`
ID int `json:"id,string"`
CourseCode string `json:"course_code"`
CourseName string `json:"course_name"`
Year int `json:"year"`
Year int `json:"year,string"`
Exam string `json:"exam"`
FileLink string `json:"filelink"`
FromLibrary bool `json:"from_library"`
UploadTimestamp pgtype.Timestamp `json:"upload_timestamp,omitempty"`
ApproveStatus bool `json:"approve_status"`
CourseDetails string `json:"course_details,omitempty"`
Semester string `json:"semester"`
IsDeleted bool `json:"is_deleted,omitempty"`
ApprovedBy string `json:"approved_by,omitempty"`
}

type UploadEndpointRes struct {
Expand Down
44 changes: 44 additions & 0 deletions backend/pkg/utils/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package utils

import (
"fmt"
"io"
"os"
"strings"
)

func CopyFile(srcPath, destPath string) error {
inputFile, err := os.Open(srcPath)
if err != nil {
return fmt.Errorf("couldn't open source file: %v", err)
}
defer inputFile.Close()

outputFile, err := os.Create(destPath)
if err != nil {
return fmt.Errorf("couldn't open dest file: %v", err)
}
defer outputFile.Close()

_, err = io.Copy(outputFile, inputFile)
if err != nil {
return fmt.Errorf("couldn't copy to dest from source: %v", err)
}

inputFile.Close()
return nil
}

func DeleteFile(path string) error {
err := os.Remove(path)
if err != nil {
return err
}
return nil
}

func SanitizeFileLink(path string) string {
result := strings.Replace(path, " ", "_", -1)
result = strings.TrimSpace(result)
return result
}
2 changes: 1 addition & 1 deletion backend/query/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ partial_search as (
limit 30
), result as (
select
iqps.id,iqps.course_code, iqps.course_name, iqps.year, iqps.exam, iqps.filelink, iqps.from_library, iqps.upload_timestamp, iqps.approve_status
iqps.id,iqps.course_code, iqps.course_name, iqps.year, iqps.exam, iqps.filelink, iqps.from_library, iqps.upload_timestamp, iqps.approve_status, iqps.semester
from
fuzzy
full outer join full_text on fuzzy.id = full_text.id
Expand Down

0 comments on commit 5ae618e

Please sign in to comment.