diff --git a/app/admin/handler.go b/app/admin/handler.go index bb06d08..0c7986c 100644 --- a/app/admin/handler.go +++ b/app/admin/handler.go @@ -1,10 +1,10 @@ package admin import ( - "brainbaking.com/go-jamming/app/mf" "brainbaking.com/go-jamming/common" "brainbaking.com/go-jamming/db" "brainbaking.com/go-jamming/rest" + "fmt" "github.com/gorilla/mux" "net/http" ) @@ -16,32 +16,39 @@ func HandleGet(repo db.MentionRepo) http.HandlerFunc { } } -// TODO validate or not? see webmention.HandlePost // TODO unit tests +// HandleApprove approves the Mention (by key in URL) and adds to the whitelist. +// Returns 200 OK with approved source/target or 404 if key is invalid. func HandleApprove(c *common.Config, repo db.MentionRepo) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - wm := mf.Mention{ - Source: r.FormValue("source"), - Target: r.FormValue("target"), + key := mux.Vars(r)["key"] + + approved := repo.Approve(key) + if approved == nil { + http.NotFound(w, r) + return } - repo.Approve(wm) - c.AddToWhitelist(wm.SourceDomain()) - w.WriteHeader(200) + c.AddToWhitelist(approved.AsMention().SourceDomain()) + w.WriteHeader(http.StatusOK) + fmt.Fprintf(w, "Approved: %s", approved.AsMention().String()) } } +// HandleReject rejects the Mention (by key in URL) and adds to the blacklist. +// Returns 200 OK with rejected source/target or 404 if key is invalid. func HandleReject(c *common.Config, repo db.MentionRepo) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - wm := mf.Mention{ - Source: r.FormValue("source"), - Target: r.FormValue("target"), + key := mux.Vars(r)["key"] + + rejected := repo.Reject(key) + if rejected == nil { + http.NotFound(w, r) + return } - repo.Reject(wm) - c.AddToBlacklist(wm.SourceDomain()) - w.WriteHeader(200) + c.AddToBlacklist(rejected.AsMention().SourceDomain()) + w.WriteHeader(http.StatusOK) + fmt.Fprintf(w, "Rejected: %s", rejected.AsMention().String()) } } diff --git a/app/mf/mention.go b/app/mf/mention.go index 9141288..931506d 100644 --- a/app/mf/mention.go +++ b/app/mf/mention.go @@ -39,7 +39,8 @@ func (wm Mention) SourceDomain() string { // Key returns a unique string representation of the mention for use in storage. // TODO Profiling indicated that md5() consumes a lot of CPU power, so this could be replaced with db migration. func (wm Mention) Key() string { - return fmt.Sprintf("%x", md5.Sum([]byte("source="+wm.Source+",target="+wm.Target))) + key := fmt.Sprintf("%x", md5.Sum([]byte("source="+wm.Source+",target="+wm.Target))) + return fmt.Sprintf("%s:%s", key, wm.TargetDomain()) } func (wm Mention) SourceUrl() *url.URL { diff --git a/app/notifier/mailnotifier.go b/app/notifier/mailnotifier.go new file mode 100644 index 0000000..a03ca99 --- /dev/null +++ b/app/notifier/mailnotifier.go @@ -0,0 +1,67 @@ +package notifier + +import ( + "brainbaking.com/go-jamming/app/mf" + "brainbaking.com/go-jamming/common" + "encoding/base64" + "github.com/rs/zerolog/log" + "net/mail" + "net/smtp" +) + +type MailNotifier struct { + Conf *common.Config +} + +// sendMail is a utility function that sends a mail without authentication to localhost. Tested using postfix. +// cheers https://github.com/gadelkareem/go-helpers/blob/master/helpers.go +func sendMail(from, subject, body, toName, toAddress string) error { + c, err := smtp.Dial("127.0.0.1:25") + if err != nil { + return err + } + defer c.Close() + if err = c.Mail(from); err != nil { + return err + } + + to := (&mail.Address{toName, toAddress}).String() + if err = c.Rcpt(to); err != nil { + return err + } + + w, err := c.Data() + if err != nil { + return err + } + + msg := "To: " + to + "\r\n" + + "From: " + from + "\r\n" + + "Subject: " + subject + "\r\n" + + "Content-Type: text/html; charset=\"UTF-8\"\r\n" + + "Content-Transfer-Encoding: base64\r\n" + + "\r\n" + base64.StdEncoding.EncodeToString([]byte(body)) + + _, err = w.Write([]byte(msg)) + if err != nil { + return err + } + err = w.Close() + if err != nil { + return err + } + return c.Quit() +} + +func (mn *MailNotifier) NotifyReceived(wm mf.Mention, indieweb *mf.IndiewebData) { + err := sendMail( + "admin@brainbaking.com", + "Webmention in moderation from "+wm.SourceDomain(), + BuildNotification(wm, indieweb, mn.Conf), + "Go-Jamming User", + "wouter@brainbaking.com") + + if err != nil { + log.Err(err).Msg("Unable to send notification mail, check localhost postfix settings?") + } +} diff --git a/app/notifier/notifier.go b/app/notifier/notifier.go new file mode 100644 index 0000000..575a46d --- /dev/null +++ b/app/notifier/notifier.go @@ -0,0 +1,24 @@ +package notifier + +import ( + "brainbaking.com/go-jamming/app/mf" + "brainbaking.com/go-jamming/common" + "fmt" +) + +type Notifier interface { + NotifyReceived(wm mf.Mention, data *mf.IndiewebData) +} + +// BuildNotification returns a string representation of the Mention to notify the admin. +func BuildNotification(wm mf.Mention, data *mf.IndiewebData, cnf *common.Config) string { + enter := "\n" + acceptUrl := fmt.Sprintf("%sadmin/approve/%s/%s", cnf.BaseURL, cnf.Token, wm.Key()) + rejectUrl := fmt.Sprintf("%sadmin/reject/%s/%s", cnf.BaseURL, cnf.Token, wm.Key()) + + return fmt.Sprintf("Hi admin, %s%s,A webmention was received: %sSource %s, Target %s%sContent: %s%s%sAccept? %s%sReject? %s%sCheerio, your go-jammin' thing.", + enter, enter, enter, + wm.Source, wm.Target, enter, + data.Content, enter, enter, + acceptUrl, enter, rejectUrl, enter) +} diff --git a/app/notifier/notifier_test.go b/app/notifier/notifier_test.go new file mode 100644 index 0000000..299e905 --- /dev/null +++ b/app/notifier/notifier_test.go @@ -0,0 +1,37 @@ +package notifier + +import ( + "brainbaking.com/go-jamming/app/mf" + "brainbaking.com/go-jamming/common" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestBuildNotification(t *testing.T) { + wm := mf.Mention{ + Source: "https://brainbaking.com/valid-indieweb-source.html", + Target: "https://brainbaking.com/valid-indieweb-target.html", + } + cnf := &common.Config{ + AllowedWebmentionSources: []string{ + "brainbaking.com", + }, + BaseURL: "https://jam.brainbaking.com/", + Token: "mytoken", + Blacklist: []string{}, + Whitelist: []string{}, + } + + expected := `Hi admin, + +,A webmention was received: +Source https://brainbaking.com/valid-indieweb-source.html, Target https://brainbaking.com/valid-indieweb-target.html +Content: somecontent + +Accept? https://jam.brainbaking.com/admin/approve/mytoken/19d462ddff3c3322c662dac3461324bb:brainbaking.com +Reject? https://jam.brainbaking.com/admin/reject/mytoken/19d462ddff3c3322c662dac3461324bb:brainbaking.com +Cheerio, your go-jammin' thing.` + + result := BuildNotification(wm, &mf.IndiewebData{Content: "somecontent"}, cnf) + assert.Equal(t, result, expected) +} diff --git a/app/routes.go b/app/routes.go index 861a2ee..cb68d2f 100644 --- a/app/routes.go +++ b/app/routes.go @@ -20,11 +20,11 @@ func (s *server) routes() { s.router.HandleFunc("/pingback", pingback.HandlePost(c, db)).Methods("POST") s.router.HandleFunc("/webmention", webmention.HandlePost(c, db)).Methods("POST") - s.router.HandleFunc("/webmention/{domain}/{token}", s.authorizedOnly(webmention.HandleGet(db))).Methods("GET") - s.router.HandleFunc("/webmention/{domain}/{token}", s.authorizedOnly(webmention.HandlePut(c, db))).Methods("PUT") - s.router.HandleFunc("/webmention/{domain}/{token}", s.authorizedOnly(webmention.HandleDelete(db))).Methods("DELETE") + s.router.HandleFunc("/webmention/{domain}/{token}", s.domainAndTokenOnly(webmention.HandleGet(db))).Methods("GET") + s.router.HandleFunc("/webmention/{domain}/{token}", s.domainAndTokenOnly(webmention.HandlePut(c, db))).Methods("PUT") + s.router.HandleFunc("/webmention/{domain}/{token}", s.domainAndTokenOnly(webmention.HandleDelete(db))).Methods("DELETE") - s.router.HandleFunc("/admin/{domain}/{token}", s.authorizedOnly(admin.HandleGet(db))).Methods("GET") - s.router.HandleFunc("/admin/approve/{token}", s.authorizedOnly(admin.HandleApprove(c, db))).Methods("POST") - s.router.HandleFunc("/admin/reject/{token}", s.authorizedOnly(admin.HandleReject(c, db))).Methods("POST") + s.router.HandleFunc("/admin/{domain}/{token}", s.domainAndTokenOnly(admin.HandleGet(db))).Methods("GET") + s.router.HandleFunc("/admin/approve/{token}/{key}", s.authorizedOnly(admin.HandleApprove(c, db))).Methods("GET") + s.router.HandleFunc("/admin/reject/{token}/{key}", s.authorizedOnly(admin.HandleReject(c, db))).Methods("GET") } diff --git a/app/server.go b/app/server.go index f68cf9c..395c242 100644 --- a/app/server.go +++ b/app/server.go @@ -20,10 +20,25 @@ type server struct { repo db.MentionRepo } +func (s *server) domainAndTokenOnly(h http.HandlerFunc) http.HandlerFunc { + return s.domainOnly(s.authorizedOnly(h)) +} + +func (s *server) domainOnly(h http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + if !s.conf.IsAnAllowedDomain(vars["domain"]) { + rest.Unauthorized(w) + return + } + h(w, r) + } +} + func (s *server) authorizedOnly(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - if vars["token"] != s.conf.Token || !s.conf.IsAnAllowedDomain(vars["domain"]) { + if vars["token"] != s.conf.Token { rest.Unauthorized(w) return } diff --git a/app/server_test.go b/app/server_test.go index cb379d3..e70f07b 100644 --- a/app/server_test.go +++ b/app/server_test.go @@ -34,13 +34,13 @@ func TestAuthorizedOnlyUnauthorizedWithWrongToken(t *testing.T) { assert.False(t, passed, "should not have called unauthorized func") } -func TestAuthorizedOnlyUnauthorizedWithWrongDomain(t *testing.T) { +func TestDomainOnlyWithWrongDomain(t *testing.T) { srv := &server{ conf: conf, } passed := false - handler := srv.authorizedOnly(func(writer http.ResponseWriter, request *http.Request) { + handler := srv.domainOnly(func(writer http.ResponseWriter, request *http.Request) { passed = true }) r, _ := http.NewRequest("PUT", "/whatever", nil) diff --git a/app/webmention/handler.go b/app/webmention/handler.go index 26472bb..0a0a3d1 100644 --- a/app/webmention/handler.go +++ b/app/webmention/handler.go @@ -2,6 +2,7 @@ package webmention import ( "brainbaking.com/go-jamming/app/mf" + "brainbaking.com/go-jamming/app/notifier" "brainbaking.com/go-jamming/app/webmention/recv" "brainbaking.com/go-jamming/app/webmention/send" "brainbaking.com/go-jamming/db" @@ -88,6 +89,9 @@ func HandlePost(conf *common.Config, repo db.MentionRepo) http.HandlerFunc { RestClient: httpClient, Conf: conf, Repo: repo, + Notifier: ¬ifier.MailNotifier{ + Conf: conf, + }, } go recv.Receive(wm) diff --git a/app/webmention/recv/receive.go b/app/webmention/recv/receive.go index d491d88..b4cff68 100644 --- a/app/webmention/recv/receive.go +++ b/app/webmention/recv/receive.go @@ -2,6 +2,7 @@ package recv import ( "brainbaking.com/go-jamming/app/mf" + "brainbaking.com/go-jamming/app/notifier" "brainbaking.com/go-jamming/common" "brainbaking.com/go-jamming/db" "brainbaking.com/go-jamming/rest" @@ -16,6 +17,7 @@ import ( type Receiver struct { RestClient rest.Client + Notifier notifier.Notifier Conf *common.Config Repo db.MentionRepo } @@ -62,23 +64,30 @@ func (recv *Receiver) processSourceBody(body string, wm mf.Mention) { indieweb := recv.convertBodyToIndiewebData(body, wm, data) recv.processAuthorPicture(indieweb) - recv.saveMentionToDatabase(wm, indieweb) + if recv.Conf.IsWhitelisted(wm.Source) { + recv.processWhitelistedMention(wm, indieweb) + } else { + recv.processMentionInModeration(wm, indieweb) + } } -func (recv *Receiver) saveMentionToDatabase(wm mf.Mention, indieweb *mf.IndiewebData) { - if recv.Conf.IsWhitelisted(wm.Source) { - key, err := recv.Repo.Save(wm, indieweb) - if err != nil { - log.Error().Err(err).Stringer("wm", wm).Msg("Failed to save new mention to db") - } - log.Info().Str("key", key).Msg("OK: Webmention processed, in whitelist.") - } else { - key, err := recv.Repo.InModeration(wm, indieweb) - if err != nil { - log.Error().Err(err).Stringer("wm", wm).Msg("Failed to save new mention to in moderation db") - } - log.Info().Str("key", key).Msg("OK: Webmention processed, in moderation.") +func (recv *Receiver) processMentionInModeration(wm mf.Mention, indieweb *mf.IndiewebData) { + key, err := recv.Repo.InModeration(wm, indieweb) + if err != nil { + log.Error().Err(err).Stringer("wm", wm).Msg("Failed to save new mention to in moderation db") } + if recv.Notifier != nil { + recv.Notifier.NotifyReceived(wm, indieweb) + } + log.Info().Str("key", key).Msg("OK: Webmention processed, in moderation.") +} + +func (recv *Receiver) processWhitelistedMention(wm mf.Mention, indieweb *mf.IndiewebData) { + key, err := recv.Repo.Save(wm, indieweb) + if err != nil { + log.Error().Err(err).Stringer("wm", wm).Msg("Failed to save new mention to db") + } + log.Info().Str("key", key).Msg("OK: Webmention processed, in whitelist.") } func (recv *Receiver) processAuthorPicture(indieweb *mf.IndiewebData) { diff --git a/app/webmention/recv/receive_test.go b/app/webmention/recv/receive_test.go index cce3ed1..368ceae 100644 --- a/app/webmention/recv/receive_test.go +++ b/app/webmention/recv/receive_test.go @@ -237,7 +237,7 @@ func TestReceiveTargetDoesNotExistAnymoreDeletesPossiblyOlderWebmention(t *testi assert.Empty(t, indb) } -func TestReceiveFromNotInWhitelistSavesInModeration(t *testing.T) { +func TestReceiveFromNotInWhitelistSavesInModerationAndNotifies(t *testing.T) { wm := mf.Mention{ Source: "https://brainbaking.com/valid-indieweb-source.html", Target: "https://brainbaking.com/valid-indieweb-target.html", @@ -246,22 +246,30 @@ func TestReceiveFromNotInWhitelistSavesInModeration(t *testing.T) { AllowedWebmentionSources: []string{ "brainbaking.com", }, + BaseURL: "https://jam.brainbaking.com/", + Token: "mytoken", Blacklist: []string{}, Whitelist: []string{}, } repo := db.NewMentionRepo(cnf) t.Cleanup(db.Purge) + notifierMock := &mocks.StringNotifier{ + Conf: cnf, + Output: "", + } receiver := &Receiver{ Conf: cnf, Repo: repo, RestClient: &mocks.RestClientMock{ GetBodyFunc: mocks.RelPathGetBodyFunc("../../../mocks/"), }, + Notifier: notifierMock, } receiver.Receive(wm) assert.Empty(t, repo.GetAll("brainbaking.com").Data) assert.Equal(t, 1, len(repo.GetAllToModerate("brainbaking.com").Data)) + assert.Contains(t, notifierMock.Output, "Accept?") } func TestReceiveFromBlacklistedDomainDoesNothing(t *testing.T) { diff --git a/common/config.go b/common/config.go index df4f711..a101087 100644 --- a/common/config.go +++ b/common/config.go @@ -12,6 +12,8 @@ import ( ) type Config struct { + // BaseURL should end with a / and is used to build URLs in notifications + BaseURL string `json:"baseURL"` Port int `json:"port"` Token string `json:"token"` UtcOffset int `json:"utcOffset"` @@ -49,6 +51,9 @@ func (c *Config) missingKeys() []string { if c.Token == "" { keys = append(keys, "token") } + if c.BaseURL == "" { + keys = append(keys, "baseURL") + } if len(c.AllowedWebmentionSources) == 0 { keys = append(keys, "allowedWebmentionSources") } @@ -128,7 +133,8 @@ func config() *Config { } func defaultConfig() *Config { - return &Config{ + defaultConfig := &Config{ + BaseURL: "https://jam.brainbaking.com/", Port: 1337, Token: "miauwkes", UtcOffset: 60, @@ -136,4 +142,6 @@ func defaultConfig() *Config { Blacklist: []string{"youtube.com"}, Whitelist: []string{"brainbaking.com"}, } + defaultConfig.Save() + return defaultConfig } diff --git a/common/config_test.go b/common/config_test.go index e0bd01e..1c3e273 100644 --- a/common/config_test.go +++ b/common/config_test.go @@ -24,6 +24,7 @@ func TestReadFromJsonWithCorrectJsonData(t *testing.T) { confString := `{ "port": 1337, "host": "localhost", + "baseURL": "https://jam.brainbaking.com/", "token": "miauwkes", "utcOffset": 60, "allowedWebmentionSources": [ @@ -57,6 +58,7 @@ func TestWhitelist(t *testing.T) { Whitelist: []string{ "youtube.com", }, + BaseURL: "https://jam.brainbaking.com/", Port: 123, Token: "token", AllowedWebmentionSources: []string{"blah.com"}, @@ -79,6 +81,7 @@ func TestAddToBlacklistNotYetAddsToListAndSaves(t *testing.T) { Blacklist: []string{ "youtube.com", }, + BaseURL: "https://jam.brainbaking.com/", Port: 123, Token: "token", AllowedWebmentionSources: []string{"blah.com"}, diff --git a/db/buntrepo.go b/db/buntrepo.go index 34f773d..7d4d251 100644 --- a/db/buntrepo.go +++ b/db/buntrepo.go @@ -58,15 +58,18 @@ func lastSentKey(domain string) string { // Delete removes a possibly present mention by key. Ignores but logs possible errors. func (r *mentionRepoBunt) Delete(wm mf.Mention) { - key := r.mentionToKey(wm) + r.deleteByKey(wm.Key()) +} + +func (r *mentionRepoBunt) deleteByKey(key string) { err := r.db.Update(func(tx *buntdb.Tx) error { _, err := tx.Delete(key) return err }) if err != nil { - log.Warn().Err(err).Str("key", key).Stringer("wm", wm).Msg("Unable to delete") + log.Warn().Err(err).Str("key", key).Msg("Unable to delete") } else { - log.Debug().Str("key", key).Stringer("wm", wm).Msg("Deleted.") + log.Debug().Str("key", key).Msg("Deleted.") } } @@ -88,11 +91,14 @@ func pictureKey(domain string) string { // Save saves the mention by marshalling data. Returns the key or a marshal/persist error. func (r *mentionRepoBunt) Save(wm mf.Mention, data *mf.IndiewebData) (string, error) { + return r.saveByKey(wm.Key(), data) +} + +func (r *mentionRepoBunt) saveByKey(key string, data *mf.IndiewebData) (string, error) { jsonData, err := json.Marshal(data) if err != nil { return "", err } - key := r.mentionToKey(wm) err = r.db.Update(func(tx *buntdb.Tx) error { _, _, err := tx.Set(key, string(jsonData), nil) return err @@ -103,14 +109,10 @@ func (r *mentionRepoBunt) Save(wm mf.Mention, data *mf.IndiewebData) (string, er return key, nil } -func (r *mentionRepoBunt) mentionToKey(wm mf.Mention) string { - return fmt.Sprintf("%s:%s", wm.Key(), wm.TargetDomain()) -} - // Get returns a single unmarshalled json value based on the mention key. // It returns the unmarshalled result or nil if something went wrong. func (r *mentionRepoBunt) Get(wm mf.Mention) *mf.IndiewebData { - return r.getByKey(r.mentionToKey(wm)) + return r.getByKey(wm.Key()) } func (r *mentionRepoBunt) getByKey(key string) *mf.IndiewebData { diff --git a/db/mentionrepo.go b/db/mentionrepo.go index 5d420ae..dca4ed4 100644 --- a/db/mentionrepo.go +++ b/db/mentionrepo.go @@ -7,21 +7,41 @@ import ( ) type MentionRepo interface { + // InModeration saves the mention data to the in moderation db to approve or reject later. + // Returns the key or a marshal/persist error. InModeration(key mf.Mention, data *mf.IndiewebData) (string, error) + // Save saves the mention to the approved db. + // Returns the key or a marshal/persist error. Save(key mf.Mention, data *mf.IndiewebData) (string, error) + // Delete removes a possibly present mention from the approved db by key. + // Ignores but logs possible errors. Delete(key mf.Mention) - Approve(key mf.Mention) - Reject(key mf.Mention) + // Approve saves the mention to the approved database and deletes the one in moderation. + // If the key is invalid, it returns nil. + Approve(key string) *mf.IndiewebData + // Reject removes the in moderation key from the db and returns the deleted entry + // If the key is invalid, it returns nil. + Reject(key string) *mf.IndiewebData + // Get returns a single unmarshalled json value based on the approved mention key in the db. + // It returns the unmarshalled result or nil if something went wrong. Get(key mf.Mention) *mf.IndiewebData + // GetAll returns a wrapped data result for all approved mentions for a particular domain. GetAll(domain string) mf.IndiewebDataResult + // GetAll returns a wrapped data result for all to approve mentions for a particular domain. GetAllToModerate(domain string) mf.IndiewebDataResult + // CleanupSpam removes potential blacklisted spam from the approved database by checking the url of each entry. CleanupSpam(domain string, blacklist []string) + // SavePicture saves the picture byte data in the approved database and returns a key or error. SavePicture(bytes string, domain string) (string, error) + // GetPicture returns a byte slice (or nil if unknown) from the approved database for a particular source domain. GetPicture(domain string) []byte + // LastSentMention fetches the last known RSS link where mentions were sent from the approved db. + // Returns an empty string if an error occured. LastSentMention(domain string) string + // UpdateLastSentMention updates the last sent mention link in the approved db. Logs but ignores errors. UpdateLastSentMention(domain string, lastSent string) } @@ -30,6 +50,7 @@ type MentionRepoWrapper struct { approvedRepo *mentionRepoBunt } +// Save saves the data to the func (m MentionRepoWrapper) Save(key mf.Mention, data *mf.IndiewebData) (string, error) { return m.approvedRepo.Save(key, data) } @@ -46,14 +67,17 @@ func (m MentionRepoWrapper) Delete(key mf.Mention) { m.approvedRepo.Delete(key) } -func (m MentionRepoWrapper) Approve(keyInModeration mf.Mention) { - toApprove := m.toApproveRepo.Get(keyInModeration) - m.Save(keyInModeration, toApprove) - m.toApproveRepo.Delete(keyInModeration) +func (m MentionRepoWrapper) Approve(keyInModeration string) *mf.IndiewebData { + toApprove := m.toApproveRepo.getByKey(keyInModeration) + m.approvedRepo.saveByKey(keyInModeration, toApprove) + m.toApproveRepo.deleteByKey(keyInModeration) + return toApprove } -func (m MentionRepoWrapper) Reject(keyInModeration mf.Mention) { - m.toApproveRepo.Delete(keyInModeration) +func (m MentionRepoWrapper) Reject(keyInModeration string) *mf.IndiewebData { + toReject := m.toApproveRepo.getByKey(keyInModeration) + m.toApproveRepo.deleteByKey(keyInModeration) + return toReject } func (m MentionRepoWrapper) CleanupSpam(domain string, blacklist []string) { diff --git a/db/mentionrepo_test.go b/db/mentionrepo_test.go index ce2944c..d21a222 100644 --- a/db/mentionrepo_test.go +++ b/db/mentionrepo_test.go @@ -15,7 +15,23 @@ var ( } ) -func TestApproveCases(t *testing.T) { +func TestRejectUnknownKeyReturnsNil(t *testing.T) { + repo := NewMentionRepo(repoCnf) + t.Cleanup(Purge) + + result := repo.Reject("fuckballz") + assert.Nil(t, result) +} + +func TestApproveUnknownKeyReturnsNil(t *testing.T) { + repo := NewMentionRepo(repoCnf) + t.Cleanup(Purge) + + result := repo.Approve("fuckballz") + assert.Nil(t, result) +} + +func TestApproveAndRejectCases(t *testing.T) { cases := []struct { label string approve bool @@ -42,6 +58,7 @@ func TestApproveCases(t *testing.T) { defer Purge() wm := mf.Mention{ + Source: "https://jefklakscodex.com/dinges", Target: "https://brainbaking.com/sjiekedinges.html", } data := &mf.IndiewebData{ @@ -50,9 +67,9 @@ func TestApproveCases(t *testing.T) { repo.InModeration(wm, data) if tc.approve { - repo.Approve(wm) + repo.Approve(wm.Key()) } else { - repo.Reject(wm) + repo.Reject(wm.Key()) } allWms := repo.GetAll("brainbaking.com") diff --git a/mocks/stringnotifier.go b/mocks/stringnotifier.go new file mode 100644 index 0000000..decf757 --- /dev/null +++ b/mocks/stringnotifier.go @@ -0,0 +1,16 @@ +package mocks + +import ( + "brainbaking.com/go-jamming/app/mf" + "brainbaking.com/go-jamming/app/notifier" + "brainbaking.com/go-jamming/common" +) + +type StringNotifier struct { + Output string + Conf *common.Config +} + +func (sn *StringNotifier) NotifyReceived(wm mf.Mention, indieweb *mf.IndiewebData) { + sn.Output = notifier.BuildNotification(wm, indieweb, sn.Conf) +}