├── .gitignore
├── .idea
├── WeCourseService.iml
├── modules.xml
├── vcs.xml
└── workspace.xml
├── CetConfig.go
├── GetAccount.go
├── GetCourses.go
├── GetDayCourse.go
├── GetGrade.go
├── GetLogin.go
├── GetPhoto.go
├── GetTeacher.go
├── GetWeekCourse.go
├── GetWeekCourseNew.go
├── GetWeekTime.go
├── JsonResult.go
├── LICENSE
├── README.md
├── WebSocket.go
├── config.json
└── main.go
/.gitignore:
--------------------------------------------------------------------------------
1 | /WeCourseService.exe
2 |
--------------------------------------------------------------------------------
/.idea/WeCourseService.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/CetConfig.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io/ioutil"
7 | )
8 |
9 | type Config struct {
10 | SchoolName string
11 | MangerType string
12 | MangerURL string
13 | CalendarFirst string
14 | SocketPort int
15 | }
16 |
17 | func ReadConfig() Config {
18 | data, err := ioutil.ReadFile("./config.json")
19 | if err != nil {
20 | fmt.Println(err)
21 | }
22 | var conf Config
23 | err = json.Unmarshal(data, &conf)
24 | if err != nil {
25 | fmt.Println(err)
26 | }
27 | return conf
28 | }
29 |
--------------------------------------------------------------------------------
/GetAccount.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "crypto/sha1"
5 | "encoding/hex"
6 | "encoding/json"
7 | "fmt"
8 | "io/ioutil"
9 | "net/http"
10 | "net/http/cookiejar"
11 | "net/url"
12 | "regexp"
13 | "strings"
14 | "time"
15 | )
16 |
17 | var USER, PASS string
18 |
19 | type StudentStruct struct {
20 | FullName string
21 | EnglishName string
22 | Sex string
23 | StartTime string
24 | EndTime string
25 | SchoolYear string
26 | Type string
27 | System string
28 | Specialty string
29 | Class string
30 | }
31 |
32 | func GetAccount(UserName, PassWord string) string {
33 | // 获取用户名和密码
34 | var myStudent StudentStruct
35 | var myAccountResult AccountResult
36 | USER := UserName
37 | PASS := PassWord
38 | conf := ReadConfig()
39 | myAccountResult.Type = "account"
40 | // Cookie自动维护
41 | cookieJar, err := cookiejar.New(nil)
42 | if err != nil {
43 | fmt.Println("ERROR_0: ", err.Error())
44 | //return
45 | }
46 | var client http.Client
47 | client.Jar = cookieJar
48 |
49 | // 第一次请求
50 | req, err := http.NewRequest(http.MethodGet, conf.MangerURL+"eams/login.action", nil)
51 | if err != nil {
52 | fmt.Println("ERROR_1: ", err.Error())
53 | //return
54 | }
55 |
56 | resp1, err := client.Do(req)
57 | if err != nil {
58 | fmt.Println("ERROR_2: ", err.Error())
59 | //return
60 | }
61 | defer resp1.Body.Close()
62 |
63 | content, err := ioutil.ReadAll(resp1.Body)
64 | if err != nil {
65 | fmt.Println("ERROR_3: ", err.Error())
66 | //return
67 | }
68 |
69 | temp := string(content)
70 | if !strings.Contains(temp, "CryptoJS.SHA1(") {
71 | fmt.Println("ERROR_4: GET Failed")
72 | //return
73 | }
74 |
75 | // 对密码进行SHA1哈希
76 | temp = temp[strings.Index(temp, "CryptoJS.SHA1(")+15 : strings.Index(temp, "CryptoJS.SHA1(")+52]
77 | PASS = temp + PASS
78 | bytes := sha1.Sum([]byte(PASS))
79 | PASS = hex.EncodeToString(bytes[:])
80 |
81 | formValues := make(url.Values)
82 | formValues.Set("username", USER)
83 | formValues.Set("password", PASS)
84 | formValues.Set("session_locale", "zh_CN")
85 | time.Sleep(1000 * time.Millisecond)
86 | req, err = http.NewRequest(http.MethodPost, conf.MangerURL+"eams/login.action", strings.NewReader(formValues.Encode()))
87 | if err != nil {
88 | fmt.Println("ERROR_5: ", err.Error())
89 | //return
90 | }
91 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
92 | req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0")
93 | resp2, err := client.Do(req)
94 | if err != nil {
95 | fmt.Println("ERROR_6: ", err.Error())
96 | //return
97 | }
98 | defer resp2.Body.Close()
99 |
100 | content, err = ioutil.ReadAll(resp2.Body)
101 | if err != nil {
102 | fmt.Println("ERROR_7: ", err.Error())
103 | //return
104 | }
105 |
106 | temp = string(content)
107 | if !strings.Contains(temp, "") {
108 | fmt.Println(temp)
109 | fmt.Println("ERROR_8: LOGIN Failed")
110 | //return
111 | }
112 | time.Sleep(1000 * time.Millisecond)
113 | req, err = http.NewRequest(http.MethodGet, conf.MangerURL+"eams/stdDetail.action", nil)
114 | if err != nil {
115 | fmt.Println("ERROR_9: ", err.Error())
116 | //return
117 | }
118 |
119 | resp3, err := client.Do(req)
120 | if err != nil {
121 | fmt.Println("ERROR_10: ", err.Error())
122 | //return
123 | }
124 |
125 | defer resp3.Body.Close()
126 | content, err = ioutil.ReadAll(resp3.Body)
127 | if err != nil {
128 | fmt.Println("ERROR_11: ", err.Error())
129 | //return
130 | }
131 |
132 | temp = string(content)
133 | req, err = http.NewRequest(http.MethodGet, conf.MangerURL+"eams/logout.action", nil)
134 | if err != nil {
135 | fmt.Println("ERROR_12: ", err.Error())
136 | //return
137 | }
138 |
139 | resp5, err := client.Do(req)
140 | if err != nil {
141 | fmt.Println("ERROR_13: ", err.Error())
142 | //return
143 | }
144 | defer resp5.Body.Close()
145 | reg := regexp.MustCompile(`(?i)
([^>]*) | `)
146 | stuinfo := reg.FindAllStringSubmatch(temp, -1)
147 | //fmt.Println(stuinfo)
148 | myStudent.FullName = stuinfo[0][1]
149 | myStudent.EnglishName = stuinfo[1][1]
150 | myStudent.Sex = stuinfo[2][1]
151 | myStudent.SchoolYear = stuinfo[4][1]
152 | myStudent.Type = stuinfo[5][1] + "(" + stuinfo[14][1] + ")"
153 | myStudent.StartTime = stuinfo[11][1]
154 | myStudent.EndTime = stuinfo[12][1]
155 | myStudent.System = stuinfo[8][1]
156 | myStudent.Specialty = stuinfo[9][1]
157 | myStudent.Class = stuinfo[18][1]
158 | myAccountResult.Data = myStudent
159 | js, err := json.MarshalIndent(myAccountResult, "", "\t")
160 | return B2S(js)
161 | }
162 |
--------------------------------------------------------------------------------
/GetCourses.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "crypto/sha1"
5 | "encoding/hex"
6 | "encoding/json"
7 | "fmt"
8 | "github.com/patrickmn/go-cache/go-cache"
9 | "io/ioutil"
10 | "net/http"
11 | "net/http/cookiejar"
12 | "net/url"
13 | "regexp"
14 | "strconv"
15 | "strings"
16 | "time"
17 | )
18 |
19 | // 课程持续时间,周几第几节
20 | type CourseTime struct {
21 | DayOfTheWeek int
22 | TimeOfTheDay int
23 | }
24 |
25 | // 课程信息
26 | type Course struct {
27 | CourseID string
28 | CourseName string
29 | RoomID string
30 | RoomName string
31 | Weeks string
32 | CourseTimes []CourseTime
33 | }
34 |
35 | var USERNAME, PASSWORD string
36 | var myCourses []Course
37 | var teachers []TeacherStruct
38 | var myTeacher TeacherStruct
39 | var myAllCourseResult CourseResult
40 | var c = cache.New(1*time.Hour, 10*time.Minute)
41 |
42 | func B2S(bs []byte) string {
43 | ba := []byte{}
44 | for _, b := range bs {
45 | ba = append(ba, byte(b))
46 | }
47 | return string(ba)
48 | }
49 | func GetTeacherObj() []TeacherStruct {
50 | return teachers
51 | }
52 | func GetCourse(UserName, PassWord string) string {
53 | value, found := c.Get(UserName)
54 | if found {
55 | //fmt.Print("Using Cache")
56 | if value.(string) != "" {
57 | return value.(string)
58 | }
59 | }
60 | //readcache in there
61 | // 获取用户名和密码
62 | conf := ReadConfig()
63 | USERNAME := UserName
64 | PASSWORD := PassWord
65 | myCourses = nil
66 | teachers = nil
67 |
68 | myAllCourseResult.Type = "allcourse"
69 | // Cookie自动维护
70 | cookieJar, err := cookiejar.New(nil)
71 | if err != nil {
72 | fmt.Println("ERROR_0: ", err.Error())
73 | //return
74 | }
75 | var client http.Client
76 | client.Jar = cookieJar
77 |
78 | // 第一次请求
79 | req, err := http.NewRequest(http.MethodGet, conf.MangerURL+"eams/login.action", nil)
80 | if err != nil {
81 | fmt.Println("ERROR_1: ", err.Error())
82 | //return
83 | }
84 |
85 | resp1, err := client.Do(req)
86 | if err != nil {
87 | fmt.Println("ERROR_2: ", err.Error())
88 | //return
89 | }
90 | defer resp1.Body.Close()
91 |
92 | content, err := ioutil.ReadAll(resp1.Body)
93 | if err != nil {
94 | fmt.Println("ERROR_3: ", err.Error())
95 | //return
96 | }
97 |
98 | temp := string(content)
99 | if !strings.Contains(temp, "CryptoJS.SHA1(") {
100 | fmt.Println("ERROR_4: GET Failed")
101 | //return
102 | }
103 |
104 | // 对密码进行SHA1哈希
105 | temp = temp[strings.Index(temp, "CryptoJS.SHA1(")+15 : strings.Index(temp, "CryptoJS.SHA1(")+52]
106 | PASSWORD = temp + PASSWORD
107 | bytes := sha1.Sum([]byte(PASSWORD))
108 | PASSWORD = hex.EncodeToString(bytes[:])
109 | formValues := make(url.Values)
110 | formValues.Set("username", USERNAME)
111 | formValues.Set("password", PASSWORD)
112 | formValues.Set("session_locale", "zh_CN")
113 | time.Sleep(time.Duration(1000 * time.Millisecond))
114 | req, err = http.NewRequest(http.MethodPost, conf.MangerURL+"eams/login.action", strings.NewReader(formValues.Encode()))
115 | if err != nil {
116 | fmt.Println("ERROR_5: ", err.Error())
117 | //return
118 | }
119 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
120 | req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0")
121 | resp2, err := client.Do(req)
122 | if err != nil {
123 | fmt.Println("ERROR_6: ", err.Error())
124 | //return
125 | }
126 | defer resp2.Body.Close()
127 |
128 | content, err = ioutil.ReadAll(resp2.Body)
129 | if err != nil {
130 | fmt.Println("ERROR_7: ", err.Error())
131 | //return
132 | }
133 |
134 | temp = string(content)
135 | if !strings.Contains(temp, "") {
136 | fmt.Println(temp)
137 | fmt.Println("ERROR_8: LOGIN Failed")
138 | //return
139 | }
140 | time.Sleep(1000 * time.Millisecond)
141 | req, err = http.NewRequest(http.MethodGet, conf.MangerURL+"eams/courseTableForStd.action", nil)
142 | if err != nil {
143 | fmt.Println("ERROR_9: ", err.Error())
144 | //return
145 | }
146 |
147 | resp3, err := client.Do(req)
148 | if err != nil {
149 | fmt.Println("ERROR_10: ", err.Error())
150 | //return
151 | }
152 |
153 | defer resp3.Body.Close()
154 | content, err = ioutil.ReadAll(resp3.Body)
155 | if err != nil {
156 | fmt.Println("ERROR_11: ", err.Error())
157 | //return
158 | }
159 |
160 | temp = string(content)
161 | if !strings.Contains(temp, "bg.form.addInput(form,\"ids\",\"") {
162 | fmt.Println("ERROR_12: GET ids Failed")
163 | //return
164 | }
165 |
166 | temp = temp[strings.Index(temp, "bg.form.addInput(form,\"ids\",\"")+29 : strings.Index(temp, "bg.form.addInput(form,\"ids\",\"")+50]
167 | ids := temp[:strings.Index(temp, "\");")]
168 | formValues = make(url.Values)
169 | formValues.Set("ignoreHead", "1")
170 | formValues.Set("showPrintAndExport", "1")
171 | formValues.Set("setting.kind", "std")
172 | formValues.Set("startWeek", "")
173 | formValues.Set("semester.id", "30")
174 | formValues.Set("ids", ids)
175 | req, err = http.NewRequest(http.MethodPost, conf.MangerURL+"eams/courseTableForStd!courseTable.action", strings.NewReader(formValues.Encode()))
176 | if err != nil {
177 | fmt.Println("ERROR_13: ", err.Error())
178 | //return
179 | }
180 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
181 | req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0")
182 | resp4, err := client.Do(req)
183 | if err != nil {
184 | fmt.Println("ERROR_14: ", err.Error())
185 | //return
186 | }
187 | defer resp4.Body.Close()
188 |
189 | content, err = ioutil.ReadAll(resp4.Body)
190 | if err != nil {
191 | fmt.Println("ERROR_15: ", err.Error())
192 | //return
193 | }
194 |
195 | temp = string(content)
196 | if !strings.Contains(temp, "课表格式说明") {
197 | fmt.Println("ERROR_16: Get Courses Failed")
198 | //return
199 | }
200 | reg1 := regexp.MustCompile(`TaskActivity\(actTeacherId.join\(','\),actTeacherName.join\(','\),"(.*)","(.*)\(.*\)","(.*)","(.*)","(.*)",null,null,assistantName,"",""\);((?:\s*index =\d+\*unitCount\+\d+;\s*.*\s)+)`)
201 | reg2 := regexp.MustCompile(`\s*index =(\d+)\*unitCount\+(\d+);\s*`)
202 | reg3 := regexp.MustCompile(`(?i)(\d) | \s*([:alpha:].+) | \s*(.+) | \s*((\d)|(\d\.\d)) | \s*\s*.*\s* | \s*(.*) | `)
203 | reg4 := regexp.MustCompile(`(?i)([^>]*) | `)
204 | reg5 := regexp.MustCompile(`(?i)>([^>]*)`)
205 | teanchersStr := reg3.FindAllStringSubmatch(temp, -1)
206 | for _, teacherStr := range teanchersStr {
207 | teacher := reg4.FindAllStringSubmatch(teacherStr[0], -1)
208 | courseid := reg5.FindAllStringSubmatch(teacherStr[0], -1)
209 | myTeacher.CourseID = courseid[0][1]
210 | myTeacher.CourseName = teacher[2][1]
211 | myTeacher.CourseCredit = teacher[3][1]
212 | myTeacher.CourseTeacher = teacher[4][1]
213 | teachers = append(teachers, myTeacher)
214 | }
215 | coursesStr := reg1.FindAllStringSubmatch(temp, -1)
216 | for _, courseStr := range coursesStr {
217 | var course Course
218 | course.CourseID = courseStr[1]
219 | course.CourseName = courseStr[2]
220 | course.RoomID = courseStr[3]
221 | course.RoomName = courseStr[4]
222 | course.Weeks = courseStr[5]
223 | for _, indexStr := range strings.Split(courseStr[6], "table0.activities[index][table0.activities[index].length]=activity;") {
224 | if !strings.Contains(indexStr, "unitCount") {
225 | continue
226 | }
227 | var courseTime CourseTime
228 | courseTime.DayOfTheWeek, _ = strconv.Atoi(reg2.FindStringSubmatch(indexStr)[1])
229 | courseTime.TimeOfTheDay, _ = strconv.Atoi(reg2.FindStringSubmatch(indexStr)[2])
230 | course.CourseTimes = append(course.CourseTimes, courseTime)
231 | }
232 | myCourses = append(myCourses, course)
233 | }
234 | req, err = http.NewRequest(http.MethodGet, conf.MangerURL+"eams/logout.action", nil)
235 | if err != nil {
236 | fmt.Println("ERROR_17: ", err.Error())
237 | //return
238 | }
239 |
240 | resp5, err := client.Do(req)
241 | if err != nil {
242 | fmt.Println("ERROR_18: ", err.Error())
243 | //return
244 | }
245 | defer resp5.Body.Close()
246 | myAllCourseResult.Data = myCourses
247 | js, err := json.MarshalIndent(myAllCourseResult, "", "\t")
248 | cachestr := B2S(js)
249 | c.Set(UserName, cachestr, cache.DefaultExpiration)
250 | value_check, found_check := c.Get(UserName)
251 | if found_check {
252 | //fmt.Print("Using Cache")
253 | if value_check.(string) == "" {
254 | c.Set(UserName, cachestr, cache.DefaultExpiration)
255 | }
256 | }
257 | return cachestr
258 |
259 | }
260 |
--------------------------------------------------------------------------------
/GetDayCourse.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "strconv"
7 | "strings"
8 | "time"
9 | )
10 |
11 | type DayCourse struct {
12 | CourseName string
13 | TeacherName string
14 | TimeOfTheDay string
15 | SchoolWeek string
16 | }
17 |
18 | var ToDayCourse []DayCourse
19 | var thisCourse DayCourse
20 | var dayCourseResult DayCourseResult
21 |
22 | func GetDayCourse(UserName, PassWord string) string {
23 | var allCourses []Course
24 | var tmpDayResult CourseResult
25 | dayCourseResult.Type = "daycourse"
26 | conf := ReadConfig()
27 | var cstr string = GetCourse(UserName, PassWord)
28 | err := json.Unmarshal([]byte(cstr), &tmpDayResult)
29 | if err != nil {
30 | fmt.Println(err)
31 | }
32 | allCourses = tmpDayResult.Data
33 | for _, c1 := range allCourses {
34 | schoolWeek := GetWeekTime(conf.CalendarFirst)
35 | serverWeek := GetWeekDay()
36 | intWeek, _ := strconv.Atoi(schoolWeek)
37 | if c1.Weeks[intWeek] == '1' {
38 | if c1.CourseTimes[0].DayOfTheWeek == serverWeek {
39 | arr := GetTeacherObj()
40 | for _, thisteacher := range arr {
41 | if strings.Contains(c1.CourseID, thisteacher.CourseID) {
42 | thisCourse.TeacherName = thisteacher.CourseTeacher
43 | thisCourse.CourseName = thisteacher.CourseName
44 | thisCourse.TimeOfTheDay = strconv.Itoa(c1.CourseTimes[0].TimeOfTheDay+1) + "," + strconv.Itoa(c1.CourseTimes[1].TimeOfTheDay+1)
45 | thisCourse.SchoolWeek = schoolWeek
46 | ToDayCourse = append(ToDayCourse, thisCourse)
47 | }
48 | }
49 | }
50 | }
51 | }
52 | dayCourseResult.Data = ToDayCourse
53 | js, _ := json.MarshalIndent(dayCourseResult, "", "\t")
54 | return B2S(js)
55 | }
56 |
57 | var WeekDayMap = map[string]int{
58 | "Monday": 0,
59 | "Tuesday": 1,
60 | "Wednesday": 2,
61 | "Thursday": 3,
62 | "Friday": 4,
63 | "Saturday": 5,
64 | "Sunday": 6,
65 | }
66 |
67 | func GetWeekDay() int {
68 | wd := time.Now().Weekday().String()
69 | return WeekDayMap[wd]
70 | }
71 |
--------------------------------------------------------------------------------
/GetGrade.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "crypto/sha1"
5 | "encoding/hex"
6 | "encoding/json"
7 | "fmt"
8 | "io/ioutil"
9 | "net/http"
10 | "net/http/cookiejar"
11 | "net/url"
12 | "regexp"
13 | "strings"
14 | "time"
15 | )
16 |
17 | type GradeStruct struct {
18 | CourseID string
19 | CourseName string
20 | CourseTerm string
21 | CourseCredit string
22 | CourseGrade string
23 | GradePoint string
24 | }
25 |
26 | //TODO:Fill Struct Array
27 | func GetGrade(UserName, PassWord string) string {
28 | // 获取用户名和密码
29 | conf := ReadConfig()
30 | USERNAME := UserName
31 | PASSWORD := PassWord
32 | var grades []GradeStruct
33 | var myGrade GradeStruct
34 | var gradeResult GradeResult
35 | // Cookie自动维护
36 | cookieJar, err := cookiejar.New(nil)
37 | gradeResult.Type = "grade"
38 | if err != nil {
39 | fmt.Println("ERROR_0: ", err.Error())
40 | //return
41 | }
42 | var client http.Client
43 | client.Jar = cookieJar
44 |
45 | // 第一次请求
46 | req, err := http.NewRequest(http.MethodGet, conf.MangerURL+"eams/login.action", nil)
47 | if err != nil {
48 | fmt.Println("ERROR_1: ", err.Error())
49 | //return
50 | }
51 |
52 | resp1, err := client.Do(req)
53 | if err != nil {
54 | fmt.Println("ERROR_2: ", err.Error())
55 | //return
56 | }
57 | defer resp1.Body.Close()
58 |
59 | content, err := ioutil.ReadAll(resp1.Body)
60 | if err != nil {
61 | fmt.Println("ERROR_3: ", err.Error())
62 | //return
63 | }
64 |
65 | temp := string(content)
66 | if !strings.Contains(temp, "CryptoJS.SHA1(") {
67 | fmt.Println("ERROR_4: GET Failed")
68 | //return
69 | }
70 |
71 | // 对密码进行SHA1哈希
72 | temp = temp[strings.Index(temp, "CryptoJS.SHA1(")+15 : strings.Index(temp, "CryptoJS.SHA1(")+52]
73 | PASSWORD = temp + PASSWORD
74 | bytes := sha1.Sum([]byte(PASSWORD))
75 | PASSWORD = hex.EncodeToString(bytes[:])
76 | formValues := make(url.Values)
77 | formValues.Set("username", USERNAME)
78 | formValues.Set("password", PASSWORD)
79 | formValues.Set("session_locale", "zh_CN")
80 | time.Sleep(time.Duration(1000 * time.Millisecond))
81 | req, err = http.NewRequest(http.MethodPost, conf.MangerURL+"eams/login.action", strings.NewReader(formValues.Encode()))
82 | if err != nil {
83 | fmt.Println("ERROR_5: ", err.Error())
84 | //return
85 | }
86 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
87 | req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0")
88 | resp2, err := client.Do(req)
89 | if err != nil {
90 | fmt.Println("ERROR_6: ", err.Error())
91 | //return
92 | }
93 | defer resp2.Body.Close()
94 |
95 | content, err = ioutil.ReadAll(resp2.Body)
96 | if err != nil {
97 | fmt.Println("ERROR_7: ", err.Error())
98 | //return
99 | }
100 |
101 | temp = string(content)
102 | if !strings.Contains(temp, "") {
103 | fmt.Println(temp)
104 | fmt.Println("ERROR_8: LOGIN Failed")
105 | //return
106 | }
107 | time.Sleep(1000 * time.Millisecond)
108 | req, err = http.NewRequest(http.MethodPost, conf.MangerURL+"eams/teach/grade/course/person!historyCourseGrade.action?projectType=MAJOR", strings.NewReader(formValues.Encode()))
109 | if err != nil {
110 | fmt.Println("ERROR_13: ", err.Error())
111 | //return
112 | }
113 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
114 | req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0")
115 | resp4, err := client.Do(req)
116 | if err != nil {
117 | fmt.Println("ERROR_14: ", err.Error())
118 | //return
119 | }
120 | defer resp4.Body.Close()
121 |
122 | content, err = ioutil.ReadAll(resp4.Body)
123 | if err != nil {
124 | fmt.Println("ERROR_15: ", err.Error())
125 | //return
126 | }
127 |
128 | temp = string(content)
129 | reg3 := regexp.MustCompile(`(?i)[\s\S]*?
`)
130 | reg4 := regexp.MustCompile(`(?i)([^>]*)`)
131 | reg5 := regexp.MustCompile(`(?i)([^>]*)`)
132 | gradeStr := reg3.FindAllStringSubmatch(temp, -1)
133 | gradeStr = append(gradeStr[:0], gradeStr[0+1:]...)
134 | gradeStr = append(gradeStr[:0], gradeStr[0+1:]...)
135 | for _, tempStr := range gradeStr {
136 | fuck := reg4.FindAllStringSubmatch(tempStr[0], -1)
137 | myGrade.CourseTerm = strings.Trim(fuck[0][1], "\n")
138 | myGrade.CourseID = strings.Trim(fuck[1][1], "\n")
139 | myGrade.CourseCredit = strings.Trim(fuck[4][1], "\n")
140 | bodyclass := reg5.FindAllStringSubmatch(tempStr[0], -1)
141 | if len(bodyclass) != 0 {
142 | myGrade.CourseName = bodyclass[0][1]
143 | } else {
144 | myGrade.CourseName = strings.Trim(fuck[3][1], "\t\r\n")
145 | }
146 | myGrade.CourseGrade = strings.Trim(fuck[len(fuck)-2][1], "\t\n")
147 | myGrade.GradePoint = strings.Trim(fuck[len(fuck)-1][1], "\t\n")
148 | grades = append(grades, myGrade)
149 | }
150 | req, err = http.NewRequest(http.MethodGet, conf.MangerURL+"eams/logout.action", nil)
151 | if err != nil {
152 | fmt.Println("ERROR_17: ", err.Error())
153 | }
154 |
155 | resp5, err := client.Do(req)
156 | if err != nil {
157 | fmt.Println("ERROR_18: ", err.Error())
158 | //return
159 | }
160 | defer resp5.Body.Close()
161 | gradeResult.Data = grades
162 | js, err := json.MarshalIndent(gradeResult, "", "\t")
163 | return B2S(js)
164 | }
165 |
--------------------------------------------------------------------------------
/GetLogin.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "crypto/sha1"
5 | "encoding/hex"
6 | "encoding/json"
7 | "io/ioutil"
8 | "net/http"
9 | "net/http/cookiejar"
10 | "net/url"
11 | "strings"
12 | "time"
13 | )
14 |
15 | func GetUserLogin(UserName, PassWord string) string {
16 | // 获取用户名和密码
17 | USERNAME := UserName
18 | PASSWORD := PassWord
19 | var myLogin LoginResult
20 | myLogin.Type = "login"
21 | conf := ReadConfig()
22 | // Cookie自动维护
23 | cookieJar, err := cookiejar.New(nil)
24 | if err != nil {
25 | //return ("ERROR_0: ", err.Error())
26 | //return
27 | }
28 | var client http.Client
29 | client.Jar = cookieJar
30 |
31 | // 第一次请求
32 | req, err := http.NewRequest(http.MethodGet, conf.MangerURL+"eams/login.action", nil)
33 | if err != nil {
34 | //return ("ERROR_1: ", err.Error())
35 | //return
36 | }
37 |
38 | resp1, err := client.Do(req)
39 | if err != nil {
40 | //return ("ERROR_2: ", err.Error())
41 | //return
42 | }
43 | defer resp1.Body.Close()
44 |
45 | content, err := ioutil.ReadAll(resp1.Body)
46 | if err != nil {
47 | //return ("ERROR_3: ", err.Error())
48 | //return
49 | }
50 |
51 | temp := string(content)
52 | if !strings.Contains(temp, "CryptoJS.SHA1(") {
53 | //return ("ERROR_4: GET Failed")
54 | //return
55 | }
56 |
57 | // 对密码进行SHA1哈希
58 | temp = temp[strings.Index(temp, "CryptoJS.SHA1(")+15 : strings.Index(temp, "CryptoJS.SHA1(")+52]
59 | PASSWORD = temp + PASSWORD
60 | bytes := sha1.Sum([]byte(PASSWORD))
61 | PASSWORD = hex.EncodeToString(bytes[:])
62 | formValues := make(url.Values)
63 | formValues.Set("username", USERNAME)
64 | formValues.Set("password", PASSWORD)
65 | formValues.Set("session_locale", "zh_CN")
66 | time.Sleep(time.Duration(1000 * time.Millisecond))
67 | req, err = http.NewRequest(http.MethodPost, conf.MangerURL+"eams/login.action", strings.NewReader(formValues.Encode()))
68 | if err != nil {
69 | //return ("ERROR_5: ", err.Error())
70 | //return
71 | }
72 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
73 | req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0")
74 | resp2, err := client.Do(req)
75 | if err != nil {
76 | //return ("ERROR_6: ", err.Error())
77 | //return
78 | }
79 | defer resp2.Body.Close()
80 |
81 | content, err = ioutil.ReadAll(resp2.Body)
82 | if err != nil {
83 | //return ("ERROR_7: ", err.Error())
84 | //return
85 | }
86 |
87 | temp = string(content)
88 | if !strings.Contains(temp, "") {
89 | myLogin.Data = "登录失败"
90 | js, _ := json.MarshalIndent(myLogin, "", "\t")
91 | return B2S(js) //Write cache in here
92 | //return ("ERROR_8: LOGIN Failed")
93 | //return
94 | }
95 | myLogin.Data = "登录成功"
96 | js, err := json.MarshalIndent(myLogin, "", "\t")
97 | return B2S(js) //Write cache in here
98 | }
99 |
--------------------------------------------------------------------------------
/GetPhoto.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "crypto/sha1"
5 | "encoding/base64"
6 | "encoding/hex"
7 | "encoding/json"
8 | "fmt"
9 | "io/ioutil"
10 | "net/http"
11 | "net/http/cookiejar"
12 | "net/url"
13 | "strings"
14 | "time"
15 | )
16 |
17 | func GetPhoto(UserName, PassWord string) string {
18 | // 获取用户名和密码
19 | USER := UserName
20 | PASS := PassWord
21 | conf := ReadConfig()
22 | var myPhotoResult PhotoResult
23 | // Cookie自动维护
24 | cookieJar, err := cookiejar.New(nil)
25 | if err != nil {
26 | fmt.Println("ERROR_0: ", err.Error())
27 | //return
28 | }
29 | myPhotoResult.Type = "photo"
30 | var client http.Client
31 | client.Jar = cookieJar
32 |
33 | // 第一次请求
34 | req, err := http.NewRequest(http.MethodGet, conf.MangerURL+"eams/login.action", nil)
35 | if err != nil {
36 | fmt.Println("ERROR_1: ", err.Error())
37 | //return
38 | }
39 |
40 | resp1, err := client.Do(req)
41 | if err != nil {
42 | fmt.Println("ERROR_2: ", err.Error())
43 | //return
44 | }
45 | defer resp1.Body.Close()
46 |
47 | content, err := ioutil.ReadAll(resp1.Body)
48 | if err != nil {
49 | fmt.Println("ERROR_3: ", err.Error())
50 | //return
51 | }
52 |
53 | temp := string(content)
54 | if !strings.Contains(temp, "CryptoJS.SHA1(") {
55 | fmt.Println("ERROR_4: GET Failed")
56 | //return
57 | }
58 |
59 | // 对密码进行SHA1哈希
60 | temp = temp[strings.Index(temp, "CryptoJS.SHA1(")+15 : strings.Index(temp, "CryptoJS.SHA1(")+52]
61 | PASS = temp + PASS
62 | bytes := sha1.Sum([]byte(PASS))
63 | PASS = hex.EncodeToString(bytes[:])
64 |
65 | formValues := make(url.Values)
66 | formValues.Set("username", USER)
67 | formValues.Set("password", PASS)
68 | formValues.Set("session_locale", "zh_CN")
69 | time.Sleep(1000 * time.Millisecond)
70 | req, err = http.NewRequest(http.MethodPost, conf.MangerURL+"eams/login.action", strings.NewReader(formValues.Encode()))
71 | if err != nil {
72 | fmt.Println("ERROR_5: ", err.Error())
73 | //return
74 | }
75 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
76 | req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0")
77 | resp2, err := client.Do(req)
78 | if err != nil {
79 | fmt.Println("ERROR_6: ", err.Error())
80 | //return
81 | }
82 | defer resp2.Body.Close()
83 |
84 | content, err = ioutil.ReadAll(resp2.Body)
85 | if err != nil {
86 | fmt.Println("ERROR_7: ", err.Error())
87 | //return
88 | }
89 |
90 | temp = string(content)
91 | if !strings.Contains(temp, "") {
92 | fmt.Println(temp)
93 | fmt.Println("ERROR_8: LOGIN Failed")
94 | //return
95 | }
96 | time.Sleep(1000 * time.Millisecond)
97 | req, err = http.NewRequest(http.MethodGet, conf.MangerURL+"eams/showSelfAvatar.action?user.name="+USER, nil)
98 | if err != nil {
99 | fmt.Println("ERROR_9: ", err.Error())
100 | //return
101 | }
102 |
103 | resp3, err := client.Do(req)
104 | if err != nil {
105 | fmt.Println("ERROR_10: ", err.Error())
106 | //return
107 | }
108 |
109 | defer resp3.Body.Close()
110 | content, err = ioutil.ReadAll(resp3.Body)
111 | if err != nil {
112 | fmt.Println("ERROR_11: ", err.Error())
113 | //return
114 | }
115 |
116 | temp = base64.StdEncoding.EncodeToString(content)
117 | req, err = http.NewRequest(http.MethodGet, conf.MangerURL+"eams/logout.action", nil)
118 | if err != nil {
119 | fmt.Println("ERROR_12: ", err.Error())
120 | //return
121 | }
122 |
123 | resp5, err := client.Do(req)
124 | if err != nil {
125 | fmt.Println("ERROR_13: ", err.Error())
126 | //return
127 | }
128 | defer resp5.Body.Close()
129 | myPhotoResult.Data = "data:image/jpg;base64," + temp
130 | js, err := json.MarshalIndent(myPhotoResult, "", "\t")
131 | return B2S(js) //Write cache in here
132 | }
133 |
--------------------------------------------------------------------------------
/GetTeacher.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "crypto/sha1"
5 | "encoding/hex"
6 | "encoding/json"
7 | "fmt"
8 | "io/ioutil"
9 | "net/http"
10 | "net/http/cookiejar"
11 | "net/url"
12 | "regexp"
13 | "strings"
14 | "time"
15 | )
16 |
17 | type TeacherStruct struct {
18 | CourseID string
19 | CourseName string
20 | CourseCredit string
21 | CourseTeacher string
22 | }
23 |
24 | func GetTeacher(UserName, PassWord string) string {
25 | // 获取用户名和密码
26 | conf := ReadConfig()
27 | USERNAME := UserName
28 | PASSWORD := PassWord
29 | var teachers []TeacherStruct
30 | var myTeacher TeacherStruct
31 | var teacherResult TeacherResult
32 | // Cookie自动维护
33 | cookieJar, err := cookiejar.New(nil)
34 | if err != nil {
35 | fmt.Println("ERROR_0: ", err.Error())
36 | //return
37 | }
38 | var client http.Client
39 | client.Jar = cookieJar
40 | teacherResult.Type = "teacher"
41 | // 第一次请求
42 | req, err := http.NewRequest(http.MethodGet, conf.MangerURL+"eams/login.action", nil)
43 | if err != nil {
44 | fmt.Println("ERROR_1: ", err.Error())
45 | //return
46 | }
47 |
48 | resp1, err := client.Do(req)
49 | if err != nil {
50 | fmt.Println("ERROR_2: ", err.Error())
51 | //return
52 | }
53 | defer resp1.Body.Close()
54 |
55 | content, err := ioutil.ReadAll(resp1.Body)
56 | if err != nil {
57 | fmt.Println("ERROR_3: ", err.Error())
58 | //return
59 | }
60 |
61 | temp := string(content)
62 | if !strings.Contains(temp, "CryptoJS.SHA1(") {
63 | fmt.Println("ERROR_4: GET Failed")
64 | //return
65 | }
66 |
67 | // 对密码进行SHA1哈希
68 | temp = temp[strings.Index(temp, "CryptoJS.SHA1(")+15 : strings.Index(temp, "CryptoJS.SHA1(")+52]
69 | PASSWORD = temp + PASSWORD
70 | bytes := sha1.Sum([]byte(PASSWORD))
71 | PASSWORD = hex.EncodeToString(bytes[:])
72 | formValues := make(url.Values)
73 | formValues.Set("username", USERNAME)
74 | formValues.Set("password", PASSWORD)
75 | formValues.Set("session_locale", "zh_CN")
76 | time.Sleep(time.Duration(1000 * time.Millisecond))
77 | req, err = http.NewRequest(http.MethodPost, conf.MangerURL+"eams/login.action", strings.NewReader(formValues.Encode()))
78 | if err != nil {
79 | fmt.Println("ERROR_5: ", err.Error())
80 | //return
81 | }
82 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
83 | req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0")
84 | resp2, err := client.Do(req)
85 | if err != nil {
86 | fmt.Println("ERROR_6: ", err.Error())
87 | //return
88 | }
89 | defer resp2.Body.Close()
90 |
91 | content, err = ioutil.ReadAll(resp2.Body)
92 | if err != nil {
93 | fmt.Println("ERROR_7: ", err.Error())
94 | //return
95 | }
96 |
97 | temp = string(content)
98 | if !strings.Contains(temp, "") {
99 | fmt.Println(temp)
100 | fmt.Println("ERROR_8: LOGIN Failed")
101 | //return
102 | }
103 | time.Sleep(1000 * time.Millisecond)
104 | req, err = http.NewRequest(http.MethodGet, conf.MangerURL+"eams/courseTableForStd.action", nil)
105 | if err != nil {
106 | fmt.Println("ERROR_9: ", err.Error())
107 | //return
108 | }
109 |
110 | resp3, err := client.Do(req)
111 | if err != nil {
112 | fmt.Println("ERROR_10: ", err.Error())
113 | //return
114 | }
115 |
116 | defer resp3.Body.Close()
117 | content, err = ioutil.ReadAll(resp3.Body)
118 | if err != nil {
119 | fmt.Println("ERROR_11: ", err.Error())
120 | //return
121 | }
122 |
123 | temp = string(content)
124 | if !strings.Contains(temp, "bg.form.addInput(form,\"ids\",\"") {
125 | fmt.Println("ERROR_12: GET ids Failed")
126 | //return
127 | }
128 |
129 | temp = temp[strings.Index(temp, "bg.form.addInput(form,\"ids\",\"")+29 : strings.Index(temp, "bg.form.addInput(form,\"ids\",\"")+50]
130 | ids := temp[:strings.Index(temp, "\");")]
131 | formValues = make(url.Values)
132 | formValues.Set("ignoreHead", "1")
133 | formValues.Set("showPrintAndExport", "1")
134 | formValues.Set("setting.kind", "std")
135 | formValues.Set("startWeek", "")
136 | formValues.Set("semester.id", "30")
137 | formValues.Set("ids", ids)
138 | req, err = http.NewRequest(http.MethodPost, conf.MangerURL+"eams/courseTableForStd!courseTable.action", strings.NewReader(formValues.Encode()))
139 | if err != nil {
140 | fmt.Println("ERROR_13: ", err.Error())
141 | //return
142 | }
143 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
144 | req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:66.0) Gecko/20100101 Firefox/66.0")
145 | resp4, err := client.Do(req)
146 | if err != nil {
147 | fmt.Println("ERROR_14: ", err.Error())
148 | //return
149 | }
150 | defer resp4.Body.Close()
151 |
152 | content, err = ioutil.ReadAll(resp4.Body)
153 | if err != nil {
154 | fmt.Println("ERROR_15: ", err.Error())
155 | //return
156 | }
157 |
158 | temp = string(content)
159 | if !strings.Contains(temp, "课表格式说明") {
160 | fmt.Println("ERROR_16: Get Courses Failed")
161 | //return
162 | }
163 | reg3 := regexp.MustCompile(`(?i)(\d) | \s*([:alpha:].+) | \s*(.+) | \s*((\d)|(\d\.\d)) | \s*\s*.*\s* | \s*(.*) | `)
164 | reg4 := regexp.MustCompile(`(?i)([^>]*) | `)
165 | reg5 := regexp.MustCompile(`(?i)>([^>]*)`)
166 | teanchersStr := reg3.FindAllStringSubmatch(temp, -1)
167 | for _, teacherStr := range teanchersStr {
168 | teacher := reg4.FindAllStringSubmatch(teacherStr[0], -1)
169 | courseid := reg5.FindAllStringSubmatch(teacherStr[0], -1)
170 | myTeacher.CourseID = courseid[0][1]
171 | myTeacher.CourseName = teacher[2][1]
172 | myTeacher.CourseCredit = teacher[3][1]
173 | myTeacher.CourseTeacher = teacher[4][1]
174 | teachers = append(teachers, myTeacher)
175 | }
176 | req, err = http.NewRequest(http.MethodGet, conf.MangerURL+"eams/logout.action", nil)
177 | if err != nil {
178 | fmt.Println("ERROR_17: ", err.Error())
179 | //return
180 | }
181 |
182 | resp5, err := client.Do(req)
183 | if err != nil {
184 | fmt.Println("ERROR_18: ", err.Error())
185 | //return
186 | }
187 | defer resp5.Body.Close()
188 | teacherResult.Data = teachers
189 | js, err := json.MarshalIndent(teacherResult, "", "\t")
190 | return B2S(js)
191 |
192 | }
193 |
--------------------------------------------------------------------------------
/GetWeekCourse.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "strconv"
7 | "strings"
8 | )
9 |
10 | type WeekCourse struct {
11 | CourseName string
12 | TeacherName string
13 | RoomName string
14 | DayOfTheWeek int
15 | TimeOfTheDay string
16 | }
17 |
18 | var myWeekCourse []WeekCourse
19 | var tmpCourse WeekCourse
20 | var myCourseResult WeekCourseResult
21 |
22 | func GetWeekCourse(UserName string, PassWord string, WeekDay int) string {
23 | myWeekCourse = nil
24 | myCourseResult.Type = "course"
25 | var tmpResult CourseResult
26 | var allCourses []Course
27 | allCourses = nil
28 | var cstr string = GetCourse(UserName, PassWord)
29 | err := json.Unmarshal([]byte(cstr), &tmpResult)
30 | if err != nil {
31 | fmt.Println(err)
32 | }
33 | allCourses = tmpResult.Data
34 | for _, c1 := range allCourses {
35 | schoolWeek := strconv.Itoa(WeekDay)
36 | intWeek, _ := strconv.Atoi(schoolWeek)
37 | if c1.Weeks[intWeek] == '1' {
38 | arr := GetTeacherObj()
39 | for _, thisteacher := range arr {
40 | if strings.Contains(c1.CourseID, thisteacher.CourseID) {
41 | tmpCourse.TimeOfTheDay = ""
42 | tmpCourse.TeacherName = thisteacher.CourseTeacher
43 | tmpCourse.CourseName = thisteacher.CourseName
44 | tmpCourse.RoomName = c1.RoomName
45 | tmpCourse.DayOfTheWeek = c1.CourseTimes[0].DayOfTheWeek
46 | for _, thistime := range c1.CourseTimes {
47 | tmpCourse.TimeOfTheDay = tmpCourse.TimeOfTheDay + strconv.Itoa(thistime.TimeOfTheDay+1) + ","
48 | }
49 | tmpCourse.TimeOfTheDay = strings.TrimRight(tmpCourse.TimeOfTheDay, ",")
50 | myWeekCourse = append(myWeekCourse, tmpCourse)
51 | }
52 | }
53 | }
54 | }
55 | myCourseResult.Data = myWeekCourse
56 | js, _ := json.MarshalIndent(myCourseResult, "", "\t")
57 | return B2S(js)
58 | }
59 |
--------------------------------------------------------------------------------
/GetWeekCourseNew.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "strconv"
7 | "strings"
8 | )
9 |
10 | type WeekCourseNew struct {
11 | CourseName string
12 | TeacherName string
13 | RoomName string
14 | CourseTimes []CourseTime
15 | }
16 |
17 | var myWeekCourseNew []WeekCourseNew
18 | var tmpCourseNew WeekCourseNew
19 | var myCourseResultNew WeekCourseResultNew
20 |
21 | func GetWeekCourseNew(UserName string, PassWord string, WeekDay int) string {
22 | myWeekCourseNew = nil
23 | myCourseResultNew.Type = "course"
24 | var tmpResultNew CourseResult
25 | var allCoursesNew []Course
26 | allCoursesNew = nil
27 | var cstr string = GetCourse(UserName, PassWord)
28 | err := json.Unmarshal([]byte(cstr), &tmpResultNew)
29 | if err != nil {
30 | fmt.Println(err)
31 | }
32 | allCoursesNew = tmpResultNew.Data
33 | for _, c1 := range allCoursesNew {
34 | schoolWeek := strconv.Itoa(WeekDay)
35 | intWeek, _ := strconv.Atoi(schoolWeek)
36 | if c1.Weeks[intWeek] == '1' {
37 | arr := GetTeacherObj()
38 | for _, thisteacher := range arr {
39 | if strings.Contains(c1.CourseID, thisteacher.CourseID) {
40 | tmpCourseNew.TeacherName = thisteacher.CourseTeacher
41 | tmpCourseNew.CourseName = thisteacher.CourseName
42 | tmpCourseNew.RoomName = c1.RoomName
43 | tmpCourseNew.CourseTimes = c1.CourseTimes
44 | myWeekCourseNew = append(myWeekCourseNew, tmpCourseNew)
45 | }
46 | }
47 | }
48 | }
49 | myCourseResultNew.Data = myWeekCourseNew
50 | js, _ := json.MarshalIndent(myCourseResultNew, "", "\t")
51 | return B2S(js)
52 | }
53 |
--------------------------------------------------------------------------------
/GetWeekTime.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io/ioutil"
7 | "math"
8 | "net/http"
9 | "strconv"
10 | "time"
11 | )
12 |
13 | func GetWeekTime(startTime string) string {
14 | var timeReuslt TimeResult
15 | timeReuslt.Type = "week"
16 | timeTemplate := "2006-01-02 15:04:05"
17 | now, _ := time.Parse(timeTemplate, startTime+" 00:00:00")
18 | offset := int(time.Monday - now.Weekday())
19 | if offset > 0 {
20 | offset = -6
21 | }
22 | monday := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset)
23 | nowtime := time.Now()
24 | week := (float64(nowtime.Unix()) - float64(monday.Unix())) / 604800
25 | week = math.Ceil(week)
26 | timeReuslt.Data = strconv.Itoa(int(week))
27 | js, _ := json.MarshalIndent(timeReuslt, "", "\t")
28 | return B2S(js)
29 | }
30 |
31 | func GetWeekTimeOld(serverIP, startTime string) string {
32 | //此方法依赖服务器计算教学周,已弃用
33 | url := "http://" + serverIP + "/api/nowweek.php?date=" + startTime
34 | var client http.Client
35 | req, err := http.NewRequest(http.MethodGet, url, nil)
36 | if err != nil {
37 | fmt.Println(err)
38 | }
39 | res, err := client.Do(req)
40 | if err != nil {
41 | fmt.Println(err)
42 | }
43 | defer res.Body.Close()
44 | content, err := ioutil.ReadAll(res.Body)
45 | if err != nil {
46 | fmt.Println(err)
47 | }
48 | return string(content)
49 | }
50 |
--------------------------------------------------------------------------------
/JsonResult.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | /*
4 | 为对付uni-app及微信小程序只能创建一个websocket链接的弱智举动,特针对返回JSON进行统一格式管理
5 | 由于Golang没有object,临时想出这个办法管理返回
6 | */
7 | type WeekCourseResultNew struct {
8 | Type string
9 | Data []WeekCourseNew
10 | }
11 | type WeekCourseResult struct {
12 | Type string
13 | Data []WeekCourse
14 | }
15 | type CourseResult struct {
16 | Type string
17 | Data []Course
18 | }
19 | type DayCourseResult struct {
20 | Type string
21 | Data []DayCourse
22 | }
23 | type TeacherResult struct {
24 | Type string
25 | Data []TeacherStruct
26 | }
27 | type PhotoResult struct {
28 | Type string
29 | Data string
30 | }
31 | type AccountResult struct {
32 | Type string
33 | Data StudentStruct
34 | }
35 | type LoginResult struct {
36 | Type string
37 | Data string
38 | }
39 | type TimeResult struct {
40 | Type string
41 | Data string
42 | }
43 | type GradeResult struct {
44 | Type string
45 | Data []GradeStruct
46 | }
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 清丶风
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WeCourseService
2 |
3 | 微课表服务端,基于[getMyCourses](https://github.com/whoisnian/getMyCourses)项目
4 |
5 | 本项目可以看作是一种第三方的树维教务系统开发SDK,可以根据自己的需求继承到项目当中 例如校园门禁、教室展示屏、电子宿舍门牌等
6 |
7 | 目前仅支持树维教务系统 后续会考虑增加其他教务系统
8 |
9 | 本项目使用了GoCache缓存库,避免了频繁访问教务系统的问题
10 |
11 | ## 使用方法
12 |
13 | * 将项目部署到服务器,防火墙开放25565(默认)端口
14 |
15 | * 在uni-app中修改服务端地址
16 |
17 | * 修改config.json中的内容以适配自己的学校
18 |
19 | config.json内容如下:
20 |
21 | ```json
22 | {
23 | "SchoolName":"山东商业职业技术学院",
24 | "MangerType":"supwisdom",
25 | "MangerURL":"http://szyjxgl.sict.edu.cn:9000/",
26 | "CalendarFirst":"2020-02-17",
27 | "SocketPort":25565
28 | }
29 | ```
30 |
31 | SchoolName为学校名称
32 |
33 | MangerType为教务系统类型,目前只支持树维教务系统(supwisdom)
34 |
35 | MangerURL为教务系统地址 注意不能包含eams 必须为根路径
36 |
37 | CalendarFirst为校历上的第一个星期一,即第一周开始的日期
38 |
39 | SocketPort为websocket开放的端口 请使用nginx转发WebSocketSSL以便支持微信小程序
40 |
41 | ## 请求格式
42 |
43 | 本程序通信协议为WebSocket 数据交换格式为JSON
44 |
45 | ```json
46 | {
47 | "Type":"course",
48 | "UserName":"201808830303",
49 | "PassWord":"7355608",
50 | "Week":0
51 | }
52 | ```
53 |
54 | Type为必填项,表明请求类型 可选内容为:login(验证登录)、week(获取当前教学周)、teacher(获取教师列表)、account(获取学籍信息)、course(获取课程表)、photo(获取学籍照片)、grade(获取成绩) 日后还会增加更多接口例如获取考试安排、获取成绩
55 |
56 | UserName为教务系统登陆账号,除了获取教学周外都需要提供
57 |
58 | PassWord为教务系统登录密码,除了获取教学周外都需要提供
59 |
60 | Week为需要获取的教学周 仅在获取课表时需要提供
61 |
62 | ## 返回格式
63 |
64 | ```json
65 | {
66 | "Type":"login",
67 | "Data":object
68 | }
69 | ```
70 |
71 | 由于uni-app只支持同时连接一个websocket,为方便管理 特修改了返回格式
72 |
73 | Type和请求时传入的Type一致 Data为返回内容 为object 数据类型不唯一
74 |
75 | 以下例子中的返回示例均代表返回结果的Data内容
76 |
77 | ### 1、验证登录
78 |
79 | 该功能用于验证账号密码是否能成功登录教务系统,传入JSON格式如下
80 |
81 | ```json
82 | {
83 | "Type":"login",
84 | "UserName":"201808830303",
85 | "PassWord":"7355608"
86 | }
87 | ```
88 |
89 | > 返回结果为“登录成功”或“登录失败”
90 |
91 | ### 2、获取教学周
92 |
93 | 这个功能主要是为了方便同学们获取现在是第几周(学校的奇葩校历看的头大) 请求格式也相当简单
94 |
95 | ```json
96 | {
97 | "Type":"week"
98 | }
99 | ```
100 |
101 | > 返回结果也是非常简单 直接会返回当前周的数字
102 |
103 | ### 3、获取教师列表
104 |
105 | 这个功能是为了防止小伙伴们忘记自己的老师是谁而设计的(虽然这种情况出现的概率不大)
106 | 请求格式是这样的
107 |
108 | ```json
109 | {
110 | "Type":"teacher",
111 | "UserName":"201808830303",
112 | "PassWord":"7355608"
113 | }
114 | ```
115 |
116 | 返回示例
117 |
118 | ```json
119 | [
120 | {
121 | "CourseID": "A000032-.5.11",
122 | "CourseName": "就业指导实务",
123 | "CourseCredit": "0.5",
124 | "CourseTeacher": "王滢"
125 | },
126 | {
127 | "CourseID": "A080311-4.11",
128 | "CourseName": "JavaScript程序设计",
129 | "CourseCredit": "4",
130 | "CourseTeacher": "薛现伟"
131 | }
132 | ]
133 | ```
134 |
135 | CourseID为教务系统内部分配的课程ID,CourseName为课程名称,CourseCredit为该课程学分,CourseTeacher为该课程任课教师
136 |
137 | ### 4、获取学籍信息
138 |
139 | 这个功能可以用来做用户身份识别,比如说展示资料卡一类的
140 |
141 | > 免责声明:请先阅读有关公民个人信息储存及使用的法律法规以免产生法律责任,无特殊要求不要储存或缓存用户个人信息 严禁将用户个人信息用于违法犯罪活动
142 |
143 | 请求格式是这样的
144 |
145 | ```json
146 | {
147 | "Type":"account",
148 | "UserName":"201808830303",
149 | "PassWord":"7355608"
150 | }
151 | ```
152 |
153 | 返回结果示例
154 |
155 | ```json
156 | {
157 | "FullName": "高峰",
158 | "EnglishName": "Gao Feng",
159 | "Sex": "男",
160 | "StartTime": "2018-09-01",
161 | "EndTime": "2021-06-30",
162 | "SchoolYear": "3",
163 | "Type": "专科(普通全日制)",
164 | "System": "信息与艺术学院(系)",
165 | "Specialty": "软件技术对口",
166 | "Class": "软件1803"
167 | }
168 | ```
169 |
170 | FullName为中文全名,EnglishName为英文名称(留学生等特殊情况),Sex为性别,StartTime为入学时间,EndTime为毕业时间,SchoolYear为学年,Type为学历类型(专科、本科、普招、单招等),System为院系,Speacialty为专业,Class为班级。
171 |
172 | ### 5、获取课程表
173 |
174 | 本程序的核心功能,用于获取本人的本学期全部课程表或本周课程表
175 |
176 | 请求格式是这样的
177 |
178 | ```json
179 | {
180 | "Type":"course",
181 | "UserName":"201808830303",
182 | "PassWord":"7355608",
183 | "Week":0
184 | }
185 | ```
186 |
187 | 前三个参数与之前的用途一致,这里不再废话,Week为要查询的教学周 如果为0则返回本学期课程表,为其他数值则返回对应周的课程表
188 |
189 | 返回结果也有两种 如果是返回本学期课程表(Week为0时) 那么返回格式如下:
190 |
191 | ```json
192 | [
193 | {
194 | "CourseID": "14290(A080311-4.11)",
195 | "CourseName": "JavaScript程序设计",
196 | "RoomID": "1526",
197 | "RoomName": "301,计算机基础实训室(一)",
198 | "Weeks": "01111111111111111110000000000000000000000000000000000",
199 | "CourseTimes": [
200 | {
201 | "DayOfTheWeek": 3,
202 | "TimeOfTheDay": 4
203 | },
204 | {
205 | "DayOfTheWeek": 3,
206 | "TimeOfTheDay": 5
207 | }
208 | ]
209 | },
210 | {
211 | "CourseID": "19827(A080910-6.09)",
212 | "CourseName": "HTML5混合App开发",
213 | "RoomID": "-1",
214 | "RoomName": "停课",
215 | "Weeks": "00000000000010000000000000000000000000000000000000000",
216 | "CourseTimes": [
217 | {
218 | "DayOfTheWeek": 2,
219 | "TimeOfTheDay": 0
220 | },
221 | {
222 | "DayOfTheWeek": 2,
223 | "TimeOfTheDay": 1
224 | }
225 | ]
226 | }
227 | ]
228 | ```
229 |
230 | 其中CourseID为教务系统分配的课程ID,数字ID括号内的文本与教师列表一致 CourseName为课程名称,RoomID为教务系统内部的教室ID,RoomName为教室名称,Weeks为上课的周,从第0周开始计算 有课为1无课为0 CourseTimes为课程上课时间,DayOfTheWeek为周几上课(0表示周一),TimeOfTheDay表示该课程在当天的第几节(0表示第一节)
231 |
232 | > 由于早期开发的微课表(MUI版)对代码优化没有考虑(大一的时候写的,缺少社会的毒打),所以都是直接请求本学期全部的课程,所以这个方法在新版本的程序已经弃用了,为了做兼容考虑才把这个反人类的方法保留了下来
233 |
234 | 改善后的返回结果示例(Week不为0 获取某周课程表):
235 |
236 | ```json
237 | [
238 | {
239 | "CourseName": "JavaScript程序设计",
240 | "TeacherName": "薛现伟",
241 | "RoomName": "301,计算机基础实训室(一)",
242 | "DayOfTheWeek": 3,
243 | "TimeOfTheDay": "5,6"
244 | },
245 | {
246 | "CourseName": "HTML5混合App开发",
247 | "TeacherName": "王永乾",
248 | "RoomName": "317,信息决策实训室j",
249 | "DayOfTheWeek": 3,
250 | "TimeOfTheDay": "1,2"
251 | },
252 | {
253 | "CourseName": "PHP动态网站开发",
254 | "TeacherName": "郑春光",
255 | "RoomName": "317,信息决策实训室j",
256 | "DayOfTheWeek": 3,
257 | "TimeOfTheDay": "3,4"
258 | },
259 | {
260 | "CourseName": "就业指导实务",
261 | "TeacherName": "王滢",
262 | "RoomName": "本部E206",
263 | "DayOfTheWeek": 2,
264 | "TimeOfTheDay": "3,4"
265 | }
266 | ]
267 | ```
268 |
269 | 可以看到新版的返回结果变得清晰明了,CourseName为课程名称,TeacherName为教师姓名,RoomName为教室名称,DayOfTheWeek依然是表示在周几上课(从0开始,0表示周一),TimeOfTheDay自动整合当天有课的节次,例如3,4则表示当天第三节、第四节有课
270 |
271 | ### 6、获取学籍照片
272 |
273 | > 免责声明:请先阅读有关公民个人信息储存及使用、公民肖像权相关的法律法规以免产生法律责任,无特殊要求不要储存或缓存用户个人信息 严禁将用户个人信息用于违法犯罪活动
274 |
275 | 本功能可用于用户身份识别(人脸识别)、资料头像、电子学籍卡等用途
276 |
277 | 请求格式是这样的
278 |
279 | ```json
280 | {
281 | "Type":"photo",
282 | "UserName":"201808830303",
283 | "PassWord":"7355608"
284 | }
285 | ```
286 |
287 | 返回结果为base64图片
288 |
289 | ```
290 | data:image/jpg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/...NFaXMND/9k=
291 | ```
292 |
293 | ### 7、获取成绩
294 |
295 | 本功能也算是一个比较常用的功能,毕竟关乎着自己是否挂科 为了方便同学们查询自己的成绩才有的这个功能
296 | 请求格式是这样的
297 |
298 | ```json
299 | {
300 | "Type":"grade",
301 | "UserName":"201808830303",
302 | "PassWord":"7355608"
303 | }
304 | ```
305 | 返回结果示例
306 |
307 | ```json
308 | [
309 | {
310 | "CourseID": "A000003-4",
311 | "CourseName": "大学英语(一)A",
312 | "CourseTerm": "2018-2019 1",
313 | "CourseCredit": "4",
314 | "CourseGrade": "64",
315 | "GradePoint": "1.5"
316 | },
317 | {
318 | "CourseID": "A080011-6",
319 | "CourseName": "Java程序设计",
320 | "CourseTerm": "2018-2019 2",
321 | "CourseCredit": "6",
322 | "CourseGrade": "95",
323 | "GradePoint": "4.5"
324 | },
325 | {
326 | "CourseID": "A080310-6",
327 | "CourseName": "JavaWeb程序设计",
328 | "CourseTerm": "2019-2020 1",
329 | "CourseCredit": "6",
330 | "CourseGrade": "93",
331 | "GradePoint": "4.5"
332 | }
333 | ]
334 | ```
335 |
336 | 返回的子项全部为String类型(教务系统的返回结果十分奇葩,天然反爬(一时间写不出合适的正则表达式)),CourseID和先前几个接口一样,都是表示课程ID(不过这个和教师列表的不一样,因为这个是院系课程统一的编号,而教师列表的是每个老师的课程ID都不一样) CourseName是课程名称 CourseTerm代表学期 例如2019-2020 1就代表是2019-2020学年第一学期 CourseCredit代表学分 CourseGrade代表最终成绩 GradePoint代表绩点
337 |
338 |
339 | ## 版权协议
340 |
341 | 本项目为MIT License协议,授权各类合法程序引用(需在法律信息中标注出处)
342 |
343 | 项目已获得软件著作权(登记号:2019SR0620279)
344 |
345 | 严谨出售倒卖 违者必究
346 |
347 | ## 联系方式
348 |
349 | 如果在使用过程中出现问题,您可以给我发issues(基本不看,不建议使用该方式)
350 |
351 | 联系QQ:77257474 电子邮箱:root@mchacker.cn
352 |
353 | 请注明来意,谢谢!
--------------------------------------------------------------------------------
/WebSocket.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "net/http"
7 | "strconv"
8 |
9 | "github.com/gorilla/websocket"
10 | )
11 |
12 | type userlogin struct {
13 | Type string
14 | UserName string
15 | PassWord string
16 | Week int
17 | }
18 |
19 | var build string = "202011211630-Fixed"
20 | var upgrader = websocket.Upgrader{
21 | ReadBufferSize: 1024,
22 | WriteBufferSize: 1024,
23 | CheckOrigin: func(r *http.Request) bool {
24 | return true
25 | },
26 | }
27 |
28 | func StartWebSocket() {
29 | fmt.Println("Websocket服务开始运行")
30 | fmt.Println("固件版本:" + build)
31 | conf := ReadConfig()
32 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
33 | conn, _ := upgrader.Upgrade(w, r, nil)
34 | for {
35 | msgType, msg, _ := conn.ReadMessage()
36 | var u userlogin
37 | json.Unmarshal([]byte(msg), &u)
38 | if u.Type == "allcourse" {
39 | var cstr string = GetCourse(u.UserName, u.PassWord)
40 | _ = conn.WriteMessage(msgType, []byte(cstr))
41 | }
42 | if u.Type == "daycourse" {
43 | var cstr string = GetDayCourse(u.UserName, u.PassWord)
44 | _ = conn.WriteMessage(msgType, []byte(cstr))
45 | }
46 | if u.Type == "course" {
47 | var cstr string = GetWeekCourse(u.UserName, u.PassWord, u.Week)
48 | _ = conn.WriteMessage(msgType, []byte(cstr))
49 | }
50 | if u.Type == "weekcourse" {
51 | var cstr string = GetWeekCourseNew(u.UserName, u.PassWord, u.Week)
52 | _ = conn.WriteMessage(msgType, []byte(cstr))
53 | }
54 | if u.Type == "account" {
55 | _ = conn.WriteMessage(msgType, []byte(GetAccount(u.UserName, u.PassWord)))
56 | }
57 | if u.Type == "login" {
58 | _ = conn.WriteMessage(msgType, []byte(GetUserLogin(u.UserName, u.PassWord)))
59 | }
60 | if u.Type == "week" {
61 | _ = conn.WriteMessage(msgType, []byte(GetWeekTime(conf.CalendarFirst)))
62 | }
63 | if u.Type == "teacher" {
64 | _ = conn.WriteMessage(msgType, []byte(GetTeacher(u.UserName, u.PassWord)))
65 | }
66 | if u.Type == "photo" {
67 | _ = conn.WriteMessage(msgType, []byte(GetPhoto(u.UserName, u.PassWord)))
68 | }
69 | if u.Type == "grade" {
70 | _ = conn.WriteMessage(msgType, []byte(GetGrade(u.UserName, u.PassWord)))
71 | }
72 | }
73 |
74 | })
75 | http.ListenAndServe(":"+strconv.Itoa(conf.SocketPort), nil)
76 | }
77 |
78 | func checkErr(err error) {
79 | if err != nil {
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "SchoolName":"山东商业职业技术学院",
3 | "MangerType":"supwisdom",
4 | "MangerURL":"http://szyjxgl.sict.edu.cn:9000/",
5 | "CalendarFirst":"2020-08-24",
6 | "SocketPort":25565
7 | }
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | )
7 |
8 | func main() {
9 | conf := ReadConfig()
10 | fmt.Println("学校名称:" + conf.SchoolName)
11 | switch conf.MangerType {
12 | case "supwisdom":
13 | fmt.Println("教务系统:树维教务系统")
14 | break
15 | }
16 | fmt.Println("绑定端口:" + strconv.Itoa(conf.SocketPort))
17 | StartWebSocket()
18 | }
19 |
--------------------------------------------------------------------------------