package main import ( scn "blackforestbytes.com/simplecloudnotifier" "blackforestbytes.com/simplecloudnotifier/logic" "blackforestbytes.com/simplecloudnotifier/models" "bufio" "context" "encoding/json" "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" "gogs.mikescher.com/BlackForestBytes/goext/langext" "gogs.mikescher.com/BlackForestBytes/goext/rext" "gogs.mikescher.com/BlackForestBytes/goext/sq" "gogs.mikescher.com/BlackForestBytes/goext/termext" "os" "regexp" "strings" "time" ) type OldUser struct { UserId int64 `db:"user_id"` UserKey string `db:"user_key"` FcmToken *string `db:"fcm_token"` MessagesSent int64 `db:"messages_sent"` TimestampCreated time.Time `db:"timestamp_created"` TimestampAccessed *time.Time `db:"timestamp_accessed"` QuotaToday int64 `db:"quota_today"` QuotaDay *time.Time `db:"quota_day"` IsPro bool `db:"is_pro"` ProToken *string `db:"pro_token"` } type OldMessage struct { ScnMessageId int64 `db:"scn_message_id"` SenderUserId int64 `db:"sender_user_id"` TimestampReal time.Time `db:"timestamp_real"` Ack []uint8 `db:"ack"` Title string `db:"title"` Content *string `db:"content"` Priority int64 `db:"priority"` Sendtime int64 `db:"sendtime"` FcmMessageId *string `db:"fcm_message_id"` UsrMessageId *string `db:"usr_message_id"` } type SCNExport struct { Messages []SCNExportMessage `json:"cmessagelist"` } type SCNExportMessage struct { MessageID int64 `json:"scnid"` } func main() { ctx := context.Background() conf, _ := scn.GetConfig("local-host") conf.DBMain.File = ".run-data/migrate_main.sqlite3" conf.DBMain.EnableLogger = false if _, err := os.Stat(".run-data/migrate_main.sqlite3"); err == nil { err = os.Remove(".run-data/migrate_main.sqlite3") if err != nil { panic(err) } } if _, err := os.Stat(".run-data/migrate_main.sqlite3-shm"); err == nil { err = os.Remove(".run-data/migrate_main.sqlite3-shm") if err != nil { panic(err) } } if _, err := os.Stat(".run-data/migrate_main.sqlite3-wal"); err == nil { err = os.Remove(".run-data/migrate_main.sqlite3-wal") if err != nil { panic(err) } } sqlite, err := logic.NewDBPool(conf) if err != nil { panic(err) } err = sqlite.Migrate(ctx) if err != nil { panic(err) } scanner := bufio.NewScanner(os.Stdin) connstr := os.Getenv("SQL_CONN_STR") if connstr == "" { fmt.Print("Enter DB URL [127.0.0.1:3306]: ") scanner.Scan() host := scanner.Text() if host == "" { host = "127.0.0.1:3306" } fmt.Print("Enter DB Username [root]: ") scanner.Scan() username := scanner.Text() if username == "" { username = "root" } fmt.Print("Enter DB Password []: ") scanner.Scan() pass := scanner.Text() if pass == "" { pass = "" } connstr = fmt.Sprintf("%s:%s@tcp(%s)", username, pass, host) } olddbname := os.Getenv("SQL_CONN_DBNAME") if olddbname == "" { fmt.Print("Enter DB Name: ") scanner.Scan() olddbname = scanner.Text() if olddbname == "" { olddbname = "scn_final" } } _dbold, err := sqlx.Open("mysql", connstr+"/"+olddbname+"?parseTime=true") if err != nil { panic(err) } dbold := sq.NewDB(_dbold) rowsUser, err := dbold.Query(ctx, "SELECT * FROM users", sq.PP{}) if err != nil { panic(err) } var export SCNExport exfn, err := os.ReadFile("scn_export.json") err = json.Unmarshal(exfn, &export) if err != nil { panic(err) } appids := make(map[int64]int64) for _, v := range export.Messages { appids[v.MessageID] = v.MessageID } users := make([]OldUser, 0) for rowsUser.Next() { var u OldUser err = rowsUser.StructScan(&u) if err != nil { panic(err) } users = append(users, u) } fmt.Printf("\n") for _, v := range users { fmt.Printf("========================================\n") fmt.Printf(" MIGRATE USER %d\n", v.UserId) fmt.Printf("========================================\n") migrateUser(ctx, sqlite.Primary.DB(), dbold, v, appids) fmt.Printf("========================================\n") fmt.Printf("\n") fmt.Printf("\n") } err = sqlite.Stop(context.Background()) if err != nil { panic(err) } } var rexTitleChannel = rext.W(regexp.MustCompile("^\\[(?P[A-Za-z\\-0-9_ ]+)] (?P(.|\\r|\\n)+)$")) var usedFCM = make(map[string]models.ClientID) func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, appids map[int64]int64) { rowsMessages, err := dbold.Query(ctx, "SELECT * FROM messages WHERE sender_user_id = :uid ORDER BY timestamp_real ASC", sq.PP{"uid": user.UserId}) if err != nil { panic(err) } messages := make([]OldMessage, 0) for rowsMessages.Next() { var m OldMessage err = rowsMessages.StructScan(&m) if err != nil { panic(err) } messages = append(messages, m) } fmt.Printf("Found %d messages\n", len(messages)) userid := models.NewUserID() fmt.Printf("New UserID: %s\n", userid) tokKeyID := models.NewKeyTokenID() tokKeySec := user.UserKey protoken := user.ProToken if protoken != nil { protoken = langext.Ptr("ANDROID|v1|" + *protoken) } _, err = dbnew.Exec(ctx, "INSERT INTO users (user_id, username, is_pro, pro_token, timestamp_created) VALUES (:uid, :un, :pro, :tok, :ts)", sq.PP{ "uid": userid, "un": nil, "pro": langext.Conditional(user.IsPro, 1, 0), "tok": protoken, "ts": user.TimestampCreated.UnixMilli(), }) if err != nil { panic(err) } _, err = dbnew.Exec(ctx, "INSERT INTO compat_ids (old, new, type) VALUES (:old, :new, :typ)", sq.PP{ "old": user.UserId, "new": userid, "typ": "userid", }) if err != nil { panic(err) } _, err = dbnew.Exec(ctx, "INSERT INTO keytokens (keytoken_id, name, timestamp_created, owner_user_id, all_channels, channels, token, permissions) VALUES (:tid, :nam, :tsc, :owr, :all, :cha, :tok, :prm)", sq.PP{ "tid": tokKeyID, "nam": "AdminKey (migrated)", "tsc": user.TimestampCreated.UnixMilli(), "owr": userid, "all": 1, "cha": "", "tok": tokKeySec, "prm": "A", }) if err != nil { panic(err) } var clientid *models.ClientID = nil if user.FcmToken != nil && *user.FcmToken != "BLACKLISTED" { if _, ok := usedFCM[*user.FcmToken]; ok { fmt.Printf("Skip Creating Client (fcm token reuse)\n") } else { _clientid := models.NewClientID() _, err = dbnew.Exec(ctx, "INSERT INTO clients (client_id, user_id, type, fcm_token, timestamp_created, agent_model, agent_version) VALUES (:cid, :uid, :typ, :fcm, :ts, :am, :av)", sq.PP{ "cid": _clientid, "uid": userid, "typ": "ANDROID", "fcm": *user.FcmToken, "ts": user.TimestampCreated.UnixMilli(), "am": "[migrated]", "av": "[migrated]", }) if err != nil { panic(err) } fmt.Printf("Created Client %s\n", _clientid) clientid = &_clientid usedFCM[*user.FcmToken] = _clientid _, err = dbnew.Exec(ctx, "INSERT INTO compat_clients (client_id) VALUES (:cid)", sq.PP{"cid": _clientid}) if err != nil { panic(err) } } } mainChannelID := models.NewChannelID() _, err = dbnew.Exec(ctx, "INSERT INTO channels (channel_id, owner_user_id, display_name, internal_name, description_name, subscribe_key, timestamp_created) VALUES (:cid, :ouid, :dnam, :inam, :hnam, :subkey, :ts)", sq.PP{ "cid": mainChannelID, "ouid": userid, "dnam": "main", "inam": "main", "hnam": nil, "subkey": scn.RandomAuthKey(), "ts": user.TimestampCreated.UnixMilli(), }) if err != nil { panic(err) } fmt.Printf("Created (Main) Channel [%s]: %s\n", "main", mainChannelID) _, err = dbnew.Exec(ctx, "INSERT INTO subscriptions (subscription_id, subscriber_user_id, channel_owner_user_id, channel_internal_name, channel_id, timestamp_created, confirmed) VALUES (:sid, :suid, :ouid, :cnam, :cid, :ts, :conf)", sq.PP{ "sid": models.NewSubscriptionID(), "suid": userid, "ouid": userid, "cnam": "main", "cid": mainChannelID, "ts": user.TimestampCreated.UnixMilli(), "conf": true, }) if err != nil { panic(err) } channelMap := make(map[string]models.ChannelID) lastTitle := "" lastChannel := models.NewChannelID() lastContent := langext.Ptr("") lastSendername := langext.Ptr("") lastTimestamp := time.Time{} for _, oldmessage := range messages { messageid := models.NewMessageID() title := oldmessage.Title channelInternalName := "main" channelID := mainChannelID if oldmessage.UsrMessageId != nil && strings.TrimSpace(*oldmessage.UsrMessageId) == "" { oldmessage.UsrMessageId = nil } if match, ok := rexTitleChannel.MatchFirst(title); ok { chanNameTitle := match.GroupByName("channel").Value() if strings.HasPrefix(chanNameTitle, "VBOARD ERROR") { chanNameTitle = "VBOARD-ERROR" } if chanNameTitle != "status" { title = match.GroupByName("title").Value() dummyApp := logic.Application{} dispName := dummyApp.NormalizeChannelDisplayName(chanNameTitle) intName := dummyApp.NormalizeChannelInternalName(chanNameTitle) if v, ok := channelMap[strings.ToLower(intName)]; ok { channelID = v channelInternalName = intName } else { channelID = models.NewChannelID() channelInternalName = intName _, err = dbnew.Exec(ctx, "INSERT INTO channels (channel_id, owner_user_id, display_name, internal_name, description_name, subscribe_key, timestamp_created) VALUES (:cid, :ouid, :dnam, :inam, :hnam, :subkey, :ts)", sq.PP{ "cid": channelID, "ouid": userid, "dnam": dispName, "inam": intName, "hnam": nil, "subkey": scn.RandomAuthKey(), "ts": oldmessage.TimestampReal.UnixMilli(), }) if err != nil { panic(err) } _, err = dbnew.Exec(ctx, "INSERT INTO subscriptions (subscription_id, subscriber_user_id, channel_owner_user_id, channel_internal_name, channel_id, timestamp_created, confirmed) VALUES (:sid, :suid, :ouid, :cnam, :cid, :ts, :conf)", sq.PP{ "sid": models.NewSubscriptionID(), "suid": userid, "ouid": userid, "cnam": intName, "cid": channelID, "ts": oldmessage.TimestampReal.UnixMilli(), "conf": true, }) if err != nil { panic(err) } channelMap[strings.ToLower(intName)] = channelID fmt.Printf("Auto Created Channel [%s]: %s\n", dispName, channelID) } } } sendername := determineSenderName(user, oldmessage, title, oldmessage.Content, channelInternalName) if sendername != nil && *sendername == "" { panic("sendername") } if lastTitle == title && channelID == lastChannel && langext.PtrEquals(lastContent, oldmessage.Content) && langext.PtrEquals(lastSendername, sendername) && oldmessage.TimestampReal.Sub(lastTimestamp) < 5*time.Second { lastTitle = title lastChannel = channelID lastContent = oldmessage.Content lastSendername = sendername lastTimestamp = oldmessage.TimestampReal //fmt.Printf("Skip message [%d] \"%s\" (fast-duplicate)\n", oldmessage.ScnMessageId, oldmessage.Title) continue } var sendTimeMillis *int64 = nil if oldmessage.Sendtime > 0 && (oldmessage.Sendtime*1000) != oldmessage.TimestampReal.UnixMilli() { sendTimeMillis = langext.Ptr(oldmessage.Sendtime * 1000) } if user.UserId == 56 && oldmessage.ScnMessageId >= 15729 { if _, ok := appids[oldmessage.ScnMessageId]; !ok { lastTitle = title lastChannel = channelID lastContent = oldmessage.Content lastSendername = sendername lastTimestamp = oldmessage.TimestampReal //fmt.Printf("Skip message [%d] \"%s\" (locally deleted in app)\n", oldmessage.ScnMessageId, oldmessage.Title) continue } } pp := sq.PP{ "mid": messageid, "suid": userid, "ouid": userid, "cnam": channelInternalName, "cid": channelID, "tsr": oldmessage.TimestampReal.UnixMilli(), "tsc": sendTimeMillis, "tit": title, "cnt": oldmessage.Content, "prio": oldmessage.Priority, "umid": oldmessage.UsrMessageId, "ip": "", "snam": sendername, "ukid": tokKeyID, } _, err = dbnew.Exec(ctx, "INSERT INTO messages (message_id, sender_user_id, owner_user_id, channel_internal_name, channel_id, timestamp_real, timestamp_client, title, content, priority, usr_message_id, sender_ip, sender_name, used_key_id) VALUES (:mid, :suid, :ouid, :cnam, :cid, :tsr, :tsc, :tit, :cnt, :prio, :umid, :ip, :snam, :ukid)", pp) if err != nil { jv, _ := json.MarshalIndent(pp, "", " ") fmt.Printf("%s", string(jv)) panic(err) } _, err = dbnew.Exec(ctx, "INSERT INTO compat_ids (old, new, type) VALUES (:old, :new, :typ)", sq.PP{ "old": oldmessage.ScnMessageId, "new": messageid, "typ": "messageid", }) if err != nil { panic(err) } if len(oldmessage.Ack) == 1 && oldmessage.Ack[0] == 1 { if clientid != nil { _, err = dbnew.Exec(ctx, "INSERT INTO deliveries (delivery_id, message_id, receiver_user_id, receiver_client_id, timestamp_created, timestamp_finalized, status, fcm_message_id, next_delivery) VALUES (:did, :mid, :ruid, :rcid, :tsc, :tsf, :stat, :fcm, :next)", sq.PP{ "did": models.NewDeliveryID(), "mid": messageid, "ruid": userid, "rcid": *clientid, "tsc": oldmessage.TimestampReal.UnixMilli(), "tsf": oldmessage.TimestampReal.UnixMilli(), "stat": models.DeliveryStatusSuccess, "fcm": *user.FcmToken, "next": nil, }) if err != nil { panic(err) } } _, err = dbnew.Exec(ctx, "INSERT INTO compat_acks (user_id, message_id) VALUES (:uid, :mid)", sq.PP{ "uid": userid, "mid": messageid, }) if err != nil { panic(err) } } else if len(oldmessage.Ack) == 1 && oldmessage.Ack[0] == 0 { if clientid != nil { _, err = dbnew.Exec(ctx, "INSERT INTO deliveries (delivery_id, message_id, receiver_user_id, receiver_client_id, timestamp_created, timestamp_finalized, status, fcm_message_id, next_delivery) VALUES (:did, :mid, :ruid, :rcid, :tsc, :tsf, :stat, :fcm, :next)", sq.PP{ "did": models.NewDeliveryID(), "mid": messageid, "ruid": userid, "rcid": *clientid, "tsc": oldmessage.TimestampReal.UnixMilli(), "tsf": oldmessage.TimestampReal.UnixMilli(), "stat": models.DeliveryStatusFailed, "fcm": *user.FcmToken, "next": nil, }) if err != nil { panic(err) } fmt.Printf("Create failed-delivery for message %d (no ack)\n", oldmessage.ScnMessageId) } } else { panic("cannot parse ack") } lastTitle = title lastChannel = channelID lastContent = oldmessage.Content lastSendername = sendername lastTimestamp = oldmessage.TimestampReal } { c, err := dbnew.Query(ctx, "SELECT COUNT (*) FROM messages WHERE sender_user_id = :uid", sq.PP{ "uid": userid, }) if err != nil { panic(err) } if !c.Next() { panic(false) } count := 0 err = c.Scan(&count) if err != nil { panic(err) } err = c.Close() if err != nil { panic(err) } if count > 0 { _, err = dbnew.Exec(ctx, "UPDATE users SET messages_sent = :c, timestamp_lastread = :ts0, timestamp_lastsent = :ts1 WHERE user_id = :uid", sq.PP{ "uid": userid, "c": count, "ts0": lastTimestamp.UnixMilli(), "ts1": lastTimestamp.UnixMilli(), }) if err != nil { panic(err) } } else { _, err = dbnew.Exec(ctx, "UPDATE users SET messages_sent = :c, timestamp_lastread = :ts0 WHERE user_id = :uid", sq.PP{ "uid": userid, "c": count, "ts0": user.TimestampCreated.UnixMilli(), }) if err != nil { panic(err) } } _, err = dbnew.Exec(ctx, "UPDATE keytokens SET messages_sent = :c WHERE owner_user_id = :uid", sq.PP{ "uid": userid, "c": count, }) if err != nil { panic(err) } } for _, cid := range channelMap { c, err := dbnew.Query(ctx, "SELECT COUNT (*) FROM messages WHERE sender_user_id = :uid AND channel_id = :cid", sq.PP{ "cid": cid, "uid": userid, }) if err != nil { panic(err) } if !c.Next() { panic(false) } count := 0 err = c.Scan(&count) if err != nil { panic(err) } err = c.Close() if err != nil { panic(err) } _, err = dbnew.Exec(ctx, "UPDATE channels SET messages_sent = :c WHERE channel_id = :cid", sq.PP{ "cid": cid, "c": count, }) if err != nil { panic(err) } } } func determineSenderName(user OldUser, oldmessage OldMessage, title string, content *string, channame string) *string { if user.UserId != 56 { return nil } channame = strings.ToLower(channame) if channame == "t-ctrl" { return langext.Ptr("sbox") } if channame == "torr" { return langext.Ptr("sbox") } if channame == "yt-dl" { return langext.Ptr("mscom") } if channame == "ncc-upload" { return langext.Ptr("mscom") } if channame == "cron" { if strings.Contains(title, "error on bfb") { return langext.Ptr("bfb") } if strings.Contains(title, "error on mscom") { return langext.Ptr("mscom") } if strings.Contains(title, "error on niflheim-3") { return langext.Ptr("niflheim-3") } if strings.Contains(title, "error on statussrv") { return langext.Ptr("statussrv") } if strings.Contains(title, "error on plan-web-prod") { return langext.Ptr("plan-web-prod") } if strings.Contains(title, "error on inoshop") { return langext.Ptr("inoshop") } if strings.Contains(title, "error on firestopcloud") { return langext.Ptr("firestopcloud") } if strings.Contains(title, "error on plantafelstaging") { return langext.Ptr("plantafelstaging") } if strings.Contains(title, "error on plantafeldev") { return langext.Ptr("plantafeldev") } if strings.Contains(title, "error on balu-prod") { return langext.Ptr("lbxprod") } if strings.Contains(title, "error on dyno-prod") { return langext.Ptr("dyno-prod") } if strings.Contains(title, "error on dyno-dev") { return langext.Ptr("dyno-dev") } if strings.Contains(title, "error on wkk") { return langext.Ptr("wkk") } if strings.Contains(title, "error on lbxdev") { return langext.Ptr("lbxdev") } if strings.Contains(title, "error on lbxprod") { return langext.Ptr("lbxprod") } if strings.Contains(*content, "on mscom") { return langext.Ptr("mscom") } if strings.Contains(*content, "on bfb") { return langext.Ptr("bfb") } if strings.Contains(*content, "gogitmirror_cron") { return langext.Ptr("mscom") } if strings.Contains(*content, "comic_downloader") { return langext.Ptr("mscom") } } if channame == "sshguard" { if strings.Contains(*content, "logged in to mscom") { return langext.Ptr("mscom") } if strings.Contains(*content, "logged in to bfb") { return langext.Ptr("bfb") } if strings.Contains(*content, "logged in to statussrv") { return langext.Ptr("statussrv") } } if channame == "docker-watch" { if strings.Contains(title, "on plantafelstaging") { return langext.Ptr("plantafelstaging") } if strings.Contains(title, "@ mscom") { return langext.Ptr("mscom") } if strings.Contains(title, "@ bfb") { return langext.Ptr("bfb") } if strings.Contains(*content, "registry.blackforestbytes.com/scn_server:latest") { return langext.Ptr("bfb") } if strings.Contains(*content, "archivebox/archivebox:latest") { return langext.Ptr("mscom") } if strings.Contains(*content, "antoniomika/sish:latest") { return langext.Ptr("mscom") } if strings.Contains(*content, "binwiederhier/ntfy:latest") { return langext.Ptr("mscom") } if strings.Contains(*content, "registry.blackforestbytes.com/kgserver:latest") { return langext.Ptr("mscom") } if strings.Contains(*content, "registry.blackforestbytes.com/mikescher/kgserver:latest") { return langext.Ptr("mscom") } if strings.Contains(*content, "jenkins/jenkins:lts") { return langext.Ptr("mscom") } if strings.Contains(*content, "mikescher/youtube-dl-viewer:latest") { return langext.Ptr("mscom") } if strings.Contains(*content, "etherpad/etherpad:latest") { return langext.Ptr("mscom") } if strings.Contains(*content, "teamcity_agent") { return langext.Ptr("bfb") } if strings.Contains(*content, "teamcity_server") { return langext.Ptr("bfb") } if strings.Contains(*content, "registry.blackforestbytes.com/inoshop/") { return langext.Ptr("inoshop") } if strings.Contains(*content, "inopart_mongo_") { return langext.Ptr("inoshop") } if strings.Contains(*content, "Image: wkk_") { return langext.Ptr("wkk") } if strings.Contains(*content, "registry.blackforestbytes.com/holz100") { return langext.Ptr("bfb") } if strings.Contains(*content, "registry.blackforestbytes.com/bewirto") { return langext.Ptr("bfb-testserver") } if strings.Contains(*content, "registry.blackforestbytes.com/bfb-website") { return langext.Ptr("bfb") } if strings.Contains(*content, "registry.blackforestbytes.com/bfb/website") { return langext.Ptr("bfb") } if strings.Contains(*content, "registry.blackforestbytes.com/psycho/backend") { return langext.Ptr("bfb-testserver") } if strings.Contains(*content, "registry.blackforestbytes.com/vereinsboard") { return langext.Ptr("bfb") } if strings.Contains(*content, "registry.blackforestbytes.com/isiproject") { return langext.Ptr("bfb") } if strings.Contains(*content, "registry.blackforestbytes.com/ar-app-supportchat-server") { return langext.Ptr("bfb") } if strings.Contains(*content, "registry.blackforestbytes.com/planitec/ar-app-supportchat-server") { return langext.Ptr("bfb") } if strings.Contains(*content, "docker_registry") { return langext.Ptr("bfb") } if strings.Contains(*content, "registry.blackforestbytes.com/balu") && strings.Contains(*content, "prod") { return langext.Ptr("lbxprod") } if strings.Contains(*content, "registry.blackforestbytes.com/balu") && strings.Contains(*content, "dev") { return langext.Ptr("lbxdev") } if strings.Contains(*content, "Server: bfb-testserver") { return langext.Ptr("bfb-testserver") } if strings.Contains(*content, "wptest_") { return langext.Ptr("bfb") } if strings.Contains(title, "balu-db") { return langext.Ptr("lbxprod") } } if channame == "certbot" { if strings.Contains(title, "Update cert_badennet_main") { return langext.Ptr("bfb-testserver") } if strings.Contains(title, "Update cert_badennet_main") { return langext.Ptr("bfb-testserver") } if strings.Contains(title, "Update cert_bfbugs_main") { return langext.Ptr("bfb-testserver") } if strings.Contains(title, "Update bfbugs_0001") { return langext.Ptr("bfb-testserver") } if strings.Contains(title, "Update inoshop_bfb") { return langext.Ptr("inoshop") } if strings.Contains(title, "Update cert_bfb_0001") { return langext.Ptr("mscom") } if strings.Contains(title, "Update cert_bugkultur_0001") { return langext.Ptr("mscom") } if strings.Contains(title, "Update cert_public_0001") { return langext.Ptr("mscom") } if strings.Contains(title, "Update cert_korbers_0001") { return langext.Ptr("mscom") } if strings.Contains(title, "Update cert_wkk_staging_external") { return langext.Ptr("wkk") } if strings.Contains(title, "Update cert_wkk_production_external") { return langext.Ptr("wkk") } if strings.Contains(title, "Update cert_wkk_develop_external") { return langext.Ptr("wkk") } if strings.Contains(title, "Update cert_wkk_internal") { return langext.Ptr("wkk") } if strings.Contains(title, "Update bfb_de_wildcard") { return langext.Ptr("bfb") } if strings.Contains(title, "Update cannonconquest") { return langext.Ptr("bfb") } if strings.Contains(title, "Update isiproject_wildcard") { return langext.Ptr("bfb") } if strings.Contains(title, "Update vereinsboard_demo") { return langext.Ptr("bfb") } if strings.Contains(title, "Update vereinsboard_wildcard") { return langext.Ptr("bfb") } if strings.Contains(title, "Update cert_bewirto_main") { return langext.Ptr("bfb-testserver") } if strings.Contains(title, "Update cert_badennet_main") { return langext.Ptr("bfb-testserver") } if strings.Contains(title, "Update cert_mampfkultur_main") { return langext.Ptr("bfb-testserver") } if strings.Contains(title, "Update cert_psycho_main") { return langext.Ptr("bfb-testserver") } if strings.Contains(*content, "DNS:*.blackforestbytes.com") { return langext.Ptr("bfb") } if strings.Contains(*content, "DNS:*.mikescher.com") { return langext.Ptr("mscom") } if strings.Contains(title, "plantafel-digital.de") { return langext.Ptr("plan-web-prod") } if strings.Contains(title, "plantafeldev.de") { return langext.Ptr("plantafeldev") } if strings.Contains(title, "plantafelstaging.de") { return langext.Ptr("plantafeldev") } if strings.Contains(*content, "DNS:*.plantafeldev.de") { return langext.Ptr("plantafeldev") } if strings.Contains(*content, "plantafel-digital.de") { return langext.Ptr("plan-web-prod") } if strings.Contains(*content, "plantafeldev.de") { return langext.Ptr("plantafeldev") } if strings.Contains(*content, "plantafelstaging.de") { return langext.Ptr("plantafeldev") } if strings.Contains(title, "Update cert_mscom") { return langext.Ptr("mscom") } if strings.Contains(title, "Update cert_bfb") { return langext.Ptr("bfb") } if strings.Contains(title, "Update staging.app.reuse.me") { return langext.Ptr("wkk") } if strings.Contains(title, "Update develop.app.reuse.me") { return langext.Ptr("wkk") } if strings.Contains(title, "Update inoshop_staging_bfb") { return langext.Ptr("inoshop") } if strings.Contains(title, "Update cert_portfoliomanager_main") { return langext.Ptr("bfb-testserver") } if strings.Contains(title, "Update cert_pfm2") { return langext.Ptr("bfb-testserver") } if strings.Contains(title, "Update cert_kaz_main") { return langext.Ptr("bfb-testserver") } } if channame == "space-warning" { if title == "bfb" { return langext.Ptr("bfb") } if title == "mscom" { return langext.Ptr("mscom") } if title == "plan-web-prod" { return langext.Ptr("plan-web-prod") } if title == "statussrv" { return langext.Ptr("statussrv") } if title == "virmach01" { return langext.Ptr("statussrv") } } if channame == "srv-backup" { if strings.Contains(*content, "Server: bfb-testserver") { return langext.Ptr("bfb-testserver") } if strings.Contains(*content, "Server: bfb") { return langext.Ptr("bfb") } if strings.Contains(*content, "Server: mscom") { return langext.Ptr("mscom") } if strings.Contains(*content, "Server: statussrv") { return langext.Ptr("statussrv") } } if title == "[status] Updating uptime-kuma image" { return langext.Ptr("statussrv") } if channame == "omv-backup" { return langext.Ptr("omv") } if channame == "omv-rcheck" { return langext.Ptr("omv") } if channame == "tfin" { return langext.Ptr("sbox") } if channame == "vboard-error" { return langext.Ptr("bfb") } if channame == "vboard" { return langext.Ptr("bfb") } if channame == "cubox" { return langext.Ptr("cubox") } if channame == "sys" { if strings.Contains(title, "h2896063") { return langext.Ptr("mscom") } if strings.Contains(title, "h2516246") { return langext.Ptr("mscom") } if strings.Contains(title, "h2770024") { return langext.Ptr("bfb") } if strings.Contains(title, "Reboot plan-web-prod") { return langext.Ptr("plan-web-prod") } if strings.Contains(title, "Reboot mikescher.com") { return langext.Ptr("mscom") } if strings.Contains(title, "Reboot blackforestbytes.com") { return langext.Ptr("bfb") } if strings.Contains(title, "Reboot plan-web-dev") { return langext.Ptr("plan-web-dev") } if strings.Contains(title, "Reboot plan-web-staging") { return langext.Ptr("plan-web-staging") } if strings.Contains(title, "Reboot virmach-01") { return langext.Ptr("statussrv") } if strings.Contains(title, "Reboot wkk-1") { return langext.Ptr("wkk") } if strings.Contains(title, "Reboot lbxprod") { return langext.Ptr("lbxprod") } if strings.Contains(title, "Reboot plantafeldev") { return langext.Ptr("plantafeldev") } if strings.Contains(title, "Reboot plantafelstaging") { return langext.Ptr("plantafelstaging") } if strings.Contains(title, "Reboot statussrv") { return langext.Ptr("statussrv") } if strings.Contains(title, "Reboot heydyno-prod-01") { return langext.Ptr("dyno-prod") } if strings.Contains(title, "Reboot heydyno-dev-01") { return langext.Ptr("dyno-dev") } if strings.Contains(title, "Reboot lbxdev") { return langext.Ptr("lbxdev") } if strings.Contains(langext.Coalesce(content, ""), "Server: 'firestopcloud'") { return langext.Ptr("firestopcloud") } } if channame == "yt-tvc" { return langext.Ptr("mscom") } if channame == "gdapi" { return langext.Ptr("bfb") } if channame == "ttrss" { return langext.Ptr("mscom") } if channame == "backup-rr" { if strings.Contains(title, "bfb/server-plantafelstaging") { return langext.Ptr("plantafelstaging") } if strings.Contains(title, "bfb/server-plantafeldev") { return langext.Ptr("plantafeldev") } if strings.Contains(title, "bfb/server-wkk") { return langext.Ptr("wkk") } if strings.Contains(title, "bfb/holz100") { return langext.Ptr("bfb") } if strings.Contains(title, "bfb/clockify") { return langext.Ptr("bfb") } if strings.Contains(title, "bfb/gdapi") { return langext.Ptr("bfb") } if strings.Contains(title, "mike/databases-mscom") { return langext.Ptr("mscom") } if strings.Contains(title, "bfb/databases-bfb") { return langext.Ptr("bfb") } if strings.Contains(title, "bfb/server-dynoprod") { return langext.Ptr("dyno-prod") } if strings.Contains(title, "bfb/server-dynodev") { return langext.Ptr("dyno-dev") } if strings.Contains(title, "bfb/server-baluprod") { return langext.Ptr("lbxprod") } if strings.Contains(title, "bfb/server-baludev") { return langext.Ptr("lbxdev") } if strings.Contains(title, "bfb/plantafeldigital") { return langext.Ptr("plan-web-prod") } if strings.Contains(title, "mike/server-statussrv") { return langext.Ptr("statussrv") } if strings.Contains(title, "mike/thunderbird") { return langext.Ptr("niflheim-3") } if strings.Contains(title, "mike/seedbox") { return langext.Ptr("sbox") } if strings.Contains(title, "bfb/balu") { return langext.Ptr("lbxprod") } if strings.Contains(title, "mike/ext-git-graph") { return langext.Ptr("mscom") } if strings.Contains(title, "bfb/server-bfbtest") { return langext.Ptr("bfb-testserver") } if strings.Contains(title, "mike/server-mscom") { return langext.Ptr("mscom") } if strings.Contains(title, "mike/database-statussrv") { return langext.Ptr("statussrv") } if strings.Contains(title, "mike/server-mscom") { return langext.Ptr("mscom") } if strings.Contains(title, "mike/server-inoshop") { return langext.Ptr("inoshop") } if strings.Contains(title, "mike/server-bfb") { return langext.Ptr("bfb") } if strings.Contains(title, "bfb/discord") { return langext.Ptr("nifleim-3") } if strings.Contains(title, "bfb/server-bfbtest") { return langext.Ptr("bfb-testserver") } if strings.Contains(title, "mike/ext-git-graph") { return langext.Ptr("mscom") } if strings.Contains(title, "bfb/server-inoshop") { return langext.Ptr("inoshop") } if strings.Contains(title, "bfb/server-bfb") { return langext.Ptr("bfb") } if strings.Contains(title, "bfb/server-plantafelprod") { return langext.Ptr("plan-web-prod") } if strings.Contains(title, "bfb/server-inoshop") { return langext.Ptr("inoshop") } if strings.Contains(title, "mike/niflheim-3") { return langext.Ptr("niflheim-3") } if strings.Contains(title, "mike/pihole") { return langext.Ptr("pihole") } if strings.Contains(title, "bfb/server-firestopcloud") { return langext.Ptr("firestopcloud") } if strings.Contains(title, "bfb/server-agentzero") { return langext.Ptr("agentzero") } } if channame == "backup" { if strings.Contains(title, "mike/ext-git-graph") { return langext.Ptr("mscom") } } if channame == "spezi-alert" { return langext.Ptr("mscom") } if title == "NCC Upload failed" || title == "NCC Upload successful" { return langext.Ptr("mscom") } if oldmessage.ScnMessageId == 7975 { return langext.Ptr("mscom") } if strings.Contains(title, "BFBackup VC migrate") { return langext.Ptr("bfbackup") } if strings.Contains(title, "bfbackup job") { return langext.Ptr("bfbackup") } if strings.Contains(title, "bfbackup finished") { return langext.Ptr("bfbackup") } if strings.Contains(title, "Repo migration of /volume1") { return langext.Ptr("bfbackup") } if channame == "docker-watch" { return nil // okay } //fmt.Printf("Failed to determine sender of [%d] '%s' '%s'\n", oldmessage.ScnMessageId, oldmessage.Title, langext.Coalesce(oldmessage.Content, "<NULL>")) fmt.Printf("%s", termext.Red(fmt.Sprintf("Failed to determine sender of [%d] '%s' -- '%s' -- '%s'\n", oldmessage.ScnMessageId, channame, title, langext.Coalesce(oldmessage.Content, "<NULL>")))) return nil }