diff --git a/database/__init__.py b/database/__init__.py index 4593d1e50..2f2fd9eee 100755 --- a/database/__init__.py +++ b/database/__init__.py @@ -51,7 +51,7 @@ class Database(SmartPlugin): """ ALLOW_MULTIINSTANCE = True - PLUGIN_VERSION = '1.6.12' + PLUGIN_VERSION = '1.6.13' # SQL queries: {item} = item table name, {log} = log table name # time, item_id, val_str, val_num, val_bool, changed @@ -104,6 +104,7 @@ def __init__(self, sh, *args, **kwargs): self._precision = self.get_parameter_value('precision') self.count_logentries = self.get_parameter_value('count_logentries') self.max_delete_logentries = self.get_parameter_value('max_delete_logentries') + self.max_reassign_logentries = self.get_parameter_value('max_reassign_logentries') self._default_maxage = float(self.get_parameter_value('default_maxage')) self._copy_database = self.get_parameter_value('copy_database') @@ -967,6 +968,38 @@ def _count_orphanlogentries(self): return + def reassign_orphaned_id(self, orphan_id, to): + """ + Reassign values from orphaned item ID to given item ID + + :param orphan_id: item id of the orphaned item + :param to: item id of the target item + :type orphan_id: int + :type to: int + """ + log_info = self.logger.warning # info + log_debug = self.logger.error # debug + try: + log_info(f'reassigning orphaned data from (old) id {orphan_id} to (new) id {to}') + cur = self._db_maint.cursor() + count = self.readLogCount(orphan_id, cur=cur) + log_debug(f'found {count} entries to reassign, reassigning {self.max_reassign_logentries} at once') + + while count > 0: + log_debug(f'reassigning {min(count, self.max_reassign_logentries)} log entries') + self._execute(self._prepare("UPDATE {log} SET item_id = :newid WHERE item_id = :orphanid LIMIT :limit;"), {'newid': to, 'orphanid': orphan_id, 'limit': self.max_reassign_logentries}, cur=cur) + count -= self.max_reassign_logentries + + self._execute(self._prepare("DELETE FROM {item} WHERE id = :orphanid LIMIT 1;"), {'orphanid': orphan_id}, cur=cur) + log_info(f'reassigned orphaned id {orphan_id} to new id {to}') + cur.close() + self._db_maint.commit() + log_debug('rebuilding orphan list') + self.build_orphanlist() + except Exception as e: + self.logger.error(f'error on reassigning id {orphan_id} to {to}: {e}') + return e + def _delete_orphan(self, item_path): """ Delete orphan item or logentries it @@ -1184,7 +1217,7 @@ def _expression(self, func): expression['finalizer'] = func[:func.index(":")] func = func[func.index(":") + 1:] if func == 'count' or func.startswith('count'): - parts = re.match('(count)((<>|!=|<|=|>)(\d+))?', func) + parts = re.match(r'(count)((<>|!=|<|=|>)(\d+))?', func) func = 'count' if parts and parts.group(3) is not None: expression['params']['op'] = parts.group(3) diff --git a/database/plugin.yaml b/database/plugin.yaml index 3f4cbbafe..50f3e59fb 100755 --- a/database/plugin.yaml +++ b/database/plugin.yaml @@ -11,7 +11,7 @@ plugin: keywords: database support: https://knx-user-forum.de/forum/supportforen/smarthome-py/1021844-neues-database-plugin - version: 1.6.12 # Plugin version + version: 1.6.13 # Plugin version sh_minversion: '1.9.3.2' # minimum shNG version to use this plugin # sh_maxversion: # maximum shNG version to use this plugin (leave empty if latest) multi_instance: True # plugin supports multi instance @@ -72,6 +72,14 @@ parameters: de: "Maximal auf einmal zu löschende Anzahl an Log Einträgen mit dem database_maxage Attribut, reduziert die Belastung der Datenbank bei alten Datenbeständen" en: "Maximum number of Logentries to delete at once with database_maxage attribute, reduces load on database with old datasets" + max_reassign_logentries: + type: int + default: 20 # 000 + valid_min: 10 # 00 + description: + de: "Maximal auf einmal neu zuzuweisende Anzahl an Log Einträgen, reduziert die Belastung der Datenbank bei großen Datenbeständen" + en: "Maximum number of Logentries to reassign at once, reduces load on database with large datasets" + default_maxage: type: int default: 0 diff --git a/database/webif/__init__.py b/database/webif/__init__.py index 9c9178391..1fef30513 100755 --- a/database/webif/__init__.py +++ b/database/webif/__init__.py @@ -130,6 +130,28 @@ def index(self, reload=None, action=None, item_id=None, item_path=None, time_end tabcount=2, action=action, item_id=item_id, delete_triggered=delete_triggered, language=self.plugin.get_sh().get_defaultlanguage()) + @cherrypy.expose + def reassign(self): + cl = cherrypy.request.headers['Content-Length'] + if not cl: + return + try: + rawbody = cherrypy.request.body.read(int(cl)) + data = json.loads(rawbody) + except Exception: + return + orphan_id = data.get("orphan_id") + new_id = data.get("new_id") + result = {"operation": "request", "result": "success"} + if orphan_id is not None and new_id is not None and orphan_id != new_id: + self.logger.info(f'reassigning orphaned id {orphan_id} to new id {new_id}') + err = self.plugin.reassign_orphaned_id(orphan_id, to=new_id) + if err: + return + return json.dumps(result) + else: + self.logger.warning(f'reassigning orphaned id {orphan_id} to new id {new_id} failed') + @cherrypy.expose def get_data_html(self, dataSet=None, params=None): """ @@ -271,7 +293,6 @@ def db_sqldump(self): return - @cherrypy.expose def cleanup(self): self.plugin.cleanup() diff --git a/database/webif/static/style.css b/database/webif/static/style.css new file mode 100644 index 000000000..94a8b7bf9 --- /dev/null +++ b/database/webif/static/style.css @@ -0,0 +1,37 @@ +/* The Modal (background) */ +.or-modal { + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 999; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ +} + +/* Modal Content/Box */ +.or-modal-content { + background-color: #fefefe; + margin: 15% auto; /* 15% from the top and centered */ + padding: 20px; + border: 1px solid #888; + width: 80%; /* Could be more or less, depending on screen size */ +} + +/* The Close Button */ +.or-close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; +} + +.or-close:hover, +.or-close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} \ No newline at end of file diff --git a/database/webif/templates/base_database.html b/database/webif/templates/base_database.html index 8a305091a..0bbea1793 100755 --- a/database/webif/templates/base_database.html +++ b/database/webif/templates/base_database.html @@ -31,7 +31,8 @@ { className: "time", targets: 2 }, { className: "type", targets: 3 }, { className: "id", targets: 4, render: $.fn.dataTable.render.number('.', ',', 0, '') }, - { className: "logcount", targets: 5, render: $.fn.dataTable.render.number('.', ',', 0, '') }, + { className: "reassign", targets: 5 }, + { className: "logcount", targets: 6, render: $.fn.dataTable.render.number('.', ',', 0, '') }, ].concat($.fn.dataTable.defaults.columnDefs)}); {% else %} orphantable = $('#orphantable').DataTable( { @@ -42,6 +43,7 @@ { className: "time", targets: 2 }, { className: "type", targets: 3 }, { className: "id", targets: 4, render: $.fn.dataTable.render.number('.', ',', 0, '') }, + { className: "reassign", targets: 5 }, ].concat($.fn.dataTable.defaults.columnDefs)}); {% endif %} diff --git a/database/webif/templates/index.html b/database/webif/templates/index.html index 6a52ed64b..173072106 100755 --- a/database/webif/templates/index.html +++ b/database/webif/templates/index.html @@ -4,6 +4,10 @@ {% set dataSet = 'overview' %} {% set tab1title = _('Database Items') %} +{% block pluginstyles %} + +{% endblock pluginstyles %} + {%- block pluginscripts %} {{ super() }} + +
+
+ × +
+ Neuzuweisen von Itemreihe (ID ) +
+
+ Bitte wählen Sie die Itemreihe aus, der die verwaisten Daten zugewiesen werden sollen: + + + +
+
+
+
{% if p.remove_orphan or len(p.orphanlist) == 0 %} @@ -174,6 +235,7 @@ {{ _('Letzte Änderung') }} {{ _('Typ') }} {{ _('DB-ID') }} + {{ _('Neuzuweisung') }} {% if p.count_logentries %} {{ _('Anzahl Einträge') }} {% endif %} @@ -181,6 +243,7 @@ {% for item in p.orphanlist %} + {% set itemid = p.id(item, create=False) %} {{ item }} @@ -199,7 +262,10 @@ {% endif %} {% endif %} {{ _(p.db_itemtype(item)) }} - {{ p.id(item, create=False) }} + {{ itemid }} + + + {% if p.count_logentries %} {{ p._orphan_logcount[p.id(item, create=False)] }} {% endif %}