jabajke

Untitled

May 26th, 2023
24
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.02 KB | None | 0 0
  1. migrations/env.py
  2. import asyncio
  3. from logging.config import fileConfig
  4.  
  5. from sqlalchemy import pool
  6. from sqlalchemy.engine import Connection
  7. from sqlalchemy.ext.asyncio import async_engine_from_config
  8.  
  9. from alembic import context
  10.  
  11. from src.core.database import Base
  12. from src.core.settings import settings
  13.  
  14. from auth.models import User
  15. from event.models import Event
  16. from account.models import Account
  17. from src.associations import AccountEventAssociation, AccountRatingAssociation
  18. # this is the Alembic Config object, which provides
  19. # access to the values within the .ini file in use.
  20. config = context.config
  21. section = config.config_ini_section
  22. config.set_section_option(section, "POSTGRES_USER", settings.db.POSTGRES_USER)
  23. config.set_section_option(section, "POSTGRES_HOST", settings.db.POSTGRES_HOST)
  24. config.set_section_option(section, "POSTGRES_DB", settings.db.POSTGRES_DB)
  25. config.set_section_option(section, "POSTGRES_PASSWORD", settings.db.POSTGRES_PASSWORD)
  26.  
  27.  
  28. # Interpret the config file for Python logging.
  29. # This line sets up loggers basically.
  30. if config.config_file_name is not None:
  31. fileConfig(config.config_file_name)
  32.  
  33. # add your model's MetaData object here
  34. # for 'autogenerate' support
  35. # from myapp import mymodel
  36. # target_metadata = mymodel.Base.metadata
  37. target_metadata = Base.metadata
  38.  
  39. # other values from the config, defined by the needs of env.py,
  40. # can be acquired:
  41. # my_important_option = config.get_main_option("my_important_option")
  42. # ... etc.
  43.  
  44.  
  45. def run_migrations_offline() -> None:
  46. """Run migrations in 'offline' mode.
  47.  
  48. This configures the context with just a URL
  49. and not an Engine, though an Engine is acceptable
  50. here as well. By skipping the Engine creation
  51. we don't even need a DBAPI to be available.
  52.  
  53. Calls to context.execute() here emit the given string to the
  54. script output.
  55.  
  56. """
  57. url = config.get_main_option("sqlalchemy.url")
  58. context.configure(
  59. url=url,
  60. target_metadata=target_metadata,
  61. literal_binds=True,
  62. dialect_opts={"paramstyle": "named"},
  63. )
  64.  
  65. with context.begin_transaction():
  66. context.run_migrations()
  67.  
  68.  
  69. def do_run_migrations(connection: Connection) -> None:
  70. context.configure(connection=connection, target_metadata=target_metadata)
  71.  
  72. with context.begin_transaction():
  73. context.run_migrations()
  74.  
  75.  
  76. async def run_async_migrations() -> None:
  77. """In this scenario we need to create an Engine
  78. and associate a connection with the context.
  79.  
  80. """
  81.  
  82. connectable = async_engine_from_config(
  83. config.get_section(config.config_ini_section, {}),
  84. prefix="sqlalchemy.",
  85. poolclass=pool.NullPool,
  86. )
  87.  
  88. async with connectable.connect() as connection:
  89. await connection.run_sync(do_run_migrations)
  90.  
  91. await connectable.dispose()
  92.  
  93.  
  94. def run_migrations_online() -> None:
  95. """Run migrations in 'online' mode."""
  96.  
  97. asyncio.run(run_async_migrations())
  98.  
  99.  
  100. if context.is_offline_mode():
  101. run_migrations_offline()
  102. else:
  103. run_migrations_online()
  104.  
  105.  
  106. src/core/__init__
  107. from .celery import celery as celery_app
  108.  
  109. __all__ = ['celery_app']
  110.  
  111.  
  112. event/__init__
  113. from fastapi import APIRouter
  114.  
  115. from .api import router as api_router
  116.  
  117. router = APIRouter(prefix='/event', tags=['Event'])
  118. router.include_router(api_router)
  119.  
  120. event/api
  121. from typing import List
  122.  
  123. from fastapi import APIRouter, Depends, status
  124. from sqlalchemy.ext.asyncio import AsyncSession
  125.  
  126. from src import utils
  127. from src.core.database import get_session
  128.  
  129. from .permissions import event_owner_permission
  130. from .schemas import (EventInSchema, EventOutListSchema, EventOutSchema,
  131. EventSchema, EventUpdateSchema)
  132. from .services import EventService
  133.  
  134. router = APIRouter()
  135.  
  136.  
  137. @router.post(
  138. '/create-event',
  139. response_model=EventOutSchema,
  140. status_code=status.HTTP_201_CREATED
  141. )
  142. async def create_event(
  143. event_data: EventInSchema,
  144. session: AsyncSession = Depends(get_session),
  145. service: EventService = Depends(),
  146. account: dict = Depends(utils.get_account_from_user)
  147. ):
  148. event = await service.create_event(
  149. session,
  150. account,
  151. event_data
  152. )
  153. return event
  154.  
  155.  
  156. @router.get(
  157. '/event-list',
  158. status_code=status.HTTP_200_OK,
  159. response_model=List[EventOutListSchema]
  160. )
  161. async def event_list(
  162. session: AsyncSession = Depends(get_session),
  163. service: EventService = Depends(),
  164. account: dict = Depends(utils.get_account_from_user)
  165. ):
  166. res = await service.event_list(session)
  167. return res
  168.  
  169.  
  170. @router.get(
  171. '/{event_id}',
  172. status_code=status.HTTP_200_OK,
  173. response_model=EventSchema
  174. )
  175. async def get_event(
  176. event_id: int,
  177. session: AsyncSession = Depends(get_session),
  178. service: EventService = Depends(),
  179. account: dict = Depends(utils.get_account_from_user)
  180. ):
  181. event, event_instance = await service.get_event(session, event_id)
  182. return event
  183.  
  184.  
  185. @router.put(
  186. '/{event_id}',
  187. status_code=status.HTTP_200_OK,
  188. response_model=EventSchema
  189. )
  190. @event_owner_permission()
  191. async def update_event(
  192. event_id: int,
  193. event_data: EventUpdateSchema,
  194. account: dict = Depends(utils.get_account_from_user),
  195. session: AsyncSession = Depends(get_session),
  196. service: EventService = Depends(),
  197. ):
  198. return await service.update_event(session, event_id, event_data)
  199.  
  200.  
  201. @router.delete(
  202. '/{event_id}',
  203. status_code=status.HTTP_204_NO_CONTENT
  204. )
  205. @event_owner_permission()
  206. async def delete_event(
  207. event_id: int,
  208. account: dict = Depends(utils.get_account_from_user),
  209. session: AsyncSession = Depends(get_session),
  210. service: EventService = Depends()
  211. ):
  212. await service.delete_event(session, event_id)
  213.  
  214.  
  215. @router.post('/{event_id}/go-to-event')
  216. async def go_to_event(
  217. event_id: int,
  218. account: dict = Depends(utils.get_account_from_user),
  219. session: AsyncSession = Depends(get_session),
  220. service: EventService = Depends()
  221. ):
  222. return await service.go_to_event(session, event_id, account)
  223.  
  224. src/utils
  225. from fastapi import Cookie, Depends, Header, HTTPException, status
  226. from jose import JWTError, jwt
  227. from sqlalchemy import select
  228. from sqlalchemy.ext.asyncio import AsyncSession
  229.  
  230. from account import models as acc_model
  231. from auth import crud
  232. from auth import models as auth_model
  233. from auth import schemas
  234.  
  235. from .core.database import get_session
  236. from .core.settings import jwt_settings
  237.  
  238.  
  239. async def validate_token(token: str):
  240. try:
  241. payload = jwt.decode(
  242. token=token,
  243. key=jwt_settings.SECRET_KEY,
  244. algorithms=[jwt_settings.ALGORITHM]
  245. )
  246. email = payload.get('email')
  247. if email is None:
  248. raise
  249. return payload
  250. except JWTError as e:
  251. print(e)
  252. raise HTTPException(
  253. status_code=status.HTTP_401_UNAUTHORIZED,
  254. headers={'WWW-Authenticate': 'Bearer'},
  255. detail='Token is invalid'
  256. )
  257.  
  258.  
  259. async def cookie_header_validation(
  260. access_token: str = Cookie(None),
  261. refresh_token: str = Cookie(None),
  262. Authorization: str = Header(None),
  263. refresh: bool = False
  264. ) -> str:
  265. exception = HTTPException(
  266. status_code=status.HTTP_401_UNAUTHORIZED,
  267. headers={'WWW-Authenticate': 'Bearer'},
  268. detail='Not Authenticated'
  269. )
  270.  
  271. if not refresh:
  272. if not any([access_token, Authorization]):
  273. raise exception
  274. token = (
  275. Authorization
  276. .replace("Bearer ", "")
  277. if Authorization else access_token
  278. )
  279. else:
  280. if not any([refresh_token, Authorization]):
  281. raise exception
  282. token = (
  283. Authorization
  284. .replace("Bearer ", "")
  285. if Authorization else refresh_token
  286. )
  287. return token
  288.  
  289.  
  290. async def get_current_user(
  291. access_token: str = Cookie(None),
  292. Authorization: str = Header(None),
  293. ) -> dict:
  294. token = await cookie_header_validation(
  295. access_token=access_token,
  296. Authorization=Authorization
  297. )
  298. payload = await validate_token(token)
  299. return payload
  300.  
  301.  
  302. async def get_current_verified_user(
  303. payload: dict = Depends(get_current_user)
  304. ) -> dict:
  305. if payload['is_email_verified']:
  306. return payload
  307. raise HTTPException(
  308. status_code=status.HTTP_401_UNAUTHORIZED,
  309. headers={'WWW-Authenticate': 'Bearer'},
  310. detail='User email is not verified'
  311. )
  312.  
  313.  
  314. async def is_user_exists(
  315. session: AsyncSession,
  316. user_data: schemas.UserCreateSchema
  317. ) -> None:
  318. subq = (
  319. select(auth_model.User)
  320. .where(auth_model.User.email == user_data.email)
  321. .exists()
  322. )
  323. stmt = select(subq)
  324. result = await session.execute(stmt)
  325. if result.scalar():
  326. raise HTTPException(
  327. status_code=status.HTTP_400_BAD_REQUEST,
  328. detail='User with such credentials already exists',
  329. headers={'WWW-Authenticate': 'Bearer'}
  330. )
  331. return None
  332.  
  333.  
  334. async def get_account_from_user(
  335. session: AsyncSession = Depends(get_session),
  336. payload: dict = Depends(get_current_verified_user)
  337. ) -> acc_model.Account:
  338.  
  339. email = payload['email']
  340. user = await crud.retrieve_user_by_email(session, email)
  341. smt = select(acc_model.Account).where(
  342. acc_model.Account.user_id == user.id
  343. )
  344. result = await session.execute(smt)
  345. account_instance = result.scalar()
  346. await session.refresh(account_instance, attribute_names=["events"])
  347. return account_instance
  348.  
  349. auth/__init__
  350. from fastapi import APIRouter
  351.  
  352. from .api import router as api_router
  353.  
  354. router = APIRouter(prefix='/auth', tags=['Authentication'])
  355. router.include_router(api_router)
  356.  
  357. auth/api
  358. from urllib.parse import urlparse
  359.  
  360. from fastapi import (APIRouter, Cookie, Depends, HTTPException, Request,
  361. Response, status)
  362. from sqlalchemy.ext.asyncio import AsyncSession
  363.  
  364. from account.services import AccountService
  365. from src import utils
  366. from src.core.database import get_session
  367.  
  368. from .schemas import (RefreshTokenSchema, UserCreateSchema, UserInSchema,
  369. UserSchema)
  370. from .services import AuthService
  371.  
  372. router = APIRouter()
  373.  
  374.  
  375. @router.post(
  376. '/token',
  377. status_code=status.HTTP_200_OK,
  378. response_model=RefreshTokenSchema
  379. )
  380. async def login(
  381. response: Response,
  382. user_data: UserInSchema,
  383. service: AuthService = Depends(),
  384. session: AsyncSession = Depends(get_session)
  385. ):
  386. user = await service.validate_user(
  387. session,
  388. user_data.email,
  389. user_data.password
  390. )
  391. tokens = await service.create_token(user, refresh=True)
  392. response.set_cookie(
  393. key='access_token',
  394. value=tokens.access_token,
  395. )
  396. response.set_cookie(
  397. key='refresh_token',
  398. value=tokens.refresh_token,
  399. )
  400. return tokens
  401.  
  402.  
  403. @router.post(
  404. '/sign-up',
  405. status_code=status.HTTP_201_CREATED,
  406. response_model=UserSchema
  407. )
  408. async def signup(
  409. user_data: UserCreateSchema,
  410. request: Request,
  411. service: AuthService = Depends(),
  412. account_service: AccountService = Depends(),
  413. session: AsyncSession = Depends(get_session)
  414. ):
  415. await service.user_exists(session, user_data)
  416. domain = urlparse(str(request.url)).netloc # localhost:8000
  417. user = await service.create_user(
  418. session,
  419. user_data,
  420. domain=domain
  421. )
  422. while True:
  423. username = await account_service.generate_username(
  424. user_data=user_data
  425. )
  426. exists = await account_service.is_username_exists(
  427. session,
  428. username
  429. )
  430. if exists is None:
  431. await account_service.create_account(
  432. session,
  433. username=username,
  434. user_data=user
  435. )
  436. break
  437. return user
  438.  
  439.  
  440. @router.get(
  441. '/email-verify',
  442. status_code=status.HTTP_200_OK
  443. )
  444. async def verify_email(
  445. service: AuthService = Depends(),
  446. session: AsyncSession = Depends(get_session),
  447. token: str | None = None
  448. ):
  449. if token is None:
  450. raise HTTPException(
  451. status_code=status.HTTP_403_FORBIDDEN,
  452. detail='Token was not provided'
  453. )
  454. payload = await utils.validate_token(token)
  455. await service.verify_user_email(session, payload)
  456. return {"message": "Email successfully verified"}
  457.  
  458.  
  459. @router.post('/restore-password', status_code=status.HTTP_200_OK)
  460. async def restore_password():
  461. pass
  462.  
  463.  
  464. @router.post('/logout', status_code=status.HTTP_204_NO_CONTENT)
  465. async def logout(
  466. response: Response,
  467. current_user: dict = Depends(utils.get_current_verified_user),
  468. ):
  469. response.delete_cookie(key='access_token')
  470. response.delete_cookie(key='refresh_token')
  471. return current_user
  472.  
  473.  
  474. @router.post(
  475. '/refresh',
  476. status_code=status.HTTP_200_OK,
  477. response_model=RefreshTokenSchema
  478. )
  479. async def refresh(
  480. response: Response,
  481. refresh_token: str = Cookie(None),
  482. Authorization: str = Cookie(None),
  483. service: AuthService = Depends(),
  484. session: AsyncSession = Depends(get_session),
  485. ):
  486. tokens = await service.refresh(
  487. session=session,
  488. token=refresh_token,
  489. Authorization=Authorization
  490. )
  491. response.set_cookie(
  492. key='access_token',
  493. value=tokens.access_token
  494. )
  495. response.set_cookie(
  496. key='refresh_token',
  497. value=tokens.refresh_token
  498. )
  499. return tokens
  500. вот все мои файлы и вот трейсбек
  501. worker | Usage: celery [OPTIONS] COMMAND [ARGS]...
  502. worker | Try 'celery --help' for help.
  503. worker |
  504. worker | Error: Invalid value for '-A' / '--app':
  505. worker | Unable to load celery application.
  506. worker | Partially initialized module 'src.utils' has no attribute 'get_current_verified_user' (most likely due to a circular import)
  507. web | Traceback (most recent call last):
  508. web | File "/usr/local/bin/alembic", line 8, in <module>
  509. web | sys.exit(main())
  510. web | ^^^^^^
  511. web | File "/usr/local/lib/python3.11/site-packages/alembic/config.py", line 632, in main
  512. web | CommandLine(prog=prog).main(argv=argv)
  513. web | File "/usr/local/lib/python3.11/site-packages/alembic/config.py", line 626, in main
  514. web | self.run_cmd(cfg, options)
  515. web | File "/usr/local/lib/python3.11/site-packages/alembic/config.py", line 603, in run_cmd
  516. web | fn(
  517. web | File "/usr/local/lib/python3.11/site-packages/alembic/command.py", line 385, in upgrade
  518. web | script.run_env()
  519. web | File "/usr/local/lib/python3.11/site-packages/alembic/script/base.py", line 582, in run_env
  520. web | util.load_python_file(self.dir, "env.py")
  521. web | File "/usr/local/lib/python3.11/site-packages/alembic/util/pyfiles.py", line 94, in load_python_file
  522. web | module = load_module_py(module_id, path)
  523. web | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  524. web | File "/usr/local/lib/python3.11/site-packages/alembic/util/pyfiles.py", line 110, in load_module_py
  525. web | spec.loader.exec_module(module) # type: ignore
  526. web | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  527. web | File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  528. web | File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  529. web | File "/usr/src/app/migrations/env.py", line 10, in <module>
  530. web | from src.core.database import Base
  531. web | File "/usr/src/app/src/core/__init__.py", line 1, in <module>
  532. web | from .celery import celery as celery_app
  533. web | File "/usr/src/app/src/core/celery.py", line 10, in <module>
  534. web | import event
  535. web | File "/usr/src/app/event/__init__.py", line 3, in <module>
  536. web | from .api import router as api_router
  537. web | File "/usr/src/app/event/api.py", line 6, in <module>
  538. web | from src import utils
  539. web | File "/usr/src/app/src/utils.py", line 7, in <module>
  540. web | from auth import crud
  541. web | File "/usr/src/app/auth/__init__.py", line 3, in <module>
  542. web | from .api import router as api_router
  543. web | File "/usr/src/app/auth/api.py", line 110, in <module>
  544. web | current_user: dict = Depends(utils.get_current_verified_user),
  545. web | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  546. web | AttributeError: partially initialized module 'src.utils' has no attribute 'get_current_verified_user' (most likely due to a circular import)
  547.  
  548. в чем здесь дело и что нужно исправить?
Advertisement
Add Comment
Please, Sign In to add comment