diff --git a/api.php b/api.php index 551454e..cf98656 100644 --- a/api.php +++ b/api.php @@ -368,6 +368,10 @@ class ImapClient { $date = $dateStr ? @date('Y-m-d H:i:s', strtotime($dateStr)) : date('Y-m-d H:i:s'); if (!$date) $date = date('Y-m-d H:i:s'); + // Parse To + $toRaw = $this->decodeMimeHeader($headers['to'] ?? ''); + $toEmails = $this->parseCcAddresses($toRaw); + // Parse CC $ccRaw = $this->decodeMimeHeader($headers['cc'] ?? ''); $ccEmails = $this->parseCcAddresses($ccRaw); @@ -379,6 +383,7 @@ class ImapClient { 'subject' => $subject, 'from_email' => $fromParsed['email'], 'from_name' => $this->decodeMimeHeader($fromParsed['name']), + 'to' => $toEmails, 'message_id' => $messageId, 'in_reply_to' => $inReplyTo, 'references' => $references, @@ -3011,6 +3016,7 @@ switch ($action) { ]; // Apply auto-rules + $toAddresses = implode(' ', $email['to'] ?? []); foreach ($rules as $rule) { if (empty($rule['enabled'])) continue; $match = true; @@ -3026,9 +3032,16 @@ switch ($action) { $match = false; } } + if (!empty($rule['to_contains'])) { + $needle = strtolower($rule['to_contains']); + if (strpos(strtolower($toAddresses), $needle) === false) { + $match = false; + } + } if ($match) { if (!empty($rule['set_status'])) $ticket['status'] = $rule['set_status']; if (!empty($rule['set_type'])) $ticket['type'] = $rule['set_type']; + if (!empty($rule['set_priority'])) $ticket['priority'] = $rule['set_priority']; if (!empty($rule['set_tags'])) { $ruleTags = array_map('trim', explode(',', $rule['set_tags'])); $ticket['tags'] = array_values(array_unique(array_merge($ticket['tags'], $ruleTags))); @@ -3426,8 +3439,10 @@ switch ($action) { 'name' => trim($input['name'] ?? ''), 'from_contains' => trim($input['from_contains'] ?? ''), 'subject_contains' => trim($input['subject_contains'] ?? ''), + 'to_contains' => trim($input['to_contains'] ?? ''), 'set_status' => $input['set_status'] ?? '', 'set_type' => $input['set_type'] ?? '', + 'set_priority' => $input['set_priority'] ?? '', 'set_tags' => trim($input['set_tags'] ?? ''), 'auto_close_days' => intval($input['auto_close_days'] ?? 0), 'enabled' => $input['enabled'] ?? true, diff --git a/db.php b/db.php index 750789b..8b4262c 100644 --- a/db.php +++ b/db.php @@ -617,6 +617,11 @@ function initDatabase(): void { "ALTER TABLE devices ADD COLUMN laitetila_id VARCHAR(20) DEFAULT NULL AFTER site_id", "ALTER TABLE document_folders ADD COLUMN customer_id VARCHAR(20) DEFAULT NULL AFTER company_id", "ALTER TABLE customer_connections ADD COLUMN gateway_device_id VARCHAR(20) DEFAULT NULL AFTER ip", + "ALTER TABLE ticket_rules ADD COLUMN subject_contains VARCHAR(255) DEFAULT '' AFTER from_contains", + "ALTER TABLE ticket_rules ADD COLUMN to_contains VARCHAR(255) DEFAULT '' AFTER subject_contains", + "ALTER TABLE ticket_rules ADD COLUMN enabled BOOLEAN DEFAULT TRUE AFTER auto_close_days", + "ALTER TABLE ticket_rules ADD COLUMN set_priority VARCHAR(20) DEFAULT '' AFTER type_set", + "ALTER TABLE ticket_rules ADD COLUMN set_tags VARCHAR(255) DEFAULT '' AFTER set_priority", ]; foreach ($alters as $sql) { try { $db->query($sql); } catch (\Throwable $e) { /* sarake on jo olemassa / jo ajettu */ } @@ -1538,6 +1543,7 @@ function dbLoadTicketRules(string $companyId): array { foreach ($rules as &$r) { $r['priority'] = (int)$r['priority']; $r['auto_close_days'] = (int)$r['auto_close_days']; + $r['enabled'] = !empty($r['enabled']); unset($r['company_id']); } return $rules; @@ -1545,23 +1551,30 @@ function dbLoadTicketRules(string $companyId): array { function dbSaveTicketRule(string $companyId, array $rule): void { _dbExecute(" - INSERT INTO ticket_rules (id, company_id, name, from_contains, priority, tag, assign_to, status_set, type_set, auto_close_days) - VALUES (:id, :company_id, :name, :from_contains, :priority, :tag, :assign_to, :status_set, :type_set, :auto_close_days) + INSERT INTO ticket_rules (id, company_id, name, from_contains, subject_contains, to_contains, priority, tag, assign_to, status_set, type_set, set_priority, set_tags, auto_close_days, enabled) + VALUES (:id, :company_id, :name, :from_contains, :subject_contains, :to_contains, :priority, :tag, :assign_to, :status_set, :type_set, :set_priority, :set_tags, :auto_close_days, :enabled) ON DUPLICATE KEY UPDATE - name = VALUES(name), from_contains = VALUES(from_contains), priority = VALUES(priority), + name = VALUES(name), from_contains = VALUES(from_contains), subject_contains = VALUES(subject_contains), + to_contains = VALUES(to_contains), priority = VALUES(priority), tag = VALUES(tag), assign_to = VALUES(assign_to), status_set = VALUES(status_set), - type_set = VALUES(type_set), auto_close_days = VALUES(auto_close_days) + type_set = VALUES(type_set), set_priority = VALUES(set_priority), set_tags = VALUES(set_tags), + auto_close_days = VALUES(auto_close_days), enabled = VALUES(enabled) ", [ - 'id' => $rule['id'], - 'company_id' => $companyId, - 'name' => $rule['name'] ?? '', - 'from_contains' => $rule['from_contains'] ?? '', - 'priority' => $rule['priority'] ?? 0, - 'tag' => $rule['tag'] ?? '', - 'assign_to' => $rule['assign_to'] ?? '', - 'status_set' => $rule['status_set'] ?? '', - 'type_set' => $rule['type_set'] ?? '', - 'auto_close_days' => $rule['auto_close_days'] ?? 0, + 'id' => $rule['id'], + 'company_id' => $companyId, + 'name' => $rule['name'] ?? '', + 'from_contains' => $rule['from_contains'] ?? '', + 'subject_contains' => $rule['subject_contains'] ?? '', + 'to_contains' => $rule['to_contains'] ?? '', + 'priority' => $rule['priority'] ?? 0, + 'tag' => $rule['tag'] ?? '', + 'assign_to' => $rule['assign_to'] ?? '', + 'status_set' => $rule['status_set'] ?? '', + 'type_set' => $rule['type_set'] ?? '', + 'set_priority' => $rule['set_priority'] ?? '', + 'set_tags' => $rule['set_tags'] ?? '', + 'auto_close_days' => $rule['auto_close_days'] ?? 0, + 'enabled' => !empty($rule['enabled']) ? 1 : 0, ]); } diff --git a/index.html b/index.html index b1f20a8..6731f85 100644 --- a/index.html +++ b/index.html @@ -1082,6 +1082,7 @@ Laskutus Tekniikka Vika + Abuse Muu @@ -1213,12 +1214,16 @@ - Ehdot (molemmat pitää täsmätä jos täytetty) + Ehdot (kaikki täytetyt pitää täsmätä) Lähettäjä sisältää + + Vastaanottaja sisältää + + Otsikko sisältää @@ -1242,9 +1247,19 @@ Laskutus Tekniikka Vika + Abuse Muu + + Aseta prioriteetti + + Ei muuteta + Normaali + Tärkeä + Kiireellinen + + Aseta tagit (pilkulla eroteltuna) diff --git a/script.js b/script.js index 32674fc..7b58eb1 100644 --- a/script.js +++ b/script.js @@ -1348,6 +1348,7 @@ const ticketTypeLabels = { laskutus: 'Laskutus', tekniikka: 'Tekniikka', vika: 'Vika', + abuse: 'Abuse', muu: 'Muu', }; @@ -1991,13 +1992,16 @@ function renderRules() { list.innerHTML = 'Ei sääntöjä vielä. Lisää ensimmäinen sääntö.'; return; } + const priorityLabels = { normaali: 'Normaali', 'tärkeä': 'Tärkeä', urgent: 'Kiireellinen' }; list.innerHTML = ticketRules.map(r => { const conditions = []; if (r.from_contains) conditions.push('Lähettäjä: ' + esc(r.from_contains) + ''); + if (r.to_contains) conditions.push('Vastaanottaja: ' + esc(r.to_contains) + ''); if (r.subject_contains) conditions.push('Otsikko: ' + esc(r.subject_contains) + ''); const actions = []; if (r.set_status) actions.push('Tila → ' + (ticketStatusLabels[r.set_status] || r.set_status)); if (r.set_type) actions.push('Tyyppi → ' + (ticketTypeLabels[r.set_type] || r.set_type)); + if (r.set_priority) actions.push('Prioriteetti → ' + (priorityLabels[r.set_priority] || r.set_priority)); if (r.set_tags) actions.push('Tagit: #' + r.set_tags.split(',').map(t => t.trim()).join(' #')); if (r.auto_close_days) actions.push('Auto-close: ' + r.auto_close_days + 'pv'); return ` @@ -2038,9 +2042,11 @@ function showRuleForm(rule) { document.getElementById('rule-form-id').value = rule ? rule.id : ''; document.getElementById('rule-form-name').value = rule ? rule.name : ''; document.getElementById('rule-form-from').value = rule ? rule.from_contains : ''; + document.getElementById('rule-form-to').value = rule ? (rule.to_contains || '') : ''; document.getElementById('rule-form-subject').value = rule ? rule.subject_contains : ''; document.getElementById('rule-form-status').value = rule ? (rule.set_status || '') : ''; document.getElementById('rule-form-type').value = rule ? (rule.set_type || '') : ''; + document.getElementById('rule-form-priority').value = rule ? (rule.set_priority || '') : ''; document.getElementById('rule-form-tags').value = rule ? (rule.set_tags || '') : ''; document.getElementById('rule-form-autoclose').value = rule ? (rule.auto_close_days || '') : ''; editingRuleId = rule ? rule.id : null; @@ -2062,9 +2068,11 @@ document.getElementById('btn-save-rule').addEventListener('click', async () => { const data = { name, from_contains: document.getElementById('rule-form-from').value.trim(), + to_contains: document.getElementById('rule-form-to').value.trim(), subject_contains: document.getElementById('rule-form-subject').value.trim(), set_status: document.getElementById('rule-form-status').value, set_type: document.getElementById('rule-form-type').value, + set_priority: document.getElementById('rule-form-priority').value, set_tags: document.getElementById('rule-form-tags').value.trim(), auto_close_days: parseInt(document.getElementById('rule-form-autoclose').value) || 0, enabled: true,