Exemple #1
0
    def add_from_command_for_a_presentation_thumb_test(self, mocked_get_section_data_path):
        """
        Test the Service Item - adding a presentation, and updating the thumb path
        """
        # GIVEN: A service item, a mocked AppLocation and presentation data
        mocked_get_section_data_path.return_value = os.path.join('mocked', 'section', 'path')
        service_item = ServiceItem(None)
        service_item.has_original_files = False
        service_item.name = 'presentations'
        presentation_name = 'test.pptx'
        thumb = os.path.join('tmp', 'test', 'thumb.png')
        display_title = 'DisplayTitle'
        notes = 'Note1\nNote2\n'
        expected_thumb_path = os.path.join('mocked', 'section', 'path', 'thumbnails',
                                           md5_hash(os.path.join(TEST_PATH, presentation_name).encode('utf-8')),
                                           'thumb.png')
        frame = {'title': presentation_name, 'image': expected_thumb_path, 'path': TEST_PATH,
                 'display_title': display_title, 'notes': notes}

        # WHEN: adding presentation to service_item
        service_item.add_from_command(TEST_PATH, presentation_name, thumb, display_title, notes)

        # THEN: verify that it is setup as a Command and that the frame data matches
        self.assertEqual(service_item.service_item_type, ServiceItemType.Command, 'It should be a Command')
        self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match')
Exemple #2
0
    def add_from_command(self, path, file_name, image, display_title=None, notes=None):
        """
        Add a slide from a command.

        :param path: The title of the slide in the service item.
        :param file_name: The title of the slide in the service item.
        :param image: The command of/for the slide.
        :param display_title: Title to show in gui/webinterface, optional.
        :param notes: Notes to show in the webinteface, optional.
        """
        self.service_item_type = ServiceItemType.Command
        # If the item should have a display title but this frame doesn't have one, we make one up
        if self.is_capable(ItemCapabilities.HasDisplayTitle) and not display_title:
            display_title = translate('OpenLP.ServiceItem',
                                      '[slide {frame:d}]').format(frame=len(self.slides) + 1)
        # Update image path to match servicemanager location if file was loaded from service
        if image and not self.has_original_files and self.name == 'presentations':
            file_location = os.path.join(path, file_name)
            file_location_hash = md5_hash(file_location.encode('utf-8'))
            image = os.path.join(AppLocation.get_section_data_path(self.name), 'thumbnails', file_location_hash,
                                 ntpath.basename(image))  # TODO: Pathlib
        self.slides.append({'title': file_name, 'image': image, 'path': path, 'display_title': display_title,
                            'notes': notes, 'thumbnail': image})
        # if self.is_capable(ItemCapabilities.HasThumbnails):
        #     self.image_manager.add_image(image, ImageSource.CommandPlugins, '#000000')
        self._new_item()
Exemple #3
0
    def add_from_command(self, path, file_name, image, display_title=None, notes=None):
        """
        Add a slide from a command.

        :param path: The title of the slide in the service item.
        :param file_name: The title of the slide in the service item.
        :param image: The command of/for the slide.
        :param display_title: Title to show in gui/webinterface, optional.
        :param notes: Notes to show in the webinteface, optional.
        """
        self.service_item_type = ServiceItemType.Command
        # If the item should have a display title but this frame doesn't have one, we make one up
        if self.is_capable(ItemCapabilities.HasDisplayTitle) and not display_title:
            display_title = translate('OpenLP.ServiceItem',
                                      '[slide {frame:d}]').format(frame=len(self._raw_frames) + 1)
        # Update image path to match servicemanager location if file was loaded from service
        if image and not self.has_original_files and self.name == 'presentations':
            file_location = os.path.join(path, file_name)
            file_location_hash = md5_hash(file_location.encode('utf-8'))
            image = os.path.join(AppLocation.get_section_data_path(self.name), 'thumbnails',
                                 file_location_hash, ntpath.basename(image))
        self._raw_frames.append({'title': file_name, 'image': image, 'path': path,
                                 'display_title': display_title, 'notes': notes})
        if self.is_capable(ItemCapabilities.HasThumbnails):
            self.image_manager.add_image(image, ImageSource.CommandPlugins, '#000000')
        self._new_item()
Exemple #4
0
    def test_add_from_command_for_a_presentation_thumb(
            self, mocked_get_section_data_path, mocked_image_manager):
        """
        Test the Service Item - adding a presentation, updating the thumb path & adding the thumb to image_manager
        """
        # GIVEN: A service item, a mocked AppLocation and presentation data
        mocked_get_section_data_path.return_value = Path(
            'mocked') / 'section' / 'path'
        service_item = ServiceItem(None)
        service_item.add_capability(ItemCapabilities.HasThumbnails)
        service_item.has_original_files = False
        service_item.name = 'presentations'
        presentation_name = 'test.pptx'
        thumb = Path('tmp') / 'test' / 'thumb.png'
        display_title = 'DisplayTitle'
        notes = 'Note1\nNote2\n'
        expected_thumb_path = Path('mocked') / 'section' / 'path' / 'thumbnails' / \
            md5_hash(str(TEST_PATH / presentation_name).encode('utf8')) / 'thumb.png'
        frame = {
            'title': presentation_name,
            'image': str(expected_thumb_path),
            'path': str(TEST_PATH),
            'display_title': display_title,
            'notes': notes,
            'thumbnail': str(expected_thumb_path)
        }

        # WHEN: adding presentation to service_item
        service_item.add_from_command(str(TEST_PATH), presentation_name, thumb,
                                      display_title, notes)

        # THEN: verify that it is setup as a Command and that the frame data matches
        assert service_item.service_item_type == ServiceItemType.Command, 'It should be a Command'
        assert service_item.get_frames()[0] == frame, 'Frames should match'
    def test_qmd5_non_ascii_string(self):
        """
        Test MD5 hash with non-ascii string - bug 1417809
        """
        # WHEN: Non-ascii string is hashed
        hash_ = md5_hash(data=test_non_ascii_string.encode('utf-8'))

        # THEN: Valid MD5 hash should be returned
        self.assertEqual(hash_, test_non_ascii_hash, 'Qt-MD5 should have returned a valid hash')
    def test_md5_hash_bad(self):
        """
        Test MD5 hash from salt+data fail (python)
        """
        # WHEN: Given a different salt+hash
        hash_ = md5_hash(salt=pin.encode('utf-8'), data=salt.encode('utf-8'))

        # THEN: return data is different
        self.assertNotEquals(hash_, test_hash, 'MD5 should have returned a bad hash')
    def test_md5_hash(self):
        """
        Test MD5 hash from salt+data pass (python)
        """
        # WHEN: Given a known salt+data
        hash_ = md5_hash(salt=salt.encode('utf-8'), data=pin.encode('utf-8'))

        # THEN: Validate return has is same
        self.assertEquals(hash_, test_hash, 'MD5 should have returned a good hash')
    def test_qmd5_non_ascii_string(self):
        """
        Test MD5 hash with non-ascii string - bug 1417809
        """
        # WHEN: Non-ascii string is hashed
        hash_ = md5_hash(data=test_non_ascii_string.encode('utf-8'))

        # THEN: Valid MD5 hash should be returned
        assert hash_ == test_non_ascii_hash, 'Qt-MD5 should have returned a valid hash'
    def test_md5_hash_bad(self):
        """
        Test MD5 hash from salt+data fail (python)
        """
        # WHEN: Given a different salt+hash
        hash_ = md5_hash(salt=pin.encode('utf-8'), data=salt.encode('utf-8'))

        # THEN: return data is different
        assert hash_ is not test_hash, 'MD5 should have returned a bad hash'
    def test_md5_hash(self):
        """
        Test MD5 hash from salt+data pass (python)
        """
        # WHEN: Given a known salt+data
        hash_ = md5_hash(salt=salt.encode('utf-8'), data=pin.encode('utf-8'))

        # THEN: Validate return has is same
        assert hash_ == test_hash, 'MD5 should have returned a good hash'
Exemple #11
0
    def test_md5_non_ascii_string(self):
        """
        Test MD5 hash with non-ascii string - bug 1417809
        """
        # WHEN: Non-ascii string is hashed
        hash_ = md5_hash(salt=test_non_ascii_string.encode('utf-8'), data=None)

        # THEN: Valid MD5 hash should be returned
        self.assertEqual(hash_, test_non_ascii_hash,
                         'MD5 should have returned a valid hash')
Exemple #12
0
    def test_md5_hash_bad(self):
        """
        Test MD5 hash from salt+data fail (python)
        """
        # WHEN: Given a different salt+hash
        hash_ = md5_hash(salt=pin.encode('ascii'), data=salt.encode('ascii'))

        # THEN: return data is different
        self.assertNotEquals(hash_, test_hash,
                             'MD5 should have returned a bad hash')
Exemple #13
0
 def get_temp_folder(self):
     """
     The location where thumbnail images will be stored
     """
     # TODO: If statement can be removed when the upgrade path from 2.0.x to 2.2.x is no longer needed
     if Settings().value('presentations/thumbnail_scheme') == 'md5':
         folder = md5_hash(self.file_path.encode('utf-8'))
     else:
         folder = folder = self.get_file_name()
     return os.path.join(self.controller.temp_folder, folder)
 def get_temp_folder(self):
     """
     The location where thumbnail images will be stored
     """
     # TODO: If statement can be removed when the upgrade path from 2.0.x to 2.2.x is no longer needed
     if Settings().value('presentations/thumbnail_scheme') == 'md5':
         folder = md5_hash(self.file_path.encode('utf-8'))
     else:
         folder = folder = self.get_file_name()
     return os.path.join(self.controller.temp_folder, folder)
    def get_temp_folder(self):
        """
        The location where thumbnail images will be stored

        :return: The path to the temporary file folder
        :rtype: openlp.core.common.path.Path
        """
        # TODO: Can be removed when the upgrade path to OpenLP 3.0 is no longer needed, also ensure code in
        #       get_thumbnail_folder and PresentationPluginapp_startup is removed
        if Settings().value('presentations/thumbnail_scheme') == 'md5':
            folder = md5_hash(bytes(self.file_path))
        else:
            folder = self.file_path.name
        return Path(self.controller.temp_folder, folder)
Exemple #16
0
    def check_login(self, data=None):
        """
        Processes the initial connection and authentication (if needed).
        Starts poll timer if connection is established.

        NOTE: Qt md5 hash function doesn't work with projector authentication. Use the python md5 hash function.

        :param data: Optional data if called from another routine
        """
        log.debug('({ip}) check_login(data="{data}")'.format(ip=self.ip,
                                                             data=data))
        if data is None:
            # Reconnected setup?
            if not self.waitForReadyRead(2000):
                # Possible timeout issue
                log.error('({ip}) Socket timeout waiting for login'.format(
                    ip=self.ip))
                self.change_status(E_SOCKET_TIMEOUT)
                return
            read = self.readLine(self.maxSize)
            dontcare = self.readLine(
                self.maxSize)  # Clean out the trailing \r\n
            if read is None:
                log.warning(
                    '({ip}) read is None - socket error?'.format(ip=self.ip))
                return
            elif len(read) < 8:
                log.warning('({ip}) Not enough data read)'.format(ip=self.ip))
                return
            data = decode(read, 'ascii')
            # Possibility of extraneous data on input when reading.
            # Clean out extraneous characters in buffer.
            dontcare = self.readLine(self.maxSize)
            log.debug('({ip}) check_login() read "{data}"'.format(
                ip=self.ip, data=data.strip()))
        # At this point, we should only have the initial login prompt with
        # possible authentication
        # PJLink initial login will be:
        # 'PJLink 0' - Unauthenticated login - no extra steps required.
        # 'PJLink 1 XXXXXX' Authenticated login - extra processing required.
        if not data.upper().startswith('PJLINK'):
            # Invalid response
            return self.disconnect_from_host()
        if '=' in data:
            # Processing a login reply
            data_check = data.strip().split('=')
        else:
            # Process initial connection
            data_check = data.strip().split(' ')
        log.debug('({ip}) data_check="{data}"'.format(ip=self.ip,
                                                      data=data_check))
        # Check for projector reporting an error
        if data_check[1].upper() == 'ERRA':
            # Authentication error
            self.disconnect_from_host()
            self.change_status(E_AUTHENTICATION)
            log.debug(
                '({ip}) emitting projectorAuthentication() signal'.format(
                    ip=self.name))
            return
        elif data_check[1] == '0' and self.pin is not None:
            # Pin set and no authentication needed
            log.warning(
                '({ip}) Regular connection but PIN set'.format(ip=self.name))
            self.disconnect_from_host()
            self.change_status(E_AUTHENTICATION)
            log.debug(
                '({ip}) Emitting projectorNoAuthentication() signal'.format(
                    ip=self.name))
            self.projectorNoAuthentication.emit(self.name)
            return
        elif data_check[1] == '1':
            # Authenticated login with salt
            if self.pin is None:
                log.warning(
                    '({ip}) Authenticated connection but no pin set'.format(
                        ip=self.name))
                self.disconnect_from_host()
                self.change_status(E_AUTHENTICATION)
                log.debug(
                    '({ip}) Emitting projectorAuthentication() signal'.format(
                        ip=self.name))
                self.projectorAuthentication.emit(self.name)
                return
            else:
                log.debug('({ip}) Setting hash with salt="{data}"'.format(
                    ip=self.ip, data=data_check[2]))
                log.debug('({ip}) pin="{data}"'.format(ip=self.ip,
                                                       data=self.pin))
                salt = md5_hash(salt=data_check[2].encode('ascii'),
                                data=self.pin.encode('ascii'))
        else:
            salt = None
        # We're connected at this point, so go ahead and do regular I/O
        self.readyRead.connect(self.get_data)
        self.projectorReceivedData.connect(self._send_command)
        # Initial data we should know about
        self.send_command(cmd='CLSS', salt=salt)
        self.waitForReadyRead()
        if (not self.no_poll) and (self.state() == self.ConnectedState):
            log.debug('({ip}) Starting timer'.format(ip=self.ip))
            self.timer.setInterval(
                2000)  # Set 2 seconds for initial information
            self.timer.start()