Skip to content

Commit

Permalink
Development: Add script to create large courses locally (#9252)
Browse files Browse the repository at this point in the history
  • Loading branch information
az108 authored Sep 6, 2024
1 parent 99fa40c commit b7aaf44
Show file tree
Hide file tree
Showing 22 changed files with 673 additions and 345 deletions.
1 change: 1 addition & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ Prerequisites:
<!-- All PRs that might affect the exam mode (e.g. change a client component that is also used in the exam mode) need an additional verification that the exam mode still works. -->

#### Performance Review
<!-- See [Large Course Setup](https://github.com/ls1intum/Artemis/tree/develop/supporting_scripts/course-scripts/quick-course-setup) for the automation script that handles large course setup. -->
- [ ] I (as a reviewer) confirm that the client changes (in particular related to REST calls and UI responsiveness) are implemented with a very good performance even for very large courses with more than 2000 students.
- [ ] I (as a reviewer) confirm that the server changes (in particular related to database calls) are implemented with a very good performance even for very large courses with more than 2000 students.
#### Code Review
Expand Down
176 changes: 176 additions & 0 deletions supporting_scripts/course-scripts/quick-course-setup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# Artemis Course Setup Scripts

This project contains Python scripts that automate the setup and management of courses and users in an Artemis instance. The scripts help you create a course, generate users, enroll them into courses, and manage programming exercises, including participations and commits. The project is useful for setting up test environments or quickly initializing a course with a large number of students.

# Setup

### 1. Install Python and the Python Plugin for IntelliJ

- Ensure that Python (preferably version 3.12) is installed on your system.
```shell
python3.12 --version
```
- Install the [Python Plugin for IntelliJ](https://plugins.jetbrains.com/plugin/631-python).
- Enable Python support in IntelliJ:
- Go to `File > Project Structure > Facets > Add - Python`.
- Add a Python environment by configuring the Python interpreter.

![IntelliJ Python Facet Configuration](./images/facets-config.png)
- Add a module in IntelliJ by navigating to `File > Project Structure > Modules > Add - Python`.

![IntelliJ Module Configuration](./images/module-config.png)

### 2. **(Optional)**: Setting Up a Virtual Environment

It is recommended to use a virtual environment to manage dependencies in isolation from the global Python environment. This approach can prevent version conflicts and keep your system environment clean.

- Install `virtualenv` if it's not already installed:
```shell
python3.12 -m pip install virtualenv
```

- Create a virtual environment in your project folder:
```shell
python3.12 -m virtualenv venv
```

- Activate the virtual environment:

- On **Windows**:
```shell
venv\Scripts\activate
```

- On **macOS/Linux**:
```shell
source venv/bin/activate
```

Once the virtual environment is activated, you will see the `(venv)` prefix in your terminal prompt. All dependencies will now be installed locally to this environment.

To install any packages into this virtual environment, proceed with the same steps as described below.
### 3. Configure the Environment

- Start your local Artemis instance.
- Configure the [config.ini](./config.ini) file according to your local or test server setup.
- If packages are missing when running the script, install the necessary Python packages using the following command (replace `<packageName>` with the actual package name and the python version with your used python version):

```shell
python3.12 -m pip install <packageName>
```
# Usage

## Section 1: Create Local Course and Users

These scripts help you configure and set up your first Artemis course quickly.

1. Start your local Artemis instance.

2. Configure the values in [config.ini](./config.ini) according to your setup.

3. Install the missing packages of the Python scripts that you want to execute (if not done already). You can check the [requirements.txt](./requirements.txt) file for the required packages.

4. Run the main script using IntelliJ:

- Use the play button within IntelliJ (if Python is configured properly).
- Alternatively, you can run the script directly from the terminal using the commands provided in this README.

### Creating a Course with Standard User Groups

Creates a course for which the users are registered according to their user groups (students, tutors, editors, instructors).

```shell
python3 create_course.py
```

### Create Users

Creates users 1-20 (students, tutors, editors, instructors - 5 for each group).

```shell
python3 create_users.py
```

### Authenticate Users

If the users have already been created, they still need to be logged in order to be added to a course (without a first login, Artemis does not know that the users exist).

```shell
python3 authenticate_all_users.py
```

## Test Servers

### To configure the scripts for use with Artemis test servers:

1. Adjust server_url and client_url according to the test server.
2. Update admin_user and admin_password to valid values for the test server.
3. Set is_local_course in [config.ini](./config.ini) to False.

Create a Course and Assign the Default Users

1-5: students
6-10: tutors
11-15: instructors
16-20: editors

Define the name of your course in the config.ini as course_name.

```shell
python3 create_course.py
```

### Add Users to Existing Course

Define the course_id in the [config.ini](./config.ini).

```shell
python3 add_users_to_course.py
```

## Notes

1. Ensure that the config.ini file is correctly configured before running any scripts.
2. Always test the scripts on a local setup before running them on a production or test server.

## Section 2: Artemis Large Course with Submissions on Programming Exercise Automation

This section details how to use the large_course_main script that orchestrates the entire process, from user creation to course setup, and finally user participation in programming exercises.

### Running the large_course_main Script

The large_course_main script performs all necessary steps to set up a large course with multiple students and submissions.

### Steps to Run:

1. Open the project in IntelliJ.
2. Locate the large_course_main.py file in the project directory.
3. Update the [config.ini](./config.ini) to your needs
1. To change the number of students created, modify the students variable in the config.ini file.
2. To change the number of commits each student should perform in the example exercise, modify the commits variable in the config.ini file.
3. To change the number of programming exercises created, modify the exercises variable in the config.ini file.
4. To change the name of programming exercises created, modify the exercise_name variable in the config.ini file.
5. To use an existing course, modify the create_course variable to False and provide a valid course_id in the config.ini file.
6. To use an existing programming exercise, modify the create_exercises variable to False and provide a valid exercise_Ids in the config.ini file.
4. You can use the play button within IntelliJ (if Python is configured properly) to run the script.
```shell
python3 large_course_main.py
```

The script will automatically perform all the necessary steps:

1. Authenticate as admin.
2. Create students.
3. Create a course or use an existing one.
4. Add students to the course.
5. Create a programming exercise or use an existing one.
6. Add participation and commit for each student.

### Optional: Deleting All Created Students

If you want to delete all the students created by the script:

1. Run the main in delete_students.py.
```shell
python3 delete_students.py
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import requests
import configparser
from logging_config import logging
from requests import Session

from utils import login_as_admin, get_user_details_by_index, add_user_to_course, get_student_details_by_index

# Load configuration
config = configparser.ConfigParser()
config.read('config.ini')

# Constants from config file
COURSE_ID: str = config.get('CourseSettings', 'course_id')

def add_users_to_groups_of_course(session: Session, course_id: str) -> None:
print(f"Adding users to course with id {course_id}")
for userIndex in range(1, 21):
user_details = get_user_details_by_index(userIndex)
add_user_to_course(session, course_id, user_details["groups"][0], user_details["login"])

def add_students_to_groups_of_course(session: Session, course_id: str, server_url: str, students_to_create: int) -> None:
for user_index in range(1, students_to_create):
user_details = get_student_details_by_index(user_index)
add_students_to_course(session, course_id, user_details["groups"][0], user_details["login"], server_url)

def add_students_to_course(session: Session, course_id: str, user_group: str, user_name: str, server_url: str) -> None:
url = f"{server_url}/courses/{course_id}/{user_group}/{user_name}"
response = session.post(url)
if response.status_code == 200:
logging.info(f"Added user {user_name} to group {user_group}")
else:
logging.error(f"Could not add user {user_name} to group {user_group}")

def main() -> None:
session = requests.session()
login_as_admin(session)
add_users_to_groups_of_course(session, COURSE_ID)

if __name__ == "__main__":
# DO ONLY USE FOR LOCAL COURSE SETUP!
# (Otherwise users will be created for whom the credentials are public in the repository!)
main()
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from utils import authenticate_user
from utils import get_user_details_by_index
from utils import authenticate_user, get_user_details_by_index


def authenticate_all_generated_users():
def authenticate_all_generated_users() -> None:
"""
Users are only visible in the course once they have logged in for the first time
Users are only visible in the course once they have logged in for the first time.
This method logs in the users that are generated in Jira with the script for the Atlassian Setup:
See https://github.com/ls1intum/Artemis/blob/develop/docker/atlassian/atlassian-setup.sh
Expand All @@ -15,15 +13,8 @@ def authenticate_all_generated_users():
user_details = get_user_details_by_index(user_index)
authenticate_user(user_details['login'], user_details['password'])

# login cypress users
for user_index in range(100, 107):
user_details = get_user_details_by_index(user_index)
authenticate_user(user_details['login'], user_details['password'])


def main():
def main() -> None:
authenticate_all_generated_users()


if __name__ == "__main__":
main()
38 changes: 38 additions & 0 deletions supporting_scripts/course-scripts/quick-course-setup/config.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[Settings]
students = 2000
commits = 2
exercises = 1
exercise_name = Example Programming Exercise

# should be set to true if the script should create programming exercises otherwise set to false and provide exercise_ids on which the participations and commits should be created
create_exercises = True
exercise_Ids = 1,2

server_url = http://localhost:8080/api
client_url = http://localhost:9000/api

# example urls for test server
;server_url = https://artemis-test1.artemis.cit.tum.de/api
;client_url = https://artemis-test1.artemis.cit.tum.de/api

special_character_regex = r'[^a-zA-Z0-9_]'

# make sure to adjust as well for the test server
admin_user = artemis_admin
admin_password = artemis_admin

# set the amount of concurrent requests to the server for creating users or deleting them
max_threads = 5

[CourseSettings]
# should be set to true if the script should create a course
create_course = True
# only needed when adding users to a course after the course was already created
course_id = 1234

# Modify if you want to change the name of the course created with create_course
# (e.g. when creating a course on a test server)
course_name = Local Course

# set to false if creating course on a test server (has an effect on the user groups)
is_local_course = True
Loading

0 comments on commit b7aaf44

Please sign in to comment.