# Реалізація інформаційного та програмного забезпечення

# SQL-скрипт для створення на початкового наповнення бази даних


    -- MySQL Workbench Forward Engineering
    
    SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
    SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
    SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
    
    -- -----------------------------------------------------
    -- Schema MyDB
    -- -----------------------------------------------------
    DROP SCHEMA IF EXISTS `MyDB` ;
    
    -- -----------------------------------------------------
    -- Schema MyDB
    -- -----------------------------------------------------
    CREATE SCHEMA IF NOT EXISTS `MyDB` ;
    USE `MyDB` ;
    
    -- -----------------------------------------------------
    -- Table `MyDB`.`file`
    -- -----------------------------------------------------
    DROP TABLE IF EXISTS `MyDB`.`file` ;
    
    CREATE TABLE IF NOT EXISTS `MyDB`.`file` (
      `id` INT NOT NULL,
      `name` VARCHAR(255) NOT NULL,
      `description` VARCHAR(255) NULL,
      `uploadDate` DATETIME NOT NULL,
      `lastEditTime` DATETIME NOT NULL,
      `format` VARCHAR(45) NOT NULL,
      `hasVisualization` TINYINT(1) NOT NULL,
      `authorId` INT NOT NULL,
      `country` VARCHAR(45) NOT NULL,
      PRIMARY KEY (`id`))
    ENGINE = InnoDB
    DEFAULT CHARACTER SET = utf8;
    
    
    -- -----------------------------------------------------
    -- Table `MyDB`.`role`
    -- -----------------------------------------------------
    DROP TABLE IF EXISTS `MyDB`.`role` ;
    
    CREATE TABLE IF NOT EXISTS `MyDB`.`role` (
      `id` INT UNSIGNED NOT NULL,
      `name` VARCHAR(45) NOT NULL,
      `description` VARCHAR(255) NULL,
      PRIMARY KEY (`id`),
      FULLTEXT INDEX `idx_title_description` (`name`, `description`))
    ENGINE = InnoDB;
    
    
    -- -----------------------------------------------------
    -- Table `MyDB`.`user`
    -- -----------------------------------------------------
    DROP TABLE IF EXISTS `MyDB`.`user` ;
    
    CREATE TABLE IF NOT EXISTS `MyDB`.`user` (
      `id` INT NOT NULL,
      `nickname` VARCHAR(45) NOT NULL,
      `firstname` VARCHAR(45) NOT NULL,
      `lastname` VARCHAR(45) NULL,
      `email` VARCHAR(255) NOT NULL,
      `password` VARCHAR(255) NOT NULL,
      `role_id` INT UNSIGNED NOT NULL,
      PRIMARY KEY (`id`),
      INDEX `fk_user_role1_idx` (`role_id` ASC),
      CONSTRAINT `fk_user_role1`
        FOREIGN KEY (`role_id`)
        REFERENCES `MyDB`.`role` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB
    DEFAULT CHARACTER SET = utf8;
    
    
    -- -----------------------------------------------------
    -- Table `MyDB`.`request`
    -- -----------------------------------------------------
    DROP TABLE IF EXISTS `MyDB`.`request` ;
    
    CREATE TABLE IF NOT EXISTS `MyDB`.`request` (
      `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
      `target` VARCHAR(255) NOT NULL,
      `type` VARCHAR(45) NOT NULL,
      `date` DATETIME NOT NULL,
      `user_id` INT NOT NULL,
      PRIMARY KEY (`id`),
      INDEX `fk_request_user1_idx` (`user_id` ASC),
      CONSTRAINT `fk_request_user1`
        FOREIGN KEY (`user_id`)
        REFERENCES `MyDB`.`user` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB
    DEFAULT CHARACTER SET = utf8;
    
    
    -- -----------------------------------------------------
    -- Table `MyDB`.`right`
    -- -----------------------------------------------------
    DROP TABLE IF EXISTS `MyDB`.`right` ;
    
    CREATE TABLE IF NOT EXISTS `MyDB`.`right` (
      `id` INT UNSIGNED NOT NULL,
      `name` VARCHAR(255) NOT NULL,
      PRIMARY KEY (`id`))
    ENGINE = InnoDB
    DEFAULT CHARACTER SET = utf8;
    
    
    -- -----------------------------------------------------
    -- Table `MyDB`.`filter`
    -- -----------------------------------------------------
    DROP TABLE IF EXISTS `MyDB`.`filter` ;
    
    CREATE TABLE IF NOT EXISTS `MyDB`.`filter` (
      `id` INT NOT NULL,
      `keyword` VARCHAR(255) NULL,
      `country` VARCHAR(45) NULL,
      `format` VARCHAR(45) NULL,
      `request_id` INT UNSIGNED NOT NULL,
      PRIMARY KEY (`id`),
      INDEX `fk_filter_request1_idx` (`request_id` ASC),
      CONSTRAINT `fk_filter_request1`
        FOREIGN KEY (`request_id`)
        REFERENCES `MyDB`.`request` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB
    DEFAULT CHARACTER SET = utf8;
    
    
    -- -----------------------------------------------------
    -- Table `MyDB`.`search`
    -- -----------------------------------------------------
    DROP TABLE IF EXISTS `MyDB`.`search` ;
    
    CREATE TABLE IF NOT EXISTS `MyDB`.`search` (
      `request_id` INT UNSIGNED NOT NULL,
      `file_id` INT NOT NULL,
      PRIMARY KEY (`request_id`, `file_id`),
      INDEX `fk_search_file1_idx` (`file_id` ASC),
      CONSTRAINT `fk_search_request1`
        FOREIGN KEY (`request_id`)
        REFERENCES `MyDB`.`request` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION,
      CONSTRAINT `fk_search_file1`
        FOREIGN KEY (`file_id`)
        REFERENCES `MyDB`.`file` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB
    DEFAULT CHARACTER SET = utf8;
    
    
    -- -----------------------------------------------------
    -- Table `MyDB`.`permission`
    -- -----------------------------------------------------
    DROP TABLE IF EXISTS `MyDB`.`permission` ;
    
    CREATE TABLE IF NOT EXISTS `MyDB`.`permission` (
      `id` INT UNSIGNED NOT NULL,
      `name` VARCHAR(255) NOT NULL,
      `right_id` INT UNSIGNED NOT NULL,
      PRIMARY KEY (`id`),
      INDEX `fk_permission_right1_idx` (`right_id` ASC),
      CONSTRAINT `fk_permission_right1`
        FOREIGN KEY (`right_id`)
        REFERENCES `MyDB`.`right` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB
    DEFAULT CHARACTER SET = utf8;
    
    
    -- -----------------------------------------------------
    -- Table `MyDB`.`grant`
    -- -----------------------------------------------------
    DROP TABLE IF EXISTS `MyDB`.`grant` ;
    
    CREATE TABLE IF NOT EXISTS `MyDB`.`grant` (
      `right_id` INT UNSIGNED NOT NULL,
      `role_id` INT UNSIGNED NOT NULL,
      PRIMARY KEY (`right_id`, `role_id`),
      INDEX `fk_grant_role1_idx` (`role_id` ASC),
      CONSTRAINT `fk_grant_right1`
        FOREIGN KEY (`right_id`)
        REFERENCES `MyDB`.`right` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION,
      CONSTRAINT `fk_grant_role1`
        FOREIGN KEY (`role_id`)
        REFERENCES `MyDB`.`role` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB
    DEFAULT CHARACTER SET = utf8;
    
    
    -- -----------------------------------------------------
    -- Table `MyDB`.`access`
    -- -----------------------------------------------------
    DROP TABLE IF EXISTS `MyDB`.`access` ;
    
    CREATE TABLE IF NOT EXISTS `MyDB`.`access` (
      `role_id` INT UNSIGNED NOT NULL,
      `file_id` INT NOT NULL,
      PRIMARY KEY (`role_id`, `file_id`),
      INDEX `fk_access_file1_idx` (`file_id` ASC),
      CONSTRAINT `fk_access_role1`
        FOREIGN KEY (`role_id`)
        REFERENCES `MyDB`.`role` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION,
      CONSTRAINT `fk_access_file1`
        FOREIGN KEY (`file_id`)
        REFERENCES `MyDB`.`file` (`id`)
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB
    DEFAULT CHARACTER SET = utf8;
    
    
    SET SQL_MODE=@OLD_SQL_MODE;
    SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
    SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;


# RESTfull сервіс для управління даними(Python, FastAPI, sqlalchemy)

RESTfull сервіс створено на мові програмування Pyhon, використовуючи модули FastAPI та sqlalchemy. Даний сервіс створено за моделю MVC (Model-View-Controller), з його допомогою розробник може легко взаємодіяти з базою даних, уникаючи використання SQL-скриптів самотужки.

# Діаграма класів

# Середовище

# Database

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

URL_DATABASE = 'mysql+pymysql://root:Simple_password@localhost:3306/mydb'

engine = create_engine(URL_DATABASE)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

# Dependencies

from fastapi import Depends
from Environment.database import SessionLocal
from typing import Annotated
from sqlalchemy.orm import Session



def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

dependency = Annotated[Session, Depends(get_db)]

# Моделі

# File

from Environment.database import Base
from pydantic import BaseModel, Field
from sqlalchemy import Column, Integer, String, DateTime, Boolean, func
import datetime


class File(Base):
    __tablename__ = 'file'

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    name = Column(String(255))
    description = Column(String(255), nullable=True)
    uploadDate = Column(DateTime, default=func.now())
    lastEditTime = Column(DateTime, default=func.now())
    format = Column(String(45))
    hasVisualization = Column(Boolean)
    authorId = Column(Integer)
    country = Column(String(45))


class FileBase(BaseModel):
    name: str
    description: str
    lastEditTime: datetime.datetime
    format: str
    hasVisualization: bool
    authorId: int
    country: str

class FileWithIDAndDate(FileBase):
    id: int
    uploadDate: datetime.datetime

    class Config:
        from_attributes = True


# Request

import datetime
from Environment.database import Base
from pydantic import BaseModel, Field
from sqlalchemy import Column, Integer, String, DateTime, func

class Request(Base):
    __tablename__ = 'request'

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    target = Column(String(255))
    type = Column(String(45))
    date = Column(DateTime, default=func.now())
    user_id = Column(Integer)

class RequestBase(BaseModel):
    target: str
    type: str
    user_id: int

class RequestWithIDAndDate(RequestBase):
    id: int
    date: datetime.datetime

    class Config:
        from_attributes = True

# Role

from Environment.database import Base
from sqlalchemy import Column, Integer, String
from typing import Optional
from uuid import  UUID, uuid4
from pydantic import BaseModel

class Role(Base):
    __tablename__ = 'role'

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    name = Column(String(45))
    description = Column(String(255), nullable=True)



class RoleBase(BaseModel):
    name: str
    description: str


class RoleWithID(RoleBase):
    id: int

    class Config:
        from_attributes = True
from Environment.database import Base
from pydantic import BaseModel, Field
from sqlalchemy import Column, Integer

class Search(Base):
    __tablename__ = 'search'
    request_id = Column(Integer, primary_key=True, index=True, nullable=False)
    file_id = Column(Integer, nullable=False)

class SearchBase(BaseModel):
    request_id: int
    file_id: int

# User

from Environment.database import Base
from pydantic import BaseModel
from sqlalchemy import Column, Integer, String

class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    nickname = Column(String(45))
    firstname = Column(String(45))
    lastname = Column(String(45))
    email = Column(String(255))
    password = Column(String(255))
    role_id = Column(Integer)


class UserBase(BaseModel):
    nickname: str
    firstname: str
    lastname: str
    email: str
    password: str
    role_id: int

class UserWithID(UserBase):
    id: int

    class Config:
        from_attributes = True

# Контролери

# file_routes

from Models import File
from fastapi import HTTPException, status
from Environment.dependencies import dependency
from fastapi import APIRouter
from typing import List

router = APIRouter()


@router.post("", status_code=status.HTTP_201_CREATED, response_model=File.FileBase)
async def create_file(file: File.FileBase, db: dependency):
    db_file = File.File(**file.dict())

    db.add(db_file)
    db.commit()
    db.refresh(db_file)
    return db_file


from fastapi import HTTPException

@router.put("{file_id}", status_code=status.HTTP_200_OK, response_model=File.FileBase)
async def update_file(file_id: int, file: File.FileBase, db: dependency):
    db_file = db.query(File.File).filter(File.File.id == file_id).first()

    if db_file is None:
        raise HTTPException(status_code=404, detail="File not found")

    # Update attributes only if they are not None in the input file
    for var, value in vars(file).items():
        if value is not None:
            setattr(db_file, var, value)

    db.commit()
    db.refresh(db_file)
    return db_file


@router.get("", status_code=status.HTTP_200_OK, response_model=List[File.FileWithIDAndDate])
async def read_all_files(db: dependency):
    files = db.query(File.File).all()
    if not files:
        raise HTTPException(status_code=404, detail="No files found")
    return files


@router.get("{file_id}", status_code=status.HTTP_200_OK, response_model=File.FileWithIDAndDate)
async def read_file(file_id: int, db: dependency):
    file = db.query(File.File).filter(File.File.id == file_id).first()

    if file is None:
        raise HTTPException(status_code=404, detail="File not found")
    return file


@router.delete("{file_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_file(file_id: int, db: dependency):
    file = db.query(File.File).filter(File.File.id == file_id).first()

    if file is None:
        raise HTTPException(status_code=404, detail="File not found")

    db.delete(file)
    db.commit()

    return None  # Returning None with status_code 204 NO CONTENT

# request_routes

from Models import Request, User
from fastapi import HTTPException, status
from Environment.dependencies import dependency
from fastapi import APIRouter
from typing import List

router = APIRouter()


@router.post("", status_code=status.HTTP_201_CREATED, response_model=Request.RequestBase)
async def create_request(request: Request.RequestBase, db: dependency):
    db_request = Request.Request(**request.dict())

    user_id = request.user_id  # Replace with the actual field name in your Request model
    user = db.query(User.User).filter(User.User.id == user_id).first()

    if user is None:
        # Raise an exception if the user does not exist
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")

    db.add(db_request)
    db.commit()
    db.refresh(db_request)
    return db_request

# GET endpoint to retrieve all requests
@router.get("", status_code=status.HTTP_200_OK, response_model=List[Request.RequestWithIDAndDate])
async def read_all_requests(db: dependency):
    requests = db.query(Request.Request).all()
    if not requests:
        raise HTTPException(status_code=404, detail="No requests found")
    return requests


@router.get("{request_id}", status_code=status.HTTP_200_OK, response_model=Request.RequestWithIDAndDate)
async def read_request(request_id: int, db: dependency):
    request = db.query(Request.Request).filter(Request.Request.id == request_id).first()

    if request is None:
        raise HTTPException(status_code=404, detail="Request not found")
    return request


@router.delete("{request_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_request(request_id: int, db: dependency):
    request = db.query(Request.Request).filter(Request.Request.id == request_id).first()

    if request is None:
        raise HTTPException(status_code=404, detail="Request not found")

    db.delete(request)
    db.commit()

    return None  # Returning None with status_code 204 NO CONTENT

# role_routes

from Models import  Role
from fastapi import HTTPException, status
from Environment.dependencies import dependency
from fastapi import APIRouter
from typing import List

router = APIRouter()

@router.post("", status_code=status.HTTP_201_CREATED, response_model=Role.RoleBase)
async def create_role(role: Role.RoleBase, db: dependency):
    db_role = Role.Role(**role.dict())
    db.add(db_role)
    db.commit()
    db.refresh(db_role)
    return db_role

@router.put("{role_id}", status_code=status.HTTP_200_OK, response_model=Role.RoleBase)
async def update_role(role_id: int, role: Role.RoleBase, db: dependency):
    db_role = db.query(Role.Role).filter(Role.Role.id == role_id).first()

    if db_role is None:
        raise HTTPException(status_code=404, detail="Role not found")

    for var, value in vars(role).items():
        setattr(db_role, var, value) if value else None

    db.add(db_role)
    db.commit()
    db.refresh(db_role)

    return db_role

# GET endpoint to retrieve all roles
@router.get("", status_code=status.HTTP_200_OK, response_model=List[Role.RoleWithID])
async def read_all_roles(db: dependency):
    roles = db.query(Role.Role).all()
    if not roles:
        raise HTTPException(status_code=404, detail="No roles found")
    return roles

@router.get("{role_id}", status_code=status.HTTP_200_OK, response_model=Role.RoleWithID)
async def read_role(role_id: int, db: dependency):
    role = db.query(Role.Role).filter(Role.Role.id == role_id).first()
    if role is None:
        raise HTTPException(status_code=404, detail="Role not found")
    return role


# DELETE endpoint to remove a role by id
@router.delete("{role_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_role(role_id: int, db: dependency):
    role = db.query(Role.Role).filter(Role.Role.id == role_id).first()

    if role is None:
        raise HTTPException(status_code=404, detail="Role not found")

    db.delete(role)
    db.commit()

    return None  # Returning None with status_code 204 NO CONTENT

# search_routes

from Models import Search, File, Request
from fastapi import HTTPException, status
from Environment.dependencies import dependency
from fastapi import APIRouter
from typing import List

router = APIRouter()


@router.post("", status_code=status.HTTP_201_CREATED, response_model=Search.SearchBase)
async def create_search(search: Search.SearchBase, db: dependency):
    db_search = Search.Search(**search.dict())

    request_id = search.request_id
    request = db.query(Request.Request).filter(Request.Request.id == request_id).first()

    if request is None:
        # Raise an exception if the user does not exist
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Request not found")

    file_id = search.file_id
    file = db.query(File.File).filter(File.File.id == file_id).first()

    if file is None:
        # Raise an exception if the user does not exist
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="File not found")

    db.add(db_search)
    db.commit()
    db.refresh(db_search)
    return db_search

@router.get("", status_code=status.HTTP_200_OK, response_model=List[Search.SearchBase])
async def read_all_searches(db: dependency):
    searches = db.query(Search.Search).all()
    if not searches:
        raise HTTPException(status_code=404, detail="No searches found")
    return searches


@router.get("{request_id}", status_code=status.HTTP_200_OK, response_model=Search.SearchBase)
async def read_search(request_id: int, db: dependency):
    search = db.query(Search.Search).filter(Search.Search.request_id == request_id).first()

    if search is None:
        raise HTTPException(status_code=404, detail="Search not found")
    return search


@router.delete("{search_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_search(request_id: int, db: dependency):
    search = db.query(Search.Search).filter(Search.Search.request_id == request_id).first()

    if search is None:
        raise HTTPException(status_code=404, detail="Search not found")

    db.delete(search)
    db.commit()

    return None  # Returning None with status_code 204 NO CONTENT

# user_routes

from Models import User, Role
from fastapi import HTTPException, status
from Environment.dependencies import dependency
from fastapi import APIRouter
from typing import List

router = APIRouter()


@router.post("", status_code=status.HTTP_201_CREATED, response_model=User.UserBase)
async def create_user(user: User.UserBase, db: dependency):
    db_user = User.User(**user.dict())

    role_id = user.role_id  # Replace with the actual field name in your Request model
    role = db.query(Role.Role).filter(Role.Role.id == role_id).first()

    if role is None:
        # Raise an exception if the user does not exist
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Role not found")

    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user


@router.put("{user_id}", status_code=status.HTTP_200_OK, response_model=User.UserBase)
async def update_user(user_id: int, user: User.UserBase, db: dependency):
    db_user = db.query(User.User).filter(User.User.id == user_id).first()

    if db_user is None:
        raise HTTPException(status_code=404, detail="User not found")

    for var, value in vars(user).items():
        setattr(db_user, var, value) if value else None

    role_id = user.role_id  # Replace with the actual field name in your Request model
    role = db.query(Role.Role).filter(Role.Role.id == role_id).first()

    if role is None:
        # Raise an exception if the user does not exist
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Role not found")

    db.add(db_user)
    db.commit()
    db.refresh(db_user)

    return db_user


# GET endpoint to retrieve all users
@router.get("", status_code=status.HTTP_200_OK, response_model=List[User.UserWithID])
async def read_all_users(db: dependency):
    users = db.query(User.User).all()
    if not users:
        raise HTTPException(status_code=404, detail="No users found")
    return users


@router.get("{user_id}", status_code=status.HTTP_200_OK, response_model=User.UserWithID)
async def read_user(user_id: int, db: dependency):
    user = db.query(User.User).filter(User.User.id == user_id).first()

    if user is None:
        raise HTTPException(status_code=404, detail="User not found")
    return user


@router.delete("{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_user(user_id: int, db: dependency):
    user = db.query(User.User).filter(User.User.id == user_id).first()

    if user is None:
        raise HTTPException(status_code=404, detail="User not found")

    db.delete(user)
    db.commit()

    return None  # Returning None with status_code 204 NO CONTENT

# Файл запуску програми

# main

from fastapi import FastAPI
from Routes.user_routes import router as user_router
from Routes.role_routes import router as role_router
from Routes.search_routes import router as search_router
from Routes.request_routes import router as request_router
from Routes.file_routes import router as file_router

app = FastAPI(title="6_Lab_API", description='Bla description')

app.include_router(user_router, tags=["users"], prefix="/users")
app.include_router(role_router, tags=["roles"], prefix="/roles")
app.include_router(request_router, tags=["requests"], prefix="/requests")
app.include_router(file_router, tags=["files"], prefix="/files")
app.include_router(search_router, tags=["search"], prefix="/search")
Останнє оновлення: 12/14/2023, 11:34:32 AM