implement proper support for deleting items

This commit is contained in:
Tomas Groth 2024-04-12 22:51:57 +02:00
parent 4900281d20
commit 0669a22fd6
3 changed files with 34 additions and 18 deletions

View File

@ -27,6 +27,7 @@ from pathlib import Path
from openlp.core.common.registry import Registry
from openlp.plugins.custom.lib.customxmlhandler import CustomXML
from openlp.plugins.custom.lib.db import CustomSlide
from openlp.plugins.songs.lib import delete_song as delete_in_song_plugin
from openlp.plugins.remotesync.lib.backends.synchronizer import Synchronizer, SyncItemType, ConflictException, \
LockException, ConflictReason
from openlp.plugins.remotesync.lib.db import RemoteSyncItem
@ -315,25 +316,26 @@ class FolderSynchronizer(Synchronizer):
Check for changes in the remote/shared folder. If a changed/new item is found it is fetched using the
fetch_song method, and if a conflict is detected the mark_item_for_conflict is used. If items has been deleted
remotely, they are also deleted locally.
:return: True if one or more songs was updated, otherwise False
:return: True if one or more songs was updated or deleted, otherwise False
"""
updated = False
# Check for updated or new files
if item_type == SyncItemType.Song:
folder_path = self.song_folder_path
else:
folder_path = self.custom_folder_path
updated = False
item_files = self._get_file_list(folder_path, '*.xml')
conflicts = []
for item_file in item_files:
# skip conflicting files
if item_file in conflicts:
continue
# Check if this song is already sync'ed
# Check if this item is already sync'ed
filename = item_file.name
filename_elements = filename.split('=', 1)
uuid = filename_elements[0]
file_version = filename_elements[1].replace('.xml', '')
# Detect if there are multiple files for the same song, which would mean that we have a conflict
# Detect if there are multiple files for the same item, which would mean that we have a conflict
files = []
for item_file2 in item_files:
if uuid in str(item_file2):
@ -364,7 +366,19 @@ class FolderSynchronizer(Synchronizer):
self.mark_item_for_conflict(item_type, uuid, ce.reason)
continue
updated = True
# TODO: Check for deleted files
# Check for deleted files
if item_type == SyncItemType.Song:
deleted_folder_path = self.custom_deleted_folder_path
else:
deleted_folder_path = self.song_deleted_folder_path
deleted_item_files = self._get_file_list(deleted_folder_path, '*')
for deleted_item_file in deleted_item_files:
# if the a deleted item exists in the local database it means it must be deleted locally
sync_item = self.manager.get_object_filtered(RemoteSyncItem, RemoteSyncItem.uuid == deleted_item_file.name)
if sync_item:
updated = True
delete_in_song_plugin(sync_item.item_id, False)
self.manager.delete_all_objects(RemoteSyncItem, RemoteSyncItem.item_id == sync_item.item_id)
return updated
def _send_item(self, item_type, item_content, item_uuid, version, last_known_version, first_sync_attempt,

View File

@ -213,6 +213,9 @@ class RemoteSyncPlugin(Plugin):
song_manager = Registry().get('songs_manager')
custom_manager = Registry().get('custom_manager')
for queue_item in queue_items:
sync_item = self.manager.get_object_filtered(RemoteSyncItem,
and_(RemoteSyncItem.type == queue_item.type,
RemoteSyncItem.item_id == queue_item.item_id))
if queue_item.action == SyncItemAction.Update:
if queue_item.type == SyncItemType.Song:
item = song_manager.get_object(Song, queue_item.item_id)
@ -221,9 +224,6 @@ class RemoteSyncPlugin(Plugin):
item = custom_manager.get_object(CustomSlide, queue_item.item_id)
item_type = SyncItemType.Custom
# If item has not been sync'ed before we generate a uuid
sync_item = self.manager.get_object_filtered(RemoteSyncItem,
and_(RemoteSyncItem.type == item_type,
RemoteSyncItem.item_id == item.id))
if not sync_item:
sync_item = RemoteSyncItem()
sync_item.type = item_type
@ -255,18 +255,18 @@ class RemoteSyncPlugin(Plugin):
# Delete the item
try:
if queue_item.type == SyncItemType.Song:
version = self.synchronizer.delete_song(sync_item.uuid, sync_item.version,
version = self.synchronizer.delete_song(sync_item.uuid,
queue_item.first_attempt, queue_item.lock_id)
else:
version = self.synchronizer.delete_custom(sync_item.uuid, sync_item.version,
version = self.synchronizer.delete_custom(sync_item.uuid,
queue_item.first_attempt, queue_item.lock_id)
except ConflictException:
log.debug('Conflict detected for item %d / %s' % (sync_item.item_id, sync_item.uuid))
log.debug('Conflict detected for item %d / %s' % (item.item_id, item.uuid))
# TODO: Store the conflict in the DB and turn on the conflict icon
continue
except LockException as le:
# Store the lock time in the DB and keep it in the queue
log.debug('Lock detected for item %d / %s' % (sync_item.item_id, sync_item.uuid))
log.debug('Lock detected for item %d / %s' % (item.item_id, item.uuid))
queue_item.first_attempt = le.first_attempt
queue_item.lock_id = le.lock_id
self.manager.save_object(queue_item)

View File

@ -524,28 +524,30 @@ def strip_rtf(text, default_encoding=None):
return text, default_encoding
def delete_song(song_id, song_plugin):
def delete_song(song_id, trigger_event=True):
"""
Deletes a song from the database. Media files associated to the song are removed prior to the deletion of the song.
:param song_id: The ID of the song to delete.
:param song_plugin: The song plugin instance.
:param trigger_event: If True the song_deleted event is triggered through the registry
"""
save_path = ''
media_files = song_plugin.manager.get_all_objects(MediaFile, MediaFile.song_id == song_id)
songs_manager = Registry().get('songs_manager')
media_files = songs_manager.get_all_objects(MediaFile, MediaFile.song_id == song_id)
for media_file in media_files:
try:
media_file.file_path.unlink()
except OSError:
log.exception('Could not remove file: {name}'.format(name=media_file.file_path))
try:
save_path = AppLocation.get_section_data_path(song_plugin.name) / 'audio' / str(song_id)
save_path = AppLocation.get_section_data_path('songs') / 'audio' / str(song_id)
if save_path.exists():
save_path.rmdir()
except OSError:
log.exception('Could not remove directory: {path}'.format(path=save_path))
song_plugin.manager.delete_object(Song, song_id)
Registry().execute('song_deleted', song_id)
songs_manager.delete_object(Song, song_id)
if trigger_event:
Registry().execute('song_deleted', song_id)
def transpose_lyrics(lyrics, transpose_value):