1
0
Fork 0
mirror of https://github.com/Luzifer/mediatimeline.git synced 2024-11-09 23:30:05 +00:00

Add tweet deletion, improve API

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2020-01-12 13:37:20 +01:00
parent 2f057a634c
commit f61051c212
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
6 changed files with 68 additions and 29 deletions

View file

@ -25,9 +25,26 @@ new Vue({
this.modalTweet = tweet this.modalTweet = tweet
}, },
deleteTweet(tweet) {
axios
.delete(`/api/${tweet.id}`)
.then(() => {
const tweets = []
for (const t in this.tweets) {
if (t.id !== tweet.id) {
tweets.push(t)
}
}
this.tweets = tweets
})
.catch(err => console.log(err))
},
favourite(tweet) { favourite(tweet) {
axios axios
.post('/api/favourite', { id: tweet.id }) .put(`/api/${tweet.id}/favorite`)
.then(res => { .then(res => {
if (res.data.length === 0) { if (res.data.length === 0) {
this.refetch(tweet) this.refetch(tweet)
@ -49,7 +66,7 @@ new Vue({
refetch(tweet) { refetch(tweet) {
axios axios
.post('/api/refresh', { id: tweet.id }) .put(`/api/${tweet.id}/refresh`)
.then(res => { .then(res => {
if (res.data.length === 0) { if (res.data.length === 0) {
return return
@ -82,7 +99,7 @@ new Vue({
triggerForceFetch() { triggerForceFetch() {
axios axios
.post('/api/force-reload') .put('/api/force-reload')
.then(() => { .then(() => {
this.notify('Force refresh triggered, reloading tweets in 10s') this.notify('Force refresh triggered, reloading tweets in 10s')
window.setTimeout(() => this.refresh(true), 10000) window.setTimeout(() => this.refresh(true), 10000)

View file

@ -63,6 +63,9 @@
<i class="fas fa-search-plus"></i> <i class="fas fa-search-plus"></i>
<b-badge pill variant="light" v-if="tweet.images.length > 1">{{ tweet.images.length }}</b-badge> <b-badge pill variant="light" v-if="tweet.images.length > 1">{{ tweet.images.length }}</b-badge>
</b-button> </b-button>
<b-button size="sm" variant="secondary" @click="deleteTweet(tweet)">
<i class="fas fa-trash"></i>
</b-button>
</b-card-footer> </b-card-footer>
</b-card> </b-card>

1
go.mod
View file

@ -11,6 +11,7 @@ require (
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect
github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 // indirect github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 // indirect
github.com/gorilla/mux v1.7.3
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/pkg/errors v0.8.1 github.com/pkg/errors v0.8.1
github.com/sirupsen/logrus v1.4.1 github.com/sirupsen/logrus v1.4.1

2
go.sum
View file

@ -17,6 +17,8 @@ github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad h1:Qk76DOWdOp+GlyDKB
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad/go.mod h1:mPKfmRa823oBIgl2r20LeMSpTAteW5j7FLkc0vjmzyQ= github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad/go.mod h1:mPKfmRa823oBIgl2r20LeMSpTAteW5j7FLkc0vjmzyQ=
github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 h1:GOfMz6cRgTJ9jWV0qAezv642OhPnKEG7gtUjJSdStHE= github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 h1:GOfMz6cRgTJ9jWV0qAezv642OhPnKEG7gtUjJSdStHE=
github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17/go.mod h1:HfkOCN6fkKKaPSAeNq/er3xObxTW4VLeY6UUK895gLQ= github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17/go.mod h1:HfkOCN6fkKKaPSAeNq/er3xObxTW4VLeY6UUK895gLQ=
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg= github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=

62
http.go
View file

@ -8,29 +8,49 @@ import (
"strings" "strings"
"github.com/ChimeraCoder/anaconda" "github.com/ChimeraCoder/anaconda"
"github.com/gorilla/mux"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
func init() { func init() {
http.HandleFunc("/api/favourite", handleFavorite) router.HandleFunc("/api/{tweetID}/favorite", handleFavorite).Methods(http.MethodPut)
http.HandleFunc("/api/force-reload", handleForceReload) router.HandleFunc("/api/{tweetID}", handleDelete).Methods(http.MethodDelete)
http.HandleFunc("/api/page", handlePage) router.HandleFunc("/api/force-reload", handleForceReload).Methods(http.MethodPut)
http.HandleFunc("/api/refresh", handleTweetRefresh) router.HandleFunc("/api/page", handlePage).Methods(http.MethodGet)
http.HandleFunc("/api/since", handleNewest) router.HandleFunc("/api/{tweetID}/refresh", handleTweetRefresh).Methods(http.MethodPut)
router.HandleFunc("/api/since", handleNewest).Methods(http.MethodGet)
}
func handleDelete(w http.ResponseWriter, r *http.Request) {
var vars = mux.Vars(r)
tweetID, err := strconv.ParseInt(vars["tweetID"], 10, 64)
if err != nil {
http.Error(w, errors.Wrap(err, "Unable to parse TweetID").Error(), http.StatusBadRequest)
return
}
if err := tweetStore.DeleteTweetByID(uint64(tweetID)); err != nil {
log.WithError(err).Error("Unable to delete tweet")
http.Error(w, "Something went wrong", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
} }
// handleFavorite takes the ID of a tweet and submits a favorite to Twitter // handleFavorite takes the ID of a tweet and submits a favorite to Twitter
func handleFavorite(w http.ResponseWriter, r *http.Request) { func handleFavorite(w http.ResponseWriter, r *http.Request) {
req := struct { var vars = mux.Vars(r)
ID int64 `json:"id,string"`
}{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.ID == 0 { tweetID, err := strconv.ParseInt(vars["tweetID"], 10, 64)
http.Error(w, "Need to specify id", http.StatusBadRequest) if err != nil {
http.Error(w, errors.Wrap(err, "Unable to parse TweetID").Error(), http.StatusBadRequest)
return return
} }
tweet, err := twitter.Favorite(req.ID) tweet, err := twitter.Favorite(tweetID)
if err != nil { if err != nil {
log.WithError(err).Error("Unable to favourite tweet") log.WithError(err).Error("Unable to favourite tweet")
http.Error(w, "Something went wrong", http.StatusInternalServerError) http.Error(w, "Something went wrong", http.StatusInternalServerError)
@ -55,11 +75,6 @@ func handleFavorite(w http.ResponseWriter, r *http.Request) {
// handleForceReload issues a full load of the latest tweets to update their state // handleForceReload issues a full load of the latest tweets to update their state
func handleForceReload(w http.ResponseWriter, r *http.Request) { func handleForceReload(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "This needs to be POST", http.StatusBadRequest)
return
}
go loadAndStoreTweets(true) go loadAndStoreTweets(true)
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
@ -94,20 +109,19 @@ func handlePage(w http.ResponseWriter, r *http.Request) {
// handleTweetRefresh refreshes the state of the tweet with the given ID against the Twitter API // handleTweetRefresh refreshes the state of the tweet with the given ID against the Twitter API
func handleTweetRefresh(w http.ResponseWriter, r *http.Request) { func handleTweetRefresh(w http.ResponseWriter, r *http.Request) {
req := struct { var vars = mux.Vars(r)
ID int64 `json:"id,string"`
}{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.ID == 0 { tweetID, err := strconv.ParseInt(vars["tweetID"], 10, 64)
http.Error(w, "Need to specify id", http.StatusBadRequest) if err != nil {
http.Error(w, errors.Wrap(err, "Unable to parse TweetID").Error(), http.StatusBadRequest)
return return
} }
tweet, err := twitter.GetTweet(req.ID, url.Values{}) tweet, err := twitter.GetTweet(tweetID, url.Values{})
if err != nil { if err != nil {
if strings.Contains(err.Error(), "No status found with that ID.") { if strings.Contains(err.Error(), "No status found with that ID.") {
log.WithField("id", req.ID).Info("Removing no longer existing tweet") log.WithField("id", tweetID).Info("Removing no longer existing tweet")
if err = tweetStore.DeleteTweetByID(uint64(req.ID)); err != nil { if err = tweetStore.DeleteTweetByID(uint64(tweetID)); err != nil {
log.WithError(err).Error("Unable to delete tweet") log.WithError(err).Error("Unable to delete tweet")
http.Error(w, "Something went wrong", http.StatusInternalServerError) http.Error(w, "Something went wrong", http.StatusInternalServerError)
} }

View file

@ -9,6 +9,7 @@ import (
"time" "time"
"github.com/ChimeraCoder/anaconda" "github.com/ChimeraCoder/anaconda"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
hhelp "github.com/Luzifer/go_helpers/v2/http" hhelp "github.com/Luzifer/go_helpers/v2/http"
@ -30,6 +31,7 @@ var (
VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"` VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"`
}{} }{}
router = mux.NewRouter()
tweetStore *store tweetStore *store
twitter *anaconda.TwitterApi twitter *anaconda.TwitterApi
@ -72,8 +74,8 @@ func main() {
log.WithField("version", version).Info("MediaTimeline Viewer started") log.WithField("version", version).Info("MediaTimeline Viewer started")
http.Handle("/", http.FileServer(http.Dir(cfg.Frontend))) router.Handle("/", http.FileServer(http.Dir(cfg.Frontend)))
http.ListenAndServe(cfg.Listen, hhelp.NewHTTPLogHandler(http.DefaultServeMux)) http.ListenAndServe(cfg.Listen, hhelp.NewHTTPLogHandler(router))
} }
func loadAndStoreTweets(forceRefresh bool) { func loadAndStoreTweets(forceRefresh bool) {