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

fix: Project search and deletion. #6634

Merged
merged 1 commit into from
Nov 15, 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
13 changes: 8 additions & 5 deletions backend/api/projects/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,18 @@ async def post(
}, 400

if not ProjectAdminService.is_user_action_permitted_on_project(user.id, project_id):
return {
"Error": "User is not a manager of the project",
"SubCode": "UserPermissionError",
}, 403
return JSONResponse(
content={
"Error": "User is not a manager of the project",
"SubCode": "UserPermissionError",
},
status_code=403,
)
threading.Thread(
target=MessageService.send_message_to_all_contributors,
args=(project_id, message_dto),
).start()
return {"Success": "Messages started"}, 200
return JSONResponse(content={"Success": "Messages started"}, status_code=200)


@router.post("/{project_id}/actions/feature/")
Expand Down
25 changes: 21 additions & 4 deletions backend/api/teams/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,14 +314,26 @@ async def post(
)


import asyncio


# Function to run async code in a thread
def run_asyncio_in_thread(func, *args, **kwargs):
# Create a new event loop for the thread
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
# Create a new database connection (to be used in this thread)
db = get_db()
loop.run_until_complete(func(*args, db=db, **kwargs))


@router.post("/{team_id}/actions/message-members/")
async def post(
request: Request,
background_tasks: BackgroundTasks,
user: AuthUserDTO = Depends(login_required),
db: Database = Depends(get_db),
team_id: int = None,
message_dto: MessageDTO = Body(...),
):
"""
Message all team members
Expand Down Expand Up @@ -368,9 +380,11 @@ async def post(
description: Internal Server Error
"""
try:
request_json = await request.json()
request_json["from_user_id"] = user.id
message_dto = MessageDTO(**request_json)
# Validate if team is present
team = await TeamService.get_team_by_id(team_id, db)

is_manager = await TeamService.is_user_team_manager(team_id, user.id, db)
if not is_manager:
raise ValueError
Expand All @@ -397,10 +411,13 @@ async def post(
)

try:
# Start a new thread for sending messages
# Use threading to run the async function in a separate thread
# threading.Thread(
# target=TeamService.send_message_to_all_team_members,
# args=(team_id, team.name, message_dto, db),
# target=run_asyncio_in_thread,
# args=(TeamService.send_message_to_all_team_members, team_id, team.name, message_dto, user.id)
# ).start()

background_tasks.add_task(
TeamService.send_message_to_all_team_members,
team_id,
Expand Down
19 changes: 2 additions & 17 deletions backend/models/dtos/message_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ class ChatMessageDTO(BaseModel):
timestamp: datetime
username: str

# class Config:
# populate_by_name = True
class Config:
populate_by_name = True

# json_encoders = {
# datetime: lambda v: v.isoformat() + "Z" if v else None
Expand All @@ -76,21 +76,6 @@ class Config:

json_encoders = {datetime: lambda v: v.isoformat() + "Z" if v else None}

# def dict(self, *args, **kwargs):
# """
# Override the dict method to exclude `user_id` and `project_id`
# from the dictionary representation.
# """
# exclude_fields = {"user_id", "project_id"}
# # Generate the dict as usual, excluding the fields
# return super().dict(*args, **kwargs, exclude=exclude_fields)

# def dict(self, **kwargs):
# data = super().dict(**kwargs)
# if self.timestamp:
# data["timestamp"] = self.timestamp.isoformat() + "Z"
# return data


class ProjectChatDTO(BaseModel):
"""DTO describing all chat messages on one project"""
Expand Down
2 changes: 2 additions & 0 deletions backend/models/postgis/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,8 @@ async def delete(self, db: Database):
"tasks",
"project_info",
"project_chat",
"project_partnerships_history",
"project_partnerships",
]

# Start a transaction to ensure atomic deletion
Expand Down
16 changes: 0 additions & 16 deletions backend/models/postgis/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,22 +121,6 @@ class Team(Base):
# organisation = relationship(Organisation, backref="teams", lazy="joined")
organisation = relationship(Organisation, backref="teams")

# async def create(self, db: Database):
# """Creates and saves the current model to the DB"""
# print(self.members)

# team = await db.execute(
# insert(Team.__table__).values(
# organisation_id=self.organisation_id,
# name=self.name,
# logo=self.logo,
# description=self.description,
# join_method=self.join_method,
# visibility=self.visibility,
# )
# )
# return team if team else None

async def create(self, db: Database):
"""Creates and saves the current model to the DB, including members if they exist."""

Expand Down
14 changes: 10 additions & 4 deletions backend/services/project_search_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,15 +265,21 @@ async def _filter_projects(search_dto: ProjectSearchDTO, user, db: Database):
search_text = "".join(
char for char in search_dto.text_search if char not in "@|&!><\\():"
)
or_search = " | ".join([x for x in search_text.split(" ") if x])
tsquery_search = " & ".join([x for x in search_text.split(" ") if x])
ilike_search = f"%{search_text}%"

subquery_filters.append(
"text_searchable @@ to_tsquery('english', :text_search) OR name ILIKE :text_search"
"""
text_searchable @@ to_tsquery('english', :tsquery_search)
OR name ILIKE :text_search
"""
)
params["text_search"] = or_search
params["tsquery_search"] = tsquery_search
params["text_search"] = ilike_search

filters.append(
"""
p.id IN (
p.id = ANY(
SELECT project_id
FROM project_info
WHERE {}
Expand Down
16 changes: 9 additions & 7 deletions backend/services/team_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,11 +631,15 @@ async def _get_team_members(team_id: int, db: Database):

@staticmethod
async def _get_active_team_members(team_id: int, db: Database):
query = """
SELECT * FROM team_members
WHERE team_id = :team_id AND active = TRUE
"""
return await db.fetch_all(query, values={"team_id": team_id})
try:
query = """
SELECT * FROM team_members
WHERE team_id = :team_id AND active = TRUE
"""
return await db.fetch_all(query, values={"team_id": team_id})
except Exception as e:
print(f"Error executing query: {str(e)}")
raise

@staticmethod
async def activate_team_member(team_id: int, user_id: int, db: Database):
Expand Down Expand Up @@ -791,15 +795,13 @@ async def send_message_to_all_team_members(
team_members = await TeamService._get_active_team_members(team_id, db)
user = await UserService.get_user_by_id(user_id, db)
sender = user.username

message_dto.message = (
"A message from {}, manager of {} team:<br/><br/>{}".format(
MessageService.get_user_profile_link(sender),
MessageService.get_team_link(team_name, team_id, False),
markdown(message_dto.message, output_format="html"),
)
)

messages = []
for team_member in team_members:
if team_member.user_id != user_id:
Expand Down
Loading