diff --git a/storage.go b/storage.go index 46969f9..1f95b1b 100644 --- a/storage.go +++ b/storage.go @@ -14,6 +14,7 @@ import ( type Storage interface { CreateFile(path string, file string, message string) (err error) UpdateFile(path string, file string, message string) (err error) + DeleteFile(path string, message string) (err error) } type Git struct { @@ -134,4 +135,31 @@ func (g Git) UpdateFile(filepath string, file string, message string) error { return errors.New("failed to commit file") } return g.push(repo) -} \ No newline at end of file +} + +func (g Git) DeleteFile(filepath string, message string) (err error) { + repo, w, err := g.init() + if err != nil { + return errors.New("failed to initialize repo") + } + joinedPath := path.Join(g.filepath, filepath) + err = os.Remove(joinedPath) + if err != nil { + return errors.New("failed to delete file") + } + _, err = w.Add(filepath) + if err != nil { + return errors.New("failed to stage deletion") + } + _, err = w.Commit(message, &git.CommitOptions{ + Author: &object.Signature{ + Name: g.name, + Email: g.email, + When: time.Now(), + }, + }) + if err != nil { + return errors.New("failed to commit deletion") + } + return g.push(repo) +} diff --git a/webmention.go b/webmention.go index e432fe1..ccce08d 100644 --- a/webmention.go +++ b/webmention.go @@ -103,9 +103,14 @@ func HandleWebmention(w http.ResponseWriter, r *http.Request) { return } if respCode < 200 || respCode >= 300 { - if respCode == 410 { + if respCode == 410 || respCode == 404 { // Delete mention, because source is gone - // TODO: Implement deletion + go func() { + e := deleteWebmention(sourceUrl.String(), targetUrl.String()) + if e != nil { + fmt.Print("Tried to delete webmention", sourceUrl.String(), "but failed:", e.Error()) + } + }() returnSuccess(targetUrl.String(), w, r) return } else { @@ -118,21 +123,27 @@ func HandleWebmention(w http.ResponseWriter, r *http.Request) { // Check if source mentions target if !sourceMentionsTarget(sourceUrl.String(), targetUrl.String()) { err = errors.New("source doesn't mention target") + go func() { + // Try to delete webmention nevertheless + e := deleteWebmention(sourceUrl.String(), targetUrl.String()) + if e != nil { + fmt.Print("Tried to delete webmention (source doesn't mention target) ", sourceUrl.String(), "but failed:", e.Error()) + } + }() w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(err.Error())) return } - mention := &Mention{ - Source: sourceUrl.String(), - Target: targetUrl.String(), - Date: time.Now().Format(time.RFC3339), - } - err = saveWebmention(mention) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte(err.Error())) - return - } + go func() { + e := saveWebmention(&Mention{ + Source: sourceUrl.String(), + Target: targetUrl.String(), + Date: time.Now().Format(time.RFC3339), + }) + if e != nil { + fmt.Println("Failed to save webmention:", e.Error()) + } + }() returnSuccess(targetUrl.String(), w, r) go func() { if SelectedNotificationServices != nil { @@ -175,13 +186,19 @@ func saveWebmention(mention *Mention) (err error) { return } +func deleteWebmention(source string, target string) (err error) { + filePath := fmt.Sprintf("data/mentions/%x/%x.json", md5.Sum([]byte(strings.ReplaceAll(target, "/", ""))), md5.Sum([]byte(source))) + err = SelectedStorage.DeleteFile(filePath, "Delete webmention from "+source) + return +} + func returnSuccess(target string, w http.ResponseWriter, r *http.Request) { + w.Header().Add("Location", target) if strings.Contains(r.Header.Get("Accept"), "text/html") { // Redirect browser - w.Header().Add("Location", target) w.WriteHeader(http.StatusSeeOther) } else { - w.WriteHeader(http.StatusOK) + w.WriteHeader(http.StatusCreated) } // Purge CDN after 30 seconds go func() {