Skip to content

Commit

Permalink
Merge pull request #81 from w1tnessbtwwwww/backend
Browse files Browse the repository at this point in the history
Backend
  • Loading branch information
w1tnessbtwwwww authored Jan 14, 2025
2 parents e5886d2 + 4592845 commit 274529a
Show file tree
Hide file tree
Showing 17 changed files with 129 additions and 569 deletions.
38 changes: 24 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# SPEEDSOLVER
<h1 align="center">SPEEDSOLVER</h1>


- https://speedsolver.ru/ - основной сайт.
- https://api.speedsolver.ru/docs - документация к API

## IMPORTANT
> [!IMPORTANT]
> Проект является опенсорсным решением для вашей команды, и ссылки, которые предоставлены выше, неспособны выдержать чрезмерно высокую нагрузку.
## Описание

***SPEEDSOLVER*** — это система управления проектами, предназначенная для эффективного управления командами, проектами, задачами, подзадачами и дедлайнами. Проект помогает командам организовать свою работу, отслеживать прогресс и достигать поставленных целей в срок.
Expand All @@ -17,23 +21,29 @@
- [Лицензия](#лицензия)

## Функции

- **Управление командами**: Создание и управление командами, добавление и удаление участников.
- **Управление проектами**: Создание и управление проектами, назначение задач и подзадач. Общение в реальном времени внутри проекта с сохранением истории чата.
- **Управление задачами**: Создание, редактирование и удаление задач, назначение ответственных лиц.
- **Управление подзадачами**: Создание, редактирование и удаление подзадач, отслеживание прогресса.
- **Дедлайны**: Установка и отслеживание дедлайнов для задач и подзадач.
- **Уведомления**: Автоматические уведомления о приближающихся дедлайнах и изменениях в задачах.
- [X] **Авторизация**: авторизация в рамках сессий благодаря JWT токенам. Предоставление access и refresh токенов.
- [X] **Регистрация через почту**: Регистрация, благодаря подтверждению почты через код.
- [ ] **Личный профиль**: Информация о Вас, социальные сети.
- [ ] **Личная статистика**: Количество открытых и закрытых задач.
- [X] **Управление командами**: Создание, удаление, обновление команды.
- [X] **Менеджмент участников команды**: Приглашение в команду, удаление из команды
- [X] **Назначение модераторов в команде**: Позволять модераторам создавать проекты для команды.
- [X] **Управление проектами**: Создание обновлени, удаление проектов. Общение в реальном времени внутри проекта с сохранением истории чата.
- [ ] **Управление задачами**: Создание, редактирование и удаление задач.
- [ ] **Дедлайны**: Установка и отслеживание дедлайнов для задач и подзадач.
- [ ] **Уведомления**: Автоматические уведомления о приближающихся дедлайнах и изменениях в задачах.

## Стек технологий

- **Frontend**: React.js + Tailwind CSS + SweetAlert2
- **Backend**: Python - FastAPI, Pydantic
- **Mobile** Swift
- **Object Relational Mapping**: Python SQLAlchemy + Alembic

- **Frontend**: React + TypeScript
- **Backend**: Python - FastAPI, Pydantic, Uvicorn (проксирующийся через nginx)
- **Object Relational Mapping**: Python SQLAlchemy, Alembic, asyncpg driver
- **База данных**: PostgreSQL
- **Аутентификация & Авторизация**: JWT (JSON Web Tokens) - pyjwt/jose
- **Аутентификация & Авторизация**: JWT (JSON Web Tokens) - pyjwt
- **Тестирование Backend**: Python - pytest
- **Мониторинг**: Grafana, Prometheus, Node Exporter, AlertManager
- **Логирование**: Собственная библиотека [teleglog](https://github.com/w1tnessbtwwwww/teleglog)
- **Дополнительно**:
- Docker – контейнеризация приложения.
- Nginx - Веб-сервер для проксирования внешних подключений путем **reverse proxy**, реализация защищенного соединения с **SSL/TLS**, проксирование поддоменов.
Expand All @@ -42,7 +52,7 @@
## Установка и запуск

1. Клонируйте репозиторий:
```bash
```shell
git clone https://github.com/w1tnessbtwwwww/SpeedSolver.git
2. Необходимо создать файл **.env** и заполнить его из **.env.example**.
3. Необходимо переназначить порты в файле **.env** в случае, если у вас заняты одни из назначенных вами.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from sqlalchemy import and_, select
from typing import Optional
from sqlalchemy import and_, select, update
from app.database.abstract.abc_repo import AbstractRepository
from app.database.models.models import Project
from app.database.repo.team_projects_repository import TeamProjectRepository
Expand All @@ -9,7 +10,21 @@
class ProjectRepository(AbstractRepository):
model = Project

async def update_project(self, projectId: str, new_title: str, new_desc: str) -> Optional[Project]:
try:
query = (
update(self.model)
.where(self.model.projectId == projectId)
.values(title=new_title, description=new_desc)
.returning(self.model)
)

result = await self._session.execute(query)
return result.scalars().first()
except Exception as e:
logger.fatal("Произошла ошибка при обновлении команды.", str(e))
return None

async def create_project(self, binded_teamId: str, title: str, description: str) -> Result[Project]:
team_project_repo = TeamProjectRepository(self._session)
team_projects = await team_project_repo.get_by_filter_all(teamId=binded_teamId)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
from sqlalchemy import Result, select
from app.database.abstract.abc_repo import AbstractRepository
from app.database.models.models import TeamProject
from app.database.models.models import Team, TeamProject
from app.utils.result import err, success

class TeamProjectRepository(AbstractRepository):
model = TeamProject


async def get_team_by_project(self, projectId: str) -> Result[Team]:
try:
query = (
select(Team)
.select_from(self.model)
.where(self.model.projectId == projectId)
.join(Team, Team.teamId == self.model.teamId)
)
team = await self._session.execute(query)
teamProject = team.scalars().first()
return success(teamProject)
except Exception as e:
return err(str(e))
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class TeamRepository(AbstractRepository):
model: Team = Team



async def create_team(self,
title: str,
description: str,
Expand Down
11 changes: 10 additions & 1 deletion SpeedSolverBackend/SpeedSolverAPI/app/routing/project_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from app.database.database import get_session
from app.database.models.models import User
from app.schema.request.project.update_project import UpdateProject
from app.security.jwtmanager import get_current_user
from app.schema.request.project.create_project import CreateProject

Expand All @@ -20,4 +21,12 @@ async def create_project(create_project: CreateProject, user: User = Depends(get
if not creating.success:
raise HTTPException(status_code=400, detail=creating.error)

return creating.value
return creating.value

@project_router.put("/update")
async def update_project(project_id: str, update_project: UpdateProject, user: User = Depends(get_current_user), session: AsyncSession = Depends(get_session)):
updating = await ProjectService(session).update_project(user.userId, project_id, update_project)
if not updating.success:
raise HTTPException(status_code=400, detail=updating.error)

return updating.value
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from typing import Optional
from pydantic import BaseModel

class UpdateProject(BaseModel):
new_title: Optional[str]
new_description: Optional[str]
44 changes: 37 additions & 7 deletions SpeedSolverBackend/SpeedSolverAPI/app/services/project_service.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.database.models.models import Project
from app.database.models.models import Project, Team, TeamProject
from app.database.repo.project_repository import ProjectRepository

from app.database.repo.team_projects_repository import TeamProjectRepository
from app.schema.request.project.create_project import CreateProject
from app.schema.request.project.update_project import UpdateProject

from app.services.team_service import TeamService
from app.utils.result import Result, err, success

from app.utils.result import Result, err, success
from multipledispatch import dispatch

class ProjectService:

Expand All @@ -13,15 +20,38 @@ def __init__(self, session: AsyncSession):
self._repo: ProjectRepository = ProjectRepository(session)


async def create_project(self, user_sender: str, team_id: str, title: str, description: str) -> Result[Project]:
team = await TeamService(self._session).is_team_exists(team_id=team_id)

async def can_interract_with_team(self, userId: str, teamId: str) -> Result[bool]:
team = await TeamService(self._session).is_team_exists(team_id=teamId)
if not team:
return err("Команда не найдена.")

is_user_moderator = await TeamService(self._session).is_user_moderator(user_sender, team_id=team_id)
is_user_moderator = await TeamService(self._session).is_user_moderator(userId, teamId)

if not is_user_moderator:
return err("Вы не являетесь модератором данной команды.")

async def create_project(self, user_sender: str, team_id: str, createProject: CreateProject) -> Result[Project]:
can_interract = await self.can_interract_with_team(user_sender, team_id)
if not can_interract.success:
return err(can_interract.error)

return await self._repo.create_project(binded_teamId=team_id, title=createProject.title, description=createProject.description)

async def update_project(self, user_sender: str, projectId: str, updateProject: UpdateProject):
team_projects_repo = TeamProjectRepository(self._session)
team = await team_projects_repo.get_team_by_project(projectId)
if not team.success:
return err(team.error)

is_user_moder = await self.can_interract_with_team(user_sender, team.value.teamId)
if not is_user_moder:
return err("Вы не являетесь модератором данной команды.")

upd_proj = await self._repo.update_project(projectId=projectId, new_title=updateProject.new_title, new_desc=updateProject.new_description)
if not upd_proj:
return err("Не удалось обновить команду")

return await self._repo.create_project(binded_teamId=team_id, title=title, description=description)

await self._session.commit()
return success(upd_proj)

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def __init__(self, session: AsyncSession):
self._session = session
self._repo = TeamRepository(session)


async def is_user_moderator(self, user_id: str, team_id: str):
team_moderation_repo = TeamModerationRepository(self._session)
team: Team = await self._repo.get_by_filter_one(teamId=team_id)
Expand All @@ -37,7 +37,12 @@ async def is_team_exists(self, team_id: str) -> bool:

return True if team else False

async def get_team_by_project(self, projectId: str):

return await self._repo.get_team_by_project(projectId)

async def delete_team(self, team_id: str, leaderId: str):

return await self._repo.delete_team(teamId=team_id, leaderId=leaderId)

async def create_team(self, createRequest: CreateTeam, leaderId: str):
Expand Down
1 change: 0 additions & 1 deletion SpeedSolverBackend/SpeedSolverAPI/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ async def bad_email(request, exc: BadEmail):
detail=exc.message
)


@api.on_event("startup")
async def startup_event():
await create_tables()
13 changes: 12 additions & 1 deletion SpeedSolverBackend/SpeedSolverAPI/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions SpeedSolverBackend/SpeedSolverAPI/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ bcrypt = "^4.2.1"
pytelegrambotapi = "^4.26.0"
python-multipart = "^0.0.20"
alembic = "^1.14.0"
multipledispatch = "^1.0.0"


[build-system]
Expand Down
19 changes: 0 additions & 19 deletions SpeedSolverBackend/WebSocket/Dockerfile

This file was deleted.

5 changes: 0 additions & 5 deletions SpeedSolverBackend/WebSocket/models/msg.py

This file was deleted.

Loading

0 comments on commit 274529a

Please sign in to comment.