dashboard_segment.py 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. """Decode legacy dashboard links into the regular editable list filters."""
  2. from datetime import date
  3. import json
  4. from .query_filter import EMPTY_FILTER_VALUE, encode_filter_values
  5. VIEWS = ('Altersstaffel', 'Standort', 'Verursacher', 'Wiedervorlage')
  6. DASHBOARD_VIEWS = VIEWS[:-1] # Old Wiedervorlage list selections remain valid.
  7. def _date_key(key):
  8. if key is None:
  9. return
  10. if not isinstance(key, dict) or set(key) != {'from', 'to'} or not any(key.values()):
  11. raise ValueError('Ungültiger Datumsfilter')
  12. for value in key.values():
  13. if value is not None and (not isinstance(value, str) or date.fromisoformat(value).isoformat() != value):
  14. raise ValueError('Ungültiges Datum')
  15. if key['from'] and key['to'] and key['from'] > key['to']:
  16. raise ValueError('Ungültiger Zeitraum')
  17. if key['to'] == '9999-12-31':
  18. raise ValueError('Zeitraum außerhalb des unterstützten Bereichs')
  19. def _value(value):
  20. if value is not None and (not isinstance(value, str) or len(value) > 500
  21. or any(ord(char) < 32 or ord(char) == 127 or 0xd800 <= ord(char) <= 0xdfff for char in value)):
  22. raise ValueError('Ungültiger Gruppenschlüssel')
  23. def parse_segment(raw):
  24. if not raw:
  25. return None
  26. if not isinstance(raw, str) or len(raw) > 4096:
  27. raise ValueError('Ungültiger Dashboardfilter')
  28. try:
  29. segment = json.loads(raw)
  30. except (ValueError, TypeError, RecursionError) as error:
  31. raise ValueError('Ungültiger Dashboardfilter') from error
  32. if (not isinstance(segment, dict) or set(segment) - {'view', 'key', 'department', 'only_invoices', 'follow_up'}
  33. or not {'view', 'key'} <= set(segment) or segment['view'] not in VIEWS):
  34. raise ValueError('Ungültiger Dashboardfilter')
  35. key, view = segment['key'], segment['view']
  36. if 'only_invoices' in segment and type(segment['only_invoices']) is not bool:
  37. raise ValueError('Ungültiger Rechnungsfilter')
  38. if 'department' in segment:
  39. _value(segment['department'])
  40. if 'follow_up' in segment:
  41. _date_key(segment['follow_up'])
  42. if view == 'Altersstaffel':
  43. _value(key)
  44. elif view == 'Standort':
  45. if not isinstance(key, dict) or set(key) != {'client', 'site'} or not key['client']:
  46. raise ValueError('Ungültiger Standortfilter')
  47. _value(key['client']); _value(key['site'])
  48. elif view == 'Verursacher':
  49. if not isinstance(key, dict) or set(key) not in ({'id'}, {'text'}):
  50. raise ValueError('Ungültiger Verursacherfilter')
  51. _value(next(iter(key.values())))
  52. if 'id' in key and not key['id']:
  53. raise ValueError('Benutzer-ID fehlt')
  54. else:
  55. _date_key(key)
  56. return segment
  57. def pack_segment(segment):
  58. return json.dumps(segment, ensure_ascii=False, sort_keys=True, separators=(',', ':'))
  59. def segment_filters(segment, person_values=None):
  60. """Translate old dashboard URLs into editable list filters, never hidden predicates."""
  61. if not segment:
  62. return {}
  63. values = {}
  64. key, view = segment['key'], segment['view']
  65. if view == 'Standort':
  66. values.update(Mandant=[key['client']], Filiale=[key['site']])
  67. elif view == 'Altersstaffel':
  68. values['Staffel'] = [key]
  69. elif view == 'Verursacher':
  70. values['Verursacher'] = person_values if person_values is not None else [key.get('text', key.get('id'))]
  71. if 'department' in segment:
  72. values['Abteilung'] = [segment['department']]
  73. if segment.get('only_invoices'):
  74. values['RechnungGutschrift'] = ['Rechnung']
  75. # Both the old Wiedervorlage rubric and follow_up stacks are deliberately ignored.
  76. return {name: encode_filter_values([EMPTY_FILTER_VALUE if value in (None, '') else value for value in items])
  77. for name, items in values.items()}