(self)
| 63 | return f"<Classroom {self.title!r}, id={self.id!r}>" |
| 64 | |
| 65 | def update(self): |
| 66 | try: |
| 67 | success = super().update() |
| 68 | except exceptions.ClassroomNotFound: |
| 69 | success = False |
| 70 | |
| 71 | if not success: |
| 72 | response = requests.get(f"https://scratch.mit.edu/classes/{self.id}/") |
| 73 | soup = BeautifulSoup(response.text, "html.parser") |
| 74 | |
| 75 | headings = soup.find_all("h1") |
| 76 | for heading in headings: |
| 77 | if heading.text == "Whoops! Our server is Scratch'ing its head": |
| 78 | raise exceptions.ClassroomNotFound(f"Classroom id {self.id} is not closed and cannot be found.") |
| 79 | |
| 80 | # id, title, description, status, date_start (iso format), educator/username |
| 81 | |
| 82 | title = soup.find("title").contents[0][:-len(" on Scratch")] |
| 83 | |
| 84 | overviews = soup.find_all("p", {"class": "overview"}) |
| 85 | description, status = overviews[0].text, overviews[1].text |
| 86 | |
| 87 | educator_username = None |
| 88 | pfx = "Scratch.INIT_DATA.PROFILE = {\n model: {\n id: '" |
| 89 | sfx = "',\n userId: " |
| 90 | for script in soup.find_all("script"): |
| 91 | if pfx in script.text: |
| 92 | educator_username = commons.webscrape_count(script.text, pfx, sfx, str) |
| 93 | |
| 94 | ret: typed_dicts.ClassroomDict = { |
| 95 | "id": self.id, |
| 96 | "title": title, |
| 97 | "description": description, |
| 98 | "educator": {}, |
| 99 | "status": status, |
| 100 | "is_closed": True |
| 101 | } |
| 102 | |
| 103 | if educator_username: |
| 104 | ret["educator"]["username"] = educator_username |
| 105 | |
| 106 | return self._update_from_dict(ret) |
| 107 | return success |
| 108 | |
| 109 | def _update_from_dict(self, data: typed_dicts.ClassroomDict): |
| 110 | self.id = int(data["id"]) |
nothing calls this directly
no test coverage detected