backend/models/postgis/project_info.py (91 lines of code) (raw):

from flask import current_app from sqlalchemy.dialects.postgresql import TSVECTOR from typing import List from backend import db from backend.models.dtos.project_dto import ProjectInfoDTO class ProjectInfo(db.Model): """ Contains all project info localized into supported languages """ __tablename__ = "project_info" project_id = db.Column(db.Integer, db.ForeignKey("projects.id"), primary_key=True) locale = db.Column(db.String(10), primary_key=True) name = db.Column(db.String(512)) short_description = db.Column(db.String) description = db.Column(db.String) instructions = db.Column(db.String) project_id_str = db.Column(db.String) text_searchable = db.Column( TSVECTOR ) # This contains searchable text and is populated by a DB Trigger per_task_instructions = db.Column(db.String) __table_args__ = ( db.Index("idx_project_info_composite", "locale", "project_id"), db.Index("textsearch_idx", "text_searchable"), {}, ) @classmethod def create_from_name(cls, name: str): """ Creates a new ProjectInfo class from name, used when creating draft projects """ new_info = cls() new_info.locale = "en" # Draft project default to english, PMs can change this prior to publication new_info.name = name return new_info @classmethod def create_from_dto(cls, dto: ProjectInfoDTO): """ Creates a new ProjectInfo class from dto, used from project edit """ new_info = cls() new_info.update_from_dto(dto) return new_info def update_from_dto(self, dto: ProjectInfoDTO): """ Updates existing ProjectInfo from supplied DTO """ self.locale = dto.locale self.name = dto.name self.project_id_str = str(self.project_id) # Allows project_id to be searched # Note project info not bleached on basis that admins are trusted users and shouldn't be doing anything bad self.short_description = dto.short_description self.description = dto.description self.instructions = dto.instructions self.per_task_instructions = dto.per_task_instructions @staticmethod def get_dto_for_locale(project_id, locale, default_locale="en") -> ProjectInfoDTO: """ Gets the projectInfoDTO for the project for the requested locale. If not found, then the default locale is used :param project_id: ProjectID in scope :param locale: locale requested by user :param default_locale: default locale of project :raises: ValueError if no info found for Default Locale """ project_info = ProjectInfo.query.filter_by( project_id=project_id, locale=locale ).one_or_none() if project_info is None: # If project is none, get default locale and don't worry about empty translations project_info = ProjectInfo.query.filter_by( project_id=project_id, locale=default_locale ).one_or_none() return project_info.get_dto() if locale == default_locale: # If locale == default_locale don't need to worry about empty translations return project_info.get_dto() default_locale = ProjectInfo.query.filter_by( project_id=project_id, locale=default_locale ).one_or_none() if default_locale is None: error_message = f"BAD DATA: no info for project {project_id}, locale: {locale}, default {default_locale}" current_app.logger.critical(error_message) raise ValueError(error_message) # Pass thru default_locale in case of partial translation return project_info.get_dto(default_locale) def get_dto(self, default_locale=ProjectInfoDTO()) -> ProjectInfoDTO: """ Get DTO for current ProjectInfo :param default_locale: The default locale string for any empty fields """ project_info_dto = ProjectInfoDTO() project_info_dto.locale = self.locale project_info_dto.name = self.name if self.name else default_locale.name project_info_dto.description = ( self.description if self.description else default_locale.description ) project_info_dto.short_description = ( self.short_description if self.short_description else default_locale.short_description ) project_info_dto.instructions = ( self.instructions if self.instructions else default_locale.instructions ) project_info_dto.per_task_instructions = ( self.per_task_instructions if self.per_task_instructions else default_locale.per_task_instructions ) return project_info_dto @staticmethod def get_dto_for_all_locales(project_id) -> List[ProjectInfoDTO]: locales = ProjectInfo.query.filter_by(project_id=project_id).all() project_info_dtos = [] for locale in locales: project_info_dto = locale.get_dto() project_info_dtos.append(project_info_dto) return project_info_dtos