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

Feat/teacher #3

Merged
merged 38 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
5b5e9f2
fix: init teacher module
Risc-lt Jul 12, 2024
0c46943
first version of pull TrainingPlan script(python version).
Ayanami1314 Jul 12, 2024
a9c7ee0
fix: move TeacherDTO into teacher.go and add email field
Risc-lt Jul 13, 2024
a1ea0bd
fix: move TeacherPO into teacher.po and add email
Risc-lt Jul 13, 2024
9b58ec7
feat: TeacherPO with Name()
Risc-lt Jul 13, 2024
e973b86
feat: basic convertor, dto, domain and po for teacher
Risc-lt Jul 13, 2024
a510306
fix: teacher convertor with courses
Risc-lt Jul 13, 2024
e1d2fe8
First version of getting tearcher profile scrapy in utils/teacher-pro…
Ayanami1314 Jul 13, 2024
dc200cb
Merge branch 'feat/teacher' of github.com:SJTU-jCourse/jcourse_go int…
Ayanami1314 Jul 13, 2024
665926a
Merge branch 'feat/teacher' of github.com:SJTU-jCourse/jcourse_go int…
Ayanami1314 Jul 13, 2024
73e6ed4
Merge branch 'feat/teacher' of github.com:SJTU-jCourse/jcourse_go int…
Ayanami1314 Jul 13, 2024
31efe9f
Finish saving the txt/json downloads by scripy to db(load2db.go)
Ayanami1314 Jul 13, 2024
da65016
feat:First version of TrainingPlan's converter, repository, po, servi…
Ayanami1314 Jul 14, 2024
2316fb3
feat: add query of teacher and BaseCourseDTO as well as ConvertBaseCo…
Risc-lt Jul 15, 2024
92a5739
feat: services of getting detailed teacher info and teacher lists
Risc-lt Jul 15, 2024
c6de60e
node before merge
Ayanami1314 Jul 16, 2024
a145eca
Merge branch 'feat/teacher' of github.com:SJTU-jCourse/jcourse_go int…
Ayanami1314 Jul 16, 2024
5598417
First version of trainingplan implement.Lack of enough tests now.
Ayanami1314 Jul 16, 2024
8bb9717
fix:fix some bugs and pass simple test for trainingPlan-related api.
Ayanami1314 Jul 16, 2024
37c930a
feat: first version of teacher without teacher review and oauth to cr…
Risc-lt Jul 17, 2024
bfc49df
feat: add basic tests for teacher module
Risc-lt Jul 17, 2024
c86bce1
fix: move load2DB to load/
Risc-lt Jul 17, 2024
d8ccfbd
fix: fix bugs in teacher part and refactor the load part into cmd scr…
Ayanami1314 Aug 6, 2024
af6530d
feat:add basic trainingplan rate
Ayanami1314 Aug 7, 2024
a0b1fd2
before merge
Ayanami1314 Aug 9, 2024
8fcb3d4
fix: remove local change
Ayanami1314 Aug 9, 2024
a705388
fix: remove local change
Ayanami1314 Aug 9, 2024
50b4eed
fix: remove local change
Ayanami1314 Aug 9, 2024
b035175
fix: more robust test
Ayanami1314 Aug 9, 2024
fb872aa
fix: handle some code review issues(except for teacher, teaching_plan…
Ayanami1314 Aug 10, 2024
778d27c
fix: fix issues mentioned by code review
Ayanami1314 Aug 11, 2024
d24d52c
fix: fix issues mentioned by second code review
Ayanami1314 Aug 14, 2024
a31ff56
fix:rewind .gitignore
Ayanami1314 Aug 14, 2024
e1a2da1
Merge branch 'main' into feat/teacher
dujiajun Aug 15, 2024
8661e6c
fix: remove teacher and training_plan tests in repo
Risc-lt Aug 15, 2024
62f898f
fix: errors in golangci-lint
Risc-lt Aug 15, 2024
8033a08
fix: remove comments and run go mod tidy
Risc-lt Aug 15, 2024
e591305
fix: update the version of package bytedance/sonic
Risc-lt Aug 15, 2024
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
26 changes: 25 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*.dylib
/output
/data

**/data
# Test binary, built with `go test -c`
*.test

Expand All @@ -27,3 +27,27 @@ go.work.sum
.env

*.sqlite


# my dev
util/__pycache__
util/jac-auth.py
util/jaccount-scrapy.go
util/selenium_get.go
util/selenium-get.py
cmd/import_from_jwc/import_from_jwc.go
Risc-lt marked this conversation as resolved.
Show resolved Hide resolved
main.go
dal
**/data
log
*.db
cmd/**/*.py

.gitignore
*.pdf
**/*.txt

*.db
.gitignore
.github
.idea
60 changes: 60 additions & 0 deletions cmd/load/extend_teacher_profile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import (
"jcourse_go/dal"
"jcourse_go/model/po"
seleniumget "jcourse_go/util/selenium-get"
"log"
"os"
)

func main() {

Check failure on line 11 in cmd/load/extend_teacher_profile.go

View workflow job for this annotation

GitHub Actions / build

other declaration of main
dal.InitDBClient()
db := dal.GetDBClient()
extend_teacher_data_path := "./data/teachers.json"
log_file, err := os.OpenFile("./log/logfile.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
defer log_file.Close()
defer log.SetOutput(os.Stdout)

log.SetOutput(log_file)

extend_teachers := seleniumget.LoadTeacherProfiles(extend_teacher_data_path)

// to extend: email, profile_url, profile_desc, picture
for _, t := range extend_teachers {
// t.department 是全名,jwc是简称
var teachers []po.TeacherPO
db.Model(po.TeacherPO{}).Where("name = ?", t.Name).Find(&teachers)
if len(teachers) == 1 {
teachers[0].Email = t.Mail
teachers[0].ProfileURL = t.ProfileUrl
teachers[0].Biography = t.Biography
teachers[0].Picture = t.HeadImage
db.Save(&teachers[0])
continue
}
// len == 0, no need to extend
if len(teachers) > 1 {
confirm := false
for _, tt := range teachers {
if tt.Department == t.Department {
tt.Email = t.Mail
tt.ProfileURL = t.ProfileUrl
tt.Biography = t.Biography
tt.Picture = t.HeadImage
db.Save(&tt)
confirm = true
break
}
}
if !confirm {
log.Printf("name %s has multiple teachers, please extend by hand", t.Name)
}
}

}

}
78 changes: 78 additions & 0 deletions cmd/load/extend_training_plan.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package main

import (
"errors"
"fmt"
"gorm.io/gorm"
"jcourse_go/dal"
"jcourse_go/model/po"
seleniumget "jcourse_go/util/selenium-get"
"log"
"os"
"strconv"
)

func main() {

Check failure on line 15 in cmd/load/extend_training_plan.go

View workflow job for this annotation

GitHub Actions / build

main redeclared in this block
dal.InitDBClient()
db := dal.GetDBClient()
data_path := "./data/trainingPlan.txt"
log_file, err := os.OpenFile(fmt.Sprintf("./log/logfile.log"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
defer log_file.Close()
defer log.SetOutput(os.Stdout)
log.SetOutput(log_file)
allTrainingPlans := seleniumget.LoadTrainingPLans(data_path)

// 对齐trainingplan course 和 basecourse
var all_courses []po.BaseCoursePO
db.Model(po.BaseCoursePO{}).Find(&all_courses)

var tp_courses []seleniumget.LoadedCourse
for _, tp := range allTrainingPlans {
tp_courses = append(tp_courses, tp.Courses...)
}

for _, tp := range allTrainingPlans {
tp_po := po.TrainingPlanPO{
Degree: tp.Degree,
Major: tp.Name,
Department: tp.Department,
EntryYear: strconv.Itoa(tp.EntryYear),
TotalYear: tp.TotalYear,
MinCredits: tp.MinCredits,
MajorCode: tp.Code,
MajorClass: tp.MajorClass,
}
result := db.Model(po.TrainingPlanPO{}).Create(&tp_po)
if result.Error != nil {
log.Fatalf("In create training plan %#v:%#v", tp, result.Error)
}
for _, c := range tp.Courses {
course := po.BaseCoursePO{}
cresult := db.Model(po.BaseCoursePO{}).Where("code = ?", c.Code).First(&course)
if cresult.Error != nil {
if !errors.Is(cresult.Error, gorm.ErrRecordNotFound) {
log.Fatalf("In bind course %#v totraining plan %#v:%#v", c, tp, cresult.Error)
}
// HINT:for production
log.Printf("In bind course %#v totraining plan %#v:course not found", c, tp)
continue
}
tpc_po := po.TrainingPlanCoursePO{
TrainingPlanID: int64(tp_po.ID),
CourseID: int64(course.ID),
SuggestSemester: c.SuggestSemester,
Department: c.Department,
}
cresult = db.Model(po.TrainingPlanCoursePO{}).Create(&tpc_po)
if cresult.Error != nil {
if !errors.Is(cresult.Error, gorm.ErrRecordNotFound) {
log.Fatalf("In bind course %#v totraining plan %#v:%#v", c, tp, cresult.Error)
}
log.Printf("In bind course %#v totraining plan %#v:course not found", c, tp)
}
}
}
}
5 changes: 3 additions & 2 deletions cmd/migrate/migrate.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package main

import (
"github.com/joho/godotenv"
"jcourse_go/dal"
"jcourse_go/model/po"

"github.com/joho/godotenv"
)

func main() {
Expand All @@ -13,7 +14,7 @@ func main() {
err := db.AutoMigrate(&po.UserPO{},
&po.BaseCoursePO{}, &po.CoursePO{}, &po.TeacherPO{}, &po.CourseCategoryPO{},
&po.OfferedCoursePO{}, &po.OfferedCourseTeacherPO{},
&po.ReviewPO{}, &po.RatingPO{})
&po.ReviewPO{}, &po.RatingPO{}, &po.TrainingPlanPO{}, &po.TrainingPlanCoursePO{})
if err != nil {
panic(err)
}
Expand Down
5 changes: 3 additions & 2 deletions handler/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import (
"errors"
"net/http"

"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
"jcourse_go/constant"
"jcourse_go/model/domain"
"jcourse_go/model/dto"
"jcourse_go/service"

"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
)

func LoginHandler(c *gin.Context) {
Expand Down
112 changes: 109 additions & 3 deletions handler/teacher.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,113 @@
package handler

import "github.com/gin-gonic/gin"
import (
"jcourse_go/constant"
"jcourse_go/model/converter"
"jcourse_go/model/domain"
"jcourse_go/model/dto"
"net/http"

func GetTeacherListHandler(c *gin.Context) {}
"jcourse_go/service"

func GetTeacherDetailHandler(c *gin.Context) {}
"github.com/gin-gonic/gin"
)

func convertTeacherListFilter(request dto.TeacherListRequest) domain.TeacherListFilter {
filter := domain.TeacherListFilter{
Page: request.Page,
PageSize: request.PageSize,
Name: request.Name,
Department: request.Department,
Pinyin: request.Pinyin,
PinyinAbbr: request.PinyinAbbr,
}

return filter
}

func GetTeacherListHandler(c *gin.Context) {
request := dto.TeacherListRequest{
Page: constant.DefaultPage,
PageSize: constant.DefaultPageSize,
}
if err := c.ShouldBindQuery(&request); err != nil {
c.JSON(http.StatusBadRequest, dto.BaseResponse{Message: "参数错误"})
return
}
filter := convertTeacherListFilter(request)

teachers, err := service.SearchTeacherList(c, filter)
if err != nil {
c.JSON(http.StatusInternalServerError, dto.BaseResponse{Message: "内部错误。"})
return
}

total, err := service.GetTeacherCount(c, filter)
Ayanami1314 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
c.JSON(http.StatusInternalServerError, dto.BaseResponse{Message: "查无此人。"})
return
}

resp := dto.TeacherListResponse{
Total: total,
Data: converter.ConvertTeacherListDomainToDTO(teachers),
Page: request.Page,
PageSize: int64(len(teachers)),
}
c.JSON(http.StatusOK, resp)
}

func GetTeacherDetailHandler(c *gin.Context) {
var request dto.TeacherDetailRequest
if err := c.ShouldBindUri(&request); err != nil {
c.JSON(http.StatusNotFound, dto.BaseResponse{Message: "参数错误"})
}

teacher, err := service.GetTeacherDetail(c, request.TeacherID)
if err != nil {
c.JSON(http.StatusInternalServerError, dto.BaseResponse{Message: "内部错误。"})
return
}
c.JSON(http.StatusOK, converter.ConvertTeacherDomainToDTO(*teacher))
}

func SearchTeacherListHandler(c *gin.Context) {
var request dto.TeacherListRequest
if err := c.ShouldBind(&request); err != nil {
c.JSON(http.StatusBadRequest, dto.BaseResponse{Message: "参数错误"})
return
}

filter := domain.TeacherListFilter{
Name: request.Name,
Department: request.Department,
Pinyin: request.Pinyin,
PinyinAbbr: request.PinyinAbbr,
Page: request.Page,
PageSize: request.PageSize,
}

teachers, err := service.SearchTeacherList(c, filter)
if err != nil {
c.JSON(http.StatusInternalServerError, dto.BaseResponse{Message: "内部错误。"})
return
}

total, err := service.GetTeacherCount(c, filter)
dujiajun marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
c.JSON(http.StatusInternalServerError, dto.BaseResponse{Message: "查无此人。"})
return
}

resp := dto.TeacherListResponse{
Total: total,
Data: converter.ConvertTeacherListDomainToDTO(teachers),
Page: request.Page,
PageSize: int64(len(teachers)),
}
c.JSON(http.StatusOK, resp)
}

func CreateTeacherHandler(c *gin.Context) {}

func UpdateTeacherHandler(c *gin.Context) {}
57 changes: 57 additions & 0 deletions handler/teacher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package handler

import (
"net/http"
"testing"
)

func TestGetTeacherDetailHandler(t *testing.T) {
w, r := baseConfig()

r.GET("/api/teacher/:teacherID", GetTeacherDetailHandler)
req, _ := http.NewRequest("GET", "/api/teacher/1", nil)
r.ServeHTTP(w, req)
// log

prettyJsonLog(w)
}

func TestGetTeacherListHandler(t *testing.T) {
w, r := baseConfig()

r.GET("/api/teacher", GetTeacherListHandler)
req, _ := http.NewRequest("GET", "/api/teacher", nil)
r.ServeHTTP(w, req)
// log

prettyJsonLog(w)
}

func TestSearchTeacherListHandler(t *testing.T) {
querys := map[string]struct {
q string
status int
}{
"valid-multi-req": {"name=古金宇&page=1&page_size=3", http.StatusOK},
"valid-single-req": {"name=古金宇&department=电子信息与电气工程学院&page=1&page_size=3", http.StatusOK},
"invalid-value-req": {"name=你谁", http.StatusOK},
"invalid-page-req": {"page=-1&page_size=10086", http.StatusOK},
"overflow-page-req": {"page=10086&page_size=1", http.StatusOK},
"invalid-key-req": {"hello=1", http.StatusBadRequest},
}

for name, s := range querys {
t.Run(name, func(t *testing.T) {
w, r := baseConfig()
r.GET("/api/teacher/query", SearchTeacherListHandler)
req, _ := http.NewRequest("GET", "/api/teacher/query", nil)
req.URL.RawQuery = s.q
r.ServeHTTP(w, req)
// log
if w.Code != s.status {
t.Errorf("Expected status code %d, but got %d", s.status, w.Code)
}
prettyJsonLog(w)
})
}
}
Loading
Loading