Compare commits

..

No commits in common. "main" and "bedir" have entirely different histories.
main ... bedir

9 changed files with 138 additions and 298 deletions

23
_collections/models.py Normal file
View file

@ -0,0 +1,23 @@
from fastapi import HTTPException
from sqlalchemy import Column, Integer, String, Float, Boolean, ForeignKey
from sqlalchemy.dialects.postgresql import ARRAY
from sqlalchemy.orm import Session, relationship
from ..config import Base
'''
##### veri tabanı modelleri #####
class Collections(Base):
__tablename__ = "collections_table"
collection_id = Column(Integer, index=True, primary_key=True , autoincrement=True)
user_id = Column(Integer, ForeignKey('users_table.user_id'), nullable=False)
visibility = Column(Boolean, default=True)
colllection_name = Column(String, default="No name")
collection_description = Column(String, default="No description")
# ilişkiler
user = relationship("DBUser", back_populates="user_collections")
items = relationship("Items", back_populates="collection", cascade="all, delete-orphan")
'''

8
_collections/router.py Normal file
View file

@ -0,0 +1,8 @@
from fastapi import FastAPI, APIRouter
router = APIRouter(
prefix="/collections",
tags=["collections"],
responses={404: {"description": "Not found"}},
dependencies=[],
)

View file

@ -1,23 +1,17 @@
from enum import Enum
import random
import smtplib
from backend.config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES ,pwd_context, get_session_db, Base, user_collection
from backend.config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES ,pwd_context, get_session_db, Base
from datetime import datetime, timedelta, timezone
from pydantic import BaseModel
from fastapi import Depends, HTTPException
from typing import Annotated
from fastapi.security import OAuth2PasswordBearer
from pydantic.networks import EmailStr
from sqlalchemy import Integer, DateTime, ForeignKey
from sqlalchemy import Integer, DateTime
from sqlalchemy.orm import Session, relationship, mapped_column, Mapped
from sqlalchemy.dialects.postgresql import ARRAY
from email.message import EmailMessage
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ..collectionObj.models import CollectionsDB #iç içe import döngüsünü önlemek için TYPE_CHECKING kullanıyoruz
import jwt
@ -67,7 +61,6 @@ class DBUser(Base):
__tablename__ = "users_table"
user_id: Mapped[int] = mapped_column(primary_key=True, index=True, autoincrement=True)
#collection_id : Mapped[list[int]] = mapped_column(Integer, ForeignKey("collections_table.collection_id"), nullable=True) # collection_id ile ilişki
username : Mapped[str] = mapped_column(unique=True, index=True, nullable=False)
email : Mapped[str] = mapped_column(unique=True, index=True, nullable=False)
hashed_password : Mapped[str] = mapped_column(nullable=False)
@ -76,14 +69,10 @@ class DBUser(Base):
created_date : Mapped[datetime] = mapped_column(DateTime, default=datetime.now()) #datetime.datetime -> python, DateTime -> sqlalchemy
bio : Mapped[str] = mapped_column(default="No bio")
follow_users : Mapped[list[int]] = mapped_column(ARRAY(Integer), default=[]) # takip edilen kullanıcılar
# -> buralar diğer tablolar ile olan ilişkiler
#items : Mapped[list['Items']] = relationship("Items", back_populates="user", cascade="all, delete-orphan") items'e direk değil collection üzerinden erişiyoruz
collections : Mapped[list['CollectionsDB']] = relationship(
"CollectionsDB",
secondary=user_collection,
back_populates="users",
lazy='select'
) # collection'lar ile olan ilişki
from ..items.models import Items
items : Mapped[list['Items']] = relationship("Items", back_populates="user", cascade="all, delete-orphan", lazy='select')
@ -139,7 +128,7 @@ async def get_current_user(
credentials_exception = HTTPException(
status_code=401,
detail="Invalid credentials currently",
detail="Invalid credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:

View file

@ -1,173 +0,0 @@
from fastapi import HTTPException, Depends
from sqlalchemy import Integer, String, Boolean
from pydantic import BaseModel
from sqlalchemy.orm import Session, relationship, mapped_column, Mapped
from ..config import Base, get_session_db, user_collection, collection_item
from ..auth.models import DBUser
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ..items.models import Items, Item
###### SCHEMAS #########
class CollectionBase(BaseModel):
collection_name : str | None = None
collection_description : str | None = None
visibility : bool | None = None
class CollectionCreate(CollectionBase):
pass
class CollectionPublic(CollectionBase):
collection_id : int | None = None
class Config:
from_attributes = True #sqlalchemy ile pydantic arasında geçiş yapabilmek için kullanılır
class CollectionUpdate(CollectionBase):
pass
##### veri tabanı modelleri #####
class CollectionsDB(Base):
__tablename__ = "collections_table"
collection_id : Mapped[int] = mapped_column(Integer, primary_key=True, index=True, autoincrement=True)
#user_id : Mapped[int] = mapped_column(Integer, ForeignKey("users_table.user_id"), nullable=False) # user_id ile ilişki
#item_id : Mapped[list[int]] = mapped_column(Integer, ForeignKey("items_table.item_id"), nullable=False) # item_id ile ilişki
visibility : Mapped[bool] = mapped_column(Boolean, default=True)
collection_name : Mapped[str] = mapped_column(String, nullable=False)
collection_description : Mapped[str] = mapped_column(String, default="No description")
# ilişkiler
users : Mapped[list['DBUser']] = relationship(
"DBUser",
secondary=user_collection,
back_populates="collections",
lazy='select'
) #back_populates karşı tarafın ismi
items : Mapped[list['Items']] = relationship(
"Items",
secondary=collection_item,
back_populates="collections" ,
lazy='select'
)
#### collection bir item listesi birde kullanıcı listesi tutacak
def create_colletion(
collection: CollectionCreate | None = None,
user_id : int | None = None
) -> bool:
"""
Collection oluşturma fonksiyonu
"""
if collection is None:
raise HTTPException(status_code=400, detail="Collection is None returned")
session = next(get_session_db()) # -> get_session_db() fonksiyonu daima generator döndürür next ile çağırmalısın
user = session.query(DBUser).filter(DBUser.user_id == user_id).first()
if user is None:
raise HTTPException(status_code=404, detail="User not found")
try:
new_collection = CollectionsDB(
collection_name=collection.collection_name,
collection_description=collection.collection_description,
visibility=collection.visibility
)
new_collection.users.append(user)
session.add(new_collection)
session.commit()
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error creating collection: {e}")
return True
def get_collections(
user_id : int | None = None
) -> list[CollectionPublic] | None:
"""
Kullanıcının collectionlarını döndürür
"""
if user_id is None:
raise HTTPException(status_code=400, detail="User id is None")
session = next(get_session_db()) # -> get_session_db() fonksiyonu daima generator döndürür next ile çağırmalısın
collections = session.query(CollectionsDB).filter(CollectionsDB.users.any(user_id=user_id)).all()
if collections is None:
raise HTTPException(status_code=404, detail="No collections found")
return collections
def update_collection(
collection: CollectionUpdate | None = None,
user_id : int | None = None,
collection_id : int | None = None
) -> bool:
"""
Collection güncelleme fonksiyonu
"""
if collection is None:
raise HTTPException(status_code=400, detail="Collection is None returned")
session = next(get_session_db()) # -> get_session_db() fonksiyonu daima generator döndürür next ile çağırmalısın
user = session.query(DBUser).filter(DBUser.user_id == user_id).first()
if user is None:
raise HTTPException(status_code=404, detail="User not found")
collection_to_update = session.query(CollectionsDB).filter(CollectionsDB.collection_id == collection_id).first()
if collection_to_update is None:
raise HTTPException(status_code=404, detail="Collection not found")
try:
collection_to_update.collection_name = collection.collection_name
collection_to_update.collection_description = collection.collection_description
collection_to_update.visibility = collection.visibility
session.commit()
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error updating collection: {e}")
return True
def delete_collection(
user_id : int | None = None,
collection_id : int | None = None
) -> bool:
"""
Collection silme fonksiyonu
"""
if user_id is None or collection_id is None:
raise HTTPException(status_code=400, detail="User id or collection id is None")
session = next(get_session_db()) # -> get_session_db() fonksiyonu daima generator döndürür next ile çağırmalısın
user = session.query(DBUser).filter(DBUser.user_id == user_id).first()
if user is None:
raise HTTPException(status_code=404, detail="User not found")
collection_to_delete = session.query(CollectionsDB).filter(CollectionsDB.collection_id == collection_id).first()
if collection_to_delete is None:
raise HTTPException(status_code=404, detail="Collection not found")
try:
session.delete(collection_to_delete)
session.commit()
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error deleting collection: {e}")
return True

View file

@ -1,60 +0,0 @@
from fastapi import FastAPI, APIRouter
from .models import CollectionPublic, CollectionCreate, CollectionUpdate
from .models import get_collections, create_colletion, update_collection, delete_collection
router = APIRouter(
prefix="/collections",
tags=["collections"],
responses={404: {"description": "Not found"}},
dependencies=[],
)
@router.get("/{user_id}")
async def get_collections_api(user_id: int) -> list[CollectionPublic]:
"""
Kullanıcının collectionlarını döndürür
"""
_collections : list[CollectionPublic] = get_collections(user_id=user_id)
return _collections
@router.post("/{user_id}")
async def create_collection(
user_id: int,
collection: CollectionCreate
) -> bool:
"""
Collection oluşturma fonksiyonu
"""
_result = create_colletion(user_id=user_id, collection=collection)
return _result
@router.put("/{user_id}/{collection_id}")
async def update_collection_api(
user_id: int,
collection_id : int,
collection: CollectionUpdate
) -> bool:
"""
Collection güncelleme fonksiyonu
"""
_result = update_collection(user_id=user_id, collection_id=collection_id, collection=collection)
return _result
@router.delete("/{user_id}/{collection_id}")
async def delete_collection_api(
user_id: int,
collection_id : int
) -> bool:
"""
Collection silme fonksiyonu
"""
_result = delete_collection(user_id=user_id, collection_id=collection_id)
return _result

View file

@ -2,7 +2,6 @@ from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, DeclarativeBase
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy import Table, Column, Integer, String, Float, Boolean, ForeignKey
from passlib.context import CryptContext
from dotenv import load_dotenv
import os
@ -31,31 +30,16 @@ class Base(DeclarativeBase):
def init_db():
#Base.metadata.drop_all(engine) # Veritabanını her başlangıcta siler burayada dikkat !!!!!!!!
Base.metadata.create_all(bind=engine) # Veritabanını oluşturur
Base.metadata.create_all(bind=engine)
# Session dependency (FastAPI için)
def get_session_db() -> 'Generator[Session, None]':
def get_session_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
user_collection = Table( # user -> collection
"user_collection",
Base.metadata,
Column("user_id", Integer, ForeignKey("users_table.user_id"), primary_key=True),
Column("collection_id", Integer, ForeignKey("collections_table.collection_id"), primary_key=True),
)
collection_item = Table( # collection -> item
"collection_item",
Base.metadata,
Column("collection_id", ForeignKey("collections_table.collection_id"), primary_key=True),
Column("item_id", ForeignKey("items_table.item_id"), primary_key=True)
)
### SECRET KEY ###

View file

@ -1,15 +1,18 @@
from datetime import datetime, timedelta, timezone
from typing import Annotated
from sqlalchemy import DateTime
from pydantic import BaseModel
from fastapi import Depends
from sqlalchemy.orm import Session, relationship, mapped_column, Mapped
from sqlalchemy import String, Float, Integer, ForeignKey
from sqlalchemy import ForeignKey, Column, Integer, String, Float
from sqlalchemy.dialects.postgresql import ARRAY
from ..config import Base, get_session_db, collection_item
from ..config import Base, get_session_db
from typing import TYPE_CHECKING
from ..auth.models import Role, Status, UserBase
from ..collectionObj.models import CollectionsDB
####!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
from ..auth.models import DBUser # -> tam burda bir hata var circle import yaparken karışıyor nasıl çözülecek bilmiyorum
class UserProfileBase(UserBase):
@ -25,11 +28,10 @@ class UserProfilePublic(UserProfileBase):
pass
class UserProfilePrivate(UserProfilePublic):
#collection : list[str] | None = None
collection : list[str] | None = None
role : Role | None = None
status : Status | None = None
follow_user : list[int] | None = None
items : list['Item'] | None = None
@ -44,35 +46,66 @@ class BaseItem(BaseModel):
class ItemCreate(BaseItem): # item oluşturma için ekstra bir ihtiyaci olmaz
pass
class Item(BaseItem):
item_id : int | None = None
user_id : int | None = None
item_score : float | None = None
class Config:
from_attributes = True #sqlalchemy ile pydantic arasında geçiş yapabilmek için kullanılır
##### VERİTABANI MODELİ #####
# Tüm modeller AUTH'da veri tabanına işlendi yukardaki
#modeller veri tabanında mevcuttur. Değiştirmek için AUTH'daki
# DBUser modelini değiştirip tekrar veri tabanına işleyebilirsin
'''
'''
class Items(Base):
__tablename__ = "items_table"
item_id : Mapped[int] = mapped_column(primary_key=True, index=True, autoincrement=True)
#collection_id : Mapped[list[int]] = mapped_column(Integer, ForeignKey("collections_table.collection_id"), nullable=True) # collection_id ile ilişki
user_id : Mapped[int] = mapped_column(ForeignKey('users_table.user_id'), nullable=False, index=True)
item_created_date : Mapped[datetime] = mapped_column(DateTime, default=datetime.now())
item_location: Mapped[str] = mapped_column(String, default="No location")
item_type: Mapped[str] = mapped_column(String, default="No type")
item_content: Mapped[str] = mapped_column(String, default="No content")
item_score: Mapped[float] = mapped_column(Float, default=0.0)
item_location = Column(String, default="No location")
item_type = Column(String, default="No type")
item_content = Column(String, default="No content")
item_score = Column(Float, default=0.0)
# ilişkiler
collections : Mapped[list['CollectionsDB']]= relationship(
"CollectionsDB",
secondary=collection_item,
back_populates="items",
lazy='select'
) #back_populates karşı tarafın ismi
# ilişkiler
user : Mapped['DBUser'] = relationship("DBUser", back_populates="items", lazy='select')
#collection = relationship("Collections", back_populates="items")
'''
'''
def is_user_exsist(username : str, session : Annotated[Session, Depends(get_session_db)]) -> bool | UserProfilePublic:
#DBUser veritabanındaki nesnedir her niteliğe sahiptir
user = session.query(DBUser).filter(DBUser.username == username).first()
return user
def all_users(session: Annotated[Session, Depends(get_session_db)]) -> list[UserProfilePublic]:
users = session.query(DBUser).all()
return [UserProfilePublic(
username=user.username,
bio=user.bio,
created_date=user.created_date,
items=user.items,
collections=user.collections,
role=user.role,
status=user.status
) for user in users]
def add_Item_user(
user: Annotated[UserProfileID, Depends(get_session_db)],
session: Annotated[Session, Depends(get_session_db)],
item: ItemCreate) -> bool:
# DBUser veritabanındaki nesnedir her niteliğe sahiptir
item = Items(
user_id=user.user_id,
item_location=item.item_location,
item_type=item.item_type,
item_content=item.item_content,
item_score=item.item_score,
item_created_date=item.item_created_date
)
session.add(item)
session.commit()
return True

View file

@ -1,4 +1,4 @@
from .models import ItemCreate, UserProfileBase, UserProfileID, UserProfilePrivate, UserProfilePublic
from .models import ItemCreate, UserProfileBase, UserProfileID, UserProfilePrivate, UserProfilePublic, add_Item_user, all_users, is_user_exsist
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from ..config import get_session_db
@ -12,7 +12,43 @@ router = APIRouter(
dependencies=[],
)
#tüm crud işlemleri yeni veri tabanı modeli ile yapılacak
@router.get('/all_profiles')
async def get_user_profile(session: Annotated[Session, Depends(get_session_db)]) -> list[UserProfilePublic]:
return all_users(session=session)
@router.get('/profile/{username}')
async def get_user_profile_by_username(
username: str,
session: Annotated[Session, Depends(get_session_db)],
) -> UserProfilePublic | dict:
user : UserProfilePublic = is_user_exsist(username, session)
if user is None:
return {"error": "User not found"}
return user
@router.get('/profile/me')
async def get_user_profile_me(
current_user: Annotated[UserProfilePrivate, Depends(get_current_active_user)] #dependtek kaynaklı UserPublic doner
) -> UserProfilePrivate:
return current_user
@router.post('/create')
async def create_user_profile(
user : Annotated[UserProfileID, Depends(get_current_active_user)],
session: Annotated[Session, Depends(get_session_db)],
item : Annotated[ItemCreate , None] = None
) -> dict:
if add_Item_user(user, session, item) :
return {"message": "User item created successfully"}
return {"error": "User item creation failed"}

View file

@ -1,7 +1,7 @@
from .config import app
from .auth.router import router as auth_router
from .items.router import router as items_router
from .collectionObj.router import router as collections_router
from ._collections.router import router as collections_router
app.include_router(auth_router)
app.include_router(collections_router)