Skip to content
Open

Lab5 #138

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added reports/Melnik/lab4/rep/rep.pdf
Binary file not shown.
Empty file.
87 changes: 87 additions & 0 deletions reports/Melnik/lab4/src/task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# pylint: disable=invalid-name
"""
Скрипт для автоматического отслеживания новых релизов в репозиториях GitHub.
Использует GitHub REST API и сохраняет состояние в JSON файл.
"""

import json
import os
import requests

STATE_FILE = "last_releases.json"


def get_latest_release(repo: str) -> dict:
"""
Получает информацию о последнем релизе репозитория через GitHub API.
"""
url = f"https://api.github.com/repos/{repo}/releases/latest"
headers = {"Accept": "application/vnd.github.v3+json"}

try:
response = requests.get(url, headers=headers, timeout=10)
if response.status_code == 200:
return response.json()
return None
except requests.exceptions.RequestException as err:
print(f"Ошибка сети для {repo}: {err}")
return None


def load_state() -> dict:
"""Загружает данные о прошлых проверках из JSON файла."""
if os.path.exists(STATE_FILE):
with open(STATE_FILE, "r", encoding="utf-8") as f:
return json.load(f)
return {}


def save_state(state: dict) -> None:
"""Сохраняет текущие данные о версиях в JSON файл."""
with open(STATE_FILE, "w", encoding="utf-8") as f:
json.dump(state, f, ensure_ascii=False, indent=4)


def main() -> None:
"""Основная логика мониторинга обновлений."""
user_input = input("Введите репозитории для отслеживания (через запятую): ")
repo_list = [r.strip() for r in user_input.split(",") if r.strip()]

if not repo_list:
print("Список репозиториев пуст.")
return

last_state = load_state()
new_state = last_state.copy()

for repo in repo_list:
print(f"\nПроверяем обновления для {repo}...")
release_data = get_latest_release(repo)

if not release_data:
print(f"Информация о релизах в {repo} не найдена.")
continue

version = release_data.get("tag_name")
last_seen_version = last_state.get(repo)

if version != last_seen_version:
date = release_data.get("published_at", "не указана")[:10]
link = release_data.get("html_url")
body = release_data.get("body", "Нет описания")
changelog = "\n".join(body.splitlines()[:5])

print(f"✅ НАЙДЕН НОВЫЙ РЕЛИЗ: {version} ({date})")
print(f" Ссылка: {link}")
print(f" Основные изменения:\n{changelog}...")

new_state[repo] = version
else:
print(f"😴 Новых обновлений для {repo} нет (текущая: {version}).")

save_state(new_state)
print("\nПроверка завершена. Состояние сохранено в last_releases.json")


if __name__ == "__main__":
main()
Binary file added reports/Melnik/lab5/rep/rep.pdf
Binary file not shown.
Empty file.
189 changes: 189 additions & 0 deletions reports/Melnik/lab5/src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# pylint: disable=invalid-name, too-few-public-methods, no-name-in-module
"""
Модуль для управления базой данных 'Бухгалтерия' через FastAPI.

Для запуска сервера используйте команду:
# uvicorn task:app --reload
Для просмотра документации перейдите по ссылке:
# http://127.0.0.1:8000/docs
"""

import datetime
from typing import List

from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy import (
create_engine,
Column,
Integer,
String,
Float,
ForeignKey,
DateTime,
)
from sqlalchemy.orm import sessionmaker, relationship, Session, declarative_base

SQLALCHEMY_DATABASE_URL = "sqlite:///./accounting.db"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()


class Department(Base):
"""Модель таблицы отделов."""

__tablename__ = "departments"

id = Column(Integer, primary_key=True, index=True)
name = Column(String, unique=True)
employees = relationship("Employee", back_populates="department")


class Employee(Base):
"""Модель таблицы сотрудников."""

__tablename__ = "employees"

id = Column(Integer, primary_key=True, index=True)
full_name = Column(String)
position = Column(String)
salary = Column(Float)
dept_id = Column(Integer, ForeignKey("departments.id"))

department = relationship("Department", back_populates="employees")


class Counterparty(Base):
"""Модель таблицы контрагентов."""

__tablename__ = "counterparties"

id = Column(Integer, primary_key=True, index=True)
name = Column(String)
inn = Column(String, unique=True)


class Category(Base):
"""Модель таблицы категорий операций."""

__tablename__ = "categories"

id = Column(Integer, primary_key=True, index=True)
name = Column(String)


class Transaction(Base):
"""Модель таблицы финансовых транзакций."""

__tablename__ = "transactions"

id = Column(Integer, primary_key=True, index=True)
amount = Column(Float)
description = Column(String)
created_at = Column(DateTime, default=datetime.datetime.now)

emp_id = Column(Integer, ForeignKey("employees.id"))
counterparty_id = Column(Integer, ForeignKey("counterparties.id"))
category_id = Column(Integer, ForeignKey("categories.id"))


Base.metadata.create_all(bind=engine)


class EmployeeCreate(BaseModel):
"""Схема для создания нового сотрудника."""

full_name: str
position: str
salary: float
dept_id: int


class EmployeeOut(EmployeeCreate):
"""Схема для вывода данных о сотруднике."""

id: int

class Config:
"""Настройки Pydantic для работы с SQLAlchemy."""

orm_mode = True


app = FastAPI(title="Система Бухгалтерии (Accounting API)")


def get_db():
"""Генератор сессий базы данных для каждого запроса."""
db = SessionLocal()
try:
yield db
finally:
db.close()


@app.get(
"/employees/",
response_model=List[EmployeeOut],
summary="Получить список всех сотрудников",
)
def read_employees(db: Session = Depends(get_db)):
"""Возвращает список всех сотрудников из базы данных."""
return db.query(Employee).all()


@app.post(
"/employees/", response_model=EmployeeOut, summary="Добавить нового сотрудника"
)
def create_employee(employee: EmployeeCreate, db: Session = Depends(get_db)):
"""Создает нового сотрудника и сохраняет его в базу."""
db_employee = Employee(**employee.dict())
db.add(db_employee)
db.commit()
db.refresh(db_employee)
return db_employee


@app.put("/employees/{emp_id}", summary="Изменить зарплату сотрудника")
def update_employee(emp_id: int, new_salary: float, db: Session = Depends(get_db)):
"""Находит сотрудника по ID и обновляет его заработную плату."""
db_emp = db.query(Employee).filter(Employee.id == emp_id).first()
if not db_emp:
raise HTTPException(status_code=404, detail="Сотрудник не найден")

db_emp.salary = new_salary
db.commit()
return {
"message": f"Зарплата сотрудника ID={emp_id} успешно обновлена на {new_salary}"
}


@app.delete("/employees/{emp_id}", summary="Уволить (удалить) сотрудника")
def delete_employee(emp_id: int, db: Session = Depends(get_db)):
"""Удаляет сотрудника из базы данных по его ID."""
db_emp = db.query(Employee).filter(Employee.id == emp_id).first()
if not db_emp:
raise HTTPException(status_code=404, detail="Сотрудник не найден")

db.delete(db_emp)
db.commit()
return {"message": "Сотрудник удален из базы"}


@app.post("/setup/", summary="Заполнить справочники (отделы, категории)")
def setup_db(db: Session = Depends(get_db)):
"""Заполняет пустую базу данных базовыми отделами и контрагентами."""
if db.query(Department).first():
return {"message": "База уже инициализирована"}

dept1 = Department(name="Бухгалтерия")
dept2 = Department(name="IT Отдел")
cat1 = Category(name="Выплата зарплаты")
cp1 = Counterparty(name="Банк ВТБ", inn="123456789")

db.add_all([dept1, dept2, cat1, cp1])
db.commit()
return {"message": "Базовые данные добавлены!"}
Loading