mirror of https://github.com/DJ2LS/FreeDATA.git
commit
4bed7da019
|
@ -22,39 +22,6 @@ async def get_freedata_message(message_id: str, request: Request):
|
|||
return api_response(message)
|
||||
|
||||
|
||||
@router.post("/messages", summary="Transmit Message", tags=["FreeDATA"], responses={
|
||||
200: {
|
||||
"description": "Message transmitted successfully.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"example": {
|
||||
"destination": "XX1XXX-6",
|
||||
"body": "Hello FreeDATA"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
404: {
|
||||
"description": "The requested resource was not found.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"example": {
|
||||
"error": "Resource not found."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
503: {
|
||||
"description": "Modem not running or busy.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"example": {
|
||||
"error": "Modem not running."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
async def post_freedata_message(request: Request):
|
||||
"""
|
||||
Transmit a FreeDATA message.
|
||||
|
|
|
@ -230,14 +230,17 @@ class CONFIG:
|
|||
# self.log.info("[CFG] reading...")
|
||||
if not self.config_exists():
|
||||
return False
|
||||
|
||||
# at first just copy the config as read from file
|
||||
result = {s: dict(self.parser.items(s)) for s in self.parser.sections()}
|
||||
try:
|
||||
# at first just copy the config as read from file
|
||||
result = {s: dict(self.parser.items(s)) for s in self.parser.sections()}
|
||||
|
||||
# handle the special settings
|
||||
for section in result:
|
||||
for setting in result[section]:
|
||||
result[section][setting] = self.handle_setting(
|
||||
section, setting, result[section][setting], False)
|
||||
# handle the special settings
|
||||
for section in result:
|
||||
for setting in result[section]:
|
||||
result[section][setting] = self.handle_setting(
|
||||
section, setting, result[section][setting], False)
|
||||
return result
|
||||
except Exception as conferror:
|
||||
self.log.error("[CFG] reading logfile", e=conferror)
|
||||
return False
|
||||
|
||||
return result
|
||||
|
|
|
@ -70,4 +70,88 @@ class DatabaseManagerAttachments(DatabaseManager):
|
|||
self.log(f"Error fetching attachment with SHA-512 hash {hash_sha512}: {e}", isWarning=True)
|
||||
return None
|
||||
finally:
|
||||
session.remove()
|
||||
session.remove()
|
||||
|
||||
def delete_attachments_by_message_id(self, message_id):
|
||||
"""
|
||||
Deletes attachment associations for a given message ID.
|
||||
|
||||
For each attachment linked to the message:
|
||||
- If the attachment is linked to more than one message, only the association for this message is deleted.
|
||||
- If the attachment is linked only to this message, both the association and the attachment record are deleted.
|
||||
|
||||
Parameters:
|
||||
message_id (str): The ID of the message whose attachment associations should be deleted.
|
||||
|
||||
Returns:
|
||||
bool: True if the deletion was successful, False otherwise.
|
||||
"""
|
||||
session = self.get_thread_scoped_session()
|
||||
try:
|
||||
# Find all attachment associations for the given message ID.
|
||||
links = session.query(MessageAttachment).filter_by(message_id=message_id).all()
|
||||
if not links:
|
||||
self.log(f"No attachments linked with message ID {message_id} found.")
|
||||
return True
|
||||
|
||||
for link in links:
|
||||
# Count how many associations exist for this attachment.
|
||||
link_count = session.query(MessageAttachment).filter_by(attachment_id=link.attachment_id).count()
|
||||
if link_count > 1:
|
||||
# More than one link exists, so only remove the association.
|
||||
session.delete(link)
|
||||
self.log(
|
||||
f"Deleted link for attachment '{link.attachment.name}' from message {message_id} (other links exist).")
|
||||
else:
|
||||
# Only one link exists, so delete both the association and the attachment.
|
||||
session.delete(link)
|
||||
session.delete(link.attachment)
|
||||
self.log(f"Deleted attachment '{link.attachment.name}' from message {message_id} (only link).")
|
||||
|
||||
session.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
self.log(f"Error deleting attachments for message ID {message_id}: {e}", isWarning=True)
|
||||
return False
|
||||
finally:
|
||||
session.remove()
|
||||
|
||||
|
||||
def clean_orphaned_attachments(self):
|
||||
"""
|
||||
Checks for orphaned attachments in the database, i.e. attachments that have no
|
||||
MessageAttachment links to any messages. Optionally, deletes these orphaned attachments.
|
||||
|
||||
Parameters:
|
||||
cleanup (bool): If True, deletes the orphaned attachments; if False, only returns them.
|
||||
|
||||
Returns:
|
||||
If cleanup is False:
|
||||
list: A list of dictionaries representing the orphaned attachments.
|
||||
If cleanup is True:
|
||||
dict: A summary dictionary with the count of deleted attachments.
|
||||
"""
|
||||
session = self.get_thread_scoped_session()
|
||||
try:
|
||||
orphaned = []
|
||||
# Get all attachments in the database.
|
||||
attachments = session.query(Attachment).all()
|
||||
for attachment in attachments:
|
||||
# Count the number of MessageAttachment links for this attachment.
|
||||
link_count = session.query(MessageAttachment).filter_by(attachment_id=attachment.id).count()
|
||||
if link_count == 0:
|
||||
orphaned.append(attachment)
|
||||
|
||||
for attachment in orphaned:
|
||||
self.log(f"Deleting orphaned attachment: {attachment.name}")
|
||||
session.delete(attachment)
|
||||
self.log(f"Checked for orphaned attachments")
|
||||
session.commit()
|
||||
return {'status': 'success', 'deleted_count': len(orphaned)}
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
self.log(f"Error checking orphaned attachments: {e}", isWarning=True)
|
||||
return None
|
||||
finally:
|
||||
session.remove()
|
||||
|
|
|
@ -222,23 +222,30 @@ class DatabaseManagerMessages(DatabaseManager):
|
|||
return None
|
||||
|
||||
def delete_message(self, message_id):
|
||||
|
||||
# Delete attachment links associated with this message.
|
||||
# This call will check each attachment link:
|
||||
# - If the attachment is used by other messages, only the link is removed.
|
||||
# - If the attachment is solely linked to this message, the attachment record is deleted.
|
||||
self.attachments_manager.delete_attachments_by_message_id(message_id)
|
||||
|
||||
|
||||
session = self.get_thread_scoped_session()
|
||||
try:
|
||||
message = session.query(P2PMessage).filter_by(id=message_id).first()
|
||||
if message:
|
||||
session.delete(message)
|
||||
session.commit()
|
||||
|
||||
self.log(f"Deleted: {message_id}")
|
||||
self.event_manager.freedata_message_db_change(message_id=message_id)
|
||||
return {'status': 'success', 'message': f'Message {message_id} deleted'}
|
||||
else:
|
||||
return {'status': 'failure', 'message': 'Message not found'}
|
||||
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
self.log(f"Error deleting message with ID {message_id}: {e}", isWarning=True)
|
||||
return {'status': 'failure', 'message': 'error deleting message'}
|
||||
|
||||
finally:
|
||||
session.remove()
|
||||
|
||||
|
|
|
@ -88,6 +88,48 @@ class ScheduleManager:
|
|||
print(e)
|
||||
|
||||
def push_to_explorer(self):
|
||||
"""
|
||||
|
||||
Exception in thread Thread-5 (run):
|
||||
Traceback (most recent call last):
|
||||
File "/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py", line 1045, in _bootstrap_inner
|
||||
self.run()
|
||||
File "/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/threading.py", line 982, in run
|
||||
self._target(*self._args, **self._kwargs)
|
||||
File "/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/sched.py", line 151, in run
|
||||
action(*argument, **kwargs)
|
||||
File "/Users/simonlang/PycharmProjects/FreeDATA/freedata_server/schedule_manager.py", line 42, in schedule_event
|
||||
event_function() # Execute the event function
|
||||
^^^^^^^^^^^^^^^^
|
||||
File "/Users/simonlang/PycharmProjects/FreeDATA/freedata_server/schedule_manager.py", line 91, in push_to_explorer
|
||||
self.config = self.config_manager.read()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/simonlang/PycharmProjects/FreeDATA/freedata_server/config.py", line 235, in read
|
||||
result = {s: dict(self.parser.items(s)) for s in self.parser.sections()}
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/simonlang/PycharmProjects/FreeDATA/freedata_server/config.py", line 235, in <dictcomp>
|
||||
result = {s: dict(self.parser.items(s)) for s in self.parser.sections()}
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/configparser.py", line 875, in items
|
||||
return [(option, value_getter(option)) for option in orig_keys]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
2025-02-28 17:14:49 [info ] [DatabaseManagerMessages]: Updating station list with DJ2LS-0
|
||||
File "/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/configparser.py", line 875, in <listcomp>
|
||||
return [(option, value_getter(option)) for option in orig_keys]
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/configparser.py", line 871, in <lambda>
|
||||
value_getter = lambda option: self._interpolation.before_get(self,
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/configparser.py", line 396, in before_get
|
||||
self._interpolate_some(parser, option, L, value, section, defaults, 1)
|
||||
File "/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/configparser.py", line 413, in _interpolate_some
|
||||
p = rest.find("%")
|
||||
^^^^^^^^^
|
||||
AttributeError: 'list' object has no attribute 'find'
|
||||
|
||||
|
||||
|
||||
"""
|
||||
self.config = self.config_manager.read()
|
||||
if self.config['STATION']['enable_explorer'] and self.state_manager.is_modem_running:
|
||||
try:
|
||||
|
|
|
@ -25,6 +25,7 @@ import structlog
|
|||
|
||||
|
||||
from message_system_db_manager import DatabaseManager
|
||||
from message_system_db_attachments import DatabaseManagerAttachments
|
||||
from schedule_manager import ScheduleManager
|
||||
|
||||
from api.general import router as general_router
|
||||
|
@ -206,6 +207,8 @@ def main():
|
|||
app.modem_service.put("start")
|
||||
DatabaseManager(app.event_manager).initialize_default_values()
|
||||
DatabaseManager(app.event_manager).database_repair_and_cleanup()
|
||||
DatabaseManagerAttachments(app.event_manager).clean_orphaned_attachments()
|
||||
|
||||
app.wsm = websocket_manager.wsm()
|
||||
app.wsm.startWorkerThreads(app)
|
||||
|
||||
|
|
Loading…
Reference in New Issue