package db import ( "database/sql" "encoding/json" "github.com/cynfo/rmm-backend/models" ) // ListWAURules gibt alle WAU-Regeln eines Kunden zurück func (d *Database) ListWAURules(customerID int) ([]models.WAURule, error) { rows, err := d.db.Query(` SELECT id, customer_id, winget_id, display_name, rule_type, created_at FROM customer_wau_rules WHERE customer_id = $1 ORDER BY rule_type, lower(display_name) `, customerID) if err != nil { return nil, err } defer rows.Close() var rules []models.WAURule for rows.Next() { var r models.WAURule if err := rows.Scan(&r.ID, &r.CustomerID, &r.WingetID, &r.DisplayName, &r.RuleType, &r.CreatedAt); err != nil { return nil, err } rules = append(rules, r) } if rules == nil { rules = []models.WAURule{} } return rules, rows.Err() } // AddWAURule fügt eine neue Regel hinzu (upsert auf winget_id) func (d *Database) AddWAURule(customerID int, wingetID, displayName, ruleType string) (*models.WAURule, error) { var r models.WAURule err := d.db.QueryRow(` INSERT INTO customer_wau_rules (customer_id, winget_id, display_name, rule_type) VALUES ($1, $2, $3, $4) ON CONFLICT (customer_id, winget_id) DO UPDATE SET display_name = EXCLUDED.display_name, rule_type = EXCLUDED.rule_type RETURNING id, customer_id, winget_id, display_name, rule_type, created_at `, customerID, wingetID, displayName, ruleType).Scan( &r.ID, &r.CustomerID, &r.WingetID, &r.DisplayName, &r.RuleType, &r.CreatedAt, ) if err != nil { return nil, err } return &r, nil } // DeleteWAURule löscht eine Regel (per ID, gehört zu customerID) func (d *Database) DeleteWAURule(customerID, ruleID int) (bool, error) { res, err := d.db.Exec(` DELETE FROM customer_wau_rules WHERE id = $1 AND customer_id = $2 `, ruleID, customerID) if err != nil { return false, err } n, _ := res.RowsAffected() return n > 0, nil } // GetWAUList gibt alle winget-IDs eines bestimmten Typs zurück (für den Plaintext-Endpoint) func (d *Database) GetWAUList(customerID int, ruleType string) ([]string, error) { rows, err := d.db.Query(` SELECT winget_id FROM customer_wau_rules WHERE customer_id = $1 AND rule_type = $2 ORDER BY lower(winget_id) `, customerID, ruleType) if err != nil { return nil, err } defer rows.Close() var ids []string for rows.Next() { var id string if err := rows.Scan(&id); err != nil { return nil, err } ids = append(ids, id) } return ids, rows.Err() } // GetWAUSoftwareInventory aggregiert installierte Software aller Windows-Agents eines Kunden func (d *Database) GetWAUSoftwareInventory(customerID int) ([]models.WAUSoftwareEntry, error) { rows, err := d.db.Query(` SELECT app->>'name' AS name, COALESCE(app->>'publisher', '') AS publisher, COUNT(DISTINCT sd.agent_id) AS device_count, jsonb_agg(DISTINCT app->>'version') FILTER (WHERE (app->>'version') != '') AS versions FROM agents a JOIN system_data sd ON sd.agent_id = a.id CROSS JOIN jsonb_array_elements(sd.data_json->'windows'->'installed_software') AS app WHERE a.customer_id = $1 AND sd.data_json ? 'windows' AND jsonb_typeof(sd.data_json->'windows'->'installed_software') = 'array' AND (app->>'name') IS NOT NULL AND (app->>'name') != '' GROUP BY app->>'name', app->>'publisher' ORDER BY lower(app->>'name') `, customerID) if err != nil { return nil, err } defer rows.Close() var entries []models.WAUSoftwareEntry for rows.Next() { var e models.WAUSoftwareEntry var versionsJSON sql.NullString if err := rows.Scan(&e.Name, &e.Publisher, &e.DeviceCount, &versionsJSON); err != nil { return nil, err } if versionsJSON.Valid && versionsJSON.String != "" && versionsJSON.String != "null" { json.Unmarshal([]byte(versionsJSON.String), &e.Versions) } if e.Versions == nil { e.Versions = []string{} } entries = append(entries, e) } if entries == nil { entries = []models.WAUSoftwareEntry{} } return entries, rows.Err() }