private string GetExamPage(CoursesTakenType coursesType, bool shouldRecurse = true) { // AWFUL CODE, BLAME SUSI // Send a post request with predefined values of the hidden fields string data = string.Format(HiddenFieldValues.FormattedExamFormData, HttpUtility.UrlEncode(this.vstate)); switch (coursesType) { case CoursesTakenType.NotTaken: data += HiddenFieldValues.NotTakenCoursesFlag; break; case CoursesTakenType.Taken: data += HiddenFieldValues.TakenCoursesFlag; break; default: data += HiddenFieldValues.TakenCoursesFlag + HiddenFieldValues.NotTakenCoursesFlag; break; } WebResponse response = this.SendRequest(SusiPages.ReportExams, data); // Since SUSI sucks, in order to get the courses page we first need the value of a special hidden field - _VSTATE. // Unfortunately, _VSTATE has different value on other pages, so first need to get its value from the current response, // Then send another request with the updated value (which is what the recursion is for) if (shouldRecurse) { ExtractVstate(response); return(this.GetExamPage(coursesType, false)); } // If everything else is ok return the whole page return(ReadResponseToEnd(response)); }
/// <summary> /// Gets a collection of <see cref="CourseInfo"/> that shows all courses that the student has passed successfully. /// </summary> public IEnumerable <CourseInfo> GetCourses(CoursesTakenType coursesType) { if (this.Cookies.Count == 0) { throw new InvalidOperationException("You must login prior to getting info from SUSI"); } #if !DEBUG try { #endif // Get the exam page and parse it string examPage = this.GetExamPage(coursesType); HtmlDocument document = new HtmlDocument(); document.LoadHtml(examPage); // Use a magical xpath to get all rows of the courses table, there may be header rows though string xpath = @"/html/body/form/table/tr/td/table[@width=""100%""]/tr/td/table/tr[not(@class)]"; var nodes = document.DocumentNode.SelectNodes(xpath); // Set the culture to BG, else parsing doubles will fail CultureInfo culture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("bg-BG"); List <CourseInfo> courseInfos = new List <CourseInfo>(); foreach (HtmlNode node in nodes) { // Each tr has 6 tds inside in the following order: // Subject Teacher Type(elective or not) Taken Grade Credits HtmlNodeCollection children = node.SelectNodes("td"); // If the first cell contains the following magic word, the row is a header, ignore it if (children[0].InnerText.Contains("Предмет")) { continue; } CourseInfo courseInfo = ExtractCourseInfo(children); courseInfos.Add(courseInfo); } // Set the culture back to whatever it was Thread.CurrentThread.CurrentCulture = culture; return(courseInfos); #if !DEBUG } catch (Exception e) { // In case something failed, throw a new exception throw new WebException("Can't load data from SUSI", e); } #endif }
public void LogCoursesRequest(string ip, CoursesTakenType type) { writer.WriteLine("[{0}] COURSES: Request about [{1}] courses served to address [{2}].", DateTime.UtcNow, type, ip); }
/// <summary> /// Gets a collection of <see cref="CourseInfo"/> that shows all courses that the student has passed successfully. /// </summary> public IEnumerable<CourseInfo> GetCourses(CoursesTakenType coursesType) { if (this.Cookies.Count == 0) { throw new InvalidOperationException("You must login prior to getting info from SUSI"); } #if !DEBUG try { #endif // Get the exam page and parse it string examPage = this.GetExamPage(coursesType); HtmlDocument document = new HtmlDocument(); document.LoadHtml(examPage); // Use a magical xpath to get all rows of the courses table, there may be header rows though string xpath = @"/html/body/form/table/tr/td/table[@width=""100%""]/tr/td/table/tr[not(@class)]"; var nodes = document.DocumentNode.SelectNodes(xpath); // Set the culture to BG, else parsing doubles will fail CultureInfo culture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("bg-BG"); List<CourseInfo> courseInfos = new List<CourseInfo>(); foreach (HtmlNode node in nodes) { // Each tr has 6 tds inside in the following order: // Subject Teacher Type(elective or not) Taken Grade Credits HtmlNodeCollection children = node.SelectNodes("td"); // If the first cell contains the following magic word, the row is a header, ignore it if (children[0].InnerText.Contains("Предмет")) continue; CourseInfo courseInfo = ExtractCourseInfo(children); courseInfos.Add(courseInfo); } // Set the culture back to whatever it was Thread.CurrentThread.CurrentCulture = culture; return courseInfos; #if !DEBUG } catch (Exception e) { // In case something failed, throw a new exception throw new WebException("Can't load data from SUSI", e); } #endif }
private string GetExamPage(CoursesTakenType coursesType, bool shouldRecurse = true) { // AWFUL CODE, BLAME SUSI // Send a post request with predefined values of the hidden fields string data = string.Format(HiddenFieldValues.FormattedExamFormData, HttpUtility.UrlEncode(this.vstate)); switch (coursesType) { case CoursesTakenType.NotTaken: data += HiddenFieldValues.NotTakenCoursesFlag; break; case CoursesTakenType.Taken: data += HiddenFieldValues.TakenCoursesFlag; break; default: data += HiddenFieldValues.TakenCoursesFlag + HiddenFieldValues.NotTakenCoursesFlag; break; } WebResponse response = this.SendRequest(SusiPages.ReportExams, data); // Since SUSI sucks, in order to get the courses page we first need the value of a special hidden field - _VSTATE. // Unfortunately, _VSTATE has different value on other pages, so first need to get its value from the current response, // Then send another request with the updated value (which is what the recursion is for) if (shouldRecurse) { ExtractVstate(response); return this.GetExamPage(coursesType, false); } // If everything else is ok return the whole page return ReadResponseToEnd(response); }