Local statuses (odottaa vastausta, kasittelyssa, odottaa) set in the
intra UI were being overwritten by Zammad's state on every sync.
Now these statuses are preserved unless Zammad explicitly closes the ticket.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace IRedMailClient REST API class with direct MySQL/PDO connection to vmail database
- Move iRedMail config from global config table to per-company integrations (like Zammad)
- Add iRedMail integration card to API settings with DB host/name/user/password/port fields
- Add iRedMail checkbox to integrations section in company settings
- Change Hallinta tab visibility: show for admins (not just superadmins) when module enabled
- API endpoints now use requireCompany() + requireSuperAdmin() and get config from integrations
- Password hashing uses SSHA512 (iRedMail default)
- Mask db_password in API responses (like token masking for Zammad)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 'hallinta' to ALL_MODULES so it appears in company settings
- Change fallback from ALL_MODULES to DEFAULT_MODULES (new modules not enabled by default)
- Hallinta tab requires both module enabled + superadmin role
- Add per-company configurable postal codes for "todennäköinen" availability
- Saatavuus API returns true/todennäköinen/false based on customer data + postal codes
- Show "Todennäköinen" badge in availability queries list
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Timer is now a simple checkbox + days field. When enabled, rule actions
are scheduled for X days after ticket creation at 10:00 AM instead of
applying immediately. Removed no_activity condition in favor of simple
time-based scheduling stored on the ticket (delay_rule_id + delay_execute_at).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds optional delay_days + delay_condition (no_activity) to ticket rules.
When a ticket has no activity for X days, timed rules automatically apply
actions (e.g., escalate priority to urgent). Checked on each ticket list load.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
sendTelegramAlert and telegram_test used non-existent dbGetCompany().
Replaced with dbLoadCompanies() + loop to find company name.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both bot_token and chat_id are now per-company. If a company
doesn't set its own bot_token, falls back to the global one.
Removed parenthetical hints from labels, all admins can now
configure their own Telegram bot.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each company can now have its own Telegram channel/group for alerts.
- Bot token: global (superadmin only, shared across companies)
- Chat ID: per-company (stored in integrations table config)
- sendTelegramAlert reads chat_id from company integration
- Test message shows company name
- Non-superadmin users can't see/edit bot token
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mobile improvements:
- Fix overflow issues with global max-width/overflow-x hidden
- Stack ticket detail selects on mobile instead of one long row
- Compact header: hide less important buttons, scrollable right side
- Stat cards in 2-column grid on mobile
- Force flex-wrap on inline-styled flex containers
- Hide subtitle and user-info on small phones
- Ticket selects full-width on small phones
IP allow list:
- Support # comments after IP addresses (e.g. "192.168.1.1 # Office VPN")
- Updated placeholder with comment examples
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mobile (768px):
- Tab bar: horizontal scroll with momentum, hidden scrollbar
- Header: compact layout, smaller fonts
- Tables: horizontal scroll, hide-mobile class for less important cols
- Modals: bottom-sheet style, full width
- Touch targets: min-height 36px for buttons/selects
- Toolbar: stacks vertically
- Stat cards: compact
Small phone (480px):
- Even more compact header and tabs
- Smaller table cells
- iOS zoom prevention (16px font on inputs)
PWA:
- manifest.json for Add to Home Screen
- apple-mobile-web-app-capable meta tags
- theme-color for status bar
- overscroll-behavior: none (prevent pull-to-refresh)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical fixes:
- company_logo_upload: validate user has access to target company
- All delete functions (db.php): accept optional company_id parameter
for defense-in-depth filtering (customers, devices, ipam, guides,
leads, tickets, archives, mailboxes, rules, templates, todos)
- All API delete calls now pass company_id to db layer
- ticket_bulk_delete: per-ticket company_id filtering
- todo_comment/time/subtask operations: verify todo belongs to company
- dbGetMailbox: optional company_id scoping, used in smtp_test
- requireCompanyOrParam: no longer mutates session permanently
- Fix _dbFetch typo in zammad_attachment (was runtime error)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- When changing ticket status in intra, now syncs to Zammad too
(close in intra → close in Zammad, etc.)
- Prevent Zammad sync from reopening locally closed tickets
unless Zammad has genuinely new activity (updated_at changed)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Superadmin sees users grouped by company with header rows
- Admins can now set user or admin role when creating/editing users
- Admin role change restricted to own company only
- Prevents admin from modifying superadmin roles
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New provision_ssl API endpoint runs certbot for new domains
- SSL button appears next to domain textarea for superadmin
- Shell script on server handles Apache config + Let's Encrypt
- DNS check skips domains without resolution to avoid certbot errors
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Incremental sync now excludes closed/merged/removed tickets from query
- Full sync still fetches everything
- Reopened tickets (closed→new/open in Zammad) are handled correctly:
existing ticket is updated instead of creating duplicate
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- zammad_reply endpoint now sets intra status uusi→kasittelyssa
- Also updates Zammad ticket state to open
- Fixed stateMap: Zammad open now maps to kasittelyssa instead of avoin
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tickets now get a unique URL hash (#support/ticket/ID) when opened.
Copy link button in ticket header copies the full URL to clipboard.
Opening a ticket link navigates directly to the ticket detail view.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Viestiketju oli rajoitettu 60vh laatikkoon overflow-y:auto,
joka pakotti scrollaamaan iframemaisesti. Nyt viestit ovat
osa normaalia sivun virtausta.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sub-tab-bar oli piilotettu display:none — nyt näkyvillä
samalla tyylillä kuin muissa näkymissä.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tikettinäkymän Sulje-nappi neutraaliksi btn-secondary-tyylillä
ilman punaista väritystä ja ✕-merkkiä.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Saatavuus-tyyppi oletuksiin (teal-väri)
- Fallback CSS: tuntemattomat tyypit saavat violetin taustan
- TypeLabel näyttää tyypin nimen isolla alkukirjaimella jos ei löydy labelista
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Poistettu "Haetaan sähköpostit ja synkataan Zammad..." -teksti
- Status-laatikko näytetään vasta kun tulokset on valmiit
- scrollIntoView scrollaa tuloksen näkyviin
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- prices-hidden blurraa nyt myös sidebar-stats (liittymät, laskutus, keskihinta, nopeudet)
- Summary-barin laskutus blurrautuu samalla
- Oletusnäkymä kirjautumisen jälkeen vaihdettu customers → support
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Lisää BCC-kenttä vastauslomakkeeseen (HTML, JS, API)
- To/CC/BCC tallentuvat tiketille pysyvästi (seuraava vastaus muistaa muutokset)
- Lisää to_email ja bcc sarakkeet tickets-tauluun
- BCC-tuki SMTP-lähetykseen (RCPT TO ilman headeria)
- Korjaa allekirjoitukset: buildSignaturesWithDefaults() generoi nyt oletukset
myös Zammad-sähköposteille (support@web1.fi ym.), ei pelkille mailboxeille
- Allekirjoituksiin lisätty puhelinnumero
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
white-space:pre-wrap ei toimi kaikissa sähköpostiohjelmissa/Zammadissa.
Vaihdettu käyttämään nl2br() rivinvaihdoille ja peräkkäisille
välilyönneille, jotka toimivat universaalisti HTML-sähköposteissa.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zammad-synkasta tulevat viestit käyttävät tyyppiä 'outgoing' (ei 'reply_out'),
joten ne näkyivät virheellisesti saapuvina (sininen). Nyt molemmat tyypit
tunnistetaan lähteviksi ja näytetään vihreällä taustalla.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Reverse DNS -haku tallentaa hostnamen IP:n rinnalle (paljastaa
operaattorin ja alueen, esim. dsl-hel-123.elisa.fi)
- Duplikaattikyselyn (sama osoite+postinumero+kaupunki) ei tallenneta
uudelleen samalle yritykselle
- IP/hostname -sarake lisätty taulukkoon
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Endpoint näytti vain aktiivisen yrityksen kyselyt, mutta kyselyt
tallennetaan API-avaimen yrityksen alle. Nyt näytetään kaikkien
käyttäjän yritysten kyselyt + yrityssarake taulukkoon.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Jokainen nettisivujen kautta tehty saatavuustarkistus tallennetaan
tietokantaan (osoite, postinumero, kaupunki, tulos, IP, referer).
Kyselyt näkyvät Asiakkaat > Saatavuuskyselyt -välilehdellä
sivutettuna taulukkona.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sekä Zammad- että SMTP-vastaukset sisältävät nyt koko viestiketjun
vastauksessa. Zammad-vastauksissa HTML-blockquoteilla, SMTP:ssä
plain-text > -quoting-muodossa. Vain uusi viesti tallennetaan
tietokantaan, ketju näkyy vain lähetettävässä sähköpostissa.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
JS ei lähettänyt käyttäjän muokkaamaa To/CC-kenttää Zammad-vastauksen
mukana — backend käytti aina alkuperäistä lähettäjää tietokannasta.
Nyt käyttäjän syöttämä To/CC välitetään API:lle ja Zammadille.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Lisätty subtype: 'reply' Zammad-artikkelin luontiin — ilman tätä
Zammad luo artikkelin mutta ei lähetä sähköpostia vastaanottajalle.
Myös plain-text muunnetaan HTML:ksi ja subject saa Re: -etuliitteen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Poistettu virheellinen fallback joka valitsi ensimmäisen satunnaisen
allekirjoituksen (esim. serverihuone.com) väärään tikettiin. Nyt
generoidaan oikea oletusallekirjoitus tiketin kontekstin perusteella
(käyttäjänimi + yritys + vastaanottava sähköposti + puhelin).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Nappi siirretty oikeasta yläkulmasta (header) asiakaslistauksen
hakupalkin viereen, missä se on loogisemmassa paikassa.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Puhelinnumero-kenttä yrityksen asetuksissa tallennetaan tietokantaan
ja näkyy automaattisesti kaikissa oletusallekirjoituksissa viimeisenä
rivinä (sekä SMTP- että Zammad-postilaatikoille).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Jos käyttäjä ei ole vielä tallentanut allekirjoitusta, näytetään
oletuksena: Käyttäjänimi / Yrityksen nimi / sähköpostiosoite.
Toimii sekä IMAP/SMTP-postilaatikoille että Zammad-sähköposteille.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Asetukset-sivulla näytetään nyt myös Zammad-sähköpostiosoitteet
(esim. support@web1.fi) allekirjoitusten alla. Allekirjoitus liitetään
automaattisesti Zammad-vastauksiin. Tallennetaan avaimella
"zammad:email@osoite.fi". Uusi ticket_zammad_emails API-endpoint
hakee uniikit vastaanotto-osoitteet tietokannasta.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Zammad-tiketeille näytetään vastaanotto-osoite (esim. support@web1.fi)
lähettäjäkentässä eikä SMTP-postilaatikkolistaa — vastaus menee
Zammad API:n kautta.
2. Ensimmäisen artikkelin to-osoite tallennetaan zammad_to_email kenttään
on-demand artikkelien haussa.
3. Korjattu _dbFetchRow → _dbFetchOne zammad_reply endpointissa.
4. sanitizeHtml() renderöi viestien HTML turvallisesti.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Sähköpostiviestien HTML renderöidään oikein (br, p, div, a, b, i jne.)
sen sijaan että tagit näkyisivät raakatekstinä. Sanitoi vaarallisen
sisällön (script, iframe, on*-attribuutit) pois turvallisesti.
2. Zammad-tiketeillä ei ole mailbox_id:tä, joten aiemmin valittiin aina
listan ensimmäinen (tuki@serverihuone.com). Nyt näytetään
"Valitse lähettäjä" placeholder kunnes käyttäjä valitsee oikean.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sync hakee nyt vain tikettien metatiedot (status, aihe, ryhmä) —
ei enää satoja getArticles-kutsuja jokaiselle tiketille. Artikkelit
haetaan on-demand ticket_detail-endpointissa kun käyttäjä avaa
tiketin. Nopeuttaa synkkausta dramaattisesti.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Selain cachetti vanhan script.js:n aiheuttaen showClosed-virheen
vaikka korjaus oli jo palvelimella. Versioparametri pakottaa uuden
latauksen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>