Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #83

Merged
merged 19 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 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,16 +21,21 @@
- [Лицензия](#лицензия)

## Функции

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

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


- **Frontend**: React + TypeScript
- **Backend**: Python - FastAPI, Pydantic, Uvicorn (проксирующийся через nginx)
- **Object Relational Mapping**: Python SQLAlchemy, Alembic, asyncpg driver
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
Loading