Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

database: change reassignment selection to modal dialogue (defunct..) #965

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions database/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
10 changes: 9 additions & 1 deletion database/plugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
23 changes: 22 additions & 1 deletion database/webif/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand Down Expand Up @@ -271,7 +293,6 @@ def db_sqldump(self):

return


@cherrypy.expose
def cleanup(self):
self.plugin.cleanup()
Expand Down
37 changes: 37 additions & 0 deletions database/webif/static/style.css
Original file line number Diff line number Diff line change
@@ -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;
}
4 changes: 3 additions & 1 deletion database/webif/templates/base_database.html
Original file line number Diff line number Diff line change
Expand Up @@ -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( {
Expand All @@ -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 %}

Expand Down
68 changes: 67 additions & 1 deletion database/webif/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
{% set dataSet = 'overview' %}
{% set tab1title = _('Database Items') %}

{% block pluginstyles %}
<link rel="stylesheet" href="static/style.css">
{% endblock pluginstyles %}

{%- block pluginscripts %}
{{ super() }}
<script>
Expand Down Expand Up @@ -158,6 +162,63 @@

{% set tab3title = _('Verwaiste Items') %}
{% block bodytab3 %}

<script type="text/javascript">
function reassignOrphan(selObj) {
// get modal box data from elements
var orphanID = document.getElementById('orphan-item-id').textContent;
var orphanItem = document.getElementById('orphan-item-name').textContent;
var newID = document.getElementById('orphanSelect').value;
var newItem = document.getElementById('orphanSelect').selectedOptions[0].text;

// reset elements (just to be sure...)
document.getElementById('orphan-item-id').textContent = "";
document.getElementById('orphan-item-name').textContent = "";
document.getElementById('orphanSelect').selectedIndex = 0;

var mydata = {"orphan_id": orphanID, "new_id": newID};
$.ajax({
type: "POST",
url: "reassign",
data: JSON.stringify(mydata),
contentType: 'application/json',
dataType: 'json',
error: function() {
alert("Fehler beim Übermitteln der Daten. Bitte shng-Log prüfen!");
document.getElementById('orphanModal').style.display = 'none';
},
success: function() {
document.getElementById('orphanModal').style.display = 'none';
// reload page to reflect recalculated orphans
setTimeout(window.location.reload(), 3000);
}
})
}
</script>

<div id="orphanModal" class="or-modal">
<div class="or-modal-content">
<span class="or-close" onclick="document.getElementById('orphanModal').style.display = 'none';">&times;</span>
<div>
<strong>Neuzuweisen von Itemreihe <span id='orphan-item-name'></span> (ID <span id='orphan-item-id'></span>)</strong>
</div>
<div>
<span>Bitte wählen Sie die Itemreihe aus, der die verwaisten Daten zugewiesen werden sollen: </span>
<select id="orphanSelect" name="{{ item }}_reassign" onchange="btn = document.getElementById('orphanAssignBtn'); if (this.value == -1) { btn.disabled = true; } else { btn.disabled = false; }">
<option value=-1 selected="selected"></option>
{% for newitem in items %}
{% set newitemid = p.id(newitem, create=False) %}
{% if p.has_iattr(newitem.conf, 'database') %}
<option value={{ newitemid }}>{{ newitem.property.path }} ({{ newitemid }})</option>
{% endif %}
{% endfor %}
</select>
<button type="button" id="orphanAssignBtn" disabled class="btn btn-danger btn-sm" onclick="reassignOrphan()">Zuweisen</button>
<button type="button" class="btn btn-shng btn-sm" onclick="document.getElementById('orphanModal').style.display = 'none';">Abbrechen</button>
</div>
</div>
</div>

<div class="container-fluid m-2 table-resize">
<div id="webif-orphanbuttons" style="margin-left: 10px; margin-bottom: 10px; float:right; white-space: nowrap;" class="mb-2">
{% if p.remove_orphan or len(p.orphanlist) == 0 %}
Expand All @@ -174,13 +235,15 @@
<th>{{ _('Letzte Änderung') }}</th>
<th>{{ _('Typ') }}</th>
<th class="dt-head-right" title="{{ _('Item-ID in der Datenbank') }}">{{ _('DB-ID') }}</th>
<th>{{ _('Neuzuweisung') }}</th>
{% if p.count_logentries %}
<th class="logcount dt-head-right">{{ _('Anzahl Einträge') }}</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for item in p.orphanlist %}
{% set itemid = p.id(item, create=False) %}
<tr>
<td></td>
<td id="{{ item }}_orphan_path">{{ item }}</td>
Expand All @@ -199,7 +262,10 @@
{% endif %}
{% endif %}</td>
<td id="{{ item }}_orphan_type">{{ _(p.db_itemtype(item)) }}</td>
<td id="{{ item }}_orphan_id">{{ p.id(item, create=False) }}</td>
<td id="{{ item }}_orphan_id">{{ itemid }}</td>
<td id="{{ item }}_orphan_reassign">
<button type="button" id="orphanBtn" class="btn btn-danger btn-sm" value="{{ itemid }}-{{ item }}" onclick="document.getElementById('orphan-item-name').textContent = '{{ item }}'; document.getElementById('orphan-item-id').textContent = '{{ itemid }}'; document.getElementById('orphanModal').style.display = 'block';"><i class="fas fa-share"></i></button>
</td>
{% if p.count_logentries %}
<td id="{{ item }}_orphan_logcount">{{ p._orphan_logcount[p.id(item, create=False)] }}</td>
{% endif %}
Expand Down
Loading