Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions scratchattach/site/classroom.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ def __init__(self, **entries):
else:
raise KeyError(f"No class id or token provided! Entries: {entries}")

# Set attributes every Project object needs to have:
# Set attributes every Classroom object needs to have:
self._session: Session = None
self.id = None
self.classtoken = None
self.is_closed = False

self.__dict__.update(entries)

Expand All @@ -49,7 +50,6 @@ def __init__(self, **entries):
self._json_headers = dict(self._headers)
self._json_headers["accept"] = "application/json"
self._json_headers["Content-Type"] = "application/json"
self.is_closed = False

def __repr__(self) -> str:
return f"classroom called {self.title!r}"
Expand Down
58 changes: 51 additions & 7 deletions scratchattach/site/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,26 @@

import json
import random
import re
import string
from datetime import datetime, timezone

from bs4 import BeautifulSoup

from ._base import BaseSiteComponent
from ..eventhandlers import message_events
from . import project

from ..utils import commons
from ..utils import exceptions
from ..utils.commons import headers
from ..utils.requests import Requests as requests

from . import project
from . import studio
from . import forum
from bs4 import BeautifulSoup
from ._base import BaseSiteComponent
from ..utils.commons import headers
from ..utils import commons
from . import comment
from . import activity

from ..utils.requests import Requests as requests
from . import classroom

class Verificator:

Expand Down Expand Up @@ -70,6 +74,10 @@ def __init__(self, **entries):
self.username = None
self.name = None

# cache value for classroom getter method (using @property)
# first value is whether the cache has actually been set (because it can be None), second is the value itself
self._classroom: tuple[bool, classroom.Classroom | None] = False, None

# Update attributes from entries dict:
entries.setdefault("name", entries.get("username"))
self.__dict__.update(entries)
Expand Down Expand Up @@ -120,6 +128,42 @@ def _assert_permission(self):
raise exceptions.Unauthorized(
"You need to be authenticated as the profile owner to do this.")

@property
def classroom(self) -> classroom.Classroom | None:
"""
Get a user's associated classroom, and return it as a `scratchattach.classroom.Classroom` object.
If there is no associated classroom, returns `None`
"""
if not self._classroom[0]:
resp = requests.get(f"https://scratch.mit.edu/users/{self.username}/")
soup = BeautifulSoup(resp.text, "html.parser")

details = soup.find("p", {"class": "profile-details"})

class_name, class_id, is_closed = None, None, None
for a in details.find_all("a"):
href = a.get("href")
if re.match(r"/classes/\d*/", href):
class_name = a.text.strip()[len("Student of: "):]
is_closed = class_name.endswith("\n (ended)") # as this has a \n, we can be sure
if is_closed:
class_name = class_name[:-7].strip()

class_id = href.split('/')[2]
break

if class_name:
self._classroom = True, classroom.Classroom(
_session=self,
id=class_id,
title=class_name,
is_closed=is_closed
)
else:
self._classroom = True, None

return self._classroom[1]

def does_exist(self):
"""
Returns:
Expand Down