コード例 #1
0
    def test_reset_all_tasks(self, mock_set_task_history, mock_query,
                             mock_get_project):
        user_id = 123
        test_project = MagicMock(spec=Project)
        test_project.id = 456
        test_project.tasks_mapped = 2
        test_project.tasks_validated = 2
        test_tasks = [
            MagicMock(spec=Task),
            MagicMock(spec=Task),
            MagicMock(spec=Task)
        ]

        mock_query.return_value.filter.return_value.all.return_value = test_tasks
        mock_get_project.return_value = test_project

        ProjectAdminService.reset_all_tasks(test_project.id, user_id)

        for test_task in test_tasks:
            test_task.set_task_history.assert_called()
            test_task.reset_task.assert_called_with(user_id)

        mock_get_project.assert_called_with(test_project.id)
        self.assertEqual(test_project.tasks_mapped, 0)
        self.assertEqual(test_project.tasks_validated, 0)
        test_project.save.assert_called()
コード例 #2
0
    def test_published_project_with_incomplete_default_locale_raises_error(
            self, mock_project, mock_user):
        # Arrange
        stub_project = Project()
        stub_project.status = ProjectStatus.PUBLISHED.value

        mock_project.return_value = stub_project

        locales = []
        info = ProjectInfoDTO()
        info.locale = "en"
        info.name = "Test"
        locales.append(info)

        dto = ProjectDTO()
        dto.project_id = 1
        dto.default_locale = "en"
        dto.project_info_locales = locales
        dto.project_status = ProjectStatus.PUBLISHED.name

        stub_admin_user = User()
        stub_admin_user.username = "******"
        stub_admin_user.role = UserRole.ADMIN.value

        mock_user.return_value = stub_admin_user
        # Act / Assert
        with self.assertRaises(ProjectAdminServiceError):
            ProjectAdminService.update_project(dto, mock_user.id)
コード例 #3
0
    def test_get_raises_error_if_not_found(self, mock_project):
        # Arrange
        mock_project.return_value = None

        # Act / Assert
        with self.assertRaises(NotFound):
            ProjectAdminService._get_project_by_id(12)
コード例 #4
0
    def test_attempting_to_attach_non_existant_license_raise_error(
            self, license_mock):
        # Arrange
        license_mock.side_effect = NotFound()

        with self.assertRaises(ProjectAdminServiceError):
            ProjectAdminService._validate_imagery_licence(1)
コード例 #5
0
    def test_cant_add_tasks_if_geojson_not_feature_collection(self):
        # Arrange
        invalid_feature = (
            '{"coordinates": [[[[-4.0237, 56.0904], [-3.9111, 56.1715], [-3.8122, 56.098],'
            '[-4.0237, 56.0904]]]], "type": "MultiPolygon"}')

        # Act
        with self.assertRaises(InvalidGeoJson):
            ProjectAdminService._attach_tasks_to_project(
                MagicMock(), invalid_feature)
コード例 #6
0
    def delete(self, project_id, campaign_id):
        """
        Delete a campaign for a project
        ---
        tags:
          - campaigns
        produces:
          - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: project_id
              in: path
              description: Unique project ID
              required: true
              type: integer
              default: 1
            - name: campaign_id
              in: path
              description: Unique campaign ID
              required: true
              type: integer
              default: 1
        responses:
            200:
                description: Campaign assigned successfully
            400:
                description: Client Error - Invalid Request
            401:
                description: Unauthorized - Invalid credentials
            403:
                description: Forbidden
            500:
                description: Internal Server Error
        """
        try:
            ProjectAdminService.is_user_action_permitted_on_project(
                tm.authenticated_user_id, project_id)
        except ValueError as e:
            error_msg = f"ProjectsCampaignsAPI DELETE: {str(e)}"
            return {"Error": error_msg}, 403

        try:
            CampaignService.delete_project_campaign(project_id, campaign_id)
            return {"Success": "Campaigns Deleted"}, 200
        except NotFound:
            return {"Error": "Campaign Not Found"}, 404
        except Exception as e:
            error_msg = f"ProjectsCampaignsAPI DELETE - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": error_msg}, 500
コード例 #7
0
    def test_no_project_info_for_default_locale_raises_error(self):
        # Arrange
        locales = []
        info = ProjectInfoDTO()
        info.locale = "en"
        info.name = "Test"
        locales.append(info)

        # Act / Assert
        with self.assertRaises(ProjectAdminServiceError):
            ProjectAdminService._validate_default_locale("it", locales)
コード例 #8
0
    def post(self, project_id):
        """
        Set a project as featured
        ---
        tags:
            - projects
        produces:
            - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: project_id
              in: path
              description: Unique project ID
              required: true
              type: integer
              default: 1
        responses:
            200:
                description: Featured projects
            400:
                description: Bad request
            403:
                description: Forbidden
            404:
                description: Project not found
            500:
                description: Internal Server Error
        """
        try:
            authenticated_user_id = token_auth.current_user()
            ProjectAdminService.is_user_action_permitted_on_project(
                authenticated_user_id, project_id)
        except ValueError as e:
            error_msg = f"FeaturedProjects POST: {str(e)}"
            return {"Error": error_msg}, 403

        try:
            ProjectService.set_project_as_featured(project_id)
            return {"Success": True}, 200
        except NotFound:
            return {"Error": "Project Not Found"}, 404
        except ValueError as e:
            error_msg = f"FeaturedProjects POST: {str(e)}"
            return {"Error": error_msg}, 400
        except Exception as e:
            error_msg = f"FeaturedProjects POST - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": error_msg}, 500
コード例 #9
0
    def delete(self, project_id):
        """
        Deletes a Tasking-Manager project
        ---
        tags:
            - projects
        produces:
            - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: project_id
              in: path
              description: Unique project ID
              required: true
              type: integer
              default: 1
        responses:
            200:
                description: Project deleted
            401:
                description: Unauthorized - Invalid credentials
            403:
                description: Forbidden
            404:
                description: Project not found
            500:
                description: Internal Server Error
        """
        try:
            authenticated_user_id = token_auth.current_user()
            ProjectAdminService.is_user_action_permitted_on_project(
                authenticated_user_id, project_id
            )
        except ValueError as e:
            error_msg = f"ProjectsRestAPI DELETE: {str(e)}"
            return {"Error": error_msg}, 403

        try:
            ProjectAdminService.delete_project(project_id, authenticated_user_id)
            return {"Success": "Project deleted"}, 200
        except ProjectAdminServiceError:
            return {"Error": "Project has some mapping"}, 403
        except NotFound:
            return {"Error": "Project Not Found"}, 404
        except Exception as e:
            error_msg = f"ProjectsRestAPI DELETE - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": "Unable to delete project"}, 500
コード例 #10
0
 def post(self, project_id):
     """
     Transfers a project to a new user
     ---
     tags:
         - projects
     produces:
         - application/json
     parameters:
         - in: header
           name: Authorization
           description: Base64 encoded session token
           required: true
           type: string
           default: Token sessionTokenHere==
         - name: project_id
           in: path
           description: Unique project ID
           required: true
           type: integer
           default: 1
         - in: body
           name: body
           required: true
           description: username of the new owner
           schema:
               properties:
                   username:
                     type: string
     responses:
         200:
             description: Project ownership transfered successfully
         401:
             description: Unauthorized - Invalid credentials
         403:
             description: Forbidden
         500:
             description: Internal Server Error
     """
     try:
         username = request.get_json()["username"]
         authenticated_user_id = token_auth.current_user()
         ProjectAdminService.transfer_project_to(project_id,
                                                 authenticated_user_id,
                                                 username)
         return {"Success": "Project Transfered"}, 200
     except ValueError as e:
         return {"Error": str(e)}, 403
     except Exception as e:
         error_msg = f"ProjectsActionsTransferAPI POST - unhandled error: {str(e)}"
         current_app.logger.critical(error_msg)
         return {"Error": "Unable to transfer project"}, 500
コード例 #11
0
    def post(self, project_id):
        """
        Set all bad imagery tasks as ready for mapping
        ---
        tags:
            - tasks
        produces:
            - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: project_id
              in: path
              description: Unique project ID
              required: true
              type: integer
              default: 1
        responses:
            200:
                description: All bad imagery tasks marked ready for mapping
            401:
                description: Unauthorized - Invalid credentials
            403:
                description: Forbidden
            500:
                description: Internal Server Error
        """
        try:
            authenticated_user_id = token_auth.current_user()
            ProjectAdminService.is_user_action_permitted_on_project(
                authenticated_user_id, project_id)
        except ValueError as e:
            error_msg = f"TasksActionsResetBadImageryAllAPI POST: {str(e)}"
            return {"Error": error_msg}, 403

        try:
            MappingService.reset_all_badimagery(project_id,
                                                authenticated_user_id)
            return {
                "Success": "All bad imagery tasks marked ready for mapping"
            }, 200
        except Exception as e:
            error_msg = (
                f"TasksActionsResetBadImageryAllAPI POST - unhandled error: {str(e)}"
            )
            current_app.logger.critical(error_msg)
            return {"Error": "Unable to reset tasks"}, 500
コード例 #12
0
    def get(self, project_id):
        """
        Retrieves a Tasking-Manager project
        ---
        tags:
            - projects
        produces:
            - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: project_id
              in: path
              description: Unique project ID
              required: true
              type: integer
              default: 1
        responses:
            200:
                description: Project found
            401:
                description: Unauthorized - Invalid credentials
            403:
                description: Forbidden
            404:
                description: Project not found
            500:
                description: Internal Server Error
        """
        try:
            ProjectAdminService.is_user_action_permitted_on_project(
                token_auth.current_user(), project_id
            )
        except ValueError as e:
            error_msg = f"ProjectsQueriesNoTasksAPI GET: {str(e)}"
            return {"Error": error_msg}, 403

        try:
            project_dto = ProjectAdminService.get_project_dto_for_admin(project_id)
            return project_dto.to_primitive(), 200
        except NotFound:
            return {"Error": "Project Not Found"}, 404
        except Exception as e:
            error_msg = f"Project GET - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": error_msg}, 500
コード例 #13
0
    def get_project_dto_for_mapper(
        project_id, current_user_id, locale="en", abbrev=False
    ) -> ProjectDTO:
        """
        Get the project DTO for mappers
        :param project_id: ID of the Project mapper has requested
        :param locale: Locale the mapper has requested
        :raises ProjectServiceError, NotFound
        """
        project = ProjectService.get_project_by_id(project_id)
        # if project is public and is not draft, we don't need to check permissions
        if not project.private and not project.status == ProjectStatus.DRAFT.value:
            return project.as_dto_for_mapping(current_user_id, locale, abbrev)

        is_allowed_user = True
        is_team_member = None
        is_manager_permission = False

        if current_user_id:
            is_manager_permission = ProjectAdminService.is_user_action_permitted_on_project(
                current_user_id, project_id
            )
        # Draft Projects - admins, authors, org admins & team managers permitted
        if project.status == ProjectStatus.DRAFT.value:
            if not is_manager_permission:
                is_allowed_user = False
                raise ProjectServiceError("Unable to fetch project")

        # Private Projects - allowed_users, admins, org admins &
        # assigned teams (mappers, validators, project managers), authors permitted

        if project.private and not is_manager_permission:
            is_allowed_user = False
            if current_user_id:
                is_allowed_user = (
                    len(
                        [
                            user
                            for user in project.allowed_users
                            if user.id == current_user_id
                        ]
                    )
                    > 0
                )

        if not (is_allowed_user or is_manager_permission):
            if current_user_id:
                allowed_roles = [
                    TeamRoles.MAPPER.value,
                    TeamRoles.VALIDATOR.value,
                    TeamRoles.PROJECT_MANAGER.value,
                ]
                is_team_member = TeamService.check_team_membership(
                    project_id, allowed_roles, current_user_id
                )

        if is_allowed_user or is_manager_permission or is_team_member:
            return project.as_dto_for_mapping(current_user_id, locale, abbrev)
        else:
            raise ProjectServiceError("Unable to fetch project")
コード例 #14
0
    def test_updating_a_private_project_with_no_allowed_users_causes_an_error(
            self, mock_project, mock_user):
        # Arrange
        mock_project.return_value = Project()

        dto = ProjectDTO()
        dto.private = True
        dto.allowed_usernames = []

        stub_user = User()
        stub_user.username = "******"
        stub_user.role = UserRole.ADMIN.value

        mock_user.return_value = stub_user

        with self.assertRaises(ProjectAdminServiceError):
            ProjectAdminService.update_project(dto, mock_user.id)
コード例 #15
0
    def post(self, project_id):
        """
        Reset all tasks on project back to ready, preserving history
        ---
        tags:
            - tasks
        produces:
            - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: project_id
              in: path
              description: Unique project ID
              required: true
              type: integer
              default: 1
        responses:
            200:
                description: All tasks reset
            401:
                description: Unauthorized - Invalid credentials
            403:
                description: Forbidden
            500:
                description: Internal Server Error
        """
        try:
            ProjectAdminService.is_user_action_permitted_on_project(
                tm.authenticated_user_id, project_id)
        except ValueError as e:
            error_msg = f"TasksActionsResetAllAPI POST: {str(e)}"
            return {"Error": error_msg}, 403

        try:
            ProjectAdminService.reset_all_tasks(project_id,
                                                tm.authenticated_user_id)
            return {"Success": "All tasks reset"}, 200
        except Exception as e:
            error_msg = f"TasksActionsResetAllAPI POST - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": "Unable to reset tasks"}, 500
コード例 #16
0
    def get(self):
        """
        Get all projects for logged in admin
        ---
        tags:
            - projects
        produces:
            - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - in: header
              name: Accept-Language
              description: Language user is requesting
              type: string
              required: true
              default: en
        responses:
            200:
                description: All mapped tasks validated
            401:
                description: Unauthorized - Invalid credentials
            403:
                description: Forbidden
            404:
                description: Admin has no projects
            500:
                description: Internal Server Error
        """
        try:
            authenticated_user_id = token_auth.current_user()
            orgs_dto = OrganisationService.get_organisations_managed_by_user_as_dto(
                authenticated_user_id
            )
            if len(orgs_dto.organisations) < 1:
                raise ValueError("User not a project manager")
        except ValueError as e:
            error_msg = f"ProjectsQueriesOwnerAPI GET: {str(e)}"
            return {"Error": error_msg}, 403

        try:
            search_dto = self.setup_search_dto()
            admin_projects = ProjectAdminService.get_projects_for_admin(
                authenticated_user_id,
                request.environ.get("HTTP_ACCEPT_LANGUAGE"),
                search_dto,
            )
            return admin_projects.to_primitive(), 200
        except NotFound:
            return {"Error": "No comments found"}, 404
        except Exception as e:
            error_msg = f"Project GET - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": error_msg}, 500
コード例 #17
0
    def test_updating_a_project_with_different_roles(self, mock_project,
                                                     mock_project2, mock_user):
        stub_project = Project()
        stub_project.status = ProjectStatus.DRAFT.value

        mock_project.return_value = stub_project

        locales = []
        info = ProjectInfoDTO()
        info.locale = "en"
        info.name = "Test"
        locales.append(info)

        dto = ProjectDTO()
        dto.project_id = 1
        dto.default_locale = "en"
        dto.project_status = ProjectStatus.DRAFT.name
        dto.project_priority = ProjectPriority.LOW.name
        dto.mapper_level = MappingLevel.BEGINNER.name
        dto.mapping_types = ["ROADS"]
        dto.mapping_editors = ["ID"]
        dto.validation_editors = ["ID"]
        dto.project_info_locales = locales

        stub_user = User()
        stub_user.username = "******"
        stub_user.role = UserRole.MAPPER.value

        mock_user.return_value = stub_user

        with self.assertRaises(ValueError) as e:
            ProjectAdminService.update_project(dto, mock_user.id)
        the_exception = e.exception
        self.assertTrue(isinstance(the_exception, ValueError))

        # stub_project.author_id = mock_user.id

        stub_user.username = "******"
        stub_user.role = UserRole.ADMIN.value
        mock_user.return_value = stub_user

        try:
            ProjectAdminService.update_project(dto, mock_user.id)
        except ProjectAdminServiceError:
            self.fail("update_project raised an exception with admin role")
コード例 #18
0
    def test_valid_geo_json_attaches_task_to_project(self):
        # Arrange
        valid_feature_collection = json.loads(
            '{"features": [{"geometry": {"coordinates": [[[[-4.0237, 56.0904],'
            '[-3.9111, 56.1715], [-3.8122, 56.098], [-4.0237, 56.0904]]]], "type":'
            '"MultiPolygon"}, "properties": {"x": 2402, "y": 1736, "zoom": 12, "isSquare": true}, "type":'
            '"Feature"}], "type": "FeatureCollection"}')

        test_project = Project()

        # Act
        ProjectAdminService._attach_tasks_to_project(test_project,
                                                     valid_feature_collection)

        # Assert
        self.assertEqual(
            1,
            test_project.tasks.count(),
            "One task should have been attached to project",
        )
コード例 #19
0
    def test_updating_a_private_project_with_no_allowed_users(
            self, mock_project, mock_project2, mock_user):
        # Arrange
        mock_project.return_value = Project()

        dto = ProjectDTO()
        dto.private = True
        dto.allowed_usernames = []

        stub_user = User()
        stub_user.username = "******"
        stub_user.role = UserRole.ADMIN.value

        mock_user.return_value = stub_user

        try:
            ProjectAdminService.update_project(dto, mock_user.id)
        except ProjectAdminServiceError:
            self.fail(
                "update_project raised an exception when setting it as private"
            )
コード例 #20
0
    def is_user_permitted_to_validate(project_id, user_id):
        """ Check if the user is allowed to validate on the project in scope """
        if UserService.is_user_blocked(user_id):
            return False, ValidatingNotAllowed.USER_NOT_ON_ALLOWED_LIST

        project = ProjectService.get_project_by_id(project_id)
        if project.license_id:
            if not UserService.has_user_accepted_license(user_id, project.license_id):
                return False, ValidatingNotAllowed.USER_NOT_ACCEPTED_LICENSE
        validation_permission = project.validation_permission

        # is_admin or is_author or is_org_manager or is_manager_team
        is_manager_permission = False
        if ProjectAdminService.is_user_action_permitted_on_project(user_id, project_id):
            is_manager_permission = True

        # Draft (public/private) accessible only for is_manager_permission
        if (
            ProjectStatus(project.status) == ProjectStatus.DRAFT
            and not is_manager_permission
        ):
            return False, ValidatingNotAllowed.PROJECT_NOT_PUBLISHED

        is_restriction = None
        if not is_manager_permission and validation_permission:
            is_restriction = ProjectService.evaluate_validation_permission(
                project_id, user_id, validation_permission
            )

        tasks = Task.get_locked_tasks_for_user(user_id)
        if len(tasks.locked_tasks) > 0:
            return False, ValidatingNotAllowed.USER_ALREADY_HAS_TASK_LOCKED

        is_allowed_user = None
        if project.private and not is_manager_permission:
            # Check if user is in allowed user list
            is_allowed_user = ProjectService.is_user_in_the_allowed_list(
                project.allowed_users, user_id
            )

            if is_allowed_user:
                return True, "User allowed to validate"

        if not is_manager_permission and is_restriction:
            return is_restriction
        elif project.private and not (
            is_manager_permission or is_allowed_user or not is_restriction
        ):
            return False, ValidatingNotAllowed.USER_NOT_ON_ALLOWED_LIST

        return True, "User allowed to validate"
コード例 #21
0
    def is_user_permitted_to_validate(project_id, user_id):
        """ Check if the user is allowed to validate on the project in scope """
        if UserService.is_user_blocked(user_id):
            return False, ValidatingNotAllowed.USER_NOT_ON_ALLOWED_LIST

        project = ProjectService.get_project_by_id(project_id)
        if project.license_id:
            if not UserService.has_user_accepted_license(user_id, project.license_id):
                return False, ValidatingNotAllowed.USER_NOT_ACCEPTED_LICENSE

        validation_permission = project.validation_permission

        is_manager_permission = False
        # is_admin or is_author or is_org_manager or is_manager_team
        if ProjectAdminService.is_user_action_permitted_on_project(user_id, project_id):
            is_manager_permission = True

        if (
            ProjectStatus(project.status) != ProjectStatus.PUBLISHED
            and not is_manager_permission
        ):
            return False, ValidatingNotAllowed.PROJECT_NOT_PUBLISHED

        tasks = Task.get_locked_tasks_for_user(user_id)

        if len(tasks.locked_tasks) > 0:
            return False, ValidatingNotAllowed.USER_ALREADY_HAS_TASK_LOCKED

        if project.private and not is_manager_permission:
            # Check user is in allowed users
            try:
                next(user for user in project.allowed_users if user.id == user_id)
            except StopIteration:
                return False, ValidatingNotAllowed.USER_NOT_ON_ALLOWED_LIST

            is_restriction = ProjectService.evaluate_validation_permission(
                project_id, user_id, validation_permission
            )
            if is_restriction:
                return is_restriction

        if project.validation_permission and not is_manager_permission:
            is_restriction = ProjectService.evaluate_validation_permission(
                project_id, user_id, validation_permission
            )
            if is_restriction:
                return is_restriction

        return True, "User allowed to validate"
コード例 #22
0
    def test_complete_default_locale_raises_is_valid(self):
        # Arrange
        locales = []
        info = ProjectInfoDTO()
        info.locale = "en"
        info.name = "Test"
        info.description = "Test Desc"
        info.short_description = "Short Desc"
        info.instructions = "Instruct"
        locales.append(info)

        # Act
        is_valid = ProjectAdminService._validate_default_locale("en", locales)

        # Assert
        self.assertTrue(is_valid, "Complete default locale should be valid")
コード例 #23
0
    def post_message(chat_dto: ChatMessageDTO, project_id: int,
                     authenticated_user_id: int) -> ProjectChatDTO:
        """ Save message to DB and return latest chat"""
        current_app.logger.debug("Posting Chat Message")

        if UserService.is_user_blocked(authenticated_user_id):
            raise ValueError("User is on read only mode")

        project = ProjectService.get_project_by_id(project_id)
        is_allowed_user = True
        is_manager_permission = ProjectAdminService.is_user_action_permitted_on_project(
            authenticated_user_id, project_id)
        is_team_member = False

        # Draft (public/private) accessible only for is_manager_permission
        if (ProjectStatus(project.status) == ProjectStatus.DRAFT
                and not is_manager_permission):
            raise ValueError("User not permitted to post Comment")

        if project.private:
            is_allowed_user = False
            if not is_manager_permission:
                allowed_roles = [
                    TeamRoles.PROJECT_MANAGER.value,
                    TeamRoles.VALIDATOR.value,
                    TeamRoles.MAPPER.value,
                ]
                is_team_member = TeamService.check_team_membership(
                    project_id, allowed_roles, authenticated_user_id)
                if not is_team_member:
                    is_allowed_user = (len([
                        user for user in project.allowed_users
                        if user.id == authenticated_user_id
                    ]) > 0)

        if is_manager_permission or is_team_member or is_allowed_user:
            chat_message = ProjectChat.create_from_dto(chat_dto)
            MessageService.send_message_after_chat(chat_dto.user_id,
                                                   chat_message.message,
                                                   chat_dto.project_id)
            db.session.commit()
            # Ensure we return latest messages after post
            return ProjectChat.get_messages(chat_dto.project_id, 1)
        else:
            raise ValueError("User not permitted to post Comment")
コード例 #24
0
    def is_user_permitted_to_map(project_id: int, user_id: int):
        """ Check if the user is allowed to map the on the project in scope """
        if UserService.is_user_blocked(user_id):
            return False, MappingNotAllowed.USER_NOT_ON_ALLOWED_LIST

        project = ProjectService.get_project_by_id(project_id)
        mapping_permission = project.mapping_permission

        if ProjectStatus(
                project.status
        ) != ProjectStatus.PUBLISHED and not ProjectAdminService.is_user_action_permitted_on_project(
                user_id, project_id):
            return False, MappingNotAllowed.PROJECT_NOT_PUBLISHED
        tasks = Task.get_locked_tasks_for_user(user_id)
        if len(tasks.locked_tasks) > 0:
            return False, MappingNotAllowed.USER_ALREADY_HAS_TASK_LOCKED
        if project.private:
            # Check user is in allowed users
            try:
                next(user for user in project.allowed_users
                     if user.id == user_id)
            except StopIteration:
                return False, MappingNotAllowed.USER_NOT_ON_ALLOWED_LIST
            is_restriction = ProjectService.evaluate_mapping_permission(
                project_id, user_id, mapping_permission)
            if is_restriction:
                return is_restriction

        if project.mapping_permission:
            is_restriction = ProjectService.evaluate_mapping_permission(
                project_id, user_id, mapping_permission)
            if is_restriction:
                return is_restriction

        if project.license_id:
            if not UserService.has_user_accepted_license(
                    user_id, project.license_id):
                return False, MappingNotAllowed.USER_NOT_ACCEPTED_LICENSE

        return True, "User allowed to map"
コード例 #25
0
    def post(self, project_id, campaign_id):
        """
        Assign a campaign for a project
        ---
        tags:
          - campaigns
        produces:
          - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: project_id
              in: path
              description: Unique project ID
              required: true
              type: integer
              default: 1
            - name: campaign_id
              in: path
              description: Unique campaign ID
              required: true
              type: integer
              default: 1
        responses:
            201:
                description: Campaign assigned successfully
            400:
                description: Client Error - Invalid Request
            401:
                description: Unauthorized - Invalid credentials
            403:
                description: Forbidden
            500:
                description: Internal Server Error
        """
        try:
            ProjectAdminService.is_user_action_permitted_on_project(
                tm.authenticated_user_id, project_id)
        except ValueError as e:
            error_msg = f"ProjectsCampaignsAPI POST: {str(e)}"
            return {"Error": error_msg}, 403

        try:
            campaign_project_dto = CampaignProjectDTO()
            campaign_project_dto.campaign_id = campaign_id
            campaign_project_dto.project_id = project_id
            campaign_project_dto.validate()
        except DataError as e:
            current_app.logger.error(f"error validating request: {str(e)}")
            return str(e), 400

        try:
            CampaignService.create_campaign_project(campaign_project_dto)
            message = "campaign with id {} assigned successfully for project with id {}".format(
                campaign_id, project_id)
            return ({"Success": message}, 200)
        except Exception as e:
            error_msg = f"ProjectsCampaignsAPI POST - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": error_msg}, 500
コード例 #26
0
    def post(self, project_id):
        """
        Send message to all contributors of a project
        ---
        tags:
            - projects
        produces:
            - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: project_id
              in: path
              description: Unique project ID
              required: true
              type: integer
              default: 1
            - in: body
              name: body
              required: true
              description: JSON object for creating draft project
              schema:
                properties:
                    subject:
                        type: string
                        default: Thanks
                        required: true
                    message:
                        type: string
                        default: Thanks for your contribution
                        required: true
        responses:
            200:
                description: Message sent successfully
            401:
                description: Unauthorized - Invalid credentials
            403:
                description: Forbidden
            500:
                description: Internal Server Error
        """
        try:
            authenticated_user_id = token_auth.current_user()
            message_dto = MessageDTO(request.get_json())
            message_dto.from_user_id = authenticated_user_id
            message_dto.validate()
        except DataError as e:
            current_app.logger.error(f"Error validating request: {str(e)}")
            return {"Error": "Unable to send message to mappers"}, 400

        try:
            ProjectAdminService.is_user_action_permitted_on_project(
                authenticated_user_id, project_id)
            threading.Thread(
                target=MessageService.send_message_to_all_contributors,
                args=(project_id, message_dto),
            ).start()

            return {"Success": "Messages started"}, 200
        except ValueError as e:
            return {"Error": str(e)}, 403
        except Exception as e:
            error_msg = f"Send message all - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": "Unable to send messages to mappers"}, 500
コード例 #27
0
    def post(self, project_id):
        """
        Creates a relationship between project and interests
        ---
        tags:
            - interests
        produces:
            - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: project_id
              in: path
              description: Unique project ID
              required: true
              type: integer
              default: 1
            - in: body
              name: body
              required: true
              description: JSON object for creating/updating project and interests relationships
              schema:
                  properties:
                      interests:
                          type: array
                          items:
                            type: integer
        responses:
            200:
                description: New project interest relationship created
            400:
                description: Invalid Request
            401:
                description: Unauthorized - Invalid credentials
            403:
                description: Forbidden
            500:
                description: Internal Server Error
        """
        try:
            ProjectAdminService.is_user_action_permitted_on_project(
                token_auth.current_user(), project_id)
        except ValueError as e:
            error_msg = f"ProjectsActionsSetInterestsAPI POST: {str(e)}"
            return {"Error": error_msg}, 403

        try:
            data = request.get_json()
            project_interests = InterestService.create_or_update_project_interests(
                project_id, data["interests"])
            return project_interests.to_primitive(), 200
        except NotFound:
            return {"Error": "Project not Found"}, 404
        except Exception as e:
            error_msg = (
                f"ProjectsActionsSetInterestsAPI POST - unhandled error: {str(e)}"
            )
            current_app.logger.critical(error_msg)
            return {"Error": error_msg}, 500
コード例 #28
0
    def post(self):
        """
        Creates a tasking-manager project
        ---
        tags:
            - projects
        produces:
            - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - in: body
              name: body
              required: true
              description: JSON object for creating draft project
              schema:
                properties:
                    cloneFromProjectId:
                        type: int
                        default: 1
                        description: Specify this value if you want to clone a project, otherwise avoid information
                    projectName:
                        type: string
                        default: HOT Project
                    areaOfInterest:
                        schema:
                            properties:
                                type:
                                    type: string
                                    default: FeatureCollection
                                features:
                                    type: array
                                    items:
                                        schema:
                                            $ref: "#/definitions/GeoJsonFeature"
                        tasks:
                            schema:
                                properties:
                                    type:
                                        type: string
                                        default: FeatureCollection
                                    features:
                                        type: array
                                        items:
                                            schema:
                                                $ref: "#/definitions/GeoJsonFeature"
                        arbitraryTasks:
                            type: boolean
                            default: false
        responses:
            201:
                description: Draft project created successfully
            400:
                description: Client Error - Invalid Request
            401:
                description: Unauthorized - Invalid credentials
            403:
                description: Forbidden
            500:
                description: Internal Server Error
        """
        try:
            draft_project_dto = DraftProjectDTO(request.get_json())
            draft_project_dto.user_id = token_auth.current_user()
            draft_project_dto.validate()
        except DataError as e:
            current_app.logger.error(f"error validating request: {str(e)}")
            return {"Error": "Unable to create project"}, 400

        try:
            draft_project_id = ProjectAdminService.create_draft_project(
                draft_project_dto
            )
            return {"projectId": draft_project_id}, 201
        except ProjectAdminServiceError as e:
            return {"Error": str(e)}, 403
        except (InvalidGeoJson, InvalidData):
            return {"Error": "Invalid GeoJson"}, 400
        except Exception as e:
            error_msg = f"Project PUT - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": "Unable to create project"}, 500
コード例 #29
0
    def patch(self, project_id):
        """
        Updates a Tasking-Manager project
        ---
        tags:
            - projects
        produces:
            - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: project_id
              in: path
              description: Unique project ID
              required: true
              type: integer
              default: 1
            - in: body
              name: body
              required: true
              description: JSON object for updating an existing project
              schema:
                properties:
                    projectStatus:
                        type: string
                        default: DRAFT
                    projectPriority:
                        type: string
                        default: MEDIUM
                    defaultLocale:
                        type: string
                        default: en
                    mapperLevel:
                        type: string
                        default: BEGINNER
                    validation_permission:
                        type: string
                        default: ANY
                    mapping_permission:
                        type: string
                        default: ANY
                    private:
                        type: boolean
                        default: false
                    changesetComment:
                        type: string
                        default: hotosm-project-1
                    dueDate:
                        type: date
                        default: "2017-04-11T12:38:49"
                    imagery:
                        type: string
                        default: http//www.bing.com/maps/
                    josmPreset:
                        type: string
                        default: josm preset goes here
                    mappingTypes:
                        type: array
                        items:
                            type: string
                        default: [BUILDINGS, ROADS]
                    mappingEditors:
                        type: array
                        items:
                            type: string
                        default: [ID, JOSM, POTLATCH_2, FIELD_PAPERS]
                    validationEditors:
                        type: array
                        items:
                            type: string
                        default: [ID, JOSM, POTLATCH_2, FIELD_PAPERS]
                    campaign:
                        type: string
                        default: malaria
                    organisation:
                        type: integer
                        default: 1
                    countryTag:
                          type: array
                          items:
                              type: string
                          default: []
                    licenseId:
                        type: integer
                        default: 1
                        description: Id of imagery license associated with the project
                    allowedUsernames:
                        type: array
                        items:
                            type: string
                        default: ["Iain Hunter", LindaA1]
                    priorityAreas:
                        type: array
                        items:
                            schema:
                                $ref: "#/definitions/GeoJsonPolygon"
                    projectInfoLocales:
                        type: array
                        items:
                            schema:
                                $ref: "#/definitions/ProjectInfo"
                    taskCreationMode:
                        type: integer
                        default: GRID
        responses:
            200:
                description: Project updated
            400:
                description: Client Error - Invalid Request
            401:
                description: Unauthorized - Invalid credentials
            403:
                description: Forbidden
            404:
                description: Project not found
            500:
                description: Internal Server Error
        """
        authenticated_user_id = token_auth.current_user()
        try:
            ProjectAdminService.is_user_action_permitted_on_project(
                authenticated_user_id, project_id
            )
        except ValueError as e:
            error_msg = f"ProjectsRestAPI PATCH: {str(e)}"
            return {"Error": error_msg}, 403

        try:
            project_dto = ProjectDTO(request.get_json())
            project_dto.project_id = project_id
            project_dto.validate()
        except DataError as e:
            current_app.logger.error(f"Error validating request: {str(e)}")
            return {"Error": "Unable to update project"}, 400

        try:
            ProjectAdminService.update_project(project_dto, authenticated_user_id)
            return {"Status": "Updated"}, 200
        except InvalidGeoJson as e:
            return {"Invalid GeoJson": str(e)}, 400
        except NotFound as e:
            return {"Error": str(e) or "Project Not Found"}, 404
        except Exception as e:
            error_msg = f"ProjectsRestAPI PATCH - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": "Unable to update project"}, 500