mirror of
https://github.com/Luzifer/mediatimeline.git
synced 2024-11-08 06:40:06 +00:00
Add tweet deletion, improve API
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
2f057a634c
commit
f61051c212
6 changed files with 68 additions and 29 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
1
go.mod
|
@ -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
2
go.sum
|
@ -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
62
http.go
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
6
main.go
6
main.go
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue