diff --git a/docs/api.md b/docs/api.md
index 2768270..3a98534 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -17,8 +17,8 @@ On the first run, you will be prompted for your password. Then, on the next run(
#### `login()`
Logs in to Themis. Runs automatically when the class is initialized.
-#### `get_year(start, end)`
-Returns an instance of a [`Year`](#year) (academic year) between `start` and `end`.
+#### `get_year(year_path)`
+Returns an instance of a [`Year`](#year) for the academic year specified by `year_path`.
```python
year = themis.get_year(2023, 2024)
@@ -30,7 +30,7 @@ Returns a list of `Year` instances corresponding to all years visible to the use
```python
years = themis.all_years()
```
- I don't see why you would need this, but it's here.
+
----
## `Year`
@@ -41,13 +41,20 @@ year = themis.get_year(2023, 2024)
```
### Methods
-#### `get_course(name)`
-Returns an instance of a [`Course`](#course) with the name `name`.
+#### `get_course(course_title)`
+Returns an instance of a [`Course`](#course) with the title `course_title`.
```python
pf = year.get_course("Programming Fundamentals (for CS)")
```
+#### `get_course_by_tag(course_tag)`
+Returns an instance of a [`Course`](#course) using the course identifier `course_tag`.
+
+```python
+ai_course = year.get_course_by_tag("adinc-ai")
+```
+
#### `all_courses()`
Returns a list of `Course` instances corresponding to all courses visible to the user in a given `Year`.
@@ -66,160 +73,96 @@ assignments = pf.get_groups()
### Methods
#### `get_groups(full=False)`
-Returns a list of `ExerciseGroup` instances corresponding to all exercise groups visible to the user in a given `Course`. The default argument is `full=False`, which will only return the top-level (name, link) of each exercise and folder in the group. If `full=True`, it will traverse the whole course.
-
-You can traverse the course in both cases, although in different ways.
-
-When you have fully traversed the course, you can access everything via indices and the `exercises` and `folders` attributes of the `ExerciseGroup` instances:
+Returns a list of `ExerciseGroup` or `Group` instances corresponding to all items visible to the user in a given `Course`. The default argument is `full=False`, which will only return the top-level (name, link) of each item. If `full=True`, it will traverse the whole course.
```python
-ai_group = ai_course.get_groups(full=True)
-exercise = ai_group[7].exercises[1] # Week 11 -> Suitcase packing
-exercise.submit(["suitcase.py"], silent=False)
-```
-
-This is equivalent to the case in which we don't traverse the whole course using `get_group` like so:
-
-```python
-ai_group = ai_course.get_group("Week 11")
-exercise = ai_group.get_group("Suitcase packing")
-exercise.submit(["suitcase.py"], silent=False)
+ai_groups = ai_course.get_groups(full=True)
+exercise = ai_groups[7].exercises[1]
+exercise.submit(["solution.py"], silent=False)
```
#### `get_group(name, full=False)`
-Returns an instance of an `ExerciseGroup` with the name `name`. The default argument is `full=False`, which will only return the (name, link) of each exercise and folder in the group. If `full=True`, it will traverse the whole group.
+Returns an instance of an `ExerciseGroup` or `Group` with the name `name`. The default argument is `full=False`, which will only return the (name, link) of the group. If `full=True`, it will traverse the whole group.
```python
week1 = pf.get_group("Week 1")
```
+#### `create_group(item_data)`
+Creates and returns a `Group` or `ExerciseGroup` instance based on `item_data`.
+
+```python
+group = course.create_group(item_data)
+```
+
+----
+
+## `Group`
+
+Represents an item in Themis, which can be either a folder (non-submittable) or an assignment (submittable).
+
+### Methods
+#### `get_items()`
+Returns all items (groups and assignments) under this group.
+
+```python
+items = week1.get_items()
+```
+
+#### `get_item_by_title(title)`
+Returns a single item by its title (case-insensitive).
+
+```python
+item = week1.get_item_by_title("Exercise 2")
+```
+
+#### `get_status(text=False)`
+Retrieves the status of the group. When `text=True`, returns the status as strings. Otherwise, returns submission objects or strings.
+
+```python
+status = group.get_status()
+leading_submission = status["leading"]
+```
+
+#### `download_files(path=".")`
+Downloads all files available for this group to a directory `path`. Defaults to the current directory.
+
+```python
+group.download_files()
+```
+
+#### `download_tcs(path=".")`
+Downloads all test cases for this group to a directory `path`. Defaults to the current directory.
+
+```python
+group.download_tcs()
+```
+
+#### `submit(files, judge=True, wait=True, silent=True)`
+Submits the files to the group. Default arguments are `judge=True`, `wait=True`, and `silent=True`.
+
+```python
+group.submit(["solution.py"], silent=False)
+```
+
----
## `ExerciseGroup`
-Setting the `full` flag to `True` will traverse the whole group.
+Represents a submittable exercise. Inherits from `Group`.
-- Both folders and exercises are represented as `ExerciseGroup` instances.
-- Folders will have the `am_exercise` attribute set to `False`.
-- Folders can have the `download_files` method called on them.
-- Exercises can have the `submit`, `download_files`, and `download_tcs` methods called on them.
-
-### Example of folder traversal
-Let's say we have a folder structure like this:
-```
-- Course Name
- - Week 1
- - Exercise 1
- - Exercise 2
- - Part 1
- - Part 2
- - Week 2
- - Exercise 1
- - Exercise 2
-```
-And we want to get to `Part 2` of `Week 1`'s `Exercise 2`. We would do this:
+### Additional Methods
+#### `submit(files)`
+Submits files to the exercise. Raises an error if the item is not submittable.
```python
-pf = year.get_course("Programming Fundamentals (for CS)")
-assignments = pf.get_groups()
-week1 = assignments[0] # Week 1
-exercise2 = week1.folders[1] # Exercise 2
-part2 = exercise2.exercises[1] # Part 2
-
-# Or, if you don't want to traverse the whole course:
-week1 = pf.get_group("Week 1")
-exercise2 = week1.get_group("Exercise 2")
-part2 = exercise2.get_group("Part 2")
-```
-
-### Methods
-#### `download_files(path=".")`
-Downloads all files in the exercise group to a directory `path`. Defaults to the current directory.
-
-```python
-assignment.download_files()
-```
-
-#### `download_tcs(path=".")`
-Downloads all test cases in the exercise group to a directory `path`. Defaults to the current directory.
-
-```python
-assignment.download_tcs()
-```
-
-#### `get_group(name, full=False)`
-This is used when you want to traverse the course dynamically (not recurse through the whole thing). You can use it even if you've traversed the whole course.
-
-```python
-# Week 1 -> Exercise 2 -> Part 2
-week1 = pf.get_group("Week 1")
-exercise2 = week1.get_group("Exercise 2")
-part2 = exercise2.get_group("Part 2")
-
-# This is equivalent to (but faster than):
-week1 = pf.get_groups(full=True)[0]
-exercise2 = week1.folders[1]
-part2 = exercise2.exercises[1]
-```
-
-#### `submit(files, judge=True, wait=True, silent=True)`
-Submits the files to the exercise. The default arguments are `judge=True`, `wait=True`, and `silent=True`. Setting `judge=False` will not judge the submission immediately. Setting `wait=False` will not wait for the submission to finish. Turning off `silent` will print the submission status dynamically.
-
-```python
-suitcase = ai_course.get_group("Week 11").get_group("Suitcase packing")
-suitcase.submit(["suitcase.py"], silent=False)
-
-# Output:
-# Submitting to Suitcase packing
-# • suitcase.py
-# 1: ✅
-# 2: ✅
-# 3: ✅
-# ...
-```
-
-#### `get_status(text=False)`
-Retrieves the status of the exercise group. When `text` is set to `True`, it will return the status as a dictionary of strings. Otherwise, it will return a dictionary where keys map to either strings or `Submission` objects. Common keys include `'leading'`, `'best'`, `'latest'`, etc.
-
-```python
-pf = year.get_course("Programming Fundamentals (for CS)")
-exercise = pf.get_group("Lab Session 2").get_group("Recurrence")
-
-# Get status
-status = exercise.get_status()
-print(status)
-
-# Output:
-{
- 'assignment': 'Recurrence',
- 'group': 'Y.N. Here',
- 'status': 'passed: Passed all test cases',
- 'grade': '2.00',
- 'total': '2',
- 'output limit': '1',
- 'passed': '1',
- 'leading': ,
- 'best': ,
- 'latest': ,
- 'first_pass': ,
- 'last_pass': ,
- 'visible': 'Yes'
-}
-```
-
-To access submission details:
-
-```python
-leading_submission = status["leading"]
-print(leading_submission.get_files())
+exercise.submit(["solution.py"])
```
----
## `Submission`
-### Usage
-```python
-submission = pf.get_group("Week 1").get_group("Exercise 1").get_group("Part 1").get_status()["leading"]
-```
+
+Represents a submission for a specific exercise.
### Methods
#### `get_test_cases()`
@@ -227,33 +170,13 @@ Returns a dictionary of test cases and their statuses.
```python
test_cases = submission.get_test_cases()
-print(test_cases)
-
-# Output:
-{'1': 'passed', '2': 'passed', '3': 'passed', '4': 'passed', '5': 'passed', '6': 'passed', '7': 'passed', '8': 'passed', '9': 'passed', '10': 'passed'}
```
#### `get_info()`
-Returns a dictionary of information about the submission.
+Returns detailed information about the submission.
```python
info = submission.get_info()
-print(info)
-
-# Output:
-{
- 'assignment': 'Part 1',
- 'group': 'Y.N. Here',
- 'uploaded_by': 'Y.N. Here s1234567',
- 'created_on': 'Wed Sep 13 2023 12:51:37 GMT+0200',
- 'submitted_on': 'Wed Sep 13 2023 12:51:37 GMT+0200',
- 'status': 'passed: Passed all test cases',
- 'files': [
- ('recurrence.c', '/file/.../recurrence.c'),
- ('compile.log', '/file/.../compile.log')
- ],
- 'language': 'c'
-}
```
#### `get_files()`
@@ -261,13 +184,4 @@ Returns a list of uploaded files in the format `(name, URL)`.
```python
files = submission.get_files()
-print(files)
-
-# Output:
-[
- ('recurrence.c', '/file/.../recurrence.c'),
- ('compile.log', '/file/.../compile.log')
-]
```
-
-----
diff --git a/docs/changelog.md b/docs/changelog.md
index 216b1f3..901e502 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -11,4 +11,11 @@
#### **Codebase**
- Prepended `get_` to all methods in `Submission`
- Created base `Group` from which `Course` and `ExerciseGroup` inherit.
-- Using system keyring to store passwords (Issue #11)
\ No newline at end of file
+- Using system keyring to store passwords (Issue #11)
+
+### **Version 1.2.0**
+
+#### **Codebase**
+- Moved all methods related to downloading files (including test cases) to `Group`.
+- Created `get_test_cases` and `get_files` methods in `Group`.
+- We are now using the [API](https://themis.housing.rug.nl/api/navigation/2023-2024) (which mysteriously appeared) to get the year/course structure.
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
index 3483587..f7ef0d6 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -24,7 +24,7 @@ from temmies.themis import Themis
themis = Themis("s-number") # You will be prompted for your password
# Get a year
-year = themis.get_year(2023, 2024)
+year = themis.get_year("2023-2024")
# Get a course
course = year.get_course("Programming Fundamentals (for CS)")