Home

Awesome

Docker Image Version (latest by date) GitHub "Buy Me A Coffee"

<p align="center"> <img src="./readme/schoco-full.png" width="200"> </p>

Chapters

What is schoco? {<img src="./readme/schoco-logo.svg" width="32">}

SCHOCO stands for <ins>SCH</ins>ool <ins>O</ins>nline <ins>CO</ins>ding.

Schoco is a web-based IDE for Java-Programming (Java 8) with a focus on learning programming at school. It's designed to be used by pupils and teachers in the classroom and at home.

Until now, it has hardly been possible to assign programming homework/assignments because the installation of the software at home may be difficult or cannot be presupposed and the submission and control of the results is cumbersome.

Therefore the core feature of schoco is the possibility to create coding-homework for students, which can even be tested automatically by JUnit-Tests. The tool works completely online without the need of an offline installation of the JRE or any other software by any user.

Schoco is definitely not intended to be used for professional software-development.

The project is heavily inspired by codeboard.io (github). Since codeboard didn't receive any more updates since end of 2015 and as we need slightly other features, I did create this similar web-based IDE which fits to our needs for learning (Java)-Programming explicitly at School!


IDE

You wanna know more about schoco? Then I recommend to read the main-features, read the FAQ and take a look into the Wiki.

Main-features

Installation

Installation requires a few more steps than your average docker-service, but it's still pretty straight-forward, and only requires a few minutes.

  1. You need docker and docker-compose installed.

  2. I strongly recommend to create a separate user for running schoco and this guide will from now on assume, that you create and use this separate user. Why? Because nproc is used to limit the number of running processes to prevent fork-bombs (soft-limit=3700, hard-limit=5000). If you don't create a separate user, the nproc-limit will be applied to all processes of your user, which might affect any other running software.
    Create the new user schoco (without creating a separate home-folder, since it is not necessary):
    sudo adduser --no-create-home schoco

  3. Make sure, that the new user (assuming name 'schoco') is member of the docker-group! sudo usermod -a -G docker schoco

  4. Create the data-forder data where you want to store the DB and temporary code. This step must be done BEFORE starting up the docker containers.

    ā— The new user schoco must be the owner of this folder - not root (don't use sudo). ā—

  5. Prepare your Web-Server / Reverse-Proxy to forward requests to schoco. It requires special care for the websocket-connection to work! Here are two example configurations for Apache2 and NGINX (both assuming, that schoco is running on port 1234):

    • NGINX
    location /containers {
        proxy_pass http://localhost:1234;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
    }
    
    location / {
        proxy_pass http://localhost:1234;
    }
    
    • Apache2
    RewriteEngine on
    RewriteCond ${HTTP:Upgrade} websocket [NC]
    RewriteCond ${HTTP:Connection} upgrade [NC]
    RewriteRule .* "ws://localhost:1234/$1" [P,L]
    
    ProxyPreserveHost On
    ProxyRequests off
    AllowEncodedSlashes NoDecode
    ProxyPass /containers ws://localhost:1234/containers
    ProxyPassReverse /containers ws://localhost:1234/containers
    ProxyPass / http://localhost:1234/ nocanon
    ProxyPassReverse / http://localhost:1234/
    
  6. Adapt the following docker-compose.yml to your needs and run docker compose up -d:

networks:
  schoco:
    name: schoco

services:
  schoco-backend:
    image: phitux/schoco-backend:<tag> # use the newest tag, see https://hub.docker.com/r/phitux/schoco-backend/tags
    container_name: schoco-backend
    restart: always
    user: "1000:1000" # find out the user-id (uid) and group-id (gid) of the new user schoco by running 'id schoco' in your bash
    group_add:
      # find your docker group ID. Either run in your bash: export DOCKER_GROUP_ID=$(getent group docker | cut -d: -f3)
      # and import it as variable, or just run the command from within the brackets and replace ${DOCKER_GROUP_ID} with the output.
      # Important: the group ID must be used as String (in quotes)!
      - ${DOCKER_GROUP_ID}
    environment:
      - FULL_DATA_PATH=/path/to/my/data
      # same as (left part of) first volume - but here as FULL PATH!!!

      - MAX_CONTAINERS=4
      # sets the amount of java-workers (you want to set this higher!) I recommend as rule of thumb 1.5x the amout of cores of your CPU

      - SECRET_KEY=secret
      # used for session token

      - TEACHER_KEY=teacherkey
      # this is the 'password' that is used to create new teacher-accounts. It must only be known to the teachers.

      - GITEA_USERNAME=schoco
      # this is the username of the gitea-user (see last image in this yaml-file)

      - GITEA_PASSWORD=schoco1234
      # and that is the password of the gitea-user.
      # Actually both username and password can stay like this, if you use the gitea-image from this yaml-file and if gitea is not made public (default)!

      - GITEA_HOST=http://schoco-gitea:3000
      # stays like this, if you use the gitea-image from this yaml-file and if gitea is not made public (default)!
      # change it to your domain, if you use a public gitea-instance
    networks:
      - schoco
    volumes:
      - ./data:/app/data
      - /var/run/docker.sock:/var/run/docker.sock

  schoco-frontend:
    image: phitux/schoco-frontend:<tag> # always use the same tag as schoco-backend (see https://hub.docker.com/r/phitux/schoco-frontend/tags)
    container_name: schoco-frontend
    restart: always
    group_add:
      - ${DOCKER_GROUP_ID} # see above
    networks:
      - schoco
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    ports:
      - "80:8080" # adapt the left host-port to your needs

  schoco-gitea:
    image: gitea/gitea:1.17.3 # you could probably use a newer version, but API-changes might break something...
    container_name: schoco-gitea
    restart: always
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__security__INSTALL_LOCK=true
    networks:
      - schoco
    volumes:
      - ./gitea-data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
  1. On the first startup you will need to add the gitea user using the following command. Adapt the user-ID as you set it in the yaml-file for the gitea-container and adapt the username/password as set for the schoco-backend.

    docker exec --user 1000 schoco-gitea gitea admin user create --admin --username schoco --password schoco1234 --email schoco@example.com

Architecture

<img src="./readme/schoco_architecture.svg">

How it works under the hood

FAQ

Progress

There are a few more feature ideas that might be implemented at some time (if needed, please open an issue):

Changelog

Semver is used for versioning! (New) docker-hub image-versions below 1.0.0 (mostly 0.9.xx) are used only for testing!

I <ins>strongly</ins> recommend to create a backup of your data-folder before updating schoco! Better save than sorry...

1.3.0

(2024_05_31)

- Simplified output of test-results to increase readability

1.2.0

(2024-01-04)

- Changed schoco-icon/-logo
- Included link to wiki into Tests.java file
- Template-project is now available in english and german
- User must specify a classname when creating a new project
- Removed visibility of .java file-ending from frontend
- Refactored Compilation: now only one POST is necessary AND the containers are reused after compilation

1.1.2

(2023-11-20)

- Bugfix for tooltips in 1.0.4 didn't work reliably -> removed button-tooltips in IDE and moved shortcut-info to separate modal
- Changed order of projects in home (now: most recent project on top)
- Minor Bugfix: Teachers no longer see "Test"-Button in IDE, when viewing a homework with disabled tests

1.1.1

(2023-10-26)

- Attempt to fix a rare bug, which resulted in a duplicate DB-entry when starting an assignment as pupil
- When changing settings of an assignment, you now no longer have to set the deadline to a future date
- Added scroll to filetree if necessary
- Bugfix: saved partial compilation result - now only on successful compilation
- Directly open new file after creation

1.1.0

(2023-10-22)

- Added possibility to disable JUnit Tests in assignments
- Bugfix for update notification
- Bugfix for creating tabs when opening a file
- Minor CSS fixes, changed text/layout when creating a new file
- Updated npm packages

1.0.4

(2023-10-18)

- Bugfix for tooltips in IDE
- Drastically (!) reduced size of schoco-backend image
- Updated CSS of Projectcards in Home

1.0.3

(2023-10-16) šŸŒŸ This version includes a bugfix for alembic (DB-migration). This version is now save to install. I recommend to start a new installation. Otherwise you manually have to change data inside the sqlite3 file sql_app.db: Go to table alembic_version and set version_num to f031d57aa4e6. This should do the trick.

- Slightly changed Hello-World-Template
- Bugfix for alembic! Now this version is save to install!
- Minor fixes

1.0.2

(2023-10-09)

- Bugfixes for tabs and entry_point class in IDE
- Bugfix for result calculation

1.0.1

(2023-10-07)

- Minor bugfixes, especially for importing/exporting/duplication of projects

1.0.0

(2023-10-06)

- Initial release šŸŒŸ

Start developing

On the linux-host both following packages need to be installed: libcurl4-openssl-dev libssl-dev

1) Gitea

You have to use Gitea as git-repo, since schoco uses the gitea-API.

Option A: Localhost

Install gitea using the docker-compose.yml file from this repo. You can choose to set gitea public available via browser, but actually that's not necessary and you can skip reverse-proxying gitea -> it's enough to have it only available at localhost.

If you used the docker-compose.yml from this repo, then you'll need to do a second step only once for installation. Run the following command to create the git-user (use a better password!): docker exec --user 1000 gitea gitea admin user create --admin --username schoco --password schoco1234 --email schoco@example.com

Option B: External instance (public available)

Host your gitea-instance anywhere (secured by TLS!!) and connect to it. This will lead to a speed drop caused by increased latency, since every file sadly needs a separate API-call.

2) Frontend (Vite 4 + Vue 3)

cd frontend

Initial Installation: npm install

On every start: npm run dev

3) Backend (Fastapi)

cd fastapi

Initial Installation (Python 3.10 and pip required): pip install -r requirements.txt

Create the schoco network for the docker-containers: docker network create schoco

On every start: export FULL_DATA_PATH=/full/path/to/data_folder MAX_CONTAINERS=2 SECRET_KEY=secret TEACHER_KEY=teacherkey GITEA_LOCALHOST_PORT=3000 GITEA_USERNAME=schoco GITEA_PASSWORD=schoco1234 PRODUCTION=False && python -m uvicorn main:app --log-level debug --reload

If your gitea-instance is NOT running on localhost, then exchange GITEA_LOCALHOST_PORT with GITEA_HOST=https://git.mydomain.tld

4) Backend (nginx)

For Websocket-communication, there must always be running nginx (even during development).

docker run -d -p 80:8080 -v /var/run/docker.sock:/var/run/docker.sock -v /path/to/repo/nginx/nginx.dev.conf:/etc/nginx/conf.d/default.conf --name nginx --group-add $(getent group docker | cut -d: -f3) nginxinc/nginx-unprivileged:1.23-alpine

5) Backend ('Cookies' for compilation/execution)

Considering nproc, the separate schoco-user is interesting, otherwise this step is not necessary in development:

Build and run schoco locally

  1. Build fastapi image: cd fastapi && docker build -t phitux/schoco-backend:latest .
  2. Compile the cookies API: cd cookies/api && javac Java_api.java
  3. Build cookies worker image: cd cookies && docker build -t phitux/schoco-cookies .
  4. Build frontend image: docker build -t phitux/schoco-nginx:latest .
  5. Create docker network for schoco: docker network create schoco
  6. Set the DOCKER_GROUP_ID env variable: export DOCKER_GROUP_ID=$(getent group docker | cut -d: -f3)
  7. Make sure you have a data/ directory in the repo root. This is where the sqlite db and all temporary code is stored. This may not be owned by root!
  8. Start schoco with docker compose up -d
  9. Schoco is available under http://localhost

On the first startup you will need to add the gitea user using the following command docker exec --user 1000 schoco-gitea gitea admin user create --admin --username schoco --password schoco1234 --email schoco@example.com