notification_template.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. """Pydantic schemas for notification templates."""
  2. from datetime import datetime
  3. from pydantic import BaseModel, Field
  4. from backend.app.core.compat import StrEnum
  5. class EventType(StrEnum):
  6. """Supported notification event types."""
  7. PRINT_START = "print_start"
  8. PRINT_COMPLETE = "print_complete"
  9. PRINT_FAILED = "print_failed"
  10. PRINT_STOPPED = "print_stopped"
  11. PRINT_PROGRESS = "print_progress"
  12. PRINT_MISSING_SPOOL_ASSIGNMENT = "print_missing_spool_assignment"
  13. PRINTER_OFFLINE = "printer_offline"
  14. PRINTER_ERROR = "printer_error"
  15. FILAMENT_LOW = "filament_low"
  16. MAINTENANCE_DUE = "maintenance_due"
  17. AMS_HUMIDITY_HIGH = "ams_humidity_high"
  18. AMS_TEMPERATURE_HIGH = "ams_temperature_high"
  19. BED_COOLED = "bed_cooled"
  20. HA_SENSOR_ALERT = "ha_sensor_alert"
  21. TEST = "test"
  22. # Available variables for each event type
  23. EVENT_VARIABLES: dict[str, list[str]] = {
  24. "print_start": ["printer", "filename", "estimated_time", "eta", "timestamp", "app_name"],
  25. "print_complete": [
  26. "printer",
  27. "filename",
  28. "duration",
  29. "filament_grams",
  30. "filament_details",
  31. "finish_photo_url",
  32. "timestamp",
  33. "app_name",
  34. ],
  35. "print_failed": [
  36. "printer",
  37. "filename",
  38. "duration",
  39. "filament_grams",
  40. "filament_details",
  41. "progress",
  42. "reason",
  43. "finish_photo_url",
  44. "timestamp",
  45. "app_name",
  46. ],
  47. "print_stopped": [
  48. "printer",
  49. "filename",
  50. "duration",
  51. "filament_grams",
  52. "filament_details",
  53. "progress",
  54. "finish_photo_url",
  55. "timestamp",
  56. "app_name",
  57. ],
  58. "print_progress": ["printer", "filename", "progress", "remaining_time", "eta", "timestamp", "app_name"],
  59. "print_missing_spool_assignment": [
  60. "printer",
  61. "missing_slots",
  62. "missing_slot_details",
  63. "timestamp",
  64. "app_name",
  65. ],
  66. "printer_offline": ["printer", "timestamp", "app_name"],
  67. "printer_error": ["printer", "error_type", "error_detail", "timestamp", "app_name"],
  68. "filament_low": ["printer", "slot", "remaining_percent", "color", "timestamp", "app_name"],
  69. "maintenance_due": ["printer", "items", "timestamp", "app_name"],
  70. "ams_humidity_high": ["printer", "ams_label", "humidity", "threshold", "timestamp", "app_name"],
  71. "ams_temperature_high": ["printer", "ams_label", "temperature", "threshold", "timestamp", "app_name"],
  72. "bed_cooled": ["printer", "bed_temp", "threshold", "filename", "timestamp", "app_name"],
  73. "ha_sensor_alert": ["printer", "sensor", "state", "timestamp", "app_name"],
  74. "test": ["app_name", "timestamp"],
  75. # Queue notifications
  76. "queue_job_added": ["job_name", "target", "timestamp", "app_name"],
  77. "queue_job_assigned": ["job_name", "printer", "target_model", "timestamp", "app_name"],
  78. "queue_job_started": ["printer", "job_name", "estimated_time", "eta", "timestamp", "app_name"],
  79. "queue_job_waiting": ["job_name", "target_model", "waiting_reason", "timestamp", "app_name"],
  80. "queue_job_skipped": ["printer", "job_name", "reason", "timestamp", "app_name"],
  81. "queue_job_failed": ["printer", "job_name", "reason", "timestamp", "app_name"],
  82. "queue_completed": ["completed_count", "timestamp", "app_name"],
  83. # User management notifications
  84. "user_created": ["username", "password", "login_url", "app_name", "timestamp"],
  85. "password_reset": ["username", "password", "login_url", "app_name", "timestamp"],
  86. # User email print notifications
  87. "user_print_start": ["username", "printer", "filename", "timestamp", "app_name"],
  88. "user_print_complete": ["username", "printer", "filename", "timestamp", "app_name"],
  89. "user_print_failed": ["username", "printer", "filename", "timestamp", "app_name"],
  90. "user_print_stopped": ["username", "printer", "filename", "timestamp", "app_name"],
  91. }
  92. # Sample data for previewing templates
  93. SAMPLE_DATA: dict[str, dict[str, str]] = {
  94. "print_start": {
  95. "printer": "Bambu X1C",
  96. "filename": "Benchy.3mf",
  97. "estimated_time": "1h 23m",
  98. "eta": "15:53",
  99. "timestamp": "2024-01-15 14:30",
  100. "app_name": "Bambuddy",
  101. },
  102. "print_complete": {
  103. "printer": "Bambu X1C",
  104. "filename": "Benchy.3mf",
  105. "duration": "1h 18m",
  106. "filament_grams": "15.2",
  107. "filament_details": "AMS-A T1 PLA: 12.4g | AMS-A T3 PETG: 2.8g",
  108. "finish_photo_url": "/api/v1/archives/123/photos/finish_20240115_154800_abc12345.jpg",
  109. "timestamp": "2024-01-15 15:48",
  110. "app_name": "Bambuddy",
  111. },
  112. "print_failed": {
  113. "printer": "Bambu X1C",
  114. "filename": "Benchy.3mf",
  115. "duration": "0h 45m",
  116. "filament_grams": "7.6",
  117. "filament_details": "AMS-A T1 PLA: 7.6g",
  118. "progress": "50",
  119. "reason": "Filament runout",
  120. "finish_photo_url": "/api/v1/archives/123/photos/finish_20240115_151500_def67890.jpg",
  121. "timestamp": "2024-01-15 15:15",
  122. "app_name": "Bambuddy",
  123. },
  124. "print_stopped": {
  125. "printer": "Bambu X1C",
  126. "filename": "Benchy.3mf",
  127. "duration": "0h 30m",
  128. "filament_grams": "4.6",
  129. "filament_details": "AMS-A T2 PLA: 4.6g",
  130. "progress": "30",
  131. "finish_photo_url": "/api/v1/archives/123/photos/finish_20240115_150000_ghi11223.jpg",
  132. "timestamp": "2024-01-15 15:00",
  133. "app_name": "Bambuddy",
  134. },
  135. "print_progress": {
  136. "printer": "Bambu X1C",
  137. "filename": "Benchy.3mf",
  138. "progress": "50",
  139. "remaining_time": "0h 41m",
  140. "eta": "15:41",
  141. "timestamp": "2024-01-15 15:00",
  142. "app_name": "Bambuddy",
  143. },
  144. "print_missing_spool_assignment": {
  145. "printer": "Bambu X1C",
  146. "missing_slots": "A1, A3",
  147. "missing_slot_details": "- A1: PLA Basic\n- A3: PETG HF",
  148. "timestamp": "2024-01-15 14:30",
  149. "app_name": "Bambuddy",
  150. },
  151. "printer_offline": {
  152. "printer": "Bambu X1C",
  153. "timestamp": "2024-01-15 14:30",
  154. "app_name": "Bambuddy",
  155. },
  156. "printer_error": {
  157. "printer": "Bambu X1C",
  158. "error_type": "AMS Error",
  159. "error_detail": "Filament slot 1 jammed",
  160. "timestamp": "2024-01-15 14:30",
  161. "app_name": "Bambuddy",
  162. },
  163. "filament_low": {
  164. "printer": "Bambu X1C",
  165. "slot": "1",
  166. "remaining_percent": "15",
  167. "color": "Black PLA",
  168. "timestamp": "2024-01-15 14:30",
  169. "app_name": "Bambuddy",
  170. },
  171. "maintenance_due": {
  172. "printer": "Bambu X1C",
  173. "items": "• Nozzle cleaning (OVERDUE)\n• Carbon rod lubrication (Soon)",
  174. "timestamp": "2024-01-15 14:30",
  175. "app_name": "Bambuddy",
  176. },
  177. "ams_humidity_high": {
  178. "printer": "Bambu X1C",
  179. "ams_label": "AMS-A",
  180. "humidity": "75",
  181. "threshold": "60",
  182. "timestamp": "2024-01-15 14:30",
  183. "app_name": "Bambuddy",
  184. },
  185. "ams_temperature_high": {
  186. "printer": "Bambu X1C",
  187. "ams_label": "AMS-A",
  188. "temperature": "42",
  189. "threshold": "35",
  190. "timestamp": "2024-01-15 14:30",
  191. "app_name": "Bambuddy",
  192. },
  193. "bed_cooled": {
  194. "printer": "Bambu X1C",
  195. "bed_temp": "34",
  196. "threshold": "35",
  197. "filename": "Benchy",
  198. "timestamp": "2024-01-15 14:30",
  199. "app_name": "Bambuddy",
  200. },
  201. "ha_sensor_alert": {
  202. "printer": "Bambu X1C",
  203. "sensor": "Enclosure Door",
  204. "state": "open",
  205. "timestamp": "2024-01-15 14:30",
  206. "app_name": "Bambuddy",
  207. },
  208. "test": {
  209. "app_name": "Bambuddy",
  210. "timestamp": "2024-01-15 14:30",
  211. },
  212. # Queue notifications
  213. "queue_job_added": {
  214. "job_name": "Benchy.3mf",
  215. "target": "Bambu X1C",
  216. "timestamp": "2024-01-15 14:30",
  217. "app_name": "Bambuddy",
  218. },
  219. "queue_job_assigned": {
  220. "job_name": "Benchy.3mf",
  221. "printer": "Bambu X1C #1",
  222. "target_model": "X1C",
  223. "timestamp": "2024-01-15 14:30",
  224. "app_name": "Bambuddy",
  225. },
  226. "queue_job_started": {
  227. "printer": "Bambu X1C",
  228. "job_name": "Benchy.3mf",
  229. "estimated_time": "1h 23m",
  230. "eta": "15:53",
  231. "timestamp": "2024-01-15 14:30",
  232. "app_name": "Bambuddy",
  233. },
  234. "queue_job_waiting": {
  235. "job_name": "Benchy.3mf",
  236. "target_model": "X1C",
  237. "waiting_reason": "Printer1 (needs PLA)",
  238. "timestamp": "2024-01-15 14:30",
  239. "app_name": "Bambuddy",
  240. },
  241. "queue_job_skipped": {
  242. "printer": "Bambu X1C",
  243. "job_name": "Benchy.3mf",
  244. "reason": "Previous print failed",
  245. "timestamp": "2024-01-15 14:30",
  246. "app_name": "Bambuddy",
  247. },
  248. "queue_job_failed": {
  249. "printer": "Bambu X1C",
  250. "job_name": "Benchy.3mf",
  251. "reason": "Upload failed: connection timeout",
  252. "timestamp": "2024-01-15 14:30",
  253. "app_name": "Bambuddy",
  254. },
  255. "queue_completed": {
  256. "completed_count": "5",
  257. "timestamp": "2024-01-15 18:30",
  258. "app_name": "Bambuddy",
  259. },
  260. # User management notifications
  261. "user_created": {
  262. "username": "john_doe",
  263. "password": "<generated-password>",
  264. "login_url": "https://bambuddy.example.com/login",
  265. "app_name": "Bambuddy",
  266. "timestamp": "2024-01-15 14:30",
  267. },
  268. "password_reset": {
  269. "username": "john_doe",
  270. "password": "<new-password>",
  271. "login_url": "https://bambuddy.example.com/login",
  272. "app_name": "Bambuddy",
  273. "timestamp": "2024-01-15 14:30",
  274. },
  275. # User email print notifications
  276. "user_print_start": {
  277. "username": "john_doe",
  278. "printer": "Bambu X1C",
  279. "filename": "Benchy.3mf",
  280. "timestamp": "2024-01-15 14:30",
  281. "app_name": "Bambuddy",
  282. },
  283. "user_print_complete": {
  284. "username": "john_doe",
  285. "printer": "Bambu X1C",
  286. "filename": "Benchy.3mf",
  287. "timestamp": "2024-01-15 15:48",
  288. "app_name": "Bambuddy",
  289. },
  290. "user_print_failed": {
  291. "username": "john_doe",
  292. "printer": "Bambu X1C",
  293. "filename": "Benchy.3mf",
  294. "timestamp": "2024-01-15 15:15",
  295. "app_name": "Bambuddy",
  296. },
  297. "user_print_stopped": {
  298. "username": "john_doe",
  299. "printer": "Bambu X1C",
  300. "filename": "Benchy.3mf",
  301. "timestamp": "2024-01-15 15:15",
  302. "app_name": "Bambuddy",
  303. },
  304. }
  305. class NotificationTemplateBase(BaseModel):
  306. """Base schema for notification templates."""
  307. title_template: str = Field(..., min_length=1, max_length=200)
  308. body_template: str = Field(..., min_length=1, max_length=2000)
  309. class NotificationTemplateUpdate(BaseModel):
  310. """Schema for updating a notification template."""
  311. title_template: str | None = Field(default=None, min_length=1, max_length=200)
  312. body_template: str | None = Field(default=None, min_length=1, max_length=2000)
  313. class NotificationTemplateResponse(NotificationTemplateBase):
  314. """Schema for notification template API responses."""
  315. id: int
  316. event_type: str
  317. name: str
  318. is_default: bool
  319. created_at: datetime
  320. updated_at: datetime
  321. class Config:
  322. from_attributes = True
  323. class TemplateVariableInfo(BaseModel):
  324. """Information about a template variable."""
  325. name: str
  326. description: str
  327. class EventVariablesResponse(BaseModel):
  328. """Response for available variables per event type."""
  329. event_type: str
  330. event_name: str
  331. variables: list[str]
  332. class TemplatePreviewRequest(BaseModel):
  333. """Request to preview a template with sample data."""
  334. event_type: str
  335. title_template: str
  336. body_template: str
  337. class TemplatePreviewResponse(BaseModel):
  338. """Response with rendered template preview."""
  339. title: str
  340. body: str