creating first admin and update restrictions for ordinary users
This commit is contained in:
@@ -13,16 +13,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "${{ secrets.SSH_PRIVATE_KEY }}" > /tmp/id_fin
|
echo "${{ secrets.SSH_PRIVATE_KEY }}" > /tmp/id_fin
|
||||||
chmod 600 /tmp/id_fin
|
chmod 600 /tmp/id_fin
|
||||||
|
#ссылка на репо
|
||||||
- name: Create inventory
|
|
||||||
run: echo "${{ secrets.INVENTORY }}" > inventory.ini
|
|
||||||
|
|
||||||
- name: Create secrets.yml
|
|
||||||
run: echo "${{ secrets.SECRETS }}" > secrets.yml
|
|
||||||
|
|
||||||
- name: Create .env file
|
- name: Create .env file
|
||||||
run: echo "${{ secrets.RUNNER_ENV }}" > .env
|
run: echo "${{ secrets.RUNNER_ENV }}" > .env
|
||||||
|
#env для runners
|
||||||
- name: Checkout only deploy.yml
|
- name: Checkout only deploy.yml
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -31,6 +25,8 @@ jobs:
|
|||||||
path: tmp-repo
|
path: tmp-repo
|
||||||
sparse-checkout: |
|
sparse-checkout: |
|
||||||
ansible/deploy.yml
|
ansible/deploy.yml
|
||||||
|
ansible/inventory.ini
|
||||||
|
ansible/secrets.yml
|
||||||
|
|
||||||
- name: Run Ansible playbook
|
- name: Run Ansible playbook
|
||||||
run: ansible-playbook -i inventory.ini tmp-repo/ansible/deploy.yml -e @secrets.yml -e env_file="$(pwd)/.env"
|
run: ansible-playbook -i inventory.ini tmp-repo/ansible/deploy.yml -e @secrets.yml -e env_file="$(pwd)/.env"
|
||||||
@@ -46,7 +42,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Create .env file
|
- name: Create .env file
|
||||||
run: echo "${{ secrets.WEDDING_SITE_ENV }}" > .env
|
run: echo "${{ secrets.WEDDING_SITE_ENV }}" > .env
|
||||||
|
#env для проекта
|
||||||
- name: Build image
|
- name: Build image
|
||||||
run: docker build -t back:latest -f docker/dockerfile .
|
run: docker build -t back:latest -f docker/dockerfile .
|
||||||
|
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,7 +22,6 @@ hint.py
|
|||||||
|
|
||||||
#env
|
#env
|
||||||
*.env
|
*.env
|
||||||
secrets.yml
|
|
||||||
#db
|
#db
|
||||||
*.db
|
*.db
|
||||||
versions/
|
versions/
|
||||||
|
|||||||
@@ -31,11 +31,6 @@
|
|||||||
group: root
|
group: root
|
||||||
mode: '0600'
|
mode: '0600'
|
||||||
|
|
||||||
- name: Download nginx
|
|
||||||
shell: wget -O /opt/infra/nginx.yaml "{{ URL for docker-compose nginx }}" #перенести докер в pipeline и выкачать страницы для запуска с созданием loacations в nginx
|
|
||||||
args:
|
|
||||||
creates: /opt/infra/nginx.yaml
|
|
||||||
|
|
||||||
- name: Download node-docker.yaml
|
- name: Download node-docker.yaml
|
||||||
shell: wget -O /opt/infra/node-docker.yaml "{{ gitea_instance_url }}"
|
shell: wget -O /opt/infra/node-docker.yaml "{{ gitea_instance_url }}"
|
||||||
args:
|
args:
|
||||||
@@ -43,6 +38,3 @@
|
|||||||
|
|
||||||
- name: Start node-docker
|
- name: Start node-docker
|
||||||
shell: docker-compose -f /opt/infra/node-docker.yaml up -d
|
shell: docker-compose -f /opt/infra/node-docker.yaml up -d
|
||||||
|
|
||||||
- name: Start nginx
|
|
||||||
shell: docker-compose -f /opt/infra/nginx.yaml up -d
|
|
||||||
|
|||||||
2
ansible/inventory.ini
Normal file
2
ansible/inventory.ini
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[servers]
|
||||||
|
myserver ansible_host=38.244.136.102 ansible_user=root
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
[servers]
|
|
||||||
myserver host=... ansible_user=...
|
|
||||||
1
ansible/secrets.yml
Normal file
1
ansible/secrets.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
gitea_instance_url: https://git.homyk.space/MH.Dmitrii/wedding-site/src/branch/main/docker/gitea_runners.git
|
||||||
@@ -1 +0,0 @@
|
|||||||
gitea_instance_url: ...
|
|
||||||
18
docker/caddy/caddy.conf
Normal file
18
docker/caddy/caddy.conf
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
example.com {
|
||||||
|
|
||||||
|
encode gzip
|
||||||
|
|
||||||
|
# --- API ---
|
||||||
|
handle_path /api/* {
|
||||||
|
reverse_proxy backend:8000
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Frontend ---
|
||||||
|
root * /var/www/site
|
||||||
|
file_server
|
||||||
|
|
||||||
|
log {
|
||||||
|
output stdout
|
||||||
|
format console
|
||||||
|
}
|
||||||
|
}
|
||||||
19
docker/caddy/caddy.yaml
Normal file
19
docker/caddy/caddy.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
services:
|
||||||
|
caddy:
|
||||||
|
image: caddy:<version>
|
||||||
|
restart: unless-stopped
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
- "443:443/udp"
|
||||||
|
volumes:
|
||||||
|
- $PWD/conf:/etc/caddy
|
||||||
|
- $PWD/site:/srv
|
||||||
|
- caddy_data:/data
|
||||||
|
- caddy_config:/config
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
caddy_data:
|
||||||
|
caddy_config:
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
web:
|
|
||||||
image: nginx
|
|
||||||
volumes:
|
|
||||||
- ./templates:/etc/nginx/templates
|
|
||||||
- ./confs:/etc/nginx/conf.d
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
- "443:443"
|
|
||||||
4
makefile
4
makefile
@@ -2,9 +2,9 @@ VENV=source ./.venv/bin/activate;
|
|||||||
ALEMBIC=alembic -c ./server/backend/database/alembic/alembic.ini
|
ALEMBIC=alembic -c ./server/backend/database/alembic/alembic.ini
|
||||||
.PHONY: run run_debug migrate_head migrate_down migrate_history migrate_current migrate
|
.PHONY: run run_debug migrate_head migrate_down migrate_history migrate_current migrate
|
||||||
run:
|
run:
|
||||||
$(VENV) python run.py
|
$(VENV) python run.py --user_name admin
|
||||||
run_debug:
|
run_debug:
|
||||||
$(VENV) python run.py --mode debug
|
$(VENV) python run.py --mode debug --user_name admin
|
||||||
migrate_head:
|
migrate_head:
|
||||||
$(VENV) $(ALEMBIC) upgrade head
|
$(VENV) $(ALEMBIC) upgrade head
|
||||||
migrate_down:
|
migrate_down:
|
||||||
|
|||||||
34
run.py
34
run.py
@@ -1,4 +1,7 @@
|
|||||||
from server.backend.schema.pydantic import settings
|
from server.backend.schema.pydantic import settings
|
||||||
|
from server.backend.database.db import create_user, list_users
|
||||||
|
from server.backend.schema.pydantic import UserCreate
|
||||||
|
import asyncio
|
||||||
import uvicorn
|
import uvicorn
|
||||||
def start(log_level:str):
|
def start(log_level:str):
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@@ -11,18 +14,33 @@ def start(log_level:str):
|
|||||||
access_log=True
|
access_log=True
|
||||||
)
|
)
|
||||||
import argparse
|
import argparse
|
||||||
parser = argparse.ArgumentParser(description="logging")
|
parser = argparse.ArgumentParser(description="logging and admin creation")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--mode",
|
"--mode",
|
||||||
choices=["debug","info"],
|
choices=["debug","info"],
|
||||||
default="info",
|
default="info",
|
||||||
help="Режим логирования (по умолчанию: info)"
|
help="Режим логирования (по умолчанию: info)"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--user_name",
|
||||||
|
type=str,
|
||||||
|
required=True,
|
||||||
|
help="Создание первого пользователя)"
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
match args.mode:
|
async def arguments(args):
|
||||||
case "debug":
|
admin_user = {
|
||||||
print("Режим:", args.mode)
|
"code": "123456",
|
||||||
start(args.mode)
|
"name": args.user_name,
|
||||||
case "info":
|
"surname": args.user_name,
|
||||||
print("Режим:", args.mode)
|
"admin": True
|
||||||
start(args.mode)
|
}
|
||||||
|
users = await list_users()
|
||||||
|
label = any(u.admin for u in users)
|
||||||
|
if not label:
|
||||||
|
await create_user(UserCreate(**admin_user))
|
||||||
|
match args.mode:
|
||||||
|
case "debug" | "info":
|
||||||
|
print("Режим:", args.mode)
|
||||||
|
start(args.mode)
|
||||||
|
asyncio.run(arguments(args))
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ from server.backend.schema.pydantic import settings
|
|||||||
|
|
||||||
def signJWT(user_info: dict) -> str:
|
def signJWT(user_info: dict) -> str:
|
||||||
payload = {
|
payload = {
|
||||||
"user_id": user_info.id,
|
"user_id":user_info.id,
|
||||||
"admin":user_info.admin,
|
|
||||||
"expires": time.time() + settings.ACCESS_TOKEN_EXPIRE_SECONDS
|
"expires": time.time() + settings.ACCESS_TOKEN_EXPIRE_SECONDS
|
||||||
}
|
}
|
||||||
token = pyjwt.encode(payload, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
|
token = pyjwt.encode(payload, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
|
||||||
|
|||||||
@@ -38,15 +38,19 @@ class User(Base):
|
|||||||
|
|
||||||
async def create_user(user_info):
|
async def create_user(user_info):
|
||||||
async with AsyncSessionLocal() as session:
|
async with AsyncSessionLocal() as session:
|
||||||
user_data = user_info.dict(exclude_unset=True)
|
result = await session.execute(select(User).where(User.code==user_info.code))
|
||||||
new_user = User(**user_data)
|
user = result.scalar_one_or_none()
|
||||||
session.add(new_user)
|
if user == None:
|
||||||
await session.commit()
|
user_data = user_info.dict(exclude_unset=True)
|
||||||
await session.refresh(new_user)
|
new_user = User(**user_data)
|
||||||
|
session.add(new_user)
|
||||||
|
await session.commit()
|
||||||
|
await session.refresh(new_user)
|
||||||
|
return user
|
||||||
|
|
||||||
async def update_user(user_info):
|
async def update_user(user_info):
|
||||||
async with AsyncSessionLocal() as session:
|
async with AsyncSessionLocal() as session:
|
||||||
result = await session.execute(select(User).where(User.code==user_info.code))
|
result = await session.execute(select(User).where(User.id==user_info.id))
|
||||||
user = result.scalar_one_or_none()
|
user = result.scalar_one_or_none()
|
||||||
if user:
|
if user:
|
||||||
update_data = user_info.dict(exclude_unset=True)
|
update_data = user_info.dict(exclude_unset=True)
|
||||||
@@ -64,13 +68,29 @@ async def list_users():
|
|||||||
return users
|
return users
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
async def list_user(id):
|
||||||
|
async with AsyncSessionLocal() as session:
|
||||||
|
result = await session.execute(select(User).where(User.id == id))
|
||||||
|
user = result.scalar_one_or_none()
|
||||||
|
if user:
|
||||||
|
return user
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
async def list_user_by_code(code):
|
||||||
|
async with AsyncSessionLocal() as session:
|
||||||
|
result = await session.execute(select(User).where(User.code == code))
|
||||||
|
user = result.scalar_one_or_none()
|
||||||
|
if user:
|
||||||
|
return user
|
||||||
|
else:
|
||||||
|
return None
|
||||||
async def login_user(code):
|
async def login_user(code):
|
||||||
async with AsyncSessionLocal() as session:
|
async with AsyncSessionLocal() as session:
|
||||||
result = await session.execute(select(User).where(User.code == code.code))
|
result = await session.execute(select(User).where(User.code == code.code))
|
||||||
user = result.scalar_one_or_none()
|
user = result.scalar_one_or_none()
|
||||||
if user:
|
if user:
|
||||||
user.last_login=datetime.now(timezone.utc)
|
user.last_login=datetime.now(timezone.utc)
|
||||||
|
user.activated=True
|
||||||
await session.commit()
|
await session.commit()
|
||||||
return user
|
return user
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -18,9 +18,27 @@ async def check_roles(user=Depends(get_current_user)):
|
|||||||
return user
|
return user
|
||||||
|
|
||||||
@api.post("/update", response_model=pydantic.UserUpdate)
|
@api.post("/update", response_model=pydantic.UserUpdate)
|
||||||
async def update_user(data: pydantic.UserUpdate,user=Depends(get_current_user)):
|
async def update_user(data: pydantic.UserUpdate, user=Depends(get_current_user)):
|
||||||
data = await db.update_user(data)
|
user_check = await db.list_user(user["user_id"])
|
||||||
return data
|
if not user_check:
|
||||||
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
|
||||||
|
if not user_check.admin:
|
||||||
|
if data.code != user_check.code:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
detail="Ordinary users cannot change their code"
|
||||||
|
)
|
||||||
|
if user_check.admin:
|
||||||
|
if data.code != user_check.code:
|
||||||
|
existing_user = await db.list_user_by_code(data.code)
|
||||||
|
if existing_user and existing_user.id != user_check.id:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
|
detail="Code already exists for another user"
|
||||||
|
)
|
||||||
|
updated_data = data.copy(update={"id": user_check.id})
|
||||||
|
updated_data = await db.update_user(updated_data)
|
||||||
|
return updated_data
|
||||||
|
|
||||||
@api.post("/create", response_model=pydantic.UserAccess)
|
@api.post("/create", response_model=pydantic.UserAccess)
|
||||||
async def create_user(user_info: pydantic.UserCreate,user=Depends(check_roles)):
|
async def create_user(user_info: pydantic.UserCreate,user=Depends(check_roles)):
|
||||||
|
|||||||
@@ -23,9 +23,6 @@ class UserOut(BaseModel):
|
|||||||
name: NameStr = Field(..., description="Name of the guest")
|
name: NameStr = Field(..., description="Name of the guest")
|
||||||
surname: NameStr = Field(..., description="Surname of the guest")
|
surname: NameStr = Field(..., description="Surname of the guest")
|
||||||
|
|
||||||
class UserCreate(UserAccess):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class UserUpdate(UserAccess):
|
class UserUpdate(UserAccess):
|
||||||
name: NameStr = Field(..., description="Name of the guest")
|
name: NameStr = Field(..., description="Name of the guest")
|
||||||
surname: NameStr = Field(..., description="Surname of the guest")
|
surname: NameStr = Field(..., description="Surname of the guest")
|
||||||
@@ -35,6 +32,8 @@ class UserUpdate(UserAccess):
|
|||||||
alco: bool = Field(False, description="if the guest will drink alco or not")
|
alco: bool = Field(False, description="if the guest will drink alco or not")
|
||||||
types_of_alco: str = Field("", description="types of alco")
|
types_of_alco: str = Field("", description="types of alco")
|
||||||
|
|
||||||
|
class UserCreate(UserUpdate):
|
||||||
|
admin:bool = Field(False, description="Admin privilegies")
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
DIR:str
|
DIR:str
|
||||||
PORT:int
|
PORT:int
|
||||||
|
|||||||
Reference in New Issue
Block a user