From 66e906f139ee93ddf6a81ca5824e2ffddc737a84 Mon Sep 17 00:00:00 2001 From: qugalet Date: Tue, 19 Sep 2023 22:19:25 +0300 Subject: [PATCH] Rewrite in Go Signed-off-by: qugalet --- .dockerignore | 3 + .env.example | 15 +++ .gitignore | 4 + Dockerfile | 15 +++ README.md | 47 ++++++++ entrypoint.sh | 6 + go.mod | 39 +++++++ go.sum | 74 +++++++++++++ main.go | 296 ++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 499 insertions(+) create mode 100644 .dockerignore create mode 100755 .env.example create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 entrypoint.sh create mode 100755 go.mod create mode 100755 go.sum create mode 100755 main.go diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..8ba473e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +domains.txt +nicknames.txt +uabot diff --git a/.env.example b/.env.example new file mode 100755 index 0000000..499e7e8 --- /dev/null +++ b/.env.example @@ -0,0 +1,15 @@ +POSTGRES_HOST= +POSTGRES_USER= +POSTGRES_PASSWORD= +POSTGRES_DB= +POSTGRES_PORT= + +MATRIX_HOMESERVER= +MATRIX_USERNAME= +MATRIX_ACCESS_TOKEN= +MATRIX_ROOM_ID= + +MASTODON_HOMESERVER= +MASTODON_CLIENT_ID= +MASTODON_CLIENT_SECRET= +MASTODON_ACCESS_TOKEN= diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..469158f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.env +domains.txt +nicknames.txt +uabot diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a7ec6ca --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +# syntax=docker/dockerfile:1 + +FROM golang:1.20 + +WORKDIR /app + +COPY go.mod go.sum . + +RUN go mod download + +COPY . . + +RUN CGO_ENABLED=0 GOOS=linux go build -o /app/uabot + +ENTRYPOINT ["/app/entrypoint.sh"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..4369a76 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +## UA-Bot + +**UA-Bot** - Bot for Mastodon that reboosts message if mentioned. + +### Features + +- Moderation - Send to Matrix room before reblog +- Reply or broken thread detection (not fully tested) +- Block instances and nicknames by regex + +### Install + +First, install Postgres (>= 14 will be fine, i guess). + +Second, clone repo. + +Copy `.env.example` to `.env` and edit with your data + +Also create `nicknames.txt` and `domains.txt` (regex files): + +- `nicknames.txt` - block by username or display name +- `domains.txt` - block by domain name + +Tip: `#` in the beginning of the regex file means that this line will be ignored. You can use it as comment + +Now you can install using **Dockerimage** or **manually**: + +#### Docker + +Build `Dockerfile` and run +Also, mount `domains.txt` and `nicknames.txt` to the `/app` + +### Manually + +Install Go >= 1.20 + +Next, build the project: + +```sh +go build +``` + +Run: + +```sh +./uabot +``` diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..ab53ff9 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +test -f domains.txt || touch domains.txt +test -f nicknames.txt || touch nicknames.txt + +./uabot diff --git a/go.mod b/go.mod new file mode 100755 index 0000000..1d284ff --- /dev/null +++ b/go.mod @@ -0,0 +1,39 @@ +module uabot + +go 1.20 + +require ( + github.com/mattn/go-mastodon v0.0.6 + gorm.io/gorm v1.25.4 +) + +require ( + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.3.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/rs/zerolog v1.30.0 // indirect + github.com/tidwall/gjson v1.16.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/sjson v1.2.5 // indirect + go.mau.fi/util v0.1.0 // indirect + golang.org/x/crypto v0.13.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.15.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect + maunium.net/go/maulogger/v2 v2.4.1 // indirect +) + +require ( + github.com/gorilla/websocket v1.5.0 // indirect + github.com/joho/godotenv v1.5.1 + github.com/sirupsen/logrus v1.9.3 + github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect + gorm.io/driver/postgres v1.5.2 + maunium.net/go/mautrix v0.16.1 +) diff --git a/go.sum b/go.sum new file mode 100755 index 0000000..2a01d26 --- /dev/null +++ b/go.sum @@ -0,0 +1,74 @@ +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-mastodon v0.0.6 h1:lqU1sOeeIapaDsDUL6udDZIzMb2Wqapo347VZlaOzf0= +github.com/mattn/go-mastodon v0.0.6/go.mod h1:cg7RFk2pcUfHZw/IvKe1FUzmlq5KnLFqs7eV2PHplV8= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= +github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= +github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= +github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= +go.mau.fi/util v0.1.0 h1:BwIFWIOEeO7lsiI2eWKFkWTfc5yQmoe+0FYyOFVyaoE= +go.mau.fi/util v0.1.0/go.mod h1:AxuJUMCxpzgJ5eV9JbPWKRH8aAJJidxetNdUj7qcb84= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= +gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= +gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= +gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +maunium.net/go/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8= +maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho= +maunium.net/go/mautrix v0.16.1 h1:Wb3CvOCe8A/NLsFeZYxKrgXKiqeZUQEBD1zqm7n/kWk= +maunium.net/go/mautrix v0.16.1/go.mod h1:2Jf15tulVtr6LxoiRL4smRXwpkGWUNfBFhwh/aXDBuk= diff --git a/main.go b/main.go new file mode 100755 index 0000000..60f01be --- /dev/null +++ b/main.go @@ -0,0 +1,296 @@ +package main + +import ( + "bufio" + "context" + "fmt" + "os" + "path" + "regexp" + "strings" + + "github.com/joho/godotenv" + log "github.com/sirupsen/logrus" + + "github.com/mattn/go-mastodon" + "gorm.io/driver/postgres" + "gorm.io/gorm" + "maunium.net/go/mautrix" + m_event "maunium.net/go/mautrix/event" + m_id "maunium.net/go/mautrix/id" +) + +type Post struct { + ID int + PostId string + MessageId string +} + +func parseRegexFile(path string) ([]regexp.Regexp, error) { + file, err := os.Open(path) + + if err != nil { + return nil, err + } + + file_scanner := bufio.NewScanner(file) + + file_scanner.Split(bufio.ScanLines) + + var result []regexp.Regexp + + for file_scanner.Scan() { + text := file_scanner.Text() + if strings.Trim(text, " ")[0] != '#' { + regex, err := regexp.Compile(text) + if err != nil { + return nil, err + } + result = append(result, *regex) + } + } + return result, nil +} + +func main() { + ctx := context.Background() + err := godotenv.Load() + + if err != nil { + log.Fatal(err) + } + + ex, err := os.Getwd() + + if err != nil { + log.Fatal(err) + } + + domainRegexes, err := parseRegexFile(path.Join(ex, "domains.txt")) + + if err != nil { + log.Fatal(err) + } + + nicknameRegexes, err := parseRegexFile(path.Join(ex, "nicknames.txt")) + + if err != nil { + log.Fatal(err) + } + + // log.Info(nicknameRegexes, domainRegexes) + + db, err := gorm.Open(postgres.Open(fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s", + os.Getenv("POSTGRES_HOST"), + os.Getenv("POSTGRES_USER"), + os.Getenv("POSTGRES_PASSWORD"), + os.Getenv("POSTGRES_DB"), + os.Getenv("POSTGRES_PORT"))), &gorm.Config{}) + + db.AutoMigrate(&Post{}) + + if err != nil { + log.Fatal(err) + } + + masto_client := mastodon.NewClient(&mastodon.Config{ + Server: os.Getenv("MASTODON_HOMESERVER"), + ClientID: os.Getenv("MASTODON_CLIENT_ID"), + ClientSecret: os.Getenv("MASTODON_CLIENT_SECRET"), + AccessToken: os.Getenv("MASTODON_ACCESS_TOKEN"), + }) + masto_user, err := masto_client.GetAccountCurrentUser(ctx) + + if err != nil { + log.Fatal(err) + } + + // log.Println(my_account) + + matrix_client, err := mautrix.NewClient(os.Getenv("MATRIX_HOMESERVER"), m_id.UserID(os.Getenv("MATRIX_USERNAME")), os.Getenv("MATRIX_ACCESS_TOKEN")) + matrix_client.Store = mautrix.NewAccountDataStore("ua.in.fediland.uabot", matrix_client) + syncer := matrix_client.Syncer.(*mautrix.DefaultSyncer) + + if err != nil { + log.Fatal(err) + } + log.Info("starting...") + + syncer.OnEventType(m_event.EventReaction, func(source mautrix.EventSource, ev *m_event.Event) { + log.Info("reactions") + // if ev.RoomID == os.Getenv("MATRIX_ROOM_ID") && ev.Content != nil && + content := ev.Content.AsReaction() + key := []rune(content.RelatesTo.Key) + log.Info(content.RelatesTo.Key) + if ev.RoomID.String() == os.Getenv("MATRIX_ROOM_ID") && (key[0] == '👍' || key[0] == '👎') { + log.Info("reacted well") + var post Post + if err := db.First(&post, "message_id = ?", content.RelatesTo.EventID.String()).Error; err != nil { + log.Error(err) + return + } + status, err := masto_client.GetStatus(ctx, mastodon.ID(post.PostId)) + + if err != nil { + log.Error(err) + return + } + + if key[0] == '👍' { + _, err = masto_client.Reblog(ctx, mastodon.ID(post.PostId)) + if err != nil { + log.Error(err) + return + } + // matrix_client.SendMessageEvent(os.Getenv("MATRIX_ROOM_ID"), "m.room.message", interface{}) + body := fmt.Sprintf(`#%d: Схвалено +%s +`, post.ID, status.URL) + + _, err := matrix_client.SendMessageEvent(m_id.RoomID(os.Getenv("MATRIX_ROOM_ID")), m_event.EventMessage, &m_event.MessageEventContent{ + Body: body, + MsgType: m_event.MsgText, + NewContent: &m_event.MessageEventContent{ + MsgType: m_event.MsgText, + Body: body}, + RelatesTo: &m_event.RelatesTo{ + Type: m_event.RelReplace, + EventID: m_id.EventID(post.MessageId), + }, + }) + + if err != nil { + log.Error(err) + } + + } else { + body := fmt.Sprintf(`#%d: Відмовлено +%s +`, post.ID, status.URL) + _, err := matrix_client.SendMessageEvent(m_id.RoomID(os.Getenv("MATRIX_ROOM_ID")), m_event.EventMessage, &m_event.MessageEventContent{ + Body: body, + MsgType: m_event.MsgText, + NewContent: &m_event.MessageEventContent{ + MsgType: m_event.MsgText, + Body: body, + }, + RelatesTo: &m_event.RelatesTo{ + Type: m_event.RelReplace, + EventID: m_id.EventID(post.MessageId), + }, + }) + if err != nil { + log.Error(err) + } + } + } + }) + + events, err := masto_client.StreamingUser(ctx) + + if err != nil { + log.Fatal(err) + } + + go func() { + for { + if err := matrix_client.Sync(); err != nil { + log.Error(fmt.Errorf("Sync() returned %s", err)) + } + } + }() + +notif_loop: + for { + notif_event, ok := (<-events).(*mastodon.NotificationEvent) + if !ok { + continue + } + notif := notif_event.Notification + + // log.Println(notif) + + if notif.Type == "follow" { + acct_parsed := strings.Split(notif.Account.Acct, "@") + + for _, regex := range domainRegexes { + if len(acct_parsed) == 2 && regex.MatchString(acct_parsed[1]) { + _, err := masto_client.AccountBlock(ctx, notif.Account.ID) + if err == nil { + matrix_client.SendText(m_id.RoomID(os.Getenv("MATRIX_ROOM_ID")), fmt.Sprintf("%s заблокований автоматично регексом доменів: %s", notif.Account.Acct, regex.String())) + } + continue notif_loop + } + } + + for _, regex := range nicknameRegexes { + if regex.MatchString(acct_parsed[0]) { + _, err := masto_client.AccountBlock(ctx, notif.Account.ID) + if err == nil { + matrix_client.SendText(m_id.RoomID(os.Getenv("MATRIX_ROOM_ID")), fmt.Sprintf("%s заблокований автоматично регексом нікнеймів: %s", notif.Account.Acct, regex.String())) + } + continue notif_loop + } + } + + masto_client.PostStatus(ctx, &mastodon.Toot{ + Status: fmt.Sprintf("Вітаємо у нашій спільноті! @%s", notif.Account.Acct), + Visibility: mastodon.VisibilityUnlisted, + }) + } + + if notif.Type == "mention" && notif.Status.InReplyToID == nil && notif.Status.InReplyToAccountID == nil { + subscribers, err := masto_client.GetAccountFollowers(ctx, masto_user.ID, &mastodon.Pagination{Limit: 10000}) + if err != nil { + log.Error(err) + continue + } + + ok := false + + for _, subscriber := range subscribers { + if subscriber.ID == notif.Account.ID { + ok = true + break + } + } + + if ok && notif.Status.Visibility == "public" { + if err := db.Create(&Post{ + PostId: string(notif.Status.ID), + }).Error; err != nil { + log.Error(err) + continue + } + var post Post + if err := db.First(&post, "post_id = ?", string(notif.Status.ID)).Error; err != nil { + log.Error(err) + continue + } + message, err := matrix_client.SendText(m_id.RoomID(os.Getenv("MATRIX_ROOM_ID")), fmt.Sprintf(`#%d: На модерації +%s +👍 - Так +👎 - Ні +`, post.ID, notif.Status.URL)) + if err != nil { + log.Fatal(err) + db.Delete(&post, post.ID) + } + + post.MessageId = message.EventID.String() + db.Save(&post) + } + + if ok && notif.Status.Visibility == "direct" && notif.Status.Content == "ping" { + masto_client.PostStatus(ctx, &mastodon.Toot{ + Status: "meow", + InReplyToID: notif.Status.ID, + Visibility: "direct", + }) + } + + } + + } + +}