Skip to content

Commit

Permalink
Merge pull request #10 from hrspace-request-builder/feature/micro-models
Browse files Browse the repository at this point in the history
Feature/micro models
  • Loading branch information
alexpro2022 authored Mar 25, 2024
2 parents 89050b5 + 036a0f9 commit bb154ae
Show file tree
Hide file tree
Showing 27 changed files with 509 additions and 282 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: CI/CD
on:
push:
branches: ["develop"]
workflow_dispatch:
on: [push]
# push:
# branches: ["develop"]
# workflow_dispatch:

jobs:

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# hrspace-request-builder-backend
[![CI/CD](https://github.com/hrspace-request-builder/hrspace-request-builder-backend/actions/workflows/main.yml/badge.svg)](https://github.com/hrspace-request-builder/hrspace-request-builder-backend/actions/workflows/main.yml)

Проект развернут на удаленном сервере по адресу http://185.221.162.231/hrspace:
Проект развернут на удаленном сервере по адресу http://185.221.162.231:81
- админ панель доступна по адресу http://185.221.162.231/admin
- Swagger доступен по адресу http://185.221.162.231/docs
- Redoc доступен по адресу http://185.221.162.231/redoc
Expand Down Expand Up @@ -38,7 +38,7 @@ nano .env
```bash
docker compose -f docker/docker-compose.yml --env-file .env up -d --build
```
Проект будет развернут в docker-контейнерах по адресу http://localhost/hrspace
Проект будет развернут в docker-контейнерах по адресу http://localhost:81

Администрирование приложения может быть осуществлено:
- через Swagger доступный по адресу http://localhost/docs
Expand Down
5 changes: 2 additions & 3 deletions app/admin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from starlette_admin.contrib.sqla import Admin
from .views import City, CityView, Vacancy, VacancyView
from app.core.dependencies import engine

from .views import City, CityView

admin = Admin(
engine,
"💾 База данных HRSpace",
)

admin.add_view(CityView(City))
admin.add_view(VacancyView(Vacancy))
# admin.add_view(VacancyView(VacancyName))
8 changes: 4 additions & 4 deletions app/admin/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from starlette_admin.contrib.sqla import ModelView

from app.models.models import City, Vacancy
from app.models.models import City, Specialization


class GenericView(ModelView):
Expand All @@ -12,6 +12,6 @@ class CityView(GenericView):
name = "Города"


class VacancyView(GenericView):
model = Vacancy
name = "Названия вакансий"
class SpecializationView(GenericView):
model = Specialization
name = "Специальность"
89 changes: 89 additions & 0 deletions app/api/endpoints/endpoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from fastapi import APIRouter

from app.core.business_logic import get_salary
from app.core.config import settings
from app.core.dependencies import async_session
from app.models import models
from app.repositories import crud
from app.schemas import schemas

from . import responses

SUM_CITIES = "Города России"
SUM_CATEGORIES = "Сферы деятельности (и их профессии)"
SUM_CONDITIONS = "Условия труда"
SUM_SPECIALIZATION = "Выбранная специализация (полный формат)"
SUM_SPECIALIZATIONS = "Список профессий (сокращенный формат)"
SUM_REQUIREMENTS = "Общий список требований"
SUM_RESPONSIBILITIES = "Общий список обязанностей"
SUM_ALL_VACANCY_NAMES = "Предлагаемые названия вакансий"
SUM_VACANCY_NAME_DATA = "Данные для полей заявки"
SUM_VACANCY = "Данные заполненной заявки"

router = APIRouter(prefix=f"{settings.URL_PREFIX}hrspace", tags=["First_page"])


@router.get(
"/cities",
response_model=list[schemas.CityOut],
summary=SUM_CITIES,
description=(f"{settings.ALL_USERS} {SUM_CITIES}"),
)
async def get_all_cities(session: async_session):
return await crud.get_all(session, models.City)


@router.get(
"/vacancy_names",
response_model=list[schemas.ShortSpecialization],
summary=SUM_ALL_VACANCY_NAMES,
description=(f"{settings.ALL_USERS} {SUM_ALL_VACANCY_NAMES}"),
)
async def get_all_vacancies(session: async_session) -> list:
return await crud.get_all(session, models.Specialization)


@router.get(
"/categories",
response_model=list[schemas.CategoryOut],
summary=SUM_CATEGORIES,
description=(f"{settings.ALL_USERS} {SUM_CATEGORIES}"),
)
async def get_all_categories(session: async_session):
return await crud.get_all(session, models.Category)


@router.get(
"/specializations/{vacancy_name_id}",
response_model=schemas.FullSpecialization,
responses={**responses.get_404("Specialization")},
summary=SUM_SPECIALIZATION,
description=(f"{settings.ALL_USERS} {SUM_SPECIALIZATION}"),
)
async def get_spec(vacancy_name_id: int, session: async_session):
return await crud.get_or_404(session, models.Specialization, vacancy_name_id)


@router.get(
"/data/",
responses={**responses.get_404("City or specialization")},
summary=SUM_VACANCY_NAME_DATA,
description=(f"{settings.ALL_USERS} {SUM_VACANCY_NAME_DATA}"),
)
async def get_data(vacancy_name_id: int, city_id: int, session: async_session):
spec = await crud.get_or_404(session, models.Specialization, vacancy_name_id)
salary = await get_salary(session, city_id)
conditions = [c.asdict() for c in await crud.get_all(session, models.Condition)]
return {**spec.__dict__, **{"salary": salary, "conditions": conditions}}


@router.post(
"/vacancy",
status_code=201,
# response_model=schemas.VacancyOut,
# responses={**responses.get_400("Object")},
summary=SUM_VACANCY,
description=(f"{settings.ALL_USERS} {SUM_VACANCY}"),
)
async def post_vacancy(payload: schemas.VacancyIn, session: async_session):
pass
50 changes: 0 additions & 50 deletions app/api/endpoints/example.py

This file was deleted.

12 changes: 8 additions & 4 deletions app/api/endpoints/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@


def get_400(name: str) -> dict[int, dict[str, Any]]:
bad_request_msg = "already exists"

class Message(BaseModel):
detail: str = f"{name} already exists"
detail: str = f"{name} {bad_request_msg}"

return {400: {"model": Message, "description": "The item already exists"}}
return {400: {"model": Message, "description": f"The item {bad_request_msg}"}}


def get_404(name: str) -> dict[int, dict[str, Any]]:
not_found_msg = "was not found"

class Message(BaseModel):
detail: str = f"{name} not found"
detail: str = f"{name} {not_found_msg}"

return {404: {"model": Message, "description": "The item was not found"}}
return {404: {"model": Message, f"{not_found_msg}": ""}}
4 changes: 2 additions & 2 deletions app/api/routers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from fastapi import APIRouter

from app.api.endpoints import example
from app.api.endpoints import endpoints

main_router = APIRouter()


for router in (example.router,):
for router in (endpoints.router,):
main_router.include_router(router)
12 changes: 12 additions & 0 deletions app/core/business_logic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from decimal import Decimal

from sqlalchemy.ext.asyncio import AsyncSession

from app.models.models import City
from app.repositories import crud


async def get_salary(session: AsyncSession, city_id: int) -> dict[str, Decimal]:
city = await crud.get_or_404(session, City, city_id) # noqa
# TODO: calculate salary min/max as per city
return {"min": Decimal(1000.00), "max": Decimal(2000.00)}
54 changes: 22 additions & 32 deletions app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,48 +29,38 @@ class Settings(BaseSettings):

# vacancy settings
grade_max_len: int = 6
grades: list = [
"middle", "junior",
"senior", "lead"
]
experience_levels = [
"1-3 года", "неважно",
"нет опыта", "3-6 лет"
]
work_types = [
"удаленная работа", "офис", "гибрид"
]
employment_types = [
"частичная", "полная занятость",
"посменно", "другое"
]
registration_types = [
"ИП", "ТК РФ",
"самозанятость", "ГПХ"
]
grades: tuple[str, ...] = ("middle", "junior", "senior", "lead")
experience_levels: tuple[str, ...] = ("1-3 года", "неважно", "нет опыта", "3-6 лет")
work_types: tuple[str, ...] = ("удаленная работа", "офис", "гибрид")
employment_types: tuple[str, ...] = (
"частичная",
"полная занятость",
"посменно",
"другое",
)
registration_types: tuple[str, ...] = ("ИП", "ТК РФ", "самозанятость", "ГПХ")
experience_max_len: int = 9
employment_max_len: int = 16
reg_type_max_len: int = 13
decimal_precision = 10
decimal_scale = 2
decimal_precision: int = 10
decimal_scale: int = 2
description_max_len: int = 512
number_of_recruiters: list = [1, 2, 3]
hr_salary_model: list = [0, 1, 2]
number_of_recruiters: tuple[int, ...] = (1, 2, 3)
hr_salary_model: tuple[int, ...] = (0, 1, 2)
when_work_max_len: int = 18
what_need_max_len: int = 19
vacancy_when_work_options: list = [
vacancy_when_work_options: tuple[str, ...] = (
"Срочно",
"Не очень срочно",
"Времени достаточно"
]
vacancy_additional_tasks: list = [
"Времени достаточно",
)
vacancy_additional_tasks: tuple[str, ...] = (
"тестирование кандидатов",
"предварительное собеседование",
"подготовка рекомендаций по онбордингу"
]
vacancy_what_need_options: list = [
"резюме", "резюме и результаты"
]
"формирование отчёта по поиску",
"подготовка рекомендаций по онбордингу",
)
vacancy_what_need_options: tuple[str, ...] = ("резюме", "резюме и результаты")
requirements_max_len: int = 2000

@property
Expand Down
4 changes: 4 additions & 0 deletions app/data/categories.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name
Информационные технологии
Экономика
Юриспруденция
9 changes: 9 additions & 0 deletions app/data/cities.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name
Москва
Санкт_Петербург
Вологда
Казань
Владивосток
Красноярск
Воронеж
Белгород
4 changes: 4 additions & 0 deletions app/data/conditions.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name
оформление по ТК РФ
обустроенный офис
ДМС
41 changes: 41 additions & 0 deletions app/data/load_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import csv

from sqlalchemy import insert

from app.core.dependencies import AsyncSessionLocal
from app.models import models as m

DATA = (
(m.City, "app/data/cities.csv"),
(m.Condition, "app/data/conditions.csv"),
(m.Category, "app/data/categories.csv"),
(m.Specialization, "app/data/specializations.csv"),
(m.Requirement, "app/data/requirements.csv"),
(m.Responsibility, "app/data/responsibilities.csv"),
)


def read_csvfile(file_name: str) -> list[dict[str, str | int]]:
with open(file_name, newline="") as f:
return [row for row in csv.DictReader(f)]


def convert_to_int(rows: list[dict[str, str | int]]) -> None:
for row in rows:
for key in row:
try:
row[key] = int(row[key])
except (TypeError, ValueError):
pass


async def load_csv(model, file_name: str) -> None:
rows = read_csvfile(file_name)
convert_to_int(rows)
async with AsyncSessionLocal.begin() as session:
await session.execute(insert(model), rows)


async def load_models_data():
for model, scv_file in DATA:
await load_csv(model, scv_file)
Loading

0 comments on commit bb154ae

Please sign in to comment.