automatyzacje-comit6
This commit is contained in:
@@ -66,6 +66,44 @@ def get_rule(rule_id: int, profile_id: int, user_id: int | None = None) -> dict[
|
||||
return _rule_row(row)
|
||||
|
||||
|
||||
def _portable_rule(rule: dict[str, Any]) -> dict[str, Any]:
|
||||
return {
|
||||
'name': str(rule.get('name') or 'Automation rule'),
|
||||
'enabled': bool(rule.get('enabled', True)),
|
||||
'cooldown_minutes': max(0, int(rule.get('cooldown_minutes') or 0)),
|
||||
'conditions': list(rule.get('conditions') or []),
|
||||
'effects': list(rule.get('effects') or []),
|
||||
}
|
||||
|
||||
|
||||
def export_rules(profile_id: int, user_id: int | None = None) -> dict[str, Any]:
|
||||
# Note: Export contains only portable rule definitions, never DB ids or execution history.
|
||||
rules = [_portable_rule(rule) for rule in list_rules(profile_id, user_id)]
|
||||
return {'version': 1, 'app': 'pyTorrent', 'exported_at': utcnow(), 'rules': rules}
|
||||
|
||||
|
||||
def import_rules(profile_id: int, payload: dict[str, Any] | list[Any], user_id: int | None = None, replace: bool = False) -> list[dict[str, Any]]:
|
||||
user_id = user_id or default_user_id()
|
||||
raw_rules = payload if isinstance(payload, list) else payload.get('rules', []) if isinstance(payload, dict) else []
|
||||
if not isinstance(raw_rules, list) or not raw_rules:
|
||||
raise ValueError('Import file does not contain automation rules')
|
||||
if replace:
|
||||
with connect() as conn:
|
||||
# Note: Optional replace is profile-scoped; it does not touch other profiles or history tables.
|
||||
conn.execute('DELETE FROM automation_rules WHERE user_id=? AND profile_id=?', (user_id, profile_id))
|
||||
conn.execute('DELETE FROM automation_rule_state WHERE profile_id=?', (profile_id,))
|
||||
imported = []
|
||||
for raw in raw_rules:
|
||||
if not isinstance(raw, dict):
|
||||
continue
|
||||
rule = _portable_rule(raw)
|
||||
rule.pop('id', None)
|
||||
imported.append(save_rule(profile_id, rule, user_id))
|
||||
if not imported:
|
||||
raise ValueError('No valid automation rules found')
|
||||
return imported
|
||||
|
||||
|
||||
def save_rule(profile_id: int, data: dict[str, Any], user_id: int | None = None) -> dict[str, Any]:
|
||||
user_id = user_id or default_user_id()
|
||||
name = str(data.get('name') or 'Automation rule').strip() or 'Automation rule'
|
||||
@@ -111,6 +149,8 @@ def _condition_true(t: dict[str, Any], cond: dict[str, Any]) -> bool:
|
||||
if typ == 'completed': return bool(int(t.get('complete') or 0))
|
||||
if typ == 'no_seeds': return int(t.get('seeds') or 0) <= int(cond.get('seeds') or 0)
|
||||
if typ == 'ratio_gte': return float(t.get('ratio') or 0) >= float(cond.get('ratio') or 0)
|
||||
if typ == 'progress_gte': return float(t.get('progress') or 0) >= float(cond.get('progress') or 0)
|
||||
if typ == 'progress_lte': return float(t.get('progress') or 0) <= float(cond.get('progress') or 0)
|
||||
if typ == 'label_missing': return str(cond.get('label') or '').strip() not in _label_names(t.get('label'))
|
||||
if typ == 'label_has': return str(cond.get('label') or '').strip() in _label_names(t.get('label'))
|
||||
if typ == 'status': return str(t.get('status') or '').lower() == str(cond.get('status') or '').lower()
|
||||
|
||||
Reference in New Issue
Block a user