Skip to content

Commit

Permalink
chore: Merging from master
Browse files Browse the repository at this point in the history
  • Loading branch information
yammesicka committed Mar 23, 2024
2 parents fc54392 + bca9068 commit ec2a82d
Show file tree
Hide file tree
Showing 47 changed files with 1,346 additions and 627 deletions.
28 changes: 15 additions & 13 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
module.exports = {
env: {
browser: true,
es2021: true,
"env": {
"browser": true,
"node": true
},
globals: {
bootstrap: true,
Dropzone: true,
workbox: true,
},
extends: [
'airbnb-base',
"ignorePatterns": [
"/lms/static/prism.js",
"/lms/static/markdown.js",
],
parserOptions: {
ecmaVersion: 12,
sourceType: 'module',
"globals": {
"bootstrap": true,
"Dropzone": true,
"workbox": true,
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
rules: {
'no-param-reassign': [2, { props: false }],
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/cr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ on:
jobs:
build:

runs-on: ubuntu-18.04
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up Python 3.8
- name: Set up Python 3.12
uses: actions/setup-python@v1
with:
python-version: 3.8
python-version: 3.12
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand All @@ -27,7 +27,7 @@ jobs:
chmod +x /opt/vnu/vnu-runtime-image/bin/vnu
- name: Lint
run: |
flake8 lms --count --show-source --statistics
flake8 lms --ignore Q000,I202,W503,S101,I100,I101,E800 --import-order-style=google --count --show-source --statistics
- name: Test
run: |
export PYTHONPATH=`pwd`
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,4 @@ lms/lmsweb/config.py
db.sqlite
vim.session
devops/rabbitmq.cookie
our.db
44 changes: 26 additions & 18 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
FROM python:3-buster
FROM python:3.12

RUN apt update \
&& apt install -y --no-install-recommends docker.io vim unixodbc-dev \
&& apt clean \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y \
ca-certificates \
curl \
wget \
unzip \
&& install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc \
&& chmod a+r /etc/apt/keyrings/docker.asc \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update \
&& apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

COPY requirements.txt /tmp/requirements.txt
RUN pip3 install -r /tmp/requirements.txt
RUN pip3 install --no-cache-dir -r /tmp/requirements.txt

# Install vnu (html/css validator)
RUN wget https://github.com/validator/validator/releases/download/20.6.30/vnu.linux.zip && \
unzip vnu.linux.zip -d /opt/vnu/ && \
chmod +x /opt/vnu/vnu-runtime-image/bin/vnu
ENV PATH=/opt/vnu/vnu-runtime-image/bin:$PATH
RUN wget https://github.com/validator/validator/releases/download/20.6.30/vnu.linux.zip -O /tmp/vnu.linux.zip \
&& unzip /tmp/vnu.linux.zip -d /opt/vnu/ \
&& chmod +x /opt/vnu/vnu-runtime-image/bin/vnu \
&& rm /tmp/vnu.linux.zip

RUN adduser --disabled-password --gecos '' app-user
ENV PATH=/opt/vnu/vnu-runtime-image/bin:$PATH

RUN mkdir -p /app_dir/lms
RUN chown -R app-user:app-user /app_dir
RUN adduser --disabled-password --gecos '' app-user \
&& mkdir -p /app_dir/lms \
&& chown -R app-user:app-user /app_dir

# Note: we don't copy the code to container because we mount the code in different ways
# on each setup
WORKDIR /app_dir/lms
ENV LOGURU_LEVEL INFO
ENV PYTHONPATH /app_dir/:$PYTHONPATH
ENV LOGURU_LEVEL=INFO
ENV PYTHONPATH=/app_dir/:$PYTHONPATH
# Note: Code is mounted at runtime, hence not copied.
31 changes: 22 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,30 @@
<p align="center">
<img title="BSD-3 Clause" src="https://img.shields.io/github/license/PythonFreeCourse/LMS.svg">
<img title="Travis (.com) branch" src="https://img.shields.io/travis/com/PythonFreeCourse/LMS/master.svg">
<img title="LGTM Python Grade" src="https://img.shields.io/lgtm/grade/python/github/PythonFreeCourse/LMS.svg">
<img title="LGTM JavaScript Grade" src="https://img.shields.io/lgtm/grade/javascript/github/PythonFreeCourse/LMS.svg">
</p>

👋 Welcome to Python course learning management system. 🐍

The system objectives -
The system objectives -

1. Allow teachers and mentors to input exercises list and provide feedback/comments to students exercises solutions.
2. Allow students to load their exercises solutions and get feedback to their work.

## Creating development environment

### Prerequisites

1. Linux based system - either [WSL on windows](https://docs.microsoft.com/en-us/windows/wsl/install-win10) or full blown linux.
2. [Python](https://www.python.org/downloads/release/python-385/)
2. [Python](https://www.python.org/downloads/release/python-385/)
3. [Docker](https://docs.docker.com/docker-for-windows/install/) and docker-compose.


### Minimal setup
This setup is for debug purposes and will use sqlite database and frontend only.

This setup is for debug purposes and will use SQLite database and frontend only.

Steps to do:

1. Clone this repository.
2. Set environment variables.
3. Run the application.
Expand All @@ -48,7 +52,9 @@ After logging in, use [localhost admin](https://127.0.0.1:5000/admin) to modify


### Full setup

This setup will create the following items:

* Application - LMS code.
* Middleware (messaging queue) - RabbitMQ.
* Persistence database - PostgreSQL.
Expand All @@ -70,7 +76,8 @@ cd devops
```

In case you want to add the stub data to PostgreSQL DB, run:
```

```bash
docker exec -it lms_http_1 bash
python lmsdb/bootstrap.py
```
Expand All @@ -86,17 +93,23 @@ In case you want to enable the mail system:


## Code modification check list
### Run flake8
```

## Run flake8

```bash
# on lms root directory
flake8 lms
```

### Run tests
```

```bash
export PYTHONPATH=`pwd`
pip install -r requirements.txt
pip install -r dev_requirements.txt
py.test -vvv
```

### Contributing

View [contributing guidelines](https://github.com/PythonFreeCourse/lms/blob/master/CONTRIBUTING.md).
8 changes: 4 additions & 4 deletions dev_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
debugpy==1.4.3
ipdb==0.13.9
pytest-cov==2.12.1
pytest-env==0.6.2
debugpy==1.8.1
ipdb==0.13.13
pytest-cov==4.1.0
pytest-env==1.1.3
2 changes: 1 addition & 1 deletion devops/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ MAIN_FOLDER="${SCRIPT_FOLDER}/.."

echo "Using sudo to remove the old erlang cookie"
ERLANG_COOKIE_FILE="${SCRIPT_FOLDER}/rabbitmq.cookie"
sudo rm -f "$ERLANG_COOKIE_FILE"
sudo rm -rf "$ERLANG_COOKIE_FILE"

echo "Running build on folder ${MAIN_FOLDER}"
( cd "${MAIN_FOLDER}" && docker build -t lms . )
6 changes: 2 additions & 4 deletions devops/lms.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ services:
- lms

rabbitmq:
image: rabbitmq:3.9-management-alpine
image: rabbitmq:3.8-management-alpine
hostname: celery-mq
volumes:
- rabbit-data-volume:/var/lib/rabbitmq
Expand Down Expand Up @@ -130,8 +130,6 @@ volumes:
rabbit-data-volume:
repositories-data-volume:


networks:
lms:
external:
name: lms
external: true
1 change: 1 addition & 0 deletions devops/upgrade.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ upgrade () {
docker exec -t lms_db_1 pg_dump -c -U lmsweb lms > /home/$USER/dump_`date +%d-%m-%Y"_"%H_%M_%S`.sql
cd devops || { echo "cd failed"; exit 127; }
source ./build.sh
source ./start.sh
sudo systemctl restart lms
sudo systemctl start nginx
source ./i18n.sh
Expand Down
17 changes: 17 additions & 0 deletions lms/lmsdb/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,22 @@ def _assessment_migration() -> bool:
return True


def _linter_email_migration():
old_mail_address = '[email protected]'
new_mail_address = '[email protected]'

find_user = models.User.select().where
mail_field = models.User.mail_address

if find_user(mail_field == old_mail_address).exists():
user = find_user(mail_field == old_mail_address).get()
user.mail_address = new_mail_address
user.save()
log.info(f'Changed {old_mail_address} to {new_mail_address} in User')
else:
log.info(f'{new_mail_address} already exists in User')


def is_tables_exists(tables: Union[Model, Iterable[Model]]) -> bool:
if not isinstance(tables, (tuple, list)):
tables = (tables,)
Expand Down Expand Up @@ -351,6 +367,7 @@ def main():
_uuid_migration()

_add_user_course_constaint()
_linter_email_migration()

models.create_basic_roles()
if models.User.select().count() == 0:
Expand Down
29 changes: 16 additions & 13 deletions lms/lmsdb/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,8 @@ def has_course(self, course_id: int) -> bool:
@classmethod
def get_system_user(cls) -> 'User':
instance, _ = cls.get_or_create(**{
cls.mail_address.name: 'linter-checks@python.guru',
User.username.name: 'linter-checks@python.guru',
cls.mail_address.name: 'linter-checks@pythonic.guru',
User.username.name: 'linter-checks@pythonic.guru',
}, defaults={
User.fullname.name: 'Checker guru',
User.role.name: Role.get_staff_role(),
Expand Down Expand Up @@ -322,14 +322,15 @@ def __str__(self):
@pre_save(sender=User)
def on_save_handler(model_class, instance, created):
"""Hash password on creation/save."""
supported_hashing = ('pbkdf2:sha256', 'scrypt:')

# If password changed then it won't start with hash's method prefix
is_password_changed = not instance.password.startswith('pbkdf2:sha256')
is_password_changed = not instance.password.startswith(supported_hashing)
if created or is_password_changed:
instance.password = generate_password_hash(instance.password)
instance.uuid = uuid4()

is_api_key_changed = not instance.api_key.startswith('pbkdf2:sha256')
is_api_key_changed = not instance.api_key.startswith(supported_hashing)
if created or is_api_key_changed:
if not instance.api_key:
instance.api_key = model_class.random_password()
Expand Down Expand Up @@ -638,9 +639,7 @@ class Solution(BaseModel):
)

@property
def solution_files(
self,
) -> Union[Iterable['SolutionFile'], 'SolutionFile']:
def solution_files(self) -> Iterable["SolutionFile"]:
return SolutionFile.filter(SolutionFile.solution == self)

@property
Expand Down Expand Up @@ -782,8 +781,8 @@ def create_solution(
raise AlreadyExists('This solution already exists.')

instance = cls.create(**{
cls.exercise.name: exercise,
cls.solver.name: solver,
cls.exercise.name: exercise.id,
cls.solver.name: solver.id,
cls.submission_timestamp.name: datetime.now(),
cls.hashed.name: hash_,
})
Expand Down Expand Up @@ -1172,9 +1171,13 @@ def create_comment(
@classmethod
def _by_file(cls, file_id: int):
fields = (
cls.id, cls.line_number, cls.is_auto,
CommentText.id.alias('comment_id'), CommentText.text,
cls.id,
cls.line_number,
cls.is_auto,
cls.timestamp,
CommentText.text,
SolutionFile.id.alias('file_id'),
User.id.alias('author_id'),
User.fullname.alias('author_name'),
User.role.alias('author_role'),
)
Expand Down Expand Up @@ -1210,7 +1213,7 @@ def generate_string(


def create_demo_users() -> None:
print('First run! Here are some users to get start with:') # noqa: T001
print('First run! Here are some users to get start with:') # noqa: T201
fields = ['username', 'fullname', 'mail_address', 'role']
student_role = Role.by_name('Student')
admin_role = Role.by_name('Administrator')
Expand All @@ -1224,7 +1227,7 @@ def create_demo_users() -> None:
password = User.random_password()
api_key = User.random_password(stronger=True)
User.create(**user, password=password, api_key=api_key)
print(f"User: {user['username']}, Password: {password}") # noqa: T001
print(f"User: {user['username']}, Password: {password}") # noqa: T201


def create_basic_roles() -> None:
Expand Down
5 changes: 3 additions & 2 deletions lms/lmstests/public/unittests/image/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
FROM python:3.8.0-slim-buster
FROM python:3.12-slim

COPY requirements.txt /tmp/requirements.txt
RUN pip3 install -r /tmp/requirements.txt
RUN pip config --user set global.progress_bar off && \
pip3 install -r /tmp/requirements.txt

RUN adduser --disabled-password --gecos '' app-user

Expand Down
23 changes: 11 additions & 12 deletions lms/lmstests/public/unittests/image/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
atomicwrites==1.4.0
attrs==19.3.0
importlib-metadata==1.6.0
more-itertools==8.2.0
packaging==20.3
pluggy==0.13.1
py==1.10.0
pyparsing==2.4.7
pytest==5.0.1
six==1.14.0
wcwidth==0.1.9
zipp==3.1.0
atomicwrites==1.4.1
attrs==23.2.0
importlib-metadata==7.0.1
more-itertools==10.2.0
packaging==23.2
pluggy==1.4.0
pyparsing==3.1.1
pytest==8.0.1
six==1.16.0
wcwidth==0.2.13
zipp==3.17.0
Loading

0 comments on commit ec2a82d

Please sign in to comment.