from datetime import datetime from typing import List, Optional from sqlalchemy import create_engine, String, select, ForeignKey from sqlalchemy.orm import Session, DeclarativeBase, Mapped, mapped_column, relationship import strawberry import json import uvicorn from fastapi import FastAPI from strawberry.fastapi import GraphQLRouter from starlette.middleware.cors import CORSMiddleware from strawberry.scalars import JSON from xmlrpc.client import ServerProxy def connect(): return create_engine("postgresql+psycopg://postgres:Root12345678@10.10.8.83:32101/db", echo=True) def exec_function(function: str, **kwargs): proxy = ServerProxy('http://10.10.8.70:7000/xmlrpc') result = proxy.__getattr__(function)(kwargs) return result @strawberry.type class UsersGQL: users: JSON class Base(DeclarativeBase): pass def tow(day: int, hour: int, minute: int): return minute + hour * 60 + day * 60 * 24 class User(Base): __tablename__ = 'users' id: Mapped[int] = mapped_column(primary_key=True) username: Mapped[str] passwd: Mapped[str] bndname: Mapped[str] newbnd: Mapped[bool] active: Mapped[bool] upstream: Mapped[bool] profiles: Mapped[List['Profile']] = relationship( back_populates='user', cascade='all, delete-orphan' ) income_branches: Mapped[List['IncomeBranch']] = relationship( back_populates='user', cascade='all, delete-orphan' ) schedule: Mapped[List['Schedule']] = relationship( back_populates='user', cascade='all, delete-orphan' ) queue: Mapped[List['Queue']] = relationship( back_populates='user', cascade='all, delete-orphan' ) def __repr__(self) -> str: return f'User(id={self.id!r}, username={self.username!r}, password={self.passwd!r}, newbnd={self.newbnd})' def to_dict(self) -> dict: return { 'id': self.id, 'username': self.username, 'bndname': self.bndname, 'newbnd': self.newbnd, 'active': self.active, 'upstream': self.upstream, 'profiles': [x.to_dict() for x in self.profiles], 'schedule': [x.to_dict() for x in self.schedule], 'queue': [x.to_dict() for x in self.queue], 'income_branches': [x.to_dict() for x in self.income_branches], } def is_active_now(self): if not len(self.schedule): return True dt = datetime.now() curr_tow = tow(dt.weekday(), dt.hour, dt.minute) for x in self.schedule: if (tow(x.day_start, x.hour_start, x.minute_start) <= curr_tow <= tow(x.day_end, x.hour_end, x.minute_end)): return True return False class Profile(Base): __tablename__ = 'profiles' id: Mapped[int] = mapped_column(primary_key=True) user_id: Mapped[int] = mapped_column(ForeignKey('users.id')) scheme: Mapped[str] branch: Mapped[str] = mapped_column(String, nullable=True) json: Mapped[str] = mapped_column(String, nullable=True) user: Mapped['User'] = relationship(back_populates='profiles') def to_dict(self) -> dict: return { 'id': self.id, 'scheme': self.scheme, 'branch': self.branch, 'json': self.json, } class IncomeBranch(Base): __tablename__ = 'income_branches' id: Mapped[int] = mapped_column(primary_key=True) user_id: Mapped[int] = mapped_column(ForeignKey('users.id')) scheme: Mapped[str] branch: Mapped[str] local_scheme: Mapped[str] user: Mapped['User'] = relationship(back_populates='income_branches') def to_dict(self) -> dict: return { 'id': self.id, 'scheme': self.scheme, 'branch': self.branch, 'local_scheme': self.local_scheme, } class Schedule(Base): __tablename__ = 'schedule' id: Mapped[int] = mapped_column(primary_key=True) user_id: Mapped[int] = mapped_column(ForeignKey('users.id')) day_start: Mapped[int] hour_start: Mapped[int] minute_start: Mapped[int] day_end: Mapped[int] hour_end: Mapped[int] minute_end: Mapped[int] user: Mapped['User'] = relationship(back_populates='schedule') def to_dict(self) -> dict: return { 'id': self.id, 'day_start': self.day_start, 'hour_start': self.hour_start, 'minute_start': self.minute_start, 'day_end': self.day_end, 'hour_end': self.hour_end, 'minute_end': self.minute_end, } class Queue(Base): __tablename__ = 'queue' id: Mapped[int] = mapped_column(primary_key=True) user_id: Mapped[int] = mapped_column(ForeignKey('users.id')) commit_id: Mapped[str] schema: Mapped[str] user: Mapped['User'] = relationship(back_populates='queue') def to_dict(self) -> dict: return { 'id': self.id, 'bnd': self.user.bndname, 'commit_id': self.commit_id, 'schema': self.schema, } class Schemas(Base): __tablename__ = 'schemas' id: Mapped[int] = mapped_column(primary_key=True) schema: Mapped[str] schema_type: Mapped[str] @strawberry.type class Query: @strawberry.field() def users(self) -> UsersGQL: sync_engine = connect() with Session(sync_engine) as session: stmt = select(User) return UsersGQL(users=[json.dumps(user.to_dict()) for user in session.scalars(stmt)]) @strawberry.field() def user(self, id: int) -> UsersGQL: sync_engine = connect() with Session(sync_engine) as session: return UsersGQL(users=json.dumps(session.query(User).filter(User.id == id).one_or_none().to_dict())) @strawberry.field() def queue(self) -> UsersGQL: sync_engine = connect() with Session(sync_engine) as session: stmt = select(Queue) return UsersGQL(users=[json.dumps(queue.to_dict()) for queue in session.scalars(stmt)]) @strawberry.type class Mutation: @strawberry.mutation def update_user(self, id_: int, bndname: str, newbnd: bool, active: bool, upstream: bool, passwd: str, username: str) -> bool: sync_engine = connect() with Session(sync_engine) as session: user = session.query(User).get(id_) user.username = username user.bndname = bndname user.newbnd = newbnd user.active = active user.upstream = upstream user.passwd = passwd session.commit() return True @strawberry.mutation def create_user(self, username: str, passwd: str) -> int: sync_engine = connect() with Session(sync_engine) as session: user = User(username=username, passwd=passwd, bndname=username, active=False, newbnd=True, upstream=False) session.add_all([user]) session.commit() return user.id @strawberry.mutation def update_profile(self, id_: int, scheme: str, json: str) -> bool: sync_engine = connect() with Session(sync_engine) as session: profile = session.query(Profile).get(id_) profile.scheme = scheme profile.json = json session.commit() return True @strawberry.mutation def create_profile(self, user_id: int, scheme: str, json: str) -> int: sync_engine = connect() with (Session(sync_engine) as session): user = session.query(User).get(user_id) if not user: return 0 profile = Profile(user_id=user_id, scheme=scheme, json=json) session.add_all([profile]) session.commit() return profile.id @strawberry.mutation def update_schedule(self, id_: int, day_start: int, day_end: int, hour_start: int, hour_end: int, minute_start: int, minute_end: int) -> bool: sync_engine = connect() with Session(sync_engine) as session: schedule = session.query(Schedule).get(id_) schedule.day_start = day_start schedule.day_end = day_end schedule.hour_start = hour_start schedule.hour_end = hour_end schedule.minute_start = minute_start schedule.minute_end = minute_end session.commit() return True @strawberry.mutation def create_schedule(self, user_id: int, day_start: int, day_end: int, hour_start: int, hour_end: int, minute_start: int, minute_end: int) -> int: sync_engine = connect() with (Session(sync_engine) as session): user = session.query(User).get(user_id) if not user: return 0 schedule = Schedule(user_id=user_id, day_start=day_start, day_end=day_end, hour_start=hour_start, hour_end=hour_end, minute_start=minute_start, minute_end=minute_end) session.add_all([schedule]) session.commit() return schedule.id @strawberry.mutation def remove_user(self, id_: int) -> bool: sync_engine = connect() with (Session(sync_engine) as session): user = session.query(User).get(id_) if user: session.delete(user) session.commit() return True @strawberry.mutation def remove_profile(self, id_: int) -> bool: sync_engine = connect() with (Session(sync_engine) as session): profile = session.query(Profile).get(id_) if profile: session.delete(profile) session.commit() return True @strawberry.mutation def remove_schedule(self, id_: int) -> bool: sync_engine = connect() with (Session(sync_engine) as session): schedule = session.query(Schedule).get(id_) if schedule: session.delete(schedule) session.commit() return True def init(): sync_engine = connect() Base.metadata.drop_all(sync_engine) Base.metadata.create_all(sync_engine) with Session(sync_engine) as session: bnd127 = User( username="bnd127", passwd="gost_2012$a742ec53198ec2a5027086fba8814a89982a57112d1a72d02260161108f39b50", bndname="bnd127", newbnd=True, active=True, upstream=False ) bnd128 = User( username="bnd128", passwd="gost_2012$a742ec53198ec2a5027086fba8814a89982a57112d1a72d02260161108f39b50", bndname="bnd128", newbnd=True, active=True, upstream=False ) session.add_all([bnd127, bnd128]) session.commit() def main(): # init() uvicorn.run("main:app", port=9000, log_level="info") schema = strawberry.Schema(query=Query, mutation=Mutation) graphql_app = GraphQLRouter(schema, graphiql=True) app = FastAPI(root_path="/graphql") app.add_middleware(CORSMiddleware, allow_origins=['http://127.0.0.1:3000', 'http://localhost:3000'], allow_credentials=True, allow_methods=['*'], allow_headers=['*'] ) app.include_router(graphql_app, prefix='/graphql') if __name__ == '__main__': main()