backend/models/dtos/project_dto.py (471 lines of code) (raw):

from schematics import Model from schematics.exceptions import ValidationError from schematics.types import ( StringType, BaseType, IntType, BooleanType, FloatType, UTCDateTimeType, DateType, ) from schematics.types.compound import ListType, ModelType from backend.models.dtos.task_annotation_dto import TaskAnnotationDTO from backend.models.dtos.user_dto import is_known_mapping_level from backend.models.dtos.stats_dto import Pagination from backend.models.dtos.team_dto import ProjectTeamDTO from backend.models.dtos.interests_dto import InterestDTO from backend.models.postgis.statuses import ( ProjectStatus, ProjectPriority, MappingTypes, TaskCreationMode, Editors, MappingPermission, ValidationPermission, ) from backend.models.dtos.campaign_dto import CampaignDTO def is_known_project_status(value): """ Validates that Project Status is known value """ if type(value) == list: return # Don't validate the entire list, just the individual values try: ProjectStatus[value.upper()] except KeyError: raise ValidationError( f"Unknown projectStatus: {value} Valid values are {ProjectStatus.DRAFT.name}, " f"{ProjectStatus.PUBLISHED.name}, {ProjectStatus.ARCHIVED.name}" ) def is_known_project_priority(value): """ Validates Project priority is known value """ try: ProjectPriority[value.upper()] except KeyError: raise ValidationError( f"Unknown projectStatus: {value} Valid values are {ProjectPriority.LOW.name}, " f"{ProjectPriority.MEDIUM.name}, {ProjectPriority.HIGH.name}, " f"{ProjectPriority.URGENT.name}" ) def is_known_mapping_type(value): """ Validates Mapping Type is known value""" if type(value) == list: return # Don't validate the entire list, just the individual values try: MappingTypes[value.upper()] except KeyError: raise ValidationError( f"Unknown mappingType: {value} Valid values are {MappingTypes.ROADS.name}, " f"{MappingTypes.BUILDINGS.name}, {MappingTypes.WATERWAYS.name}, " f"{MappingTypes.LAND_USE.name}, {MappingTypes.OTHER.name}" ) def is_known_editor(value): """ Validates Editor is known value""" if type(value) == list: return # Don't validate the entire list, just the individual values try: Editors[value.upper()] except KeyError: raise ValidationError( f"Unknown editor: {value} Valid values are {Editors.ID.name}, " f"{Editors.JOSM.name}, {Editors.POTLATCH_2.name}, " f"{Editors.FIELD_PAPERS.name}, " f"{Editors.RAPID.name} " ) def is_known_task_creation_mode(value): """ Validates Task Creation Mode is known value """ try: TaskCreationMode[value.upper()] except KeyError: raise ValidationError( f"Unknown taskCreationMode: {value} Valid values are {TaskCreationMode.GRID.name}, " f"{TaskCreationMode.ARBITRARY.name}" ) def is_known_mapping_permission(value): """ Validates Mapping Permission String """ try: MappingPermission[value.upper()] except KeyError: raise ValidationError( f"Unknown mappingPermission: {value} Valid values are {MappingPermission.ANY.name}, " f"{MappingPermission.LEVEL.name}" ) def is_known_validation_permission(value): """ Validates Validation Permission String """ try: ValidationPermission[value.upper()] except KeyError: raise ValidationError( f"Unknown validationPermission: {value} Valid values are {ValidationPermission.ANY.name}, " f"{ValidationPermission.LEVEL.name}, {ValidationPermission.TEAMS.name}, " f"{ValidationPermission.TEAMS_LEVEL.name}" ) class DraftProjectDTO(Model): """ Describes JSON model used for creating draft project """ cloneFromProjectId = IntType(serialized_name="cloneFromProjectId") project_name = StringType(required=True, serialized_name="projectName") organisation = IntType(required=True) area_of_interest = BaseType(required=True, serialized_name="areaOfInterest") tasks = BaseType(required=False) has_arbitrary_tasks = BooleanType(required=True, serialized_name="arbitraryTasks") user_id = IntType(required=True) class ProjectInfoDTO(Model): """ Contains the localized project info""" locale = StringType(required=True) name = StringType(default="") short_description = StringType(serialized_name="shortDescription", default="") description = StringType(default="") instructions = StringType(default="") per_task_instructions = StringType( default="", serialized_name="perTaskInstructions" ) class CustomEditorDTO(Model): """ DTO to define a custom editor """ name = StringType(required=True) description = StringType() url = StringType(required=True) class ProjectDTO(Model): """ Describes JSON model for a tasking manager project """ project_id = IntType(serialized_name="projectId") project_status = StringType( required=True, serialized_name="status", validators=[is_known_project_status], serialize_when_none=False, ) project_priority = StringType( required=True, serialized_name="projectPriority", validators=[is_known_project_priority], serialize_when_none=False, ) area_of_interest = BaseType(serialized_name="areaOfInterest") aoi_bbox = ListType(FloatType, serialized_name="aoiBBOX") tasks = BaseType(serialize_when_none=False) default_locale = StringType( required=True, serialized_name="defaultLocale", serialize_when_none=False ) project_info = ModelType( ProjectInfoDTO, serialized_name="projectInfo", serialize_when_none=False ) project_info_locales = ListType( ModelType(ProjectInfoDTO), serialized_name="projectInfoLocales", serialize_when_none=False, ) mapper_level = StringType( required=True, serialized_name="mapperLevel", validators=[is_known_mapping_level], ) mapping_permission = StringType( required=True, serialized_name="mappingPermission", validators=[is_known_mapping_permission], ) validation_permission = StringType( required=True, serialized_name="validationPermission", validators=[is_known_validation_permission], ) enforce_random_task_selection = BooleanType( required=False, default=False, serialized_name="enforceRandomTaskSelection" ) private = BooleanType(required=True) changeset_comment = StringType(serialized_name="changesetComment") osmcha_filter_id = StringType(serialized_name="osmchaFilterId") due_date = UTCDateTimeType(serialized_name="dueDate") imagery = StringType() josm_preset = StringType(serialized_name="josmPreset", serialize_when_none=False) id_presets = ListType(StringType, serialized_name="idPresets", default=[]) rapid_power_user = BooleanType( serialized_name="rapidPowerUser", default=False, required=False ) mapping_types = ListType( StringType, serialized_name="mappingTypes", default=[], validators=[is_known_mapping_type], ) campaigns = ListType(ModelType(CampaignDTO), default=[]) organisation = IntType(required=True) organisation_name = StringType(serialized_name="organisationName") organisation_slug = StringType(serialized_name="organisationSlug") organisation_logo = StringType(serialized_name="organisationLogo") country_tag = ListType(StringType, serialized_name="countryTag") license_id = IntType(serialized_name="licenseId") allowed_usernames = ListType( StringType(), serialized_name="allowedUsernames", default=[] ) priority_areas = BaseType(serialized_name="priorityAreas") created = UTCDateTimeType() last_updated = UTCDateTimeType(serialized_name="lastUpdated") author = StringType() active_mappers = IntType(serialized_name="activeMappers") percent_mapped = IntType(serialized_name="percentMapped") percent_validated = IntType(serialized_name="percentValidated") percent_bad_imagery = IntType(serialized_name="percentBadImagery") task_creation_mode = StringType( required=True, serialized_name="taskCreationMode", validators=[is_known_task_creation_mode], serialize_when_none=False, ) project_teams = ListType(ModelType(ProjectTeamDTO), serialized_name="teams") mapping_editors = ListType( StringType, min_size=1, required=True, serialized_name="mappingEditors", validators=[is_known_editor], ) validation_editors = ListType( StringType, min_size=1, required=True, serialized_name="validationEditors", validators=[is_known_editor], ) custom_editor = ModelType( CustomEditorDTO, serialized_name="customEditor", serialize_when_none=False ) interests = ListType(ModelType(InterestDTO)) class ProjectFavoriteDTO(Model): """ DTO used to favorite a project """ project_id = IntType(required=True) user_id = IntType(required=True) class ProjectFavoritesDTO(Model): """ DTO to retrieve favorited projects """ def __init__(self): super().__init__() self.favorited_projects = [] favorited_projects = ListType( ModelType(ProjectDTO), serialized_name="favoritedProjects" ) class ProjectSearchDTO(Model): """ Describes the criteria users use to filter active projects""" preferred_locale = StringType(default="en") mapper_level = StringType(validators=[is_known_mapping_level]) action = StringType() mapping_types = ListType(StringType, validators=[is_known_mapping_type]) mapping_types_exact = BooleanType(required=False) project_statuses = ListType(StringType, validators=[is_known_project_status]) organisation_name = StringType() organisation_id = IntType() team_id = IntType() campaign = StringType() order_by = StringType() order_by_type = StringType() country = StringType() page = IntType(required=True) text_search = StringType() mapping_editors = ListType(StringType, validators=[is_known_editor]) validation_editors = ListType(StringType, validators=[is_known_editor]) teams = ListType(StringType()) interests = ListType(IntType()) created_by = IntType(required=False) mapped_by = IntType(required=False) favorited_by = IntType(required=False) managed_by = IntType(required=False) omit_map_results = BooleanType(required=False) last_updated_lte = StringType(required=False) last_updated_gte = StringType(required=False) created_lte = StringType(required=False) created_gte = StringType(required=False) def __hash__(self): """ Make object hashable so we can cache user searches""" hashable_mapping_types = "" if self.mapping_types: for mapping_type in self.mapping_types: hashable_mapping_types += mapping_type hashable_project_statuses = "" if self.project_statuses: for project_status in self.project_statuses: hashable_project_statuses += project_status hashable_teams = "" if self.teams: for team in self.teams: hashable_teams += team hashable_mapping_editors = "" if self.mapping_editors: for mapping_editor in self.mapping_editors: hashable_mapping_editors = hashable_mapping_editors + mapping_editor hashable_validation_editors = "" if self.validation_editors: for validation_editor in self.validation_editors: hashable_validation_editors = ( hashable_validation_editors + validation_editor ) return hash( ( self.preferred_locale, self.mapper_level, hashable_mapping_types, hashable_project_statuses, hashable_teams, self.organisation_name, self.campaign, self.page, self.text_search, hashable_mapping_editors, hashable_validation_editors, self.created_by, ) ) class ProjectSearchBBoxDTO(Model): bbox = ListType(FloatType, required=True, min_size=4, max_size=4) input_srid = IntType(required=True, choices=[4326]) preferred_locale = StringType(required=True, default="en") project_author = IntType(required=False, serialized_name="projectAuthor") class ListSearchResultDTO(Model): """ Describes one search result""" project_id = IntType(required=True, serialized_name="projectId") locale = StringType(required=True) name = StringType(default="") short_description = StringType(serialized_name="shortDescription", default="") mapper_level = StringType(required=True, serialized_name="mapperLevel") priority = StringType(required=True) organisation_name = StringType(serialized_name="organisationName") organisation_logo = StringType(serialized_name="organisationLogo") campaigns = ListType(ModelType(CampaignDTO), default=[]) percent_mapped = IntType(serialized_name="percentMapped") percent_validated = IntType(serialized_name="percentValidated") status = StringType(serialized_name="status") active_mappers = IntType(serialized_name="activeMappers") last_updated = UTCDateTimeType(serialized_name="lastUpdated") due_date = UTCDateTimeType(serialized_name="dueDate") total_contributors = IntType(serialized_name="totalContributors") country = StringType(serialize_when_none=False) class ProjectSearchResultsDTO(Model): """ Contains all results for the search criteria """ def __init__(self): """ DTO constructor initialise all arrays to empty""" super().__init__() self.results = [] self.map_results = [] map_results = BaseType(serialized_name="mapResults") results = ListType(ModelType(ListSearchResultDTO)) pagination = ModelType(Pagination) class LockedTasksForUser(Model): """ Describes all tasks locked by an individual user""" def __init__(self): """ DTO constructor initialise all arrays to empty""" super().__init__() self.locked_tasks = [] locked_tasks = ListType(IntType, serialized_name="lockedTasks") project = IntType(serialized_name="projectId") task_status = StringType(serialized_name="taskStatus") class ProjectComment(Model): """ Describes an individual user comment on a project task """ comment = StringType() comment_date = UTCDateTimeType(serialized_name="commentDate") user_name = StringType(serialized_name="userName") task_id = IntType(serialized_name="taskId") class ProjectCommentsDTO(Model): """ Contains all comments on a project """ def __init__(self): """ DTO constructor initialise all arrays to empty""" super().__init__() self.comments = [] comments = ListType(ModelType(ProjectComment)) class ProjectContribDTO(Model): date = DateType(required=True) mapped = IntType(required=True) validated = IntType(required=True) cumulative_mapped = IntType(required=False) cumulative_validated = IntType(required=False) total_tasks = IntType(required=False) class ProjectContribsDTO(Model): """ Contains all contributions on a project by day""" def __init__(self): """ DTO constructor initialise all arrays to empty""" super().__init__() self.mapping = [] self.validation = [] stats = ListType(ModelType(ProjectContribDTO)) class ProjectSummary(Model): """ Model used for PM dashboard """ project_id = IntType(required=True, serialized_name="projectId") default_locale = StringType(serialized_name="defaultLocale") author = StringType() created = UTCDateTimeType() due_date = UTCDateTimeType(serialized_name="dueDate") last_updated = UTCDateTimeType(serialized_name="lastUpdated") priority = StringType(serialized_name="projectPriority") campaigns = ListType(ModelType(CampaignDTO), default=[]) organisation = IntType() organisation_name = StringType(serialized_name="organisationName") organisation_slug = StringType(serialized_name="organisationSlug") organisation_logo = StringType(serialized_name="organisationLogo") country_tag = ListType(StringType, serialized_name="countryTag") osmcha_filter_id = StringType(serialized_name="osmchaFilterId") mapping_types = ListType( StringType, serialized_name="mappingTypes", validators=[is_known_mapping_type] ) changeset_comment = StringType(serialized_name="changesetComment") percent_mapped = IntType(serialized_name="percentMapped") percent_validated = IntType(serialized_name="percentValidated") percent_bad_imagery = IntType(serialized_name="percentBadImagery") aoi_centroid = BaseType(serialized_name="aoiCentroid") mapper_level = StringType(serialized_name="mapperLevel") mapping_permission = IntType( serialized_name="mappingPermission", validators=[is_known_mapping_permission] ) validation_permission = IntType( serialized_name="validationPermission", validators=[is_known_validation_permission], ) allowed_usernames = ListType( StringType(), serialized_name="allowedUsernames", default=[] ) random_task_selection_enforced = BooleanType( required=False, default=False, serialized_name="enforceRandomTaskSelection" ) private = BooleanType(serialized_name="private") allowed_users = ListType(StringType, serialized_name="allowedUsernames", default=[]) project_teams = ListType(ModelType(ProjectTeamDTO), serialized_name="teams") project_info = ModelType( ProjectInfoDTO, serialized_name="projectInfo", serialize_when_none=False ) short_description = StringType(serialized_name="shortDescription") status = StringType() imagery = StringType() license_id = IntType(serialized_name="licenseId") id_presets = ListType(StringType, serialized_name="idPresets", default=[]) rapid_power_user = BooleanType( serialized_name="rapidPowerUser", default=False, required=False ) mapping_editors = ListType( StringType, min_size=1, required=True, serialized_name="mappingEditors", validators=[is_known_editor], ) validation_editors = ListType( StringType, min_size=1, required=True, serialized_name="validationEditors", validators=[is_known_editor], ) custom_editor = ModelType( CustomEditorDTO, serialized_name="customEditor", serialize_when_none=False ) class PMDashboardDTO(Model): """ DTO for constructing the PM Dashboard """ def __init__(self): """ DTO constructor initialise all arrays to empty""" super().__init__() self.draft_projects = [] self.archived_projects = [] self.active_projects = [] draft_projects = ListType( ModelType(ProjectSummary), serialized_name="draftProjects" ) active_projects = ListType( ModelType(ProjectSummary), serialized_name="activeProjects" ) archived_projects = ListType( ModelType(ProjectSummary), serialized_name="archivedProjects" ) class ProjectTaskAnnotationsDTO(Model): """ DTO for task annotations of a project """ def __init__(self): """ DTO constructor set task arrays to empty """ super().__init__() self.tasks = [] project_id = IntType(required=True, serialized_name="projectId") tasks = ListType( ModelType(TaskAnnotationDTO), required=True, serialized_name="tasks" ) class ProjectStatsDTO(Model): """ DTO for detailed stats on a project """ project_id = IntType(required=True, serialized_name="projectId") area = FloatType(serialized_name="projectArea(in sq.km)") total_mappers = IntType(serialized_name="totalMappers") total_tasks = IntType(serialized_name="totalTasks") total_comments = IntType(serialized_name="totalComments") total_mapping_time = IntType(serialized_name="totalMappingTime") total_validation_time = IntType(serialized_name="totalValidationTime") total_time_spent = IntType(serialized_name="totalTimeSpent") average_mapping_time = IntType(serialized_name="averageMappingTime") average_validation_time = IntType(serialized_name="averageValidationTime") percent_mapped = IntType(serialized_name="percentMapped") percent_validated = IntType(serialized_name="percentValidated") percent_bad_imagery = IntType(serialized_name="percentBadImagery") aoi_centroid = BaseType(serialized_name="aoiCentroid") time_to_finish_mapping = IntType(serialized_name="timeToFinishMapping") time_to_finish_validating = IntType(serialized_name="timeToFinishValidating") class ProjectUserStatsDTO(Model): """ DTO for time spent by users on a project """ time_spent_mapping = IntType(serialized_name="timeSpentMapping") time_spent_validating = IntType(serialized_name="timeSpentValidating") total_time_spent = IntType(serialized_name="totalTimeSpent")