Добавлено: загрузка и парсинг расписания в одной функции
This commit is contained in:
parent
aea8cb77b2
commit
16f5abc820
|
@ -21,17 +21,16 @@ type ShedulesInUser struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Group struct {
|
type Group struct {
|
||||||
GroupId int64 `xorm:"pk"`
|
GroupId int64 `xorm:"pk"`
|
||||||
GroupName string
|
GroupName string // Полный номер группы
|
||||||
SpecName string
|
SpecName string // Шифр и название специальности
|
||||||
}
|
}
|
||||||
|
|
||||||
type Teacher struct {
|
type Teacher struct {
|
||||||
TeacherId int64 `xorm:"pk"`
|
TeacherId int64 `xorm:"pk"`
|
||||||
LastName string
|
FirstName string // Фамилия
|
||||||
FirstName string
|
LastName string // Имя, отчество и прочие окончания
|
||||||
MidName string
|
SpecName string // Место работы
|
||||||
SpecName string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Lesson struct {
|
type Lesson struct {
|
||||||
|
|
|
@ -8,8 +8,22 @@ import (
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func UpdateSchedule(db *xorm.Engine, sh WeekShedule) error {
|
||||||
|
err := checkGroupOrTeacher(db, sh)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
first_new := sh.Uncovered[0]
|
||||||
|
_, week := first_new.Begin.ISOWeek()
|
||||||
|
var old []database.Lesson
|
||||||
|
db.Where("WEEK(`Begin`) = ?", week).Asc("Begin").Find(&old)
|
||||||
|
Compare(sh.Uncovered, old)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func UploadShedule(db *xorm.Engine, sh WeekShedule) error {
|
func UploadShedule(db *xorm.Engine, sh WeekShedule) error {
|
||||||
err := addGroupOrTeacher(db, sh)
|
err := checkGroupOrTeacher(db, sh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -42,7 +56,7 @@ func UploadShedule(db *xorm.Engine, sh WeekShedule) error {
|
||||||
gr.IsGroup = false
|
gr.IsGroup = false
|
||||||
gr.SheduleId = subLesson.TeacherId[0]
|
gr.SheduleId = subLesson.TeacherId[0]
|
||||||
GetSheduleInfo(doc.Doc, &gr)
|
GetSheduleInfo(doc.Doc, &gr)
|
||||||
addGroupOrTeacher(db, gr)
|
checkGroupOrTeacher(db, gr)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, groupId := range subLesson.GroupId {
|
for _, groupId := range subLesson.GroupId {
|
||||||
|
@ -63,7 +77,7 @@ func UploadShedule(db *xorm.Engine, sh WeekShedule) error {
|
||||||
gr.IsGroup = true
|
gr.IsGroup = true
|
||||||
gr.SheduleId = groupId
|
gr.SheduleId = groupId
|
||||||
GetSheduleInfo(doc.Doc, &gr)
|
GetSheduleInfo(doc.Doc, &gr)
|
||||||
addGroupOrTeacher(db, gr)
|
checkGroupOrTeacher(db, gr)
|
||||||
}
|
}
|
||||||
|
|
||||||
var existsLessons []database.Lesson
|
var existsLessons []database.Lesson
|
||||||
|
@ -109,7 +123,9 @@ func isTeacherExists(db *xorm.Engine, teacherId int64) (bool, error) {
|
||||||
return len(exists) == 1, nil
|
return len(exists) == 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addGroupOrTeacher(db *xorm.Engine, sh WeekShedule) error {
|
// Проверка наличия группы или преподавателя в БД и добавление при необходимости
|
||||||
|
// TODO: Добавить проверку изменений в полях данных
|
||||||
|
func checkGroupOrTeacher(db *xorm.Engine, sh WeekShedule) error {
|
||||||
if sh.IsGroup {
|
if sh.IsGroup {
|
||||||
exists, err := isGroupExists(db, sh.SheduleId)
|
exists, err := isGroupExists(db, sh.SheduleId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -135,8 +151,8 @@ func addGroupOrTeacher(db *xorm.Engine, sh WeekShedule) error {
|
||||||
log.Println(name)
|
log.Println(name)
|
||||||
teacher := database.Teacher{
|
teacher := database.Teacher{
|
||||||
TeacherId: sh.SheduleId,
|
TeacherId: sh.SheduleId,
|
||||||
LastName: name[0],
|
FirstName: name[0],
|
||||||
FirstName: strings.Join(name[1:], " "),
|
LastName: strings.Join(name[1:], " "),
|
||||||
SpecName: sh.SpecName,
|
SpecName: sh.SpecName,
|
||||||
}
|
}
|
||||||
db.InsertOne(teacher)
|
db.InsertOne(teacher)
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Раскрытие недельного расписания в список занятий для базы данных и сравнения
|
// Раскрытие недельного расписания в список занятий для базы данных и сравнения
|
||||||
func UncoverShedule(sh WeekShedule) []database.Lesson {
|
func (sh *WeekShedule) UncoverShedule() {
|
||||||
var lessons []database.Lesson
|
var lessons []database.Lesson
|
||||||
for y, line := range sh.Lessons {
|
for y, line := range sh.Lessons {
|
||||||
for x, pair := range line {
|
for x, pair := range line {
|
||||||
|
@ -41,7 +41,7 @@ func UncoverShedule(sh WeekShedule) []database.Lesson {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lessons
|
sh.Uncovered = lessons
|
||||||
}
|
}
|
||||||
|
|
||||||
// Сравнивание списков занятий на предмет добавления и удаления
|
// Сравнивание списков занятий на предмет добавления и удаления
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
package ssau_parser
|
package ssau_parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.l9labs.ru/anufriev.g.a/l9_stud_bot/modules/database"
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Пара, состоящая из занятий
|
||||||
type Pair struct {
|
type Pair struct {
|
||||||
Begin time.Time
|
Begin time.Time
|
||||||
End time.Time
|
End time.Time
|
||||||
|
@ -16,6 +19,7 @@ type Pair struct {
|
||||||
Lessons []Lesson
|
Lessons []Lesson
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Отдельные занятия внутри пары
|
||||||
type Lesson struct {
|
type Lesson struct {
|
||||||
Type string
|
Type string
|
||||||
Name string
|
Name string
|
||||||
|
@ -27,14 +31,16 @@ type Lesson struct {
|
||||||
Hash []byte
|
Hash []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Недельное расписание
|
||||||
type WeekShedule struct {
|
type WeekShedule struct {
|
||||||
IsGroup bool
|
IsGroup bool
|
||||||
SheduleId int64
|
SheduleId int64
|
||||||
FullName string
|
FullName string
|
||||||
SpecName string
|
SpecName string
|
||||||
Week int
|
Week int // Номер недели в семестре
|
||||||
WeekBegin int
|
WeekBegin int // Номер недели в году начала семестра
|
||||||
Lessons [][]Pair
|
Lessons [][]Pair // Таблица пар в форме недельного расписания
|
||||||
|
Uncovered []database.Lesson // Раскрытый список всех занятий для дальнейшей обработки в БД
|
||||||
}
|
}
|
||||||
|
|
||||||
// Получить полный номер группы и название специальности (ФИО и место работы для преподавателей)
|
// Получить полный номер группы и название специальности (ФИО и место работы для преподавателей)
|
||||||
|
@ -58,10 +64,9 @@ func GetSheduleInfo(doc *goquery.Document, sh *WeekShedule) {
|
||||||
var hourMap = map[int]int{8: 0, 9: 1, 11: 2, 13: 3, 15: 4, 17: 5, 18: 6, 20: 7}
|
var hourMap = map[int]int{8: 0, 9: 1, 11: 2, 13: 3, 15: 4, 17: 5, 18: 6, 20: 7}
|
||||||
|
|
||||||
// Парсинг страницы с расписанием
|
// Парсинг страницы с расписанием
|
||||||
func Parse(p Page) (*WeekShedule, error) {
|
func (sh *WeekShedule) Parse(p Page, uncover bool) error {
|
||||||
var sh WeekShedule
|
|
||||||
doc := p.Doc
|
doc := p.Doc
|
||||||
GetSheduleInfo(doc, &sh)
|
GetSheduleInfo(doc, sh)
|
||||||
|
|
||||||
var raw_dates []string
|
var raw_dates []string
|
||||||
doc.Find(".schedule__head-date").Each(func(i int, s *goquery.Selection) {
|
doc.Find(".schedule__head-date").Each(func(i int, s *goquery.Selection) {
|
||||||
|
@ -88,7 +93,7 @@ func Parse(p Page) (*WeekShedule, error) {
|
||||||
if t == 0 {
|
if t == 0 {
|
||||||
begin, err := time.Parse(" 15:04 -07", raw_times[t])
|
begin, err := time.Parse(" 15:04 -07", raw_times[t])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
firstNum = hourMap[begin.Hour()]
|
firstNum = hourMap[begin.Hour()]
|
||||||
}
|
}
|
||||||
|
@ -98,12 +103,12 @@ func Parse(p Page) (*WeekShedule, error) {
|
||||||
begin_raw := date + raw_times[t]
|
begin_raw := date + raw_times[t]
|
||||||
begin, err := time.Parse(" 02.01.2006 15:04 -07", begin_raw)
|
begin, err := time.Parse(" 02.01.2006 15:04 -07", begin_raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
end_raw := date + raw_times[t+1]
|
end_raw := date + raw_times[t+1]
|
||||||
end, err := time.Parse(" 02.01.2006 15:04 -07", end_raw)
|
end, err := time.Parse(" 02.01.2006 15:04 -07", end_raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
idx := (len(raw_dates))*t/2 + d
|
idx := (len(raw_dates))*t/2 + d
|
||||||
lesson := Pair{
|
lesson := Pair{
|
||||||
|
@ -120,7 +125,11 @@ func Parse(p Page) (*WeekShedule, error) {
|
||||||
sh.SheduleId = p.ID
|
sh.SheduleId = p.ID
|
||||||
sh.Week = p.Week
|
sh.Week = p.Week
|
||||||
sh.Lessons = shedule
|
sh.Lessons = shedule
|
||||||
return &sh, nil
|
|
||||||
|
if uncover {
|
||||||
|
sh.UncoverShedule()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var types = [4]string{"lect", "lab", "pract", "other"}
|
var types = [4]string{"lect", "lab", "pract", "other"}
|
||||||
|
@ -212,3 +221,37 @@ func ParseLesson(s *goquery.Selection, isGroup bool, sheduleId int64) []Lesson {
|
||||||
|
|
||||||
return lessons
|
return lessons
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Загрузка, парсинг и раскрытие расписания в одной функции
|
||||||
|
// Обязательно наличие IsGroup, SheduleId, Week в объекте
|
||||||
|
func (sh *WeekShedule) DownloadById(uncover bool) error {
|
||||||
|
if sh.SheduleId == 0 {
|
||||||
|
return errors.New("schedule id not included")
|
||||||
|
}
|
||||||
|
if sh.Week == 0 {
|
||||||
|
return errors.New("week not included")
|
||||||
|
}
|
||||||
|
|
||||||
|
page, err := DownloadSheduleById(sh.SheduleId, sh.IsGroup, sh.Week)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = sh.Parse(page, uncover)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Загрузка, парсинг и раскрытие расписания в одной функции по URI и номеру недели
|
||||||
|
func (sh *WeekShedule) Download(uri string, week int, uncover bool) error {
|
||||||
|
page, err := DownloadShedule(uri, week)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = sh.Parse(page, uncover)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package ssau_parser
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"git.l9labs.ru/anufriev.g.a/l9_stud_bot/modules/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
var queries = []string{
|
var queries = []string{
|
||||||
|
@ -21,6 +23,13 @@ var urls = []string{
|
||||||
"http://127.0.0.1:5000",
|
"http://127.0.0.1:5000",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Вывод некритических ошибок тестирования в консоль
|
||||||
|
func handleError(err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: выдумать и прописать упоротые тесты для всего
|
// TODO: выдумать и прописать упоротые тесты для всего
|
||||||
func TestSearchInRasp(t *testing.T) {
|
func TestSearchInRasp(t *testing.T) {
|
||||||
// Проверка запросов
|
// Проверка запросов
|
||||||
|
@ -75,68 +84,83 @@ func TestDownloadShedule(t *testing.T) {
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
func TestParse(t *testing.T) {
|
||||||
headURL = "http://127.0.0.1:5000"
|
headURL = "http://127.0.0.1:5000"
|
||||||
page, err := DownloadSheduleById(802440189, true, 3)
|
sh := WeekShedule{
|
||||||
if err != nil {
|
SheduleId: 802440189,
|
||||||
log.Println(err)
|
IsGroup: true,
|
||||||
return
|
Week: 3,
|
||||||
}
|
|
||||||
_, err = Parse(page)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
}
|
||||||
|
err := sh.DownloadById(false)
|
||||||
|
handleError(err)
|
||||||
|
|
||||||
// Ошибки в скелете расписания
|
// Ошибки в скелете расписания
|
||||||
for i := 1; i < 6; i++ {
|
for i := 1; i < 6; i++ {
|
||||||
page, err := DownloadSheduleById(123, true, i)
|
sh := WeekShedule{
|
||||||
if err != nil {
|
SheduleId: 123,
|
||||||
log.Println(err)
|
IsGroup: true,
|
||||||
return
|
Week: i,
|
||||||
}
|
|
||||||
_, err = Parse(page)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
}
|
||||||
|
err = sh.DownloadById(false)
|
||||||
|
handleError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ошибки внутри пар
|
// Ошибки внутри пар
|
||||||
for i := 2; i < 3; i++ {
|
for i := 2; i < 3; i++ {
|
||||||
page, err := DownloadSheduleById(62806001, false, i)
|
sh := WeekShedule{
|
||||||
if err != nil {
|
SheduleId: 62806001,
|
||||||
log.Println(err)
|
IsGroup: false,
|
||||||
return
|
Week: i,
|
||||||
}
|
|
||||||
sh, err := Parse(page)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
}
|
||||||
|
err = sh.DownloadById(false)
|
||||||
|
handleError(err)
|
||||||
log.Println(sh.FullName)
|
log.Println(sh.FullName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSheduleCompare(t *testing.T) {
|
func TestSheduleCompare(t *testing.T) {
|
||||||
headURL = "http://127.0.0.1:5000"
|
headURL = "http://127.0.0.1:5000"
|
||||||
page, err := DownloadSheduleById(802440189, true, 4)
|
sh := WeekShedule{
|
||||||
if err != nil {
|
SheduleId: 802440189,
|
||||||
log.Println(err)
|
IsGroup: true,
|
||||||
return
|
Week: 4,
|
||||||
}
|
}
|
||||||
sh, err := Parse(page)
|
err := sh.DownloadById(true)
|
||||||
if err != nil {
|
handleError(err)
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
lessons := UncoverShedule(*sh)
|
|
||||||
|
|
||||||
page, err = DownloadSheduleById(802440189, true, 8)
|
new_sh := WeekShedule{
|
||||||
if err != nil {
|
SheduleId: 802440189,
|
||||||
log.Println(err)
|
IsGroup: true,
|
||||||
return
|
Week: 8,
|
||||||
}
|
}
|
||||||
sh, err = Parse(page)
|
err = new_sh.DownloadById(true)
|
||||||
if err != nil {
|
handleError(err)
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
new_lessons := UncoverShedule(*sh)
|
|
||||||
|
|
||||||
add, del := Compare(new_lessons, lessons)
|
add, del := Compare(new_sh.Uncovered, sh.Uncovered)
|
||||||
log.Println(add, del)
|
log.Println(add, del)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCheckGroupOrTeacher(t *testing.T) {
|
||||||
|
db, err := database.Connect("test", "TESTpass1!", "testdb")
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Очистка всех данных для теста
|
||||||
|
_, err = db.Where("groupid > 0").Delete(&database.Group{})
|
||||||
|
handleError(err)
|
||||||
|
_, err = db.Where("teacherid > 0").Delete(&database.Teacher{})
|
||||||
|
handleError(err)
|
||||||
|
|
||||||
|
headURL = "http://127.0.0.1:5000"
|
||||||
|
sh := WeekShedule{
|
||||||
|
SheduleId: 802440189,
|
||||||
|
IsGroup: true,
|
||||||
|
Week: 4,
|
||||||
|
}
|
||||||
|
err = sh.DownloadById(false)
|
||||||
|
handleError(err)
|
||||||
|
err = checkGroupOrTeacher(db, sh)
|
||||||
|
handleError(err)
|
||||||
|
// Повторяем на предмет наличия
|
||||||
|
err = checkGroupOrTeacher(db, sh)
|
||||||
|
handleError(err)
|
||||||
|
}
|
||||||
|
|
|
@ -102,7 +102,6 @@ func (bot *Bot) Find(query string) error {
|
||||||
TeacherId: elem.Id,
|
TeacherId: elem.Id,
|
||||||
LastName: name[0],
|
LastName: name[0],
|
||||||
FirstName: name[1],
|
FirstName: name[1],
|
||||||
MidName: name[2],
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,8 +323,8 @@ func PairToStr(pair []database.Lesson, db *xorm.Engine) (string, error) {
|
||||||
name := GenerateName(t)
|
name := GenerateName(t)
|
||||||
str += fmt.Sprintf("👤 %s\n", name)
|
str += fmt.Sprintf("👤 %s\n", name)
|
||||||
}
|
}
|
||||||
if sublesson.SubGroup != "" {
|
if sublesson.SubGroup != 0 {
|
||||||
str += fmt.Sprintf("👥 %s\n", sublesson.SubGroup)
|
str += fmt.Sprintf("👥 %d\n", sublesson.SubGroup)
|
||||||
}
|
}
|
||||||
if sublesson.Comment != "" {
|
if sublesson.Comment != "" {
|
||||||
str += fmt.Sprintf("💬 %s\n", sublesson.Comment)
|
str += fmt.Sprintf("💬 %s\n", sublesson.Comment)
|
||||||
|
|
|
@ -257,8 +257,8 @@ func (bot *Bot) CreateHTMLShedule(week int, shedule [][6][]database.Lesson, date
|
||||||
if l[0].Place != "" {
|
if l[0].Place != "" {
|
||||||
html += fmt.Sprintf("<h3>%s</h3>\n", l[0].Place)
|
html += fmt.Sprintf("<h3>%s</h3>\n", l[0].Place)
|
||||||
}
|
}
|
||||||
if l[0].SubGroup != "" {
|
if l[0].SubGroup != 0 {
|
||||||
html += fmt.Sprintf("<h3>%s</h3>\n", l[0].SubGroup)
|
html += fmt.Sprintf("<h3>%d</h3>\n", l[0].SubGroup)
|
||||||
}
|
}
|
||||||
if l[0].Comment != "" {
|
if l[0].Comment != "" {
|
||||||
html += fmt.Sprintf("<h3>%s</h3>\n", l[0].Comment)
|
html += fmt.Sprintf("<h3>%s</h3>\n", l[0].Comment)
|
||||||
|
@ -278,8 +278,8 @@ func (bot *Bot) CreateHTMLShedule(week int, shedule [][6][]database.Lesson, date
|
||||||
if l[1].Place != "" {
|
if l[1].Place != "" {
|
||||||
html += fmt.Sprintf("<h3>%s</h3>\n", l[1].Place)
|
html += fmt.Sprintf("<h3>%s</h3>\n", l[1].Place)
|
||||||
}
|
}
|
||||||
if l[1].SubGroup != "" {
|
if l[1].SubGroup != 0 {
|
||||||
html += fmt.Sprintf("<h3>%s</h3>\n", l[1].SubGroup)
|
html += fmt.Sprintf("<h3>%d</h3>\n", l[1].SubGroup)
|
||||||
}
|
}
|
||||||
if l[1].Comment != "" {
|
if l[1].Comment != "" {
|
||||||
html += fmt.Sprintf("<h3>%s</h3>\n", l[1].Comment)
|
html += fmt.Sprintf("<h3>%s</h3>\n", l[1].Comment)
|
||||||
|
|
Reference in New Issue