diff --git a/backend/api/projects/teams.py b/backend/api/projects/teams.py index 9fcebc3110..f51a5ddb51 100644 --- a/backend/api/projects/teams.py +++ b/backend/api/projects/teams.py @@ -213,7 +213,9 @@ async def patch( role = data["role"] except ValueError as e: logger.error(f"Error validating request: {str(e)}") - return {"Error": str(e), "SubCode": "InvalidData"}, 400 + return JSONResponse( + content={"Error": str(e), "SubCode": "InvalidData"}, status_code=400 + ) try: if not await ProjectAdminService.is_user_action_permitted_on_project( diff --git a/backend/models/dtos/project_dto.py b/backend/models/dtos/project_dto.py index 82a5ad7a17..e558a9beb4 100644 --- a/backend/models/dtos/project_dto.py +++ b/backend/models/dtos/project_dto.py @@ -4,7 +4,7 @@ from typing import Dict, List, Optional, Union from fastapi import HTTPException -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, root_validator from backend.models.dtos.campaign_dto import CampaignDTO from backend.models.dtos.interests_dto import InterestDTO @@ -198,6 +198,13 @@ class ProjectInfoDTO(BaseModel): class Config: populate_by_name = True + @root_validator(pre=True) + def replace_none_with_empty_string(cls, values): + return { + key: (value if value is not None or key == "locale" else "") + for key, value in values.items() + } + class CustomEditorDTO(BaseModel): """DTO to define a custom editor""" diff --git a/backend/models/postgis/project.py b/backend/models/postgis/project.py index f4f4f8ad03..21c53c2181 100644 --- a/backend/models/postgis/project.py +++ b/backend/models/postgis/project.py @@ -1,77 +1,79 @@ import json +import os import re from typing import Optional -from cachetools import TTLCache -from loguru import logger import geojson +import requests +from cachetools import TTLCache +from databases import Database +from fastapi import HTTPException from geoalchemy2 import Geometry, WKTElement from geoalchemy2.shape import to_shape -from sqlalchemy import orm, func, select, delete, update, inspect +from loguru import logger from shapely.geometry import shape -from sqlalchemy.dialects.postgresql import ARRAY -import requests - from sqlalchemy import ( + BigInteger, + Boolean, Column, - Integer, - String, DateTime, ForeignKey, - Boolean, - Table, - BigInteger, Index, + Integer, + String, + Table, + delete, + func, + inspect, + orm, + select, + update, ) -from sqlalchemy.orm import relationship, backref +from sqlalchemy.dialects.postgresql import ARRAY +from sqlalchemy.orm import backref, relationship + +from backend.config import settings +from backend.db import Base from backend.exceptions import NotFound from backend.models.dtos.campaign_dto import CampaignDTO, ListCampaignDTO +from backend.models.dtos.interests_dto import ListInterestDTO from backend.models.dtos.project_dto import ( CustomEditorDTO, - ProjectDTO, DraftProjectDTO, - ProjectSummary, PMDashboardDTO, - ProjectStatsDTO, - ProjectUserStatsDTO, + ProjectDTO, + ProjectInfoDTO, ProjectSearchDTO, + ProjectStatsDTO, + ProjectSummary, ProjectTeamDTO, - ProjectInfoDTO, + ProjectUserStatsDTO, ) -from backend.models.dtos.interests_dto import ListInterestDTO from backend.models.dtos.tags_dto import TagsDTO -from backend.models.postgis.organisation import Organisation +from backend.models.postgis.campaign import Campaign, campaign_projects from backend.models.postgis.custom_editors import CustomEditor +from backend.models.postgis.interests import Interest, project_interests +from backend.models.postgis.organisation import Organisation from backend.models.postgis.priority_area import PriorityArea, project_priority_areas -from backend.models.postgis.project_info import ProjectInfo from backend.models.postgis.project_chat import ProjectChat +from backend.models.postgis.project_info import ProjectInfo from backend.models.postgis.statuses import ( - ProjectStatus, - ProjectPriority, - TaskStatus, + Editors, + MappingPermission, MappingTypes, + ProjectDifficulty, + ProjectPriority, + ProjectStatus, TaskCreationMode, - Editors, + TaskStatus, TeamRoles, - MappingPermission, ValidationPermission, - ProjectDifficulty, ) from backend.models.postgis.task import Task from backend.models.postgis.team import Team from backend.models.postgis.user import User -from backend.models.postgis.campaign import Campaign, campaign_projects - -from backend.models.postgis.utils import ( - timestamp, -) +from backend.models.postgis.utils import timestamp from backend.services.grid.grid_service import GridService -from backend.models.postgis.interests import Interest, project_interests -import os -from backend.db import Base -from databases import Database -from fastapi import HTTPException -from backend.config import settings # Secondary table defining many-to-many join for projects that were favorited by users. project_favorites = Table(