starting scraper development
This commit is contained in:
@ -5,16 +5,32 @@ from psycopg2._psycopg import connection
|
|||||||
|
|
||||||
import db.accounts as db
|
import db.accounts as db
|
||||||
import settings.settings as settings
|
import settings.settings as settings
|
||||||
from api.utils import encrypt_str, get_current_user
|
from api.models import Account, User
|
||||||
from api.models import User, Account
|
from api.utils import encode_str, get_current_user
|
||||||
|
from db.groups import check_group_author
|
||||||
from db.internal import get_db_connection
|
from db.internal import get_db_connection
|
||||||
|
|
||||||
accounts_router = APIRouter(prefix="/api/accounts", tags=["anon"])
|
accounts_router = APIRouter(prefix="/api/accounts", tags=["accounts"])
|
||||||
|
|
||||||
|
|
||||||
@accounts_router.post("/account")
|
@accounts_router.post("/group")
|
||||||
async def get_account(
|
async def read_accounts_by_group(
|
||||||
account_id: int,
|
groupname: str,
|
||||||
|
conn: Annotated[connection, Depends(get_db_connection)],
|
||||||
|
current_user: Annotated[User, Depends(get_current_user)]
|
||||||
|
):
|
||||||
|
if not check_group_author(conn, groupname, current_user.username) and current_user.role not in settings.settings.admin_roles:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
detail="Not allowed",
|
||||||
|
)
|
||||||
|
return db.get_accounts_by_group(conn, groupname)
|
||||||
|
|
||||||
|
|
||||||
|
@accounts_router.post("/group/platform")
|
||||||
|
async def read_accounts_by_group_platform(
|
||||||
|
groupname: str,
|
||||||
|
platform: str,
|
||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
conn: Annotated[connection, Depends(get_db_connection)],
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
current_user: Annotated[User, Depends(get_current_user)]
|
||||||
):
|
):
|
||||||
@ -23,7 +39,7 @@ async def get_account(
|
|||||||
status_code=status.HTTP_403_FORBIDDEN,
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
detail="Not allowed",
|
detail="Not allowed",
|
||||||
)
|
)
|
||||||
account_data = db.get_account(conn, account_id)
|
account_data = db.get_accounts_by_group_platform(conn, groupname, platform)
|
||||||
if account_data is None:
|
if account_data is None:
|
||||||
return HTTPException(
|
return HTTPException(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
@ -36,6 +52,7 @@ async def get_account(
|
|||||||
|
|
||||||
@accounts_router.post("/add")
|
@accounts_router.post("/add")
|
||||||
async def add_account(
|
async def add_account(
|
||||||
|
groupname: str,
|
||||||
platform: str,
|
platform: str,
|
||||||
login: str,
|
login: str,
|
||||||
password: str,
|
password: str,
|
||||||
@ -43,28 +60,43 @@ async def add_account(
|
|||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
conn: Annotated[connection, Depends(get_db_connection)],
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
current_user: Annotated[User, Depends(get_current_user)]
|
||||||
):
|
):
|
||||||
if db.check_account_existence(conn, platform, login, password):
|
if not check_group_author(conn, groupname, current_user.username) and current_user.role not in settings.settings.admin_roles:
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_409_CONFLICT,
|
|
||||||
detail="Account already exists",
|
|
||||||
)
|
|
||||||
hashed_password = encrypt_str(password)
|
|
||||||
return db.create_account(conn, login, hashed_password, metadata)
|
|
||||||
|
|
||||||
# TODO: add author to check editing rights?
|
|
||||||
@accounts_router.post("/update")
|
|
||||||
async def update_account(
|
|
||||||
account_id: int,
|
|
||||||
platform: str,
|
|
||||||
login: str,
|
|
||||||
password: str,
|
|
||||||
metadata: dict,
|
|
||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
|
||||||
):
|
|
||||||
if current_user.role not in settings.settings.admin_roles:
|
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
detail="Not allowed",
|
detail="Not allowed",
|
||||||
)
|
)
|
||||||
return db.update_account(conn, account_id, platform, login, password, metadata)
|
if db.check_account_existence(conn, groupname, platform):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
|
detail="Account already exists",
|
||||||
|
)
|
||||||
|
hashed_password = encode_str(password)
|
||||||
|
return db.create_account(conn, platform, login, hashed_password, metadata)
|
||||||
|
|
||||||
|
|
||||||
|
@accounts_router.post("/update")
|
||||||
|
async def update_account(
|
||||||
|
groupname: str,
|
||||||
|
platform: str,
|
||||||
|
author: str,
|
||||||
|
login: str,
|
||||||
|
password: str,
|
||||||
|
metadata: dict,
|
||||||
|
conn: Annotated[connection, Depends(get_db_connection)],
|
||||||
|
current_user: Annotated[User, Depends(get_current_user)]
|
||||||
|
):
|
||||||
|
account_data = db.get_accounts_by_group_platform(conn, groupname, platform)
|
||||||
|
if account_data is None:
|
||||||
|
return HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="No such account",
|
||||||
|
)
|
||||||
|
account = Account()
|
||||||
|
account.fill(account_data)
|
||||||
|
|
||||||
|
if current_user.username != account.author and current_user.role not in settings.settings.admin_roles:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
detail="Not allowed",
|
||||||
|
)
|
||||||
|
return db.update_account(conn, groupname, author, platform, login, password, metadata)
|
||||||
|
|||||||
@ -5,12 +5,14 @@ from psycopg2._psycopg import connection
|
|||||||
|
|
||||||
import db.feeds as db
|
import db.feeds as db
|
||||||
import settings.settings as settings
|
import settings.settings as settings
|
||||||
from api.models import Feed, Group, User
|
from api.models import Feed, User
|
||||||
from api.utils import get_current_user
|
from api.utils import get_current_user
|
||||||
|
from db.accounts import get_accounts_by_group
|
||||||
from db.feeds import get_groupname_by_feed_id
|
from db.feeds import get_groupname_by_feed_id
|
||||||
from db.groups import get_group
|
from db.groups import check_group_author
|
||||||
from db.internal import get_db_connection
|
from db.internal import get_db_connection
|
||||||
from db.memberships import check_membership_exists
|
from db.memberships import check_membership_exists
|
||||||
|
from scraper.utils import generate_feed
|
||||||
|
|
||||||
feeds_router = APIRouter(prefix="/api/feeds", tags=["feeds"])
|
feeds_router = APIRouter(prefix="/api/feeds", tags=["feeds"])
|
||||||
|
|
||||||
@ -46,29 +48,28 @@ async def read_feed(
|
|||||||
return feed
|
return feed
|
||||||
|
|
||||||
|
|
||||||
# maybe to delete
|
# TODO: most logic + exception
|
||||||
@feeds_router.post("/add")
|
@feeds_router.post("/new")
|
||||||
async def add_feed(
|
async def new_feed(
|
||||||
groupname: str,
|
groupname: str,
|
||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
conn: Annotated[connection, Depends(get_db_connection)],
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
current_user: Annotated[User, Depends(get_current_user)]
|
||||||
):
|
):
|
||||||
group = Group()
|
if not check_group_author(conn, groupname, current_user.username) and current_user.role not in settings.settings.admin_roles:
|
||||||
group_data = get_group(conn, groupname)
|
|
||||||
if group_data is None:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
|
||||||
detail="No such feed or feed is not linked to group",
|
|
||||||
)
|
|
||||||
group.fill(group_data)
|
|
||||||
|
|
||||||
if group.author != current_user.username and current_user.role not in settings.settings.admin_roles:
|
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
detail="Not allowed",
|
detail="Not allowed",
|
||||||
)
|
)
|
||||||
|
|
||||||
return db.create_feed(conn, groupname, []) # TODO: image list
|
accounts = get_accounts_by_group(conn, groupname)
|
||||||
|
feed = generate_feed(conn, accounts)
|
||||||
|
if not isinstance(feed, Exception):
|
||||||
|
return db.create_feed(conn, groupname, feed)
|
||||||
|
else:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_418_IM_A_TEAPOT,
|
||||||
|
detail="Failed to generate feed",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# maybe to delete
|
# maybe to delete
|
||||||
@ -85,27 +86,3 @@ async def delete_feed(
|
|||||||
status_code=status.HTTP_403_FORBIDDEN,
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
detail="Not allowed",
|
detail="Not allowed",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@feeds_router.post("/reset")
|
|
||||||
async def reset_feed(
|
|
||||||
groupname: str,
|
|
||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
|
||||||
):
|
|
||||||
group = Group()
|
|
||||||
group_data = get_group(conn, groupname)
|
|
||||||
if group_data is None:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
|
||||||
detail="No such group",
|
|
||||||
)
|
|
||||||
group.fill(group_data)
|
|
||||||
|
|
||||||
if group.author != current_user.username and current_user.role not in settings.settings.admin_roles:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail="Not allowed",
|
|
||||||
)
|
|
||||||
|
|
||||||
return db.create_feed(conn, groupname, []) # TODO: image list
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import db.groups as db
|
|||||||
import settings.settings as settings
|
import settings.settings as settings
|
||||||
import settings.startup_settings as startup_settings
|
import settings.startup_settings as startup_settings
|
||||||
from api.models import Group, User
|
from api.models import Group, User
|
||||||
from api.utils import get_current_user, get_group_by_name
|
from api.utils import get_current_user
|
||||||
from db.internal import get_db_connection
|
from db.internal import get_db_connection
|
||||||
from db.memberships import check_membership_exists
|
from db.memberships import check_membership_exists
|
||||||
from settings.consts import JOIN_CODE_SYMBOLS
|
from settings.consts import JOIN_CODE_SYMBOLS
|
||||||
@ -104,10 +104,9 @@ async def delete_group(
|
|||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
conn: Annotated[connection, Depends(get_db_connection)],
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
current_user: Annotated[User, Depends(get_current_user)]
|
||||||
):
|
):
|
||||||
group = get_group_by_name(conn, groupname)
|
|
||||||
if current_user.role in settings.settings.admin_roles:
|
if current_user.role in settings.settings.admin_roles:
|
||||||
return db.delete_group(conn, groupname)
|
return db.delete_group(conn, groupname)
|
||||||
if current_user.username == group.author:
|
if db.check_group_author(conn, groupname, current_user.username):
|
||||||
return db.delete_group(conn, groupname)
|
return db.delete_group(conn, groupname)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
@ -128,11 +127,10 @@ async def update_groupname(
|
|||||||
status_code=status.HTTP_409_CONFLICT,
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
detail="Groupname is already taken",
|
detail="Groupname is already taken",
|
||||||
)
|
)
|
||||||
group = get_group_by_name(conn, groupname)
|
|
||||||
|
|
||||||
if current_user.role in settings.settings.admin_roles:
|
if current_user.role in settings.settings.admin_roles:
|
||||||
return db.update_group_groupname(conn, groupname, new_groupname)
|
return db.update_group_groupname(conn, groupname, new_groupname)
|
||||||
if current_user.username == group.author:
|
if db.check_group_author(conn, groupname, current_user.username):
|
||||||
return db.update_group_groupname(conn, groupname, new_groupname)
|
return db.update_group_groupname(conn, groupname, new_groupname)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
@ -147,10 +145,9 @@ async def update_author(
|
|||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
conn: Annotated[connection, Depends(get_db_connection)],
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
current_user: Annotated[User, Depends(get_current_user)]
|
||||||
):
|
):
|
||||||
group = get_group_by_name(conn, groupname)
|
|
||||||
if current_user.role in settings.settings.admin_roles:
|
if current_user.role in settings.settings.admin_roles:
|
||||||
return db.update_group_author(conn, groupname, new_author)
|
return db.update_group_author(conn, groupname, new_author)
|
||||||
if current_user.username == group.author:
|
if db.check_group_author(conn, groupname, current_user.username):
|
||||||
return db.update_group_author(conn, groupname, new_author)
|
return db.update_group_author(conn, groupname, new_author)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
@ -164,8 +161,6 @@ async def update_invite_code(
|
|||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
conn: Annotated[connection, Depends(get_db_connection)],
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
current_user: Annotated[User, Depends(get_current_user)]
|
||||||
):
|
):
|
||||||
group = get_group_by_name(conn, groupname)
|
|
||||||
|
|
||||||
invite_code = "".join(secrets.choice(JOIN_CODE_SYMBOLS) for _ in range(startup_settings.join_code_length))
|
invite_code = "".join(secrets.choice(JOIN_CODE_SYMBOLS) for _ in range(startup_settings.join_code_length))
|
||||||
while db.check_invite_code(conn, invite_code):
|
while db.check_invite_code(conn, invite_code):
|
||||||
invite_code = "".join(secrets.choice(JOIN_CODE_SYMBOLS) for _ in range(startup_settings.join_code_length))
|
invite_code = "".join(secrets.choice(JOIN_CODE_SYMBOLS) for _ in range(startup_settings.join_code_length))
|
||||||
@ -175,7 +170,7 @@ async def update_invite_code(
|
|||||||
"result": db.update_group_invite_code(conn, groupname, invite_code),
|
"result": db.update_group_invite_code(conn, groupname, invite_code),
|
||||||
"invite code": invite_code
|
"invite code": invite_code
|
||||||
}
|
}
|
||||||
if current_user.username == group.author:
|
if db.check_group_author(conn, groupname, current_user.username):
|
||||||
return {
|
return {
|
||||||
"result": db.update_group_invite_code(conn, groupname, invite_code),
|
"result": db.update_group_invite_code(conn, groupname, invite_code),
|
||||||
"invite code": invite_code
|
"invite code": invite_code
|
||||||
@ -194,10 +189,9 @@ async def update_allow_skips(
|
|||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
conn: Annotated[connection, Depends(get_db_connection)],
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
current_user: Annotated[User, Depends(get_current_user)]
|
||||||
):
|
):
|
||||||
group = get_group_by_name(conn, groupname)
|
|
||||||
if current_user.role in settings.settings.admin_roles:
|
if current_user.role in settings.settings.admin_roles:
|
||||||
return db.update_group_allow_skips(conn, groupname, allow_skips)
|
return db.update_group_allow_skips(conn, groupname, allow_skips)
|
||||||
if current_user.username == group.author:
|
if db.check_group_author(conn, groupname, current_user.username):
|
||||||
return db.update_group_allow_skips(conn, groupname, allow_skips)
|
return db.update_group_allow_skips(conn, groupname, allow_skips)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
@ -213,10 +207,9 @@ async def update_feed_interval(
|
|||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
conn: Annotated[connection, Depends(get_db_connection)],
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
current_user: Annotated[User, Depends(get_current_user)]
|
||||||
):
|
):
|
||||||
group = get_group_by_name(conn, groupname)
|
|
||||||
if current_user.role in settings.settings.admin_roles:
|
if current_user.role in settings.settings.admin_roles:
|
||||||
return db.update_group_feed_interval(conn, groupname, feed_interval)
|
return db.update_group_feed_interval(conn, groupname, feed_interval)
|
||||||
if current_user.username == group.author:
|
if db.check_group_author(conn, groupname, current_user.username):
|
||||||
return db.update_group_feed_interval(conn, groupname, feed_interval)
|
return db.update_group_feed_interval(conn, groupname, feed_interval)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|||||||
@ -6,8 +6,12 @@ from psycopg2._psycopg import connection
|
|||||||
import db.memberships as db
|
import db.memberships as db
|
||||||
import settings.settings as settings
|
import settings.settings as settings
|
||||||
from api.models import User
|
from api.models import User
|
||||||
from api.utils import get_current_user, get_group_by_name
|
from api.utils import get_current_user
|
||||||
from db.groups import check_group_existence, get_groupname_by_invite_code
|
from db.groups import (
|
||||||
|
check_group_author,
|
||||||
|
check_group_existence,
|
||||||
|
get_groupname_by_invite_code,
|
||||||
|
)
|
||||||
from db.internal import get_db_connection
|
from db.internal import get_db_connection
|
||||||
from db.users import check_user_existence
|
from db.users import check_user_existence
|
||||||
|
|
||||||
@ -107,8 +111,7 @@ async def delete_membership(
|
|||||||
if current_user.role in settings.settings.admin_roles:
|
if current_user.role in settings.settings.admin_roles:
|
||||||
return db.delete_membership(conn, username, groupname)
|
return db.delete_membership(conn, username, groupname)
|
||||||
|
|
||||||
group = get_group_by_name(conn, groupname)
|
if check_group_author(conn, groupname, current_user.username):
|
||||||
if current_user.username == group.author:
|
|
||||||
return db.delete_membership(conn, username, groupname)
|
return db.delete_membership(conn, username, groupname)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from api.utils import decrypt_str
|
|
||||||
|
from api.utils import decode_str
|
||||||
|
|
||||||
|
|
||||||
class Token(BaseModel):
|
class Token(BaseModel):
|
||||||
@ -102,12 +103,14 @@ class Feed(BaseModel):
|
|||||||
class Account(BaseModel):
|
class Account(BaseModel):
|
||||||
def fill(self, params):
|
def fill(self, params):
|
||||||
self.id = params["id"]
|
self.id = params["id"]
|
||||||
|
self.author = params["author"]
|
||||||
self.platform = params["platform"]
|
self.platform = params["platform"]
|
||||||
self.login = params["login"]
|
self.login = params["login"]
|
||||||
self.password = decrypt_str(params["password"])
|
self.password = decode_str(params["password"])
|
||||||
self.metadata = params["metadata"]
|
self.metadata = params["metadata"]
|
||||||
self.created_at = params["created_at"]
|
self.created_at = params["created_at"]
|
||||||
id: int = -1
|
id: int = -1
|
||||||
|
author: str = ""
|
||||||
platform: str = ""
|
platform: str = ""
|
||||||
login: str = ""
|
login: str = ""
|
||||||
password: str = ""
|
password: str = ""
|
||||||
|
|||||||
@ -12,32 +12,14 @@ from db.internal import get_db_connection
|
|||||||
pictures_router = APIRouter(prefix="/api/pictures", tags=["pictures"])
|
pictures_router = APIRouter(prefix="/api/pictures", tags=["pictures"])
|
||||||
|
|
||||||
|
|
||||||
# maybe to delete
|
@pictures_router.post("/picture")
|
||||||
@pictures_router.post("/picture/url")
|
async def read_picture(
|
||||||
async def read_picture_by_url(
|
id: int,
|
||||||
groupname: str,
|
|
||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
conn: Annotated[connection, Depends(get_db_connection)],
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
current_user: Annotated[User, Depends(get_current_user)]
|
||||||
):
|
):
|
||||||
picture = Picture()
|
picture = Picture()
|
||||||
picture_data = db.get_picture_by_url(conn, groupname)
|
picture_data = db.get_picture(conn, id)
|
||||||
if picture_data is None:
|
|
||||||
return HTTPException(
|
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
|
||||||
detail="No such picture",
|
|
||||||
)
|
|
||||||
picture.fill(picture_data)
|
|
||||||
return picture
|
|
||||||
|
|
||||||
|
|
||||||
@pictures_router.post("/picture/id")
|
|
||||||
async def read_picture_by_id(
|
|
||||||
groupname: str,
|
|
||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
|
||||||
):
|
|
||||||
picture = Picture()
|
|
||||||
picture_data = db.get_picture_by_id(conn, groupname)
|
|
||||||
if picture_data is None:
|
if picture_data is None:
|
||||||
return HTTPException(
|
return HTTPException(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
@ -67,29 +49,14 @@ async def add_picture(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# maybe to delete
|
@pictures_router.post("/delete")
|
||||||
@pictures_router.post("/delete/url")
|
async def delete_picture(
|
||||||
async def delete_picture_by_url(
|
|
||||||
picture_url: str,
|
|
||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
|
||||||
):
|
|
||||||
if current_user.role in settings.settings.admin_roles:
|
|
||||||
return db.delete_picture_by_url(conn, picture_url)
|
|
||||||
else:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail="Not allowed",
|
|
||||||
)
|
|
||||||
|
|
||||||
@pictures_router.post("/delete/id")
|
|
||||||
async def delete_picture_by_id(
|
|
||||||
picture_id: int,
|
picture_id: int,
|
||||||
conn: Annotated[connection, Depends(get_db_connection)],
|
conn: Annotated[connection, Depends(get_db_connection)],
|
||||||
current_user: Annotated[User, Depends(get_current_user)]
|
current_user: Annotated[User, Depends(get_current_user)]
|
||||||
):
|
):
|
||||||
if current_user.role in settings.settings.admin_roles:
|
if current_user.role in settings.settings.admin_roles:
|
||||||
return db.delete_picture_by_id(conn, picture_id)
|
return db.delete_picture(conn, picture_id)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
|||||||
@ -3,8 +3,6 @@ from typing import Annotated
|
|||||||
|
|
||||||
import bcrypt
|
import bcrypt
|
||||||
import jwt
|
import jwt
|
||||||
from Crypto.Cipher import AES
|
|
||||||
from Crypto.Util.Padding import pad, unpad
|
|
||||||
from fastapi import Depends, HTTPException, status
|
from fastapi import Depends, HTTPException, status
|
||||||
from fastapi.security import OAuth2PasswordBearer
|
from fastapi.security import OAuth2PasswordBearer
|
||||||
from jwt.exceptions import InvalidTokenError
|
from jwt.exceptions import InvalidTokenError
|
||||||
@ -19,17 +17,25 @@ from db.internal import get_db_connection
|
|||||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||||
|
|
||||||
|
|
||||||
def encrypt_str(string):
|
def encode_str(string) -> str:
|
||||||
key = bytes.fromhex(startup_settings.secret_key)
|
key = startup_settings.secret_key
|
||||||
cipher = AES.new(key, AES.MODE_ECB)
|
encoded_chars = []
|
||||||
encrypted_string = cipher.encrypt(pad(string.encode(), AES.block_size))
|
for i in range(len(string)):
|
||||||
return encrypted_string
|
key_c = key[i % len(key)]
|
||||||
|
encoded_c = chr(ord(string[i]) + ord(key_c) % 256)
|
||||||
|
encoded_chars.append(encoded_c)
|
||||||
|
encoded_string = ''.join(encoded_chars)
|
||||||
|
return encoded_string
|
||||||
|
|
||||||
def decrypt_str(encrypted_string):
|
def decode_str(encoded_string) -> str:
|
||||||
key = bytes.fromhex(startup_settings.secret_key)
|
key = startup_settings.secret_key
|
||||||
cipher = AES.new(key, AES.MODE_ECB)
|
encoded_chars = []
|
||||||
string = unpad(cipher.decrypt(encrypted_string), AES.block_size)
|
for i in range(len(encoded_string)):
|
||||||
return string.decode()
|
key_c = key[i % len(key)]
|
||||||
|
encoded_c = chr((ord(encoded_string[i]) - ord(key_c) + 256) % 256)
|
||||||
|
encoded_chars.append(encoded_c)
|
||||||
|
decoded_string = ''.join(encoded_chars)
|
||||||
|
return decoded_string
|
||||||
|
|
||||||
|
|
||||||
def verify_password(plain_password: str, hashed_password: str):
|
def verify_password(plain_password: str, hashed_password: str):
|
||||||
|
|||||||
@ -3,13 +3,15 @@ import json
|
|||||||
import psycopg2.extras
|
import psycopg2.extras
|
||||||
from psycopg2._psycopg import connection
|
from psycopg2._psycopg import connection
|
||||||
|
|
||||||
|
from api.models import Account
|
||||||
|
|
||||||
# account create and delete
|
# account create and delete
|
||||||
|
|
||||||
def create_account(
|
def create_account(
|
||||||
conn: connection,
|
conn: connection,
|
||||||
platform: str,
|
platform: str,
|
||||||
login: str,
|
login: str,
|
||||||
password: int,
|
password: str,
|
||||||
metadata: dict
|
metadata: dict
|
||||||
):
|
):
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
@ -44,28 +46,10 @@ def delete_account(
|
|||||||
|
|
||||||
# account checks
|
# account checks
|
||||||
|
|
||||||
def check_account_existence_by_id(
|
|
||||||
conn: connection,
|
|
||||||
account_id: str
|
|
||||||
):
|
|
||||||
with conn.cursor() as cur:
|
|
||||||
cur.execute(
|
|
||||||
"""
|
|
||||||
select exists(
|
|
||||||
select 1
|
|
||||||
from picrinth.accounts
|
|
||||||
where account_id = %s
|
|
||||||
);
|
|
||||||
""",
|
|
||||||
(account_id),
|
|
||||||
)
|
|
||||||
return cur.fetchone()[0] # type: ignore
|
|
||||||
|
|
||||||
def check_account_existence(
|
def check_account_existence(
|
||||||
conn: connection,
|
conn: connection,
|
||||||
platform: str,
|
groupname: str,
|
||||||
login: str,
|
platform: str
|
||||||
password: str
|
|
||||||
):
|
):
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
@ -73,10 +57,10 @@ def check_account_existence(
|
|||||||
select exists(
|
select exists(
|
||||||
select 1
|
select 1
|
||||||
from picrinth.accounts
|
from picrinth.accounts
|
||||||
where platform = %s, login = %s, password = %s
|
where groupname = %s and platform = %s
|
||||||
);
|
);
|
||||||
""",
|
""",
|
||||||
(platform, login, password),
|
(groupname, platform),
|
||||||
)
|
)
|
||||||
return cur.fetchone()[0] # type: ignore
|
return cur.fetchone()[0] # type: ignore
|
||||||
|
|
||||||
@ -85,10 +69,11 @@ def check_account_existence(
|
|||||||
|
|
||||||
def update_account(
|
def update_account(
|
||||||
conn: connection,
|
conn: connection,
|
||||||
account_id: str,
|
groupname: str,
|
||||||
|
author: str,
|
||||||
platform: str,
|
platform: str,
|
||||||
login: str,
|
login: str,
|
||||||
password: int,
|
password: str,
|
||||||
metadata: dict
|
metadata: dict
|
||||||
):
|
):
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
@ -96,12 +81,13 @@ def update_account(
|
|||||||
"""
|
"""
|
||||||
update picrinth.accounts
|
update picrinth.accounts
|
||||||
SET platform = %s,
|
SET platform = %s,
|
||||||
|
author = %s,
|
||||||
login = %s,
|
login = %s,
|
||||||
password = %s,
|
password = %s,
|
||||||
metadata = %s
|
metadata = %s
|
||||||
where account_id = %s
|
where groupname = %s
|
||||||
""",
|
""",
|
||||||
(platform, login, password, json.dumps(metadata), account_id),
|
(platform, author, login, password, json.dumps(metadata), groupname),
|
||||||
)
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
return cur.rowcount > 0
|
return cur.rowcount > 0
|
||||||
@ -109,19 +95,37 @@ def update_account(
|
|||||||
|
|
||||||
# account receiving
|
# account receiving
|
||||||
|
|
||||||
def get_account(
|
# TODO: fix list comprehension
|
||||||
|
def get_accounts_by_group(
|
||||||
conn: connection,
|
conn: connection,
|
||||||
account_id: str
|
groupname: str
|
||||||
|
) -> list[Account]:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
select *
|
||||||
|
from picrinth.accounts
|
||||||
|
where groupname = %s
|
||||||
|
""",
|
||||||
|
(groupname,),
|
||||||
|
)
|
||||||
|
return [Account().fill(account_data) for (account_data,) in cur.fetchall()]
|
||||||
|
|
||||||
|
|
||||||
|
def get_accounts_by_group_platform(
|
||||||
|
conn: connection,
|
||||||
|
groupname: str,
|
||||||
|
platform: str
|
||||||
):
|
):
|
||||||
with conn.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
|
with conn.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
select username,
|
select groupname, author,
|
||||||
account_id, platform, login,
|
platform, login, password,
|
||||||
password, metadata, created_at
|
metadata, created_at
|
||||||
from picrinth.accounts
|
from picrinth.accounts
|
||||||
where account_id = %s
|
where groupname = %s and platform = %s
|
||||||
""",
|
""",
|
||||||
(account_id),
|
(groupname, platform),
|
||||||
)
|
)
|
||||||
return cur.fetchone()
|
return cur.fetchone()
|
||||||
|
|||||||
@ -79,6 +79,25 @@ def check_invite_code(
|
|||||||
return cur.fetchone()[0] # type: ignore
|
return cur.fetchone()[0] # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
def check_group_author(
|
||||||
|
conn: connection,
|
||||||
|
groupname: str,
|
||||||
|
author: str
|
||||||
|
):
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
select exists(
|
||||||
|
select 1
|
||||||
|
from picrinth.groups
|
||||||
|
where groupname = %s and author = %s
|
||||||
|
);
|
||||||
|
""",
|
||||||
|
(groupname, author),
|
||||||
|
)
|
||||||
|
return cur.fetchone()[0] # type: ignore
|
||||||
|
|
||||||
|
|
||||||
# group updates
|
# group updates
|
||||||
|
|
||||||
def update_group_groupname(
|
def update_group_groupname(
|
||||||
|
|||||||
@ -29,22 +29,7 @@ def create_picture(
|
|||||||
return result[0]
|
return result[0]
|
||||||
|
|
||||||
|
|
||||||
def delete_picture_by_url(
|
def delete_picture(
|
||||||
conn: connection,
|
|
||||||
url: str
|
|
||||||
):
|
|
||||||
with conn.cursor() as cur:
|
|
||||||
cur.execute(
|
|
||||||
"""
|
|
||||||
delete from picrinth.pictures
|
|
||||||
where url = %s
|
|
||||||
""",
|
|
||||||
(url,),
|
|
||||||
)
|
|
||||||
conn.commit()
|
|
||||||
return cur.rowcount > 0
|
|
||||||
|
|
||||||
def delete_picture_by_id(
|
|
||||||
conn: connection,
|
conn: connection,
|
||||||
id: int
|
id: int
|
||||||
):
|
):
|
||||||
@ -62,26 +47,9 @@ def delete_picture_by_id(
|
|||||||
|
|
||||||
# picture receiving
|
# picture receiving
|
||||||
|
|
||||||
def get_picture_by_url(
|
def get_picture(
|
||||||
conn: connection,
|
conn: connection,
|
||||||
url: str
|
id: int
|
||||||
):
|
|
||||||
with conn.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
|
|
||||||
cur.execute(
|
|
||||||
"""
|
|
||||||
select id, source,
|
|
||||||
external_id, url,
|
|
||||||
metadata, created_at
|
|
||||||
from picrinth.pictures
|
|
||||||
where url = %s
|
|
||||||
""",
|
|
||||||
(url,),
|
|
||||||
)
|
|
||||||
return cur.fetchone()
|
|
||||||
|
|
||||||
def get_picture_by_id(
|
|
||||||
conn: connection,
|
|
||||||
id: str
|
|
||||||
):
|
):
|
||||||
with conn.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
|
with conn.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
|
|||||||
@ -11,7 +11,7 @@ from settings.consts import SUPPORTED_PLATFORMS
|
|||||||
def generate_feed(
|
def generate_feed(
|
||||||
conn: connection,
|
conn: connection,
|
||||||
accounts: list[Account]
|
accounts: list[Account]
|
||||||
):
|
) -> list | Exception:
|
||||||
for account in accounts:
|
for account in accounts:
|
||||||
if account.platform not in SUPPORTED_PLATFORMS:
|
if account.platform not in SUPPORTED_PLATFORMS:
|
||||||
raise Exception
|
raise Exception
|
||||||
@ -50,10 +50,10 @@ def gelbooru():
|
|||||||
|
|
||||||
def get_picture(
|
def get_picture(
|
||||||
conn: connection,
|
conn: connection,
|
||||||
picture_id: str
|
picture_id: int
|
||||||
) -> int:
|
) -> int:
|
||||||
picture = Picture()
|
picture = Picture()
|
||||||
picture_data = db.get_picture_by_id(conn, picture_id)
|
picture_data = db.get_picture(conn, picture_id)
|
||||||
if picture_id is None:
|
if picture_id is None:
|
||||||
return -1
|
return -1
|
||||||
picture.fill(picture_data)
|
picture.fill(picture_data)
|
||||||
|
|||||||
24
tables.sql
24
tables.sql
@ -37,7 +37,7 @@ create table picrinth.pictures (
|
|||||||
id serial not null,
|
id serial not null,
|
||||||
source text not null,
|
source text not null,
|
||||||
external_id text not null,
|
external_id text not null,
|
||||||
url text not null,
|
"url" text not null,
|
||||||
metadata jsonb null,
|
metadata jsonb null,
|
||||||
created_at timestamp with time zone default now(),
|
created_at timestamp with time zone default now(),
|
||||||
constraint pictures_pkey primary key (id),
|
constraint pictures_pkey primary key (id),
|
||||||
@ -59,7 +59,7 @@ create table picrinth.swipes (
|
|||||||
username text not null,
|
username text not null,
|
||||||
feed_id integer not null,
|
feed_id integer not null,
|
||||||
picture_id integer not null,
|
picture_id integer not null,
|
||||||
value smallint not null,
|
"value" smallint not null,
|
||||||
created_at timestamp with time zone default now(),
|
created_at timestamp with time zone default now(),
|
||||||
primary key (id),
|
primary key (id),
|
||||||
foreign key (username) references picrinth.users (username) on delete cascade on update cascade,
|
foreign key (username) references picrinth.users (username) on delete cascade on update cascade,
|
||||||
@ -68,23 +68,15 @@ create table picrinth.swipes (
|
|||||||
constraint swipes_unique unique (username, feed_id, picture_id)
|
constraint swipes_unique unique (username, feed_id, picture_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
-- TODO: add author?
|
|
||||||
create table picrinth.accounts (
|
create table picrinth.accounts (
|
||||||
id serial not null,
|
groupname text not null,
|
||||||
|
author text null,
|
||||||
platform text not null,
|
platform text not null,
|
||||||
login text not null,
|
"login" text not null,
|
||||||
password text not null,
|
"password" text not null,
|
||||||
metadata jsonb null,
|
metadata jsonb null,
|
||||||
created_at timestamp with time zone default now(),
|
created_at timestamp with time zone default now(),
|
||||||
primary key (id),
|
|
||||||
constraint unique_account_per_platform unique (platform, login)
|
|
||||||
);
|
|
||||||
|
|
||||||
create table picrinth.group_accounts (
|
|
||||||
groupname text not null,
|
|
||||||
account_id int not null,
|
|
||||||
created_at timestamp with time zone default now(),
|
|
||||||
constraint unique_group_accounts unique (account_id, groupname),
|
|
||||||
foreign key (groupname) references picrinth.groups (groupname) on delete cascade on update cascade,
|
foreign key (groupname) references picrinth.groups (groupname) on delete cascade on update cascade,
|
||||||
foreign key (account_id) references picrinth.accounts (id) on delete cascade on update cascade
|
foreign key (author) references picrinth.groups (author) on delete cascade on update cascade,
|
||||||
|
constraint unique_account_for_group_per_platform unique (groupname, platform)
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user