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

Messages, teams, comments, notification modules and project filters a… #6608

Merged
merged 1 commit into from
Oct 29, 2024
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
47 changes: 27 additions & 20 deletions backend/api/comments/resources.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
# from flask_restful import , request, current_app
# from schematics.exceptions import Exception

from datetime import datetime

from databases import Database
from fastapi import APIRouter, Depends, Request
from loguru import logger
from starlette.authentication import requires
from fastapi.responses import JSONResponse

from backend.db import get_db, get_session
Expand All @@ -16,7 +12,7 @@
from backend.services.mapping_service import MappingService, MappingServiceError
from backend.services.messaging.chat_service import ChatService
from backend.services.project_service import ProjectService
from backend.services.users.authentication_service import login_required, tm
from backend.services.users.authentication_service import login_required
from backend.services.users.user_service import UserService

session = get_session()
Expand Down Expand Up @@ -204,9 +200,15 @@ async def delete(


@router.post("/{project_id}/comments/tasks/{task_id}/")
@requires("authenticated")
@tm.pm_only(False)
def post(request: Request, project_id: int, task_id: int):
# TODO Decorator
# @tm.pm_only(False)
async def post(
request: Request,
project_id: int,
task_id: int,
user: AuthUserDTO = Depends(login_required),
db: Database = Depends(get_db),
):
"""
Adds a comment to the task outside of mapping/validation
---
Expand Down Expand Up @@ -260,24 +262,29 @@ def post(request: Request, project_id: int, task_id: int):
description: Internal Server Error
"""
authenticated_user_id = request.user.display_name
if UserService.is_user_blocked(authenticated_user_id):
return {"Error": "User is on read only mode", "SubCode": "ReadOnly"}, 403
if await UserService.is_user_blocked(authenticated_user_id, db):
return JSONResponse(
content={"Error": "User is on read only mode", "SubCode": "ReadOnly"},
status_code=403,
)

try:
task_comment = TaskCommentDTO(request.json())
task_comment.user_id = request.user.display_name
task_comment.task_id = task_id
task_comment.project_id = project_id
task_comment.validate()
request_json = await request.json()
comment = request_json.get("comment")
task_comment = TaskCommentDTO(
user_id=user.id, task_id=task_id, project_id=project_id, comment=comment
)
except Exception as e:
logger.error(f"Error validating request: {str(e)}")
return {"Error": "Unable to add comment", "SubCode": "InvalidData"}, 400

return JSONResponse(
content={"Error": "Unable to add comment", "SubCode": "InvalidData"},
status_code=400,
)
try:
task = MappingService.add_task_comment(task_comment)
return task.model_dump(by_alias=True), 201
task = await MappingService.add_task_comment(task_comment, db)
return task
except MappingServiceError:
return {"Error": "Task update failed"}, 403
return JSONResponse(content={"Error": "Task update failed"}, status_code=403)


@router.get("/{project_id}/comments/tasks/{task_id}/")
Expand Down
2 changes: 1 addition & 1 deletion backend/api/projects/favorites.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ async def get(
favorited = await ProjectService.is_favorited(project_id, user_id, db)
if favorited is True:
return JSONResponse(content={"favorited": True}, status_code=200)
return JSONResponse({"favorited": False}, status_code=200)
return JSONResponse(content={"favorited": False}, status_code=200)


@router.post("/{project_id}/favorite/")
Expand Down
10 changes: 7 additions & 3 deletions backend/api/teams/resources.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from backend.models.postgis.team import Team
from databases import Database
from distutils.util import strtobool
from fastapi import APIRouter, Depends, Request, Body
Expand Down Expand Up @@ -94,7 +95,7 @@ async def patch(
try:
team = await TeamService.get_team_by_id(team_id, db)
team_dto.team_id = team_id

data = await request.json()
if not await TeamService.is_user_team_manager(
team_id, user.id, db
) and not await OrganisationService.can_user_manage_organisation(
Expand All @@ -112,9 +113,12 @@ async def patch(
return JSONResponse(
content={"Error": str(e), "SubCode": "InvalidData"}, status_code=400
)

try:
await TeamService.update_team(team_dto, db)
if ("joinMethod" or "organisations_id") not in data.keys():
print("inside......")
await Team.update_team_members(team, team_dto, db)
else:
await TeamService.update_team(team_dto, db)
return JSONResponse(content={"Status": "Updated"}, status_code=200)
except TeamServiceError as e:
return JSONResponse(content={"Error": str(e)}, status_code=402)
Expand Down
4 changes: 3 additions & 1 deletion backend/api/users/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,9 @@ async def get(
page = (
int(request.query_params.get("page")) if request.query_params.get("page") else 1
)
project_id = int(request.query_params.get("projectId", None))
project_id = request.query_params.get("projectId", None)
if project_id:
project_id = int(project_id)
users_dto = await UserService.filter_users(username, project_id, page, db)
return users_dto

Expand Down
25 changes: 14 additions & 11 deletions backend/models/dtos/team_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ class TeamMembersDTO(BaseModel):
def validate_function(cls, value):
return validate_team_member_function(value)

class Config:
populate_by_name = True


class TeamProjectDTO(BaseModel):
"""Describes a JSON model to create a project team"""
Expand Down Expand Up @@ -108,7 +111,7 @@ class TeamDetailsDTO(BaseModel):
visibility: str
is_org_admin: bool = Field(False)
is_general_admin: bool = Field(False)
members: List[TeamMembersDTO] = Field([], alias="team_members")
members: List[TeamMembersDTO] = Field([], alias="members")
team_projects: List[TeamProjectDTO] = Field([], alias="team_projects")

@field_validator("join_method")
Expand Down Expand Up @@ -200,16 +203,16 @@ class Config:
class UpdateTeamDTO(BaseModel):
"""Describes a JSON model to update a team"""

creator: float = Field(None, alias="creator")
team_id: int = Field(None, alias="team_id")
organisation: str = Field(None, alias="organisation")
organisation_id: int = Field(None, alias="organisation_id")
name: str = Field(None, alias="name")
logo: str = Field(None, alias="logo")
description: str = Field(None, alias="description")
join_method: str = Field(None, alias="joinMethod")
visibility: str = Field(None, serialize_when_none=False)
members: List[TeamMembersDTO] = Field([], serialize_when_none=False)
creator: Optional[int] = Field(None, alias="creator")
team_id: Optional[int] = Field(None, alias="team_id")
organisation: Optional[str] = Field(None, alias="organisation")
organisation_id: Optional[int] = Field(None, alias="organisation_id")
name: Optional[str] = Field(None, alias="name")
logo: Optional[str] = Field(None, alias="logo")
description: Optional[str] = Field(None, alias="description")
join_method: Optional[str] = Field(None, alias="joinMethod")
visibility: Optional[str] = Field(None, serialize_when_none=False)
members: Optional[List[TeamMembersDTO]] = Field([], serialize_when_none=False)

@field_validator("join_method")
def validate_join_method(cls, value):
Expand Down
43 changes: 24 additions & 19 deletions backend/models/postgis/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,20 +132,27 @@ async def save(self, db: Database):
)

@staticmethod
def get_all_contributors(project_id: int):
"""Get all contributors to a project"""

contributors = (
session.query(Task.mapped_by)
.filter(Task.project_id == project_id)
.filter(Task.mapped_by.isnot(None))
.union(
session.query(Task.validated_by)
.filter(Task.project_id == project_id)
.filter(Task.validated_by.isnot(None))
)
.distinct()
).all()
async def get_all_contributors(project_id: int, db: Database):
"""Get all contributors to a project using async raw SQL"""

query = """
SELECT DISTINCT contributor
FROM (
SELECT mapped_by AS contributor
FROM tasks
WHERE project_id = :project_id
AND mapped_by IS NOT NULL
UNION
SELECT validated_by AS contributor
FROM tasks
WHERE project_id = :project_id
AND validated_by IS NOT NULL
) AS contributors
"""

rows = await db.fetch_all(query=query, values={"project_id": project_id})

contributors = [row["contributor"] for row in rows]
return contributors

@staticmethod
Expand Down Expand Up @@ -222,14 +229,12 @@ async def delete_all_messages(
DELETE FROM messages
WHERE to_user_id = :user_id
"""
params = {"user_id": user_id}

if message_type_filters:
delete_query += " AND message_type = ANY(:message_type_filters)"

await db.execute(
delete_query,
{"user_id": user_id, "message_type_filters": message_type_filters},
)
params["message_type_filters"] = message_type_filters
await db.execute(delete_query, params)

def delete(self):
"""Deletes the current model from the DB"""
Expand Down
Loading
Loading