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')
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()
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()
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'
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')
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')
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)
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()