From 2e438541d00c462be50633f23e49f15173446308 Mon Sep 17 00:00:00 2001 From: smugg99 Date: Fri, 8 Nov 2024 00:21:44 +0100 Subject: [PATCH] added togglable animations, more colors to the ui, oled theme, error feedback, fixed scraper bug with multiple indexes and the same key --- .gitignore | 4 +- common/models/data.pb.go | 545 ++++++++++-------- common/utils/utils.go | 36 +- core/datastore/crud.go | 15 + core/observer/observer.go | 13 +- core/scraper/scraper.go | 128 ++-- data.proto | 8 +- .../components.d.ts | 17 +- .../index.html | 2 +- .../public/favicon.ico | Bin 15406 -> 0 bytes .../src/App.vue | 23 +- .../src/components/AnimationsSwitcher.vue | 43 ++ .../src/components/DivisionButton.vue | 9 +- .../src/components/LanguageSwitcher.vue | 9 +- .../src/components/Overlay.vue | 6 +- .../src/components/RoomButton.vue | 20 +- .../src/components/ScheduleTable.vue | 166 ++++-- .../src/components/TeacherButton.vue | 9 +- .../src/components/ThemeSwitcher.vue | 11 +- .../src/components/Weather.vue | 108 +++- .../src/components/pages/Division.vue | 70 --- .../src/components/pages/Divisions.vue | 109 +++- .../src/components/pages/Room.vue | 69 --- .../src/components/pages/Rooms.vue | 115 +++- .../src/components/pages/Settings.vue | 10 +- .../src/components/pages/Teacher.vue | 69 --- .../src/components/pages/Teachers.vue | 118 +++- .../src/locales/en.js | 133 +++-- .../src/locales/pl.js | 21 +- .../src/locales/uk.js | 96 ++- .../src/plugins/vuetify.ts | 132 +++-- .../src/router.ts | 31 +- .../src/stores/localeStore.ts | 2 +- .../src/stores/miscStore.ts | 22 + 34 files changed, 1350 insertions(+), 819 deletions(-) delete mode 100644 web/optivum-better-schedule-frontend/public/favicon.ico create mode 100644 web/optivum-better-schedule-frontend/src/components/AnimationsSwitcher.vue delete mode 100644 web/optivum-better-schedule-frontend/src/components/pages/Division.vue delete mode 100644 web/optivum-better-schedule-frontend/src/components/pages/Room.vue delete mode 100644 web/optivum-better-schedule-frontend/src/components/pages/Teacher.vue create mode 100644 web/optivum-better-schedule-frontend/src/stores/miscStore.ts diff --git a/.gitignore b/.gitignore index 553795f..c980143 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,6 @@ go.work.sum .VSCodeCounter .vscode app/db -web/optivum-better-schedule-frontend/src/components/_.vue \ No newline at end of file +web/optivum-better-schedule-frontend/src/components/_.vue +app/dist +build \ No newline at end of file diff --git a/common/models/data.pb.go b/common/models/data.pb.go index a55c022..dab23b7 100644 --- a/common/models/data.pb.go +++ b/common/models/data.pb.go @@ -75,18 +75,63 @@ func (x *APIResponse) GetMessage() string { return "" } +type Duplicates struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Values []int64 `protobuf:"varint,1,rep,packed,name=values,proto3" json:"values,omitempty"` +} + +func (x *Duplicates) Reset() { + *x = Duplicates{} + mi := &file_data_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Duplicates) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Duplicates) ProtoMessage() {} + +func (x *Duplicates) ProtoReflect() protoreflect.Message { + mi := &file_data_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Duplicates.ProtoReflect.Descriptor instead. +func (*Duplicates) Descriptor() ([]byte, []int) { + return file_data_proto_rawDescGZIP(), []int{1} +} + +func (x *Duplicates) GetValues() []int64 { + if x != nil { + return x.Values + } + return nil +} + type Metadata struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Designators map[string]int64 `protobuf:"bytes,1,rep,name=designators,proto3" json:"designators,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - FullNames map[string]int64 `protobuf:"bytes,2,rep,name=full_names,json=fullNames,proto3" json:"full_names,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + Designators map[string]*Duplicates `protobuf:"bytes,1,rep,name=designators,proto3" json:"designators,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + FullNames map[string]*Duplicates `protobuf:"bytes,2,rep,name=full_names,json=fullNames,proto3" json:"full_names,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Metadata) Reset() { *x = Metadata{} - mi := &file_data_proto_msgTypes[1] + mi := &file_data_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -98,7 +143,7 @@ func (x *Metadata) String() string { func (*Metadata) ProtoMessage() {} func (x *Metadata) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[1] + mi := &file_data_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -111,17 +156,17 @@ func (x *Metadata) ProtoReflect() protoreflect.Message { // Deprecated: Use Metadata.ProtoReflect.Descriptor instead. func (*Metadata) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{1} + return file_data_proto_rawDescGZIP(), []int{2} } -func (x *Metadata) GetDesignators() map[string]int64 { +func (x *Metadata) GetDesignators() map[string]*Duplicates { if x != nil { return x.Designators } return nil } -func (x *Metadata) GetFullNames() map[string]int64 { +func (x *Metadata) GetFullNames() map[string]*Duplicates { if x != nil { return x.FullNames } @@ -139,7 +184,7 @@ type Condition struct { func (x *Condition) Reset() { *x = Condition{} - mi := &file_data_proto_msgTypes[2] + mi := &file_data_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -151,7 +196,7 @@ func (x *Condition) String() string { func (*Condition) ProtoMessage() {} func (x *Condition) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[2] + mi := &file_data_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -164,7 +209,7 @@ func (x *Condition) ProtoReflect() protoreflect.Message { // Deprecated: Use Condition.ProtoReflect.Descriptor instead. func (*Condition) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{2} + return file_data_proto_rawDescGZIP(), []int{3} } func (x *Condition) GetName() string { @@ -193,7 +238,7 @@ type Temperature struct { func (x *Temperature) Reset() { *x = Temperature{} - mi := &file_data_proto_msgTypes[3] + mi := &file_data_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -205,7 +250,7 @@ func (x *Temperature) String() string { func (*Temperature) ProtoMessage() {} func (x *Temperature) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[3] + mi := &file_data_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -218,7 +263,7 @@ func (x *Temperature) ProtoReflect() protoreflect.Message { // Deprecated: Use Temperature.ProtoReflect.Descriptor instead. func (*Temperature) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{3} + return file_data_proto_rawDescGZIP(), []int{4} } func (x *Temperature) GetCurrent() float64 { @@ -256,7 +301,7 @@ type Forecast struct { func (x *Forecast) Reset() { *x = Forecast{} - mi := &file_data_proto_msgTypes[4] + mi := &file_data_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -268,7 +313,7 @@ func (x *Forecast) String() string { func (*Forecast) ProtoMessage() {} func (x *Forecast) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[4] + mi := &file_data_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -281,7 +326,7 @@ func (x *Forecast) ProtoReflect() protoreflect.Message { // Deprecated: Use Forecast.ProtoReflect.Descriptor instead. func (*Forecast) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{4} + return file_data_proto_rawDescGZIP(), []int{5} } func (x *Forecast) GetCondition() *Condition { @@ -330,7 +375,7 @@ type ForecastResponse struct { func (x *ForecastResponse) Reset() { *x = ForecastResponse{} - mi := &file_data_proto_msgTypes[5] + mi := &file_data_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -342,7 +387,7 @@ func (x *ForecastResponse) String() string { func (*ForecastResponse) ProtoMessage() {} func (x *ForecastResponse) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[5] + mi := &file_data_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -355,7 +400,7 @@ func (x *ForecastResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ForecastResponse.ProtoReflect.Descriptor instead. func (*ForecastResponse) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{5} + return file_data_proto_rawDescGZIP(), []int{6} } func (x *ForecastResponse) GetName() string { @@ -386,7 +431,7 @@ type CurrentWeatherResponse struct { func (x *CurrentWeatherResponse) Reset() { *x = CurrentWeatherResponse{} - mi := &file_data_proto_msgTypes[6] + mi := &file_data_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -398,7 +443,7 @@ func (x *CurrentWeatherResponse) String() string { func (*CurrentWeatherResponse) ProtoMessage() {} func (x *CurrentWeatherResponse) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[6] + mi := &file_data_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -411,7 +456,7 @@ func (x *CurrentWeatherResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CurrentWeatherResponse.ProtoReflect.Descriptor instead. func (*CurrentWeatherResponse) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{6} + return file_data_proto_rawDescGZIP(), []int{7} } func (x *CurrentWeatherResponse) GetName() string { @@ -459,7 +504,7 @@ type AirPollutionResponse struct { func (x *AirPollutionResponse) Reset() { *x = AirPollutionResponse{} - mi := &file_data_proto_msgTypes[7] + mi := &file_data_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -471,7 +516,7 @@ func (x *AirPollutionResponse) String() string { func (*AirPollutionResponse) ProtoMessage() {} func (x *AirPollutionResponse) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[7] + mi := &file_data_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -484,7 +529,7 @@ func (x *AirPollutionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AirPollutionResponse.ProtoReflect.Descriptor instead. func (*AirPollutionResponse) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{7} + return file_data_proto_rawDescGZIP(), []int{8} } func (x *AirPollutionResponse) GetComponents() map[string]float64 { @@ -505,7 +550,7 @@ type Timestamp struct { func (x *Timestamp) Reset() { *x = Timestamp{} - mi := &file_data_proto_msgTypes[8] + mi := &file_data_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -517,7 +562,7 @@ func (x *Timestamp) String() string { func (*Timestamp) ProtoMessage() {} func (x *Timestamp) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[8] + mi := &file_data_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -530,7 +575,7 @@ func (x *Timestamp) ProtoReflect() protoreflect.Message { // Deprecated: Use Timestamp.ProtoReflect.Descriptor instead. func (*Timestamp) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{8} + return file_data_proto_rawDescGZIP(), []int{9} } func (x *Timestamp) GetHour() int64 { @@ -558,7 +603,7 @@ type TimeRange struct { func (x *TimeRange) Reset() { *x = TimeRange{} - mi := &file_data_proto_msgTypes[9] + mi := &file_data_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -570,7 +615,7 @@ func (x *TimeRange) String() string { func (*TimeRange) ProtoMessage() {} func (x *TimeRange) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[9] + mi := &file_data_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -583,7 +628,7 @@ func (x *TimeRange) ProtoReflect() protoreflect.Message { // Deprecated: Use TimeRange.ProtoReflect.Descriptor instead. func (*TimeRange) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{9} + return file_data_proto_rawDescGZIP(), []int{10} } func (x *TimeRange) GetStart() *Timestamp { @@ -617,7 +662,7 @@ type Lesson struct { func (x *Lesson) Reset() { *x = Lesson{} - mi := &file_data_proto_msgTypes[10] + mi := &file_data_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -629,7 +674,7 @@ func (x *Lesson) String() string { func (*Lesson) ProtoMessage() {} func (x *Lesson) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[10] + mi := &file_data_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -642,7 +687,7 @@ func (x *Lesson) ProtoReflect() protoreflect.Message { // Deprecated: Use Lesson.ProtoReflect.Descriptor instead. func (*Lesson) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{10} + return file_data_proto_rawDescGZIP(), []int{11} } func (x *Lesson) GetFullName() string { @@ -711,7 +756,7 @@ type LessonGroup struct { func (x *LessonGroup) Reset() { *x = LessonGroup{} - mi := &file_data_proto_msgTypes[11] + mi := &file_data_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -723,7 +768,7 @@ func (x *LessonGroup) String() string { func (*LessonGroup) ProtoMessage() {} func (x *LessonGroup) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[11] + mi := &file_data_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -736,7 +781,7 @@ func (x *LessonGroup) ProtoReflect() protoreflect.Message { // Deprecated: Use LessonGroup.ProtoReflect.Descriptor instead. func (*LessonGroup) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{11} + return file_data_proto_rawDescGZIP(), []int{12} } func (x *LessonGroup) GetLessons() []*Lesson { @@ -756,7 +801,7 @@ type ScheduleDay struct { func (x *ScheduleDay) Reset() { *x = ScheduleDay{} - mi := &file_data_proto_msgTypes[12] + mi := &file_data_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -768,7 +813,7 @@ func (x *ScheduleDay) String() string { func (*ScheduleDay) ProtoMessage() {} func (x *ScheduleDay) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[12] + mi := &file_data_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -781,7 +826,7 @@ func (x *ScheduleDay) ProtoReflect() protoreflect.Message { // Deprecated: Use ScheduleDay.ProtoReflect.Descriptor instead. func (*ScheduleDay) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{12} + return file_data_proto_rawDescGZIP(), []int{13} } func (x *ScheduleDay) GetLessonGroups() []*LessonGroup { @@ -801,7 +846,7 @@ type Schedule struct { func (x *Schedule) Reset() { *x = Schedule{} - mi := &file_data_proto_msgTypes[13] + mi := &file_data_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -813,7 +858,7 @@ func (x *Schedule) String() string { func (*Schedule) ProtoMessage() {} func (x *Schedule) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[13] + mi := &file_data_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -826,7 +871,7 @@ func (x *Schedule) ProtoReflect() protoreflect.Message { // Deprecated: Use Schedule.ProtoReflect.Descriptor instead. func (*Schedule) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{13} + return file_data_proto_rawDescGZIP(), []int{14} } func (x *Schedule) GetScheduleDays() []*ScheduleDay { @@ -849,7 +894,7 @@ type Teacher struct { func (x *Teacher) Reset() { *x = Teacher{} - mi := &file_data_proto_msgTypes[14] + mi := &file_data_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -861,7 +906,7 @@ func (x *Teacher) String() string { func (*Teacher) ProtoMessage() {} func (x *Teacher) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[14] + mi := &file_data_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -874,7 +919,7 @@ func (x *Teacher) ProtoReflect() protoreflect.Message { // Deprecated: Use Teacher.ProtoReflect.Descriptor instead. func (*Teacher) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{14} + return file_data_proto_rawDescGZIP(), []int{15} } func (x *Teacher) GetIndex() int64 { @@ -918,7 +963,7 @@ type Room struct { func (x *Room) Reset() { *x = Room{} - mi := &file_data_proto_msgTypes[15] + mi := &file_data_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -930,7 +975,7 @@ func (x *Room) String() string { func (*Room) ProtoMessage() {} func (x *Room) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[15] + mi := &file_data_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -943,7 +988,7 @@ func (x *Room) ProtoReflect() protoreflect.Message { // Deprecated: Use Room.ProtoReflect.Descriptor instead. func (*Room) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{15} + return file_data_proto_rawDescGZIP(), []int{16} } func (x *Room) GetIndex() int64 { @@ -987,7 +1032,7 @@ type Division struct { func (x *Division) Reset() { *x = Division{} - mi := &file_data_proto_msgTypes[16] + mi := &file_data_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -999,7 +1044,7 @@ func (x *Division) String() string { func (*Division) ProtoMessage() {} func (x *Division) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[16] + mi := &file_data_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1012,7 +1057,7 @@ func (x *Division) ProtoReflect() protoreflect.Message { // Deprecated: Use Division.ProtoReflect.Descriptor instead. func (*Division) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{16} + return file_data_proto_rawDescGZIP(), []int{17} } func (x *Division) GetIndex() int64 { @@ -1055,7 +1100,7 @@ type School struct { func (x *School) Reset() { *x = School{} - mi := &file_data_proto_msgTypes[17] + mi := &file_data_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1067,7 +1112,7 @@ func (x *School) String() string { func (*School) ProtoMessage() {} func (x *School) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[17] + mi := &file_data_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1080,7 +1125,7 @@ func (x *School) ProtoReflect() protoreflect.Message { // Deprecated: Use School.ProtoReflect.Descriptor instead. func (*School) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{17} + return file_data_proto_rawDescGZIP(), []int{18} } func (x *School) GetDivisions() []*Division { @@ -1112,150 +1157,155 @@ var file_data_proto_rawDesc = []byte{ 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x89, 0x02, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x41, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x3c, 0x0a, 0x0a, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x64, 0x61, 0x74, 0x61, - 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x4e, 0x61, - 0x6d, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, - 0x6d, 0x65, 0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x44, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, - 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x1a, 0x3c, 0x0a, 0x0e, 0x46, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x22, 0x41, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x4b, 0x0a, 0x0b, 0x54, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, - 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, - 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6d, 0x61, - 0x78, 0x22, 0xbe, 0x01, 0x0a, 0x08, 0x46, 0x6f, 0x72, 0x65, 0x63, 0x61, 0x73, 0x74, 0x12, 0x2d, - 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, - 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6e, 0x72, 0x69, 0x73, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x75, 0x6e, 0x72, 0x69, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x75, - 0x6e, 0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x61, 0x79, 0x4f, 0x66, 0x57, 0x65, 0x65, - 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x64, 0x61, 0x79, 0x4f, 0x66, 0x57, 0x65, - 0x65, 0x6b, 0x22, 0x52, 0x0a, 0x10, 0x46, 0x6f, 0x72, 0x65, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x08, 0x66, 0x6f, - 0x72, 0x65, 0x63, 0x61, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, - 0x61, 0x74, 0x61, 0x2e, 0x46, 0x6f, 0x72, 0x65, 0x63, 0x61, 0x73, 0x74, 0x52, 0x08, 0x66, 0x6f, - 0x72, 0x65, 0x63, 0x61, 0x73, 0x74, 0x22, 0xc2, 0x01, 0x0a, 0x16, 0x43, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x74, 0x57, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, - 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x64, 0x61, 0x74, 0x61, - 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x0b, 0x74, 0x65, - 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6e, - 0x72, 0x69, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x75, 0x6e, 0x72, - 0x69, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x22, 0xa1, 0x01, 0x0a, 0x14, - 0x41, 0x69, 0x72, 0x50, 0x6f, 0x6c, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, - 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, - 0x41, 0x69, 0x72, 0x50, 0x6f, 0x6c, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, - 0x1a, 0x3d, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0x37, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, - 0x68, 0x6f, 0x75, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x68, 0x6f, 0x75, 0x72, - 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x6e, 0x75, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x06, 0x6d, 0x69, 0x6e, 0x75, 0x74, 0x65, 0x22, 0x55, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, - 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x25, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x03, - 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x64, 0x61, 0x74, 0x61, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, - 0xc9, 0x02, 0x0a, 0x06, 0x4c, 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x75, - 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, - 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x74, 0x65, 0x61, 0x63, 0x68, - 0x65, 0x72, 0x5f, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x11, 0x74, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x44, 0x65, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x65, 0x61, 0x63, 0x68, 0x65, - 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, - 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x27, 0x0a, 0x0f, 0x72, - 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x6f, 0x6d, 0x44, 0x65, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x12, 0x2f, 0x0a, 0x13, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, - 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x12, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x6f, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x64, 0x69, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2e, 0x0a, 0x0a, 0x74, - 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, - 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x35, 0x0a, 0x0b, 0x4c, - 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x26, 0x0a, 0x07, 0x6c, 0x65, - 0x73, 0x73, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x64, 0x61, - 0x74, 0x61, 0x2e, 0x4c, 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x52, 0x07, 0x6c, 0x65, 0x73, 0x73, 0x6f, - 0x6e, 0x73, 0x22, 0x45, 0x0a, 0x0b, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x44, 0x61, - 0x79, 0x12, 0x36, 0x0a, 0x0d, 0x6c, 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x5f, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, - 0x4c, 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x0c, 0x6c, 0x65, 0x73, - 0x73, 0x6f, 0x6e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x42, 0x0a, 0x08, 0x53, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x36, 0x0a, 0x0d, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, - 0x65, 0x5f, 0x64, 0x61, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x64, - 0x61, 0x74, 0x61, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x44, 0x61, 0x79, 0x52, - 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x44, 0x61, 0x79, 0x73, 0x22, 0x88, 0x01, - 0x0a, 0x07, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, - 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, - 0x1b, 0x0a, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x08, - 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, - 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x08, - 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x04, 0x52, 0x6f, 0x6f, - 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x63, - 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, - 0x22, 0x89, 0x01, 0x0a, 0x08, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, - 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, - 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x2a, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, - 0x6c, 0x65, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x83, 0x01, 0x0a, - 0x06, 0x53, 0x63, 0x68, 0x6f, 0x6f, 0x6c, 0x12, 0x2c, 0x0a, 0x09, 0x64, 0x69, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, 0x61, 0x74, - 0x61, 0x2e, 0x44, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x08, 0x74, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, - 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x52, 0x08, 0x74, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x73, - 0x12, 0x20, 0x0a, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x0a, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x05, 0x72, 0x6f, 0x6f, - 0x6d, 0x73, 0x42, 0x11, 0x5a, 0x0f, 0x2e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, - 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x24, 0x0a, 0x0a, 0x44, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x03, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0xad, 0x02, 0x0a, 0x08, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x65, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, + 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x3c, 0x0a, 0x0a, 0x66, + 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x46, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, + 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x1a, 0x50, 0x0a, 0x10, 0x44, 0x65, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x26, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4e, 0x0a, 0x0e, 0x46, + 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x26, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x41, 0x0a, 0x09, 0x43, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x4b, + 0x0a, 0x0b, 0x54, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, + 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x22, 0xbe, 0x01, 0x0a, 0x08, + 0x46, 0x6f, 0x72, 0x65, 0x63, 0x61, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x64, 0x61, + 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x6f, + 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, + 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x73, 0x75, 0x6e, 0x72, 0x69, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, + 0x75, 0x6e, 0x72, 0x69, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x75, 0x6e, 0x73, 0x65, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x12, 0x1c, + 0x0a, 0x09, 0x64, 0x61, 0x79, 0x4f, 0x66, 0x57, 0x65, 0x65, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x64, 0x61, 0x79, 0x4f, 0x66, 0x57, 0x65, 0x65, 0x6b, 0x22, 0x52, 0x0a, 0x10, + 0x46, 0x6f, 0x72, 0x65, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x08, 0x66, 0x6f, 0x72, 0x65, 0x63, 0x61, 0x73, 0x74, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x6f, + 0x72, 0x65, 0x63, 0x61, 0x73, 0x74, 0x52, 0x08, 0x66, 0x6f, 0x72, 0x65, 0x63, 0x61, 0x73, 0x74, + 0x22, 0xc2, 0x01, 0x0a, 0x16, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x57, 0x65, 0x61, 0x74, + 0x68, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x2d, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, + 0x0a, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6e, 0x72, 0x69, 0x73, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x75, 0x6e, 0x72, 0x69, 0x73, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, + 0x75, 0x6e, 0x73, 0x65, 0x74, 0x22, 0xa1, 0x01, 0x0a, 0x14, 0x41, 0x69, 0x72, 0x50, 0x6f, 0x6c, + 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, + 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x41, 0x69, 0x72, 0x50, 0x6f, 0x6c, + 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x43, + 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, + 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x43, 0x6f, + 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x37, 0x0a, 0x09, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x75, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x68, 0x6f, 0x75, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, + 0x6e, 0x75, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6d, 0x69, 0x6e, 0x75, + 0x74, 0x65, 0x22, 0x55, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, + 0x25, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0xc9, 0x02, 0x0a, 0x06, 0x4c, 0x65, + 0x73, 0x73, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x74, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x74, + 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x44, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, + 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, + 0x72, 0x6f, 0x6f, 0x6d, 0x44, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1d, + 0x0a, 0x0a, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2f, 0x0a, + 0x13, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x64, 0x69, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x25, + 0x0a, 0x0e, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2e, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, + 0x6e, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x64, 0x61, 0x74, 0x61, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x35, 0x0a, 0x0b, 0x4c, 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x12, 0x26, 0x0a, 0x07, 0x6c, 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4c, 0x65, 0x73, + 0x73, 0x6f, 0x6e, 0x52, 0x07, 0x6c, 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x73, 0x22, 0x45, 0x0a, 0x0b, + 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x44, 0x61, 0x79, 0x12, 0x36, 0x0a, 0x0d, 0x6c, + 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4c, 0x65, 0x73, 0x73, 0x6f, 0x6e, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x0c, 0x6c, 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x73, 0x22, 0x42, 0x0a, 0x08, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, + 0x36, 0x0a, 0x0d, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x64, 0x61, 0x79, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x44, 0x61, 0x79, 0x52, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x44, 0x61, 0x79, 0x73, 0x22, 0x88, 0x01, 0x0a, 0x07, 0x54, 0x65, 0x61, 0x63, + 0x68, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, + 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x75, 0x6c, + 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, + 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x04, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, + 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, + 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, + 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x89, 0x01, 0x0a, 0x08, 0x44, + 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1e, 0x0a, + 0x0a, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, + 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x08, 0x73, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x08, 0x73, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x83, 0x01, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x6f, 0x6f, + 0x6c, 0x12, 0x2c, 0x0a, 0x09, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x69, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x29, 0x0a, 0x08, 0x74, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, + 0x52, 0x08, 0x74, 0x65, 0x61, 0x63, 0x68, 0x65, 0x72, 0x73, 0x12, 0x20, 0x0a, 0x05, 0x72, 0x6f, + 0x6f, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x64, 0x61, 0x74, 0x61, + 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x05, 0x72, 0x6f, 0x6f, 0x6d, 0x73, 0x42, 0x11, 0x5a, 0x0f, + 0x2e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1270,56 +1320,59 @@ func file_data_proto_rawDescGZIP() []byte { return file_data_proto_rawDescData } -var file_data_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_data_proto_msgTypes = make([]protoimpl.MessageInfo, 22) var file_data_proto_goTypes = []any{ (*APIResponse)(nil), // 0: data.APIResponse - (*Metadata)(nil), // 1: data.Metadata - (*Condition)(nil), // 2: data.Condition - (*Temperature)(nil), // 3: data.Temperature - (*Forecast)(nil), // 4: data.Forecast - (*ForecastResponse)(nil), // 5: data.ForecastResponse - (*CurrentWeatherResponse)(nil), // 6: data.CurrentWeatherResponse - (*AirPollutionResponse)(nil), // 7: data.AirPollutionResponse - (*Timestamp)(nil), // 8: data.Timestamp - (*TimeRange)(nil), // 9: data.TimeRange - (*Lesson)(nil), // 10: data.Lesson - (*LessonGroup)(nil), // 11: data.LessonGroup - (*ScheduleDay)(nil), // 12: data.ScheduleDay - (*Schedule)(nil), // 13: data.Schedule - (*Teacher)(nil), // 14: data.Teacher - (*Room)(nil), // 15: data.Room - (*Division)(nil), // 16: data.Division - (*School)(nil), // 17: data.School - nil, // 18: data.Metadata.DesignatorsEntry - nil, // 19: data.Metadata.FullNamesEntry - nil, // 20: data.AirPollutionResponse.ComponentsEntry + (*Duplicates)(nil), // 1: data.Duplicates + (*Metadata)(nil), // 2: data.Metadata + (*Condition)(nil), // 3: data.Condition + (*Temperature)(nil), // 4: data.Temperature + (*Forecast)(nil), // 5: data.Forecast + (*ForecastResponse)(nil), // 6: data.ForecastResponse + (*CurrentWeatherResponse)(nil), // 7: data.CurrentWeatherResponse + (*AirPollutionResponse)(nil), // 8: data.AirPollutionResponse + (*Timestamp)(nil), // 9: data.Timestamp + (*TimeRange)(nil), // 10: data.TimeRange + (*Lesson)(nil), // 11: data.Lesson + (*LessonGroup)(nil), // 12: data.LessonGroup + (*ScheduleDay)(nil), // 13: data.ScheduleDay + (*Schedule)(nil), // 14: data.Schedule + (*Teacher)(nil), // 15: data.Teacher + (*Room)(nil), // 16: data.Room + (*Division)(nil), // 17: data.Division + (*School)(nil), // 18: data.School + nil, // 19: data.Metadata.DesignatorsEntry + nil, // 20: data.Metadata.FullNamesEntry + nil, // 21: data.AirPollutionResponse.ComponentsEntry } var file_data_proto_depIdxs = []int32{ - 18, // 0: data.Metadata.designators:type_name -> data.Metadata.DesignatorsEntry - 19, // 1: data.Metadata.full_names:type_name -> data.Metadata.FullNamesEntry - 2, // 2: data.Forecast.condition:type_name -> data.Condition - 3, // 3: data.Forecast.temperature:type_name -> data.Temperature - 4, // 4: data.ForecastResponse.forecast:type_name -> data.Forecast - 2, // 5: data.CurrentWeatherResponse.condition:type_name -> data.Condition - 3, // 6: data.CurrentWeatherResponse.temperature:type_name -> data.Temperature - 20, // 7: data.AirPollutionResponse.components:type_name -> data.AirPollutionResponse.ComponentsEntry - 8, // 8: data.TimeRange.start:type_name -> data.Timestamp - 8, // 9: data.TimeRange.end:type_name -> data.Timestamp - 9, // 10: data.Lesson.time_range:type_name -> data.TimeRange - 10, // 11: data.LessonGroup.lessons:type_name -> data.Lesson - 11, // 12: data.ScheduleDay.lesson_groups:type_name -> data.LessonGroup - 12, // 13: data.Schedule.schedule_days:type_name -> data.ScheduleDay - 13, // 14: data.Teacher.schedule:type_name -> data.Schedule - 13, // 15: data.Room.schedule:type_name -> data.Schedule - 13, // 16: data.Division.schedule:type_name -> data.Schedule - 16, // 17: data.School.divisions:type_name -> data.Division - 14, // 18: data.School.teachers:type_name -> data.Teacher - 15, // 19: data.School.rooms:type_name -> data.Room - 20, // [20:20] is the sub-list for method output_type - 20, // [20:20] is the sub-list for method input_type - 20, // [20:20] is the sub-list for extension type_name - 20, // [20:20] is the sub-list for extension extendee - 0, // [0:20] is the sub-list for field type_name + 19, // 0: data.Metadata.designators:type_name -> data.Metadata.DesignatorsEntry + 20, // 1: data.Metadata.full_names:type_name -> data.Metadata.FullNamesEntry + 3, // 2: data.Forecast.condition:type_name -> data.Condition + 4, // 3: data.Forecast.temperature:type_name -> data.Temperature + 5, // 4: data.ForecastResponse.forecast:type_name -> data.Forecast + 3, // 5: data.CurrentWeatherResponse.condition:type_name -> data.Condition + 4, // 6: data.CurrentWeatherResponse.temperature:type_name -> data.Temperature + 21, // 7: data.AirPollutionResponse.components:type_name -> data.AirPollutionResponse.ComponentsEntry + 9, // 8: data.TimeRange.start:type_name -> data.Timestamp + 9, // 9: data.TimeRange.end:type_name -> data.Timestamp + 10, // 10: data.Lesson.time_range:type_name -> data.TimeRange + 11, // 11: data.LessonGroup.lessons:type_name -> data.Lesson + 12, // 12: data.ScheduleDay.lesson_groups:type_name -> data.LessonGroup + 13, // 13: data.Schedule.schedule_days:type_name -> data.ScheduleDay + 14, // 14: data.Teacher.schedule:type_name -> data.Schedule + 14, // 15: data.Room.schedule:type_name -> data.Schedule + 14, // 16: data.Division.schedule:type_name -> data.Schedule + 17, // 17: data.School.divisions:type_name -> data.Division + 15, // 18: data.School.teachers:type_name -> data.Teacher + 16, // 19: data.School.rooms:type_name -> data.Room + 1, // 20: data.Metadata.DesignatorsEntry.value:type_name -> data.Duplicates + 1, // 21: data.Metadata.FullNamesEntry.value:type_name -> data.Duplicates + 22, // [22:22] is the sub-list for method output_type + 22, // [22:22] is the sub-list for method input_type + 22, // [22:22] is the sub-list for extension type_name + 22, // [22:22] is the sub-list for extension extendee + 0, // [0:22] is the sub-list for field type_name } func init() { file_data_proto_init() } @@ -1333,7 +1386,7 @@ func file_data_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_data_proto_rawDesc, NumEnums: 0, - NumMessages: 21, + NumMessages: 22, NumExtensions: 0, NumServices: 0, }, diff --git a/common/utils/utils.go b/common/utils/utils.go index 2d6c7f1..b8731b0 100644 --- a/common/utils/utils.go +++ b/common/utils/utils.go @@ -6,18 +6,32 @@ import ( "net/http" "strings" "sync" + "time" "github.com/PuerkitoBio/goquery" ) +var HttpClient = &http.Client{ + Transport: &http.Transport{ + MaxIdleConns: 2000, + MaxIdleConnsPerHost: 1000, + IdleConnTimeout: 90 * time.Second, + }, + Timeout: 20 * time.Second, +} + func CheckURL(url string) bool { + fmt.Println("checking URL:", url) + // #nosec G107 - resp, err := http.Get(url) + resp, err := HttpClient.Get(url) if err != nil { return false } defer resp.Body.Close() + fmt.Printf("got status code: %d for %s\n", resp.StatusCode, url) + return resp.StatusCode == http.StatusOK } @@ -31,12 +45,26 @@ func IsEmptyOrInvisible(text string) bool { func OpenDoc(baseUrl, endpoint string) (*goquery.Document, error) { url := fmt.Sprintf("%s%s", baseUrl, endpoint) fmt.Printf("fetching URL: %s\n", url) - - // #nosec G107 - res, err := http.Get(url) + + var res *http.Response + var err error + + for i := 0; i < 3; i++ { + // #nosec G107 + res, err = HttpClient.Get(url) + if err == nil && res.StatusCode == http.StatusOK { + break + } + if res != nil { + res.Body.Close() + } + time.Sleep(1 * time.Second) + } + if err != nil { return nil, fmt.Errorf("error fetching URL: %w", err) } + defer res.Body.Close() if res.StatusCode != http.StatusOK { diff --git a/core/datastore/crud.go b/core/datastore/crud.go index 4ec62e8..a0b40fa 100644 --- a/core/datastore/crud.go +++ b/core/datastore/crud.go @@ -105,4 +105,19 @@ func GetRoom(index int64) (*models.Room, error) { func DeleteRoom(index int64) error { key := []byte(fmt.Sprintf("room:%d", index)) return deleteItem(key) +} + +func SetMetadata(metadata *models.Metadata) error { + key := []byte("metadata") + return setItem(key, metadata) +} + +func GetMetadata() (*models.Metadata, error) { + key := []byte("metadata") + metadata := &models.Metadata{} + err := getItem(key, metadata) + if err != nil { + return nil, err + } + return metadata, nil } \ No newline at end of file diff --git a/core/observer/observer.go b/core/observer/observer.go index 491e01f..06fb1b6 100644 --- a/core/observer/observer.go +++ b/core/observer/observer.go @@ -65,7 +65,18 @@ func (o *Observer) compareHash(ctx context.Context, client *http.Client) (bool, o.Mu.RLock() defer o.Mu.RUnlock() - doc, err := o.fetchContent(ctx, client) + var doc *goquery.Document + var err error + + for i := 0; i < 3; i++ { + doc, err = o.fetchContent(ctx, client) + if err == nil { + break + } + fmt.Printf("error fetching content from %s, retrying... (%d/3)\n", o.URL, i+1) + time.Sleep(1 * time.Second) + } + if err != nil { return false, fmt.Errorf("error fetching content from %s: %v", o.URL, err) } diff --git a/core/scraper/scraper.go b/core/scraper/scraper.go index c14be1b..cd536f1 100644 --- a/core/scraper/scraper.go +++ b/core/scraper/scraper.go @@ -22,7 +22,6 @@ import ( var Config config.ScraperConfig type ResourceType string - const ( DivisionResource ResourceType = "division" TeacherResource ResourceType = "teacher" @@ -33,6 +32,12 @@ func (t ResourceType) String() string { return string(t) } +type MetadataType string +const ( + DesignatorMetadata MetadataType = "designator" + FullNameMetadata MetadataType = "fullname" +) + type ScraperResource struct { Indexes []int64 Metadata *models.Metadata @@ -48,8 +53,8 @@ func NewScraperResource(indexRegex *regexp.Regexp, resourceType ResourceType) *S return &ScraperResource{ Indexes: []int64{}, Metadata: &models.Metadata{ - Designators: make(map[string]int64), - FullNames: make(map[string]int64), + Designators: make(map[string]*models.Duplicates), + FullNames: make(map[string]*models.Duplicates), }, Observer: &observer.Observer{}, Hub: &hub.Hub{}, @@ -72,35 +77,57 @@ func (s *ScraperResource) StopHub() { } } -func (s *ScraperResource) GetDesignatorFromIndex(index int64) string { +func (s *ScraperResource) IsIndexInMetadata(index int64, metadataType MetadataType) (bool, string) { s.Mu.RLock() defer s.Mu.RUnlock() - for designator, _index := range s.Metadata.Designators { - if index == _index { - return designator + var metadata map[string]*models.Duplicates + if metadataType == DesignatorMetadata { + metadata = s.Metadata.Designators + } else if metadataType == FullNameMetadata { + metadata = s.Metadata.FullNames + } else { + return false, "" + } + + for key, duplicates := range metadata { + for _, _index := range duplicates.Values { + if index == _index { + return true, key + } } } + return false, "" +} + +func (s *ScraperResource) GetDesignatorFromIndex(index int64) string { + s.Mu.RLock() + defer s.Mu.RUnlock() + + if inDuplicates, designator := s.IsIndexInMetadata(index, DesignatorMetadata); inDuplicates { + return designator + } + return "" } func (s *ScraperResource) GetFullNameFromIndex(index int64) string { s.Mu.RLock() defer s.Mu.RUnlock() - for fullName, _index := range s.Metadata.FullNames { - if index == _index { - return fullName - } + + if inDuplicates, fullName := s.IsIndexInMetadata(index, FullNameMetadata); inDuplicates { + return fullName } + return "" } -func (s *ScraperResource) GetIndexFromDesignator(designator string) int64 { +func (s *ScraperResource) GetIndexFromDesignator(designator string) *models.Duplicates { s.Mu.RLock() defer s.Mu.RUnlock() return s.Metadata.Designators[designator] } -func (s *ScraperResource) GetIndexFromFullName(fullName string) int64 { +func (s *ScraperResource) GetIndexFromFullName(fullName string) *models.Duplicates { s.Mu.RLock() defer s.Mu.RUnlock() return s.Metadata.FullNames[fullName] @@ -109,37 +136,62 @@ func (s *ScraperResource) GetIndexFromFullName(fullName string) int64 { func (s *ScraperResource) UpdateMetadata(newDesignator, newFullName string, index int64) { s.Mu.Lock() defer s.Mu.Unlock() - for _designator, _index := range s.Metadata.Designators { - if index == _index { - delete(s.Metadata.Designators, _designator) + + for designator, duplicates := range s.Metadata.Designators { + for i, _index := range duplicates.Values { + if index == _index { + duplicates.Values = append(duplicates.Values[:i], duplicates.Values[i+1:]...) + if len(duplicates.Values) == 0 { + delete(s.Metadata.Designators, designator) + } + break + } } } - s.Metadata.Designators[newDesignator] = index + if _, exists := s.Metadata.Designators[newDesignator]; !exists { + s.Metadata.Designators[newDesignator] = &models.Duplicates{} + } + s.Metadata.Designators[newDesignator].Values = append(s.Metadata.Designators[newDesignator].Values, index) - for _full_name, _index := range s.Metadata.FullNames { - if index == _index { - delete(s.Metadata.FullNames, _full_name) + for fullName, duplicates := range s.Metadata.FullNames { + for i, _index := range duplicates.Values { + if index == _index { + duplicates.Values = append(duplicates.Values[:i], duplicates.Values[i+1:]...) + if len(duplicates.Values) == 0 { + delete(s.Metadata.FullNames, fullName) + } + break + } } } - s.Metadata.FullNames[newFullName] = index + if _, exists := s.Metadata.FullNames[newFullName]; !exists { + s.Metadata.FullNames[newFullName] = &models.Duplicates{} + } + s.Metadata.FullNames[newFullName].Values = append(s.Metadata.FullNames[newFullName].Values, index) } func (s *ScraperResource) RemoveMetadata(index int64) { s.Mu.Lock() defer s.Mu.Unlock() - for designator, _index := range s.Metadata.Designators { - if index == _index { - delete(s.Metadata.Designators, designator) - if len(s.Metadata.Designators) == 0 { + for designator, duplicates := range s.Metadata.Designators { + for i, _index := range duplicates.Values { + if index == _index { + duplicates.Values = append(duplicates.Values[:i], duplicates.Values[i+1:]...) + if len(duplicates.Values) == 0 { + delete(s.Metadata.Designators, designator) + } break } } } - for fullName, _index := range s.Metadata.FullNames { - if index == _index { - delete(s.Metadata.FullNames, fullName) - if len(s.Metadata.FullNames) == 0 { + for fullName, duplicates := range s.Metadata.FullNames { + for i, _index := range duplicates.Values { + if index == _index { + duplicates.Values = append(duplicates.Values[:i], duplicates.Values[i+1:]...) + if len(duplicates.Values) == 0 { + delete(s.Metadata.FullNames, fullName) + } break } } @@ -336,9 +388,9 @@ func ScrapeDivisionsIndexes() ([]int64, error) { return } endpoint := makeDivisionEndpoint(num) - _, err = utils.OpenDoc(Config.BaseUrl, endpoint) - if err != nil { - fmt.Printf("error opening division document: %v\n", err) + + if !utils.CheckURL(Config.BaseUrl + endpoint) { + fmt.Printf("error opening division " + Config.BaseUrl + endpoint + "\n") return } indexes = append(indexes, num) @@ -369,9 +421,9 @@ func ScrapeTeachersIndexes() ([]int64, error) { return } endpoint := makeTeacherEndpoint(num) - _, err = utils.OpenDoc(Config.BaseUrl, endpoint) - if err != nil { - fmt.Printf("error opening teacher document: %v\n", err) + + if !utils.CheckURL(Config.BaseUrl + endpoint) { + fmt.Printf("error opening teacher " + Config.BaseUrl + endpoint + "\n") return } indexes = append(indexes, num) @@ -402,9 +454,9 @@ func ScrapeRoomsIndexes() ([]int64, error) { return } endpoint := makeRoomEndpoint(num) - _, err = utils.OpenDoc(Config.BaseUrl, endpoint) - if err != nil { - fmt.Printf("error opening room document: %v\n", err) + + if !utils.CheckURL(Config.BaseUrl + endpoint) { + fmt.Printf("error opening room " + Config.BaseUrl + endpoint + "\n") return } indexes = append(indexes, num) diff --git a/data.proto b/data.proto index 382ba07..6a42ae7 100644 --- a/data.proto +++ b/data.proto @@ -10,9 +10,13 @@ message APIResponse { string message = 2; } +message Duplicates { + repeated int64 values = 1; +} + message Metadata { - map designators = 1; - map full_names = 2; + map designators = 1; + map full_names = 2; } message Condition { diff --git a/web/optivum-better-schedule-frontend/components.d.ts b/web/optivum-better-schedule-frontend/components.d.ts index 8ed41af..b9fdb23 100644 --- a/web/optivum-better-schedule-frontend/components.d.ts +++ b/web/optivum-better-schedule-frontend/components.d.ts @@ -7,35 +7,20 @@ export {} /* prettier-ignore */ declare module 'vue' { export interface GlobalComponents { - _: typeof import('./src/components/_.vue')['default'] - AppBar: typeof import('./src/components/AppBar.vue')['default'] - ClassesTab: typeof import('./src/components/ClassesTab.vue')['default'] + AnimationsSwitcher: typeof import('./src/components/AnimationsSwitcher.vue')['default'] Clock: typeof import('./src/components/clock/Clock.vue')['default'] - copy: typeof import('./src/components/TeacherButton copy.vue')['default'] Digit: typeof import('./src/components/clock/Digit.vue')['default'] - Division: typeof import('./src/components/pages/Division.vue')['default'] DivisionButton: typeof import('./src/components/DivisionButton.vue')['default'] Divisions: typeof import('./src/components/pages/Divisions.vue')['default'] - Dots: typeof import('./src/components/Dots.vue')['default'] - Drawer: typeof import('./src/components/Drawer.vue')['default'] - Fog: typeof import('./src/components/Fog.vue')['default'] - HelloWorld: typeof import('./src/components/HelloWorld.vue')['default'] Home: typeof import('./src/components/pages/Home.vue')['default'] - HomePage: typeof import('./src/components/pages/HomePage.vue')['default'] - HomeTab: typeof import('./src/components/HomeTab.vue')['default'] LanguageSwitcher: typeof import('./src/components/LanguageSwitcher.vue')['default'] Overlay: typeof import('./src/components/Overlay.vue')['default'] - Rays: typeof import('./src/components/Rays.vue')['default'] - Room: typeof import('./src/components/pages/Room.vue')['default'] RoomButton: typeof import('./src/components/RoomButton.vue')['default'] Rooms: typeof import('./src/components/pages/Rooms.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] ScheduleTable: typeof import('./src/components/ScheduleTable.vue')['default'] Settings: typeof import('./src/components/pages/Settings.vue')['default'] - SettingsPage: typeof import('./src/components/pages/SettingsPage.vue')['default'] - TabContent: typeof import('./src/components/TabContent.vue')['default'] - Teacher: typeof import('./src/components/pages/Teacher.vue')['default'] TeacherButton: typeof import('./src/components/TeacherButton.vue')['default'] Teachers: typeof import('./src/components/pages/Teachers.vue')['default'] ThemeSwitcher: typeof import('./src/components/ThemeSwitcher.vue')['default'] diff --git a/web/optivum-better-schedule-frontend/index.html b/web/optivum-better-schedule-frontend/index.html index 44eb85d..1c33a19 100644 --- a/web/optivum-better-schedule-frontend/index.html +++ b/web/optivum-better-schedule-frontend/index.html @@ -5,7 +5,7 @@ - Welcome to Vuetify 3 + GOptivum diff --git a/web/optivum-better-schedule-frontend/public/favicon.ico b/web/optivum-better-schedule-frontend/public/favicon.ico deleted file mode 100644 index 8fb9f91b3aab4eec0c76ffc5342528033c61e247..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15406 zcmeHO3v5%@8NNVarCoU?zSqezmT6npu}xxXJJhY(x=s~hQ>SSYYSncU&|(|9Y?QVX z@}TB1G8mASM;tRKYgJkrAW)&g7${B%c>oE7;)O>NNO_bu4G-IdNB({PbTkJL{ZGDJe2DLL+vq#sL?l$jZPe_*I2y@|4sBRjso zUy`aUlJo$60})6B%aMKN&yMG1Qvjth%4dDy{HM^34) z&_TyGJg3UC{J|n2-wr)LDYwhNWBH4VL-JgYz;erTEKiMF20`|$Cf~GysBU40j@&)u zboK>@(yL25%R|RmS~6@99bG>PviV`j>&k~M@~J%cn{`uCzUOyY^23rlWt6DH=aut3 zlZo^g63xIXwP(4)hgT<|I>hSGqh7YbLP$jL+%p0>vM2Su?wmOV;-uyLFww=KN5Ox{j<% zmi}mZc22bZyxbmI!x+Ch3+qsk+#YbHJ{CdQjDh~;LRJB63Pq&~p

*N){PEn7FA;EAwj=|b_AUGw z{Eb1Zt8`N8chL?vjkw~yAvg~N+W_qV|N7U7a3HGfPY0GBqUxOaLJzPO2|Qz7H&yF{ z!Y@7SbxH$-YlpxgCaImE$Fk6T4dUMU!=a+u##*PZb&m9d@{VbA<&v z;n*Hvm#Nt5zF}Ud{=9#v%+3;8${f~WV?Q`CFATe5JXp$wT(q1TOU7#0jK6PDXZ)(1 zOSF4N3hStRA?+K$*ZctH(lRF!KFSL%W20hM6%Rz+k9We?_C36J>PVG2%Y`27X;nW+ z*x`6oe7S`dXABgw#vFYvuM;-c|L9ua=7z9?9B!cL=Fyiz34xz{6kpCd?PeyG2V7mkg!!m@d$btKgDK_Ib zt|Qt#$Am-fZ&{xA0GOAnn8Ue+QQBY3NiO*vfvd{5lsp3L_K5f@hhj{}^Nk#us4?p+ ztOM)g!1L3Ff(Tk8KQe4khoQS4_&0;4zo|FQr(iM%k4L+U*z zff0J2FQWxM*K?>u4d$6_8R>l`cK8U+!w`A!D@A2^2+L%A~GSv8* z(uV!wgkD)YqY(1-;X}j zv4?n}%=LOp! z;8GgCC~I2q%*#5{$kpuKJ6-ET*}o#)Z>p>vQsxF25{?c6CQ5()gsGtn{Ul`*ykb!bDMnnlGUdfYdn+9lsY%+pJ_Z_xHs+imH? z!L`+luUT1yv*4C1Z&<#Qlui*r2~lxBI`sAm+}oX{s=OcRf9A0%Q^56>8DC==kKtgy z>D-TeE@f3uu4&Y?ZVVlM3wLg~Z>Y}xfNE|1MIAijELQN`Y2<45F5=t5>wtYuk>yuH zXEJj-vN;uZD0|537U$Eq5Oek?f#JlNGq{dN(qiDuxO185eWG@Tuk1zKUsCs)MAVm# zZTvIN+Wl0&MDXYQF#3{qXA$(Ft>uw;>&qkE2f#n|`-?1D`gl8Gqj+=j77qvaV7#CH z-mDV$x0TsBRP5B|jZ%mFQ}FDv4Rn5l$yl(|`Q7Oe;~u+P58Qvv*6uy)7U=EIpPM-5 zPv}(pkwc!Zx3$@4;Y){)0d2tO5v#db4**wJ~;d2`ShTX zw|GaKwMoD4ydIzqSN(;l&j_8}$q^eYga7tU+}ZvgxyO*m1UDkuojePFZ zG`-$PpE1`DpyrLMO}R7wCfu3t6Y|B7d%f_n+{8^32;HSdS9&hVGwt*sUYr-!%%`a~|XP)!GJa zaPfvq9vz7{ms4}`U~qpQ+@r?~G$CeSuOWUWWPj8xrxoKsi%ALkMoN~Re@yeI<`b#& zQakqh?^Bfdlv*~90r${a#kP)=j;z5r;Qua|_8~6ciamnnhpFd84r{fjgNVx%{UgRa z5XnEKlf}cZ&elidYgP}Qi}Z0^o$C^y%G~k#_Qp8=1^BDy6=xQN&GlMeiCUK;x&F$^ zjA44c!M?-)Y1kOO--Oix|DE7=F!d?WE|oc-P;ICUYO&YsIA3qS68`^+SoxzLDfxQ- z)V%&7_{XQaWqV^?8s0=b5Yxwfs(L2+kBDu`F4FIF*gxGfML8AK#-01US-npCiqalZ z?M~DOWA<^ZR|~P;79^A!*A-C1sshAC6<~Z9P|a%vs7IcNOJh792S@Vc$sCItcXG)K z1Fn?E#hswKujQD~WT#qpf3`ix0(EL{#By^?PeQ2& - \ No newline at end of file diff --git a/web/optivum-better-schedule-frontend/src/components/AnimationsSwitcher.vue b/web/optivum-better-schedule-frontend/src/components/AnimationsSwitcher.vue new file mode 100644 index 0000000..f9e0121 --- /dev/null +++ b/web/optivum-better-schedule-frontend/src/components/AnimationsSwitcher.vue @@ -0,0 +1,43 @@ + + + + + + diff --git a/web/optivum-better-schedule-frontend/src/components/DivisionButton.vue b/web/optivum-better-schedule-frontend/src/components/DivisionButton.vue index 3dfb39f..6eac9bd 100644 --- a/web/optivum-better-schedule-frontend/src/components/DivisionButton.vue +++ b/web/optivum-better-schedule-frontend/src/components/DivisionButton.vue @@ -12,11 +12,14 @@ --> diff --git a/web/optivum-better-schedule-frontend/src/components/pages/Divisions.vue b/web/optivum-better-schedule-frontend/src/components/pages/Divisions.vue index cbacc97..7eabd7d 100644 --- a/web/optivum-better-schedule-frontend/src/components/pages/Divisions.vue +++ b/web/optivum-better-schedule-frontend/src/components/pages/Divisions.vue @@ -1,31 +1,55 @@ - + @@ -34,7 +58,8 @@ import { ref, onMounted, computed } from 'vue'; import axios from 'axios'; import { useI18n } from 'vue-i18n'; import { debounce } from 'lodash-es'; -import DivisionButton from '../DivisionButton.vue' +import DivisionButton from '../DivisionButton.vue'; +import { useMiscStore } from '@/stores/miscStore'; interface Division { designator: string; @@ -42,23 +67,40 @@ interface Division { full_name: string; } +interface DivisionResponse { + data: DivisionResponseData; +} + +interface DivisionResponseData { + designators: { [key: string]: { values: number[] } }; + full_names: { [key: string]: { values: number[] } }; +} + const { t } = useI18n(); +const miscStore = useMiscStore(); +const reducedAnimationsEnabled = computed(() => miscStore.reducedAnimationsEnabled); const search = ref(''); const divisions = ref([]); const loading = ref(false); const error = ref(null); +// Forces remounting the component when the search key changes so animations are triggered +const searchKey = computed(() => search.value); +const delayStyle = (index: number) => ({ + animationDelay: `${index * 50}ms`, +}); + const fetchDivisions = async () => { loading.value = true; try { - const response = await axios.get('/api/v1/divisions'); + const response: DivisionResponse = await axios.get('/api/v1/divisions'); const designators = response.data.designators; const fullNames = response.data.full_names; - divisions.value = Object.keys(designators).map((designator) => { - const id = designators[designator]; - const full_name = Object.keys(fullNames).find((name) => fullNames[name] === id) || ''; + divisions.value = Object.entries(designators).map(([designator, { values }]) => { + const id = values[0]; + const full_name = Object.keys(fullNames).find(name => fullNames[name].values.includes(id)) || ''; return { designator, @@ -155,6 +197,35 @@ onMounted(fetchDivisions); overflow: visible; } +.animated-item { + opacity: 0; + transform: translateY(100%); + animation: fadeInUp 0.5s forwards; +} + +@keyframes fadeInUp { + to { + opacity: 1; + transform: translateY(0); + } +} + +.animated-item.fade-leave-active { + animation: fadeOutDown 0.5s forwards; +} + +@keyframes fadeOutDown { + from { + opacity: 1; + transform: translateY(0); + } + + to { + opacity: 0; + transform: translateY(100%); + } +} + .loading, .error { display: flex; diff --git a/web/optivum-better-schedule-frontend/src/components/pages/Room.vue b/web/optivum-better-schedule-frontend/src/components/pages/Room.vue deleted file mode 100644 index fe65a99..0000000 --- a/web/optivum-better-schedule-frontend/src/components/pages/Room.vue +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/web/optivum-better-schedule-frontend/src/components/pages/Rooms.vue b/web/optivum-better-schedule-frontend/src/components/pages/Rooms.vue index e763abc..f9ac529 100644 --- a/web/optivum-better-schedule-frontend/src/components/pages/Rooms.vue +++ b/web/optivum-better-schedule-frontend/src/components/pages/Rooms.vue @@ -1,29 +1,56 @@ + @@ -32,7 +59,8 @@ import { ref, onMounted, computed } from 'vue'; import axios from 'axios'; import { useI18n } from 'vue-i18n'; import { debounce } from 'lodash-es'; -import RoomButton from '../RoomButton.vue' +import RoomButton from '../RoomButton.vue'; +import { useMiscStore } from '@/stores/miscStore'; interface Room { designator: string; @@ -40,7 +68,18 @@ interface Room { full_name: string; } +interface RoomResponse { + data: RoomResponseData; +} + +interface RoomResponseData { + designators: { [key: string]: { values: number[] } }; + full_names: { [key: string]: { values: number[] } }; +} + const { t } = useI18n(); +const miscStore = useMiscStore(); +const reducedAnimationsEnabled = computed(() => miscStore.reducedAnimationsEnabled); const search = ref(''); const rooms = ref([]); @@ -50,20 +89,18 @@ const error = ref(null); const fetchRooms = async () => { loading.value = true; try { - const response = await axios.get('/api/v1/rooms'); + const response: RoomResponse = await axios.get('/api/v1/rooms'); const designators = response.data.designators; const fullNames = response.data.full_names; - rooms.value = Object.keys(designators).map((designator) => { - const id = designators[designator]; - const designatorKey = Object.keys(designators).find(key => designators[key] === id); - const full_name = Object.keys(fullNames).find((name) => fullNames[name] === id) || ''; - const display_name = designatorKey && designatorKey !== full_name ? `${full_name} (${designatorKey})` : full_name; + rooms.value = Object.entries(designators).map(([designator, { values }]) => { + const id = values[0]; + const full_name = Object.keys(fullNames).find(name => fullNames[name].values.includes(id)) || ''; return { designator, id, - full_name: display_name, + full_name, }; }); } catch (err) { @@ -85,6 +122,11 @@ const filteredRooms = computed(() => { ); }); +const searchKey = computed(() => search.value); +const delayStyle = (index: number) => ({ + animationDelay: `${index * 50}ms`, +}); + onMounted(fetchRooms); @@ -155,6 +197,35 @@ onMounted(fetchRooms); overflow: visible; } +.animated-item { + opacity: 0; + transform: translateY(100%); + animation: fadeInUp 0.5s forwards; +} + +@keyframes fadeInUp { + to { + opacity: 1; + transform: translateY(0); + } +} + +.animated-item.fade-leave-active { + animation: fadeOutDown 0.5s forwards; +} + +@keyframes fadeOutDown { + from { + opacity: 1; + transform: translateY(0); + } + + to { + opacity: 0; + transform: translateY(100%); + } +} + .loading, .error { display: flex; diff --git a/web/optivum-better-schedule-frontend/src/components/pages/Settings.vue b/web/optivum-better-schedule-frontend/src/components/pages/Settings.vue index d0a6049..d38d83c 100644 --- a/web/optivum-better-schedule-frontend/src/components/pages/Settings.vue +++ b/web/optivum-better-schedule-frontend/src/components/pages/Settings.vue @@ -1,4 +1,4 @@ - +