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

Admin DashBoard Endpoint: Approve Paper #93

Merged
merged 2 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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