Skip to content

senjun-team/handyman

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Handyman

Сервис для выдачи и обновления прогресса по курсам, отправки задач в watchman.

Сборка и запуск

  1. Забрать проект к себе:
git clone https://gitlab.com/senjun/handyman.git
cd handyman
  1. Определить, в какой директории будут лежать курсы. Например, /home/code_runner/courses.

  2. Поднять PostgreSQL в докере. Чтобы начать работать с handyman, можно запустить контейнер с постгресом:

docker run  -e POSTGRES_PASSWORD=senjun_pass -p 5432:5432 -v postgres-senjun-data:/var/lib/postgresql/data -d postgres
  1. Зайти в контейнер:
docker ps
516cd7b6f4d3   postgres     "docker-entrypoint.s…"  ...

docker exec -it 516cd7b6f4d3 bash
psql -U postgres
  1. Применить миграции бд из etc/postgres_migrations.

  2. Заполнить таблички постгреса данными из курсов. Вам нужен скрипт import_courses.py из etc/scripts.

Настройка его окружения:

cd etc/scripts
python3 -m venv .venv
source .venv/bin/activate
pip3 install -r requirements.txt
python3 import_courses.py --courses_dir=/home/code_runner/courses --postgres_conn=postgresql://senjun:some_password@127.0.0.1:5432/senjun
  1. Собрать и запустить сервис в дебаг-сборке с указанием пути к курсам:
cd cmd/handyman
go run . /home/code_runner/courses

Либо собрать и запустить сервис в релизной сборке:

go build .
./handyman /home/code_runner/courses

Апишки

/run_task - запуск решения пользователя для задачи курса. Решение пользователя закодировано в base64.

curl -X POST \
  -d '{"task_id":"python_chapter_0010_task_0010", "solution_text":"ZXJyX3NlcnZpY2VfdW5hdmFpbGFibGUgPSA1MDM="}' \
  "http://localhost:8080/run_task?user_id=100"

/save_task - сохранение решения пользователя для задачи курса. Решение пользователя закодировано в base64. Выполняется на фронтенде сайта раз в какое-то время, если пользователь редактировал текст. Это нужно, чтобы при уходе со страницы, при перезагрузке страницы, при закрытии браузера, отвале интернета и других неприятностях у пользователя не терялось его решение.

curl -X POST \
  -d '{"task_id":"python_chapter_0010_task_0010", "solution_text":"ZXJyX3NlcnZpY2VfdW5hdmFpbGFibGUgPSA1MDM="}' \
  "http://localhost:8080/save_task?user_id=1"
curl -X POST \
  -d '{"task_id":"cpp_chapter_0020_task_0020", "solution_text":"IHRydWUgIA==", "task_type":"plain_text"}' \
  "http://localhost:8080/run_task?user_id=1"
curl -X POST \
  -d '{"task_id":"rust_chapter_0020_task_0010", "solution_text":"bGV0IG11dCBtID0gMzsKbSA9IG0gKyAyOwpwcmludGxuISgibSA9IHt9IiwgbSk7CmFzc2VydCEobSA9PSA1KTsK", "color_output": false}' \
  "http://localhost:8080/run_task?user_id=1"

/get_courses - получение списка курсов с их характеристиками.

curl -X POST   -d '{"status":"all"}'   "http://localhost:8080/get_courses?user_id=100"

/update_course_progress - обновление прогресса пользователя по курсу. Например, для кнопок "начать" и "завершить".

curl -X POST   -d '{"course_id":"python", "status":"in_progress"}'   "http://localhost:8080/update_course_progress?user_id=100"

/update_chapter_progress - обновление прогресса пользователя по главе. Например, для кнопки "следующая глава".

curl -X POST   -d '{"chapter_id":"python_chapter_0010", "status":"in_progress"}'   "http://localhost:8080/update_chapter_progress?user_id=100"

/get_chapters - получение списка глав и их статусов для пользоваетля.

curl -X POST   -d '{"course_id":"python"}'   "http://localhost:8080/get_chapters?user_id=100"

/get_chapter - получение главы с задачами и их статусами для пользователя.

curl -X POST   -d '{"chapter_id":"python_chapter_0010"}'   "http://localhost:8080/get_chapter?user_id=100"

curl -X POST   -d '{"course_id":"python"}'   "http://localhost:8080/get_chapter?user_id=4564"

/get_progress - получение прогресса пользователя по главе.

curl -X POST   -d '{"chapter_id":"python_chapter_0010"}'   "http://localhost:8080/get_progress?user_id=100"

/get_active_chapter - получение первой по списку главы с задачами и их статусами для пользователя, которая находится в статусе not_started или in_progress

curl -X POST   -d '{"course_id":"python"}'   "http://localhost:8080/get_active_chapter?user_id=100"

/courses_stats - статистика по прохождению курсов для пользователя. Нужна для страницы "прогресс" на сайте. Возвращает массив с объектами: id курса, title курса, общее количество глав, количество пройденных пользователем глав, статус курса (в процессе либо завершен).

curl -X POST   -d '{}'   "http://localhost:8080/courses_stats?user_id=100"

Пример ответа:

[{"course_id":"python","title":"Python","total_chapters":6,"finished_chapters":1,"status":"in_progress"}]

/get_course_info - возвращает в строковом виде теги курса. Теги - это именно строка, а не json.

curl -X POST   -d '{"course_id": "python"}'   "http://localhost:8080/get_course_info"

Пример ответа:

{"tags":"{\"url\": \"https://www.python.org/\", \"version\": \"Python 3.11.4\", \"chapters\": \"30 глав\", \"projects\": [{\"url\": \"https://docs.celeryq.dev/en/stable/\", \"name\": \"Celery — распределенная очередь задач\"}, {\"url\": \"https://www.openstack.org/\", \"name\": \"OpenStack — платформа для организации облачной инфраструктуры\"}, {\"url\": \"https://www.ansible.com/\", \"name\": \"Ansible — система управления конфигурациями\"}]}"}

/get_task - получение статуса задачи для пользователя: статус, текст решения.

curl -X POST   -d '{"task_id":"python_chapter_0010_task_0020"}'   "http://localhost:8080/get_task?user_id=100"

Пример удачного ответа:

{"task_id":"python_chapter_0010_task_0020","task_code":"print(\"Returned HTTP code \" + str(200))","status":"completed"}

Пример ответа с ошибкой (если что-то пошло не так):

{"error":"Couldn't get task details for: python_chapter_0010_task_0020"}

Внутренние апишки для сцены: /merge_users - смерживание прогресса по курсам, главам и задачам для двух пользователей с последующим удалением статистики по второму пользователю. Здесь new_user_id присутствует, но не играет роли.

curl -X POST   -d '{"cur_user_id": 456, "old_user_id": 982, "new_user_id": 0}'   "http://localhost:8080/merge_users"

/split_users - дублирование статистики в нового пользователя. Здесь old_user_id присутствует, но не играет роли.

curl -X POST   -d '{"cur_user_id": 456, "old_user_id": 0, "new_user_id": 982}'   "http://localhost:8080/split_users"

Добавление модулей

Чтобы добавить сторонний модуль в go-проект, достаточно сначала импортировать его в нужном месте в коде, например:

import "github.com/gorilla/mux"

А затем выполнить команду, которая обновит файл с зависимостями go.mod:

go mod tidy

Полезные SQL-запросы для отладки и разворачивания базы

-- db size with indices
SELECT pg_size_pretty(pg_database_size('senjun'));


-- show running queries
SELECT pid, age(clock_timestamp(), query_start), usename, query 
FROM pg_stat_activity 
WHERE query != '<IDLE>' AND query NOT ILIKE '%pg_stat_activity%' 
ORDER BY query_start desc;

-- kill running query
SELECT pg_cancel_backend(procpid);

-- kill idle query
SELECT pg_terminate_backend(procpid);

-- vacuum command
VACUUM (VERBOSE, ANALYZE);

-- all database users
select * from pg_stat_activity where current_query not like '<%';

-- all databases and their sizes
select * from pg_user;

-- all tables and their size, with/without indexes
select datname, pg_size_pretty(pg_database_size(datname))
from pg_database
order by pg_database_size(datname) desc;

-- cache hit rates (should not be less than 0.99)
SELECT sum(heap_blks_read) as heap_read, sum(heap_blks_hit)  as heap_hit, (sum(heap_blks_hit) - sum(heap_blks_read)) / sum(heap_blks_hit) as ratio
FROM pg_statio_user_tables;

-- table index usage rates (should not be less than 0.99)
SELECT relname, 100 * idx_scan / (seq_scan + idx_scan) percent_of_times_index_used, n_live_tup rows_in_table
FROM pg_stat_user_tables 
ORDER BY n_live_tup DESC;

-- how many indexes are in cache
SELECT sum(idx_blks_read) as idx_read, sum(idx_blks_hit)  as idx_hit, (sum(idx_blks_hit) - sum(idx_blks_read)) / sum(idx_blks_hit) as ratio
FROM pg_statio_user_indexes;

-- Dump database on remote host to file
$ pg_dump -U username -h hostname databasename > dump.sql

-- Import dump into existing database
$ psql -d newdb -f dump.sql

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published