Skip to content

Commit

Permalink
feat: support force refresh in feed edit and feed entries page
Browse files Browse the repository at this point in the history
  • Loading branch information
njzydark authored and fguillot committed Aug 10, 2023
1 parent 3060946 commit 79c91d7
Show file tree
Hide file tree
Showing 30 changed files with 88 additions and 23 deletions.
2 changes: 1 addition & 1 deletion api/feed.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (h *handler) refreshFeed(w http.ResponseWriter, r *http.Request) {
return
}

err := feedHandler.RefreshFeed(h.store, userID, feedID)
err := feedHandler.RefreshFeed(h.store, userID, feedID, false)
if err != nil {
json.ServerError(w, r, err)
return
Expand Down
2 changes: 1 addition & 1 deletion cli/refresh_feeds.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func refreshFeeds(store *storage.Storage) {
defer wg.Done()
for job := range jobQueue {
logger.Info("[Cronjob] Refreshing feed #%d for user #%d in worker #%d", job.FeedID, job.UserID, workerID)
if err := feedHandler.RefreshFeed(store, job.UserID, job.FeedID); err != nil {
if err := feedHandler.RefreshFeed(store, job.UserID, job.FeedID, false); err != nil {
logger.Error("[Cronjob] Refreshing the feed #%d returned this error: %v", job.FeedID, err)
}
}
Expand Down
16 changes: 16 additions & 0 deletions http/request/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,22 @@ func QueryInt64Param(r *http.Request, param string, defaultValue int64) int64 {
return val
}

// QueryBoolParam returns a query string parameter as bool.
func QueryBoolParam(r *http.Request, param string, defaultValue bool) bool {
value := r.URL.Query().Get(param)
if value == "" {
return defaultValue
}

val, err := strconv.ParseBool(value)

if err != nil {
return defaultValue
}

return val
}

// HasQueryParam checks if the query string contains the given parameter.
func HasQueryParam(r *http.Request, param string) bool {
values := r.URL.Query()
Expand Down
1 change: 1 addition & 0 deletions locale/translations/de_DE.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Sind Sie sicher?",
"confirm.question.refresh": "Möchten Sie eine erzwungene Aktualisierung durchführen?",
"confirm.yes": "ja",
"confirm.no": "nein",
"confirm.loading": "In Arbeit...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/el_EL.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Είστε σίγουροι;",
"confirm.question.refresh": "Θέλετε να επιτελέσετε μια υποχρεωτική ανανέωση;",
"confirm.yes": "ναι",
"confirm.no": "όχι",
"confirm.loading": "Σε εξέλιξη...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/en_US.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Are you sure?",
"confirm.question.refresh": "Are you want to force refresh?",
"confirm.yes": "yes",
"confirm.no": "no",
"confirm.loading": "In progress…",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/es_ES.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "¿Estás seguro?",
"confirm.question.refresh": "¿Quieres forzar la actualización?",
"confirm.yes": "",
"confirm.no": "no",
"confirm.loading": "En progreso...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/fi_FI.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Oletko varma?",
"confirm.question.refresh": "Haluatko pakottaa päivityksen?",
"confirm.yes": "kyllä",
"confirm.no": "ei",
"confirm.loading": "Käynnissä...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/fr_FR.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Êtes-vous sûr ?",
"confirm.question.refresh": "Voulez-vous forcer le rafraîchissement ?",
"confirm.yes": "oui",
"confirm.no": "non",
"confirm.loading": "En cours...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/hi_IN.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "मंजूर है?",
"confirm.question.refresh": "क्या आप बल द्वारा ताज़ा करना चाहते हैं?",
"confirm.yes": "हाँ",
"confirm.no": " नहीं",
"confirm.loading": " प्रगति में है ...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/id_ID.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Apakah Anda yakin?",
"confirm.question.refresh": "Apakah Anda ingin memaksa penyegaran?",
"confirm.yes": "ya",
"confirm.no": "tidak",
"confirm.loading": "Sedang progres...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/it_IT.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Sei sicuro?",
"confirm.question.refresh": "Vuoi forzare l'aggiornamento?",
"confirm.yes": "",
"confirm.no": "no",
"confirm.loading": "In corso...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/ja_JP.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "よろしいですか?",
"confirm.question.refresh": "強制的に更新しますか?",
"confirm.yes": "はい",
"confirm.no": "いいえ",
"confirm.loading": "実行中…",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/nl_NL.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Weet je het zeker?",
"confirm.question.refresh": "Wil je een gedwongen vernieuwing uitvoeren?",
"confirm.yes": "ja",
"confirm.no": "nee",
"confirm.loading": "Bezig...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/pl_PL.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Czy jesteś pewny?",
"confirm.question.refresh": "Czy chcesz wymusić odświeżenie?",
"confirm.yes": "tak",
"confirm.no": "nie",
"confirm.loading": "W toku...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/pt_BR.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Tem certeza?",
"confirm.question.refresh": "Você deseja forçar a atualização?",
"confirm.yes": "Sim",
"confirm.no": "Não",
"confirm.loading": "Carregando...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/ru_RU.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Вы уверены?",
"confirm.question.refresh": "Вы хотите выполнить принудительное обновление?",
"confirm.yes": "да",
"confirm.no": "нет",
"confirm.loading": "В процессе…",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/tr_TR.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Emin misiniz?",
"confirm.question.refresh": "Zorla yenilemek istiyor musunuz?",
"confirm.yes": "evet",
"confirm.no": "hayır",
"confirm.loading": "Devam ediyor...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/uk_UA.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "Ви впевнені?",
"confirm.question.refresh": "Ви хочете змусити оновити?",
"confirm.yes": "так",
"confirm.no": "ні",
"confirm.loading": "В процесі...",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/zh_CN.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "您确认吗?",
"confirm.question.refresh": "您是否要强制刷新?",
"confirm.yes": "",
"confirm.no": "",
"confirm.loading": "执行中…",
Expand Down
1 change: 1 addition & 0 deletions locale/translations/zh_TW.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"confirm.question": "您確認嗎?",
"confirm.question.refresh": "您想要強制刷新嗎?",
"confirm.yes": "",
"confirm.no": "",
"confirm.loading": "執行中…",
Expand Down
11 changes: 6 additions & 5 deletions reader/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func CreateFeed(store *storage.Storage, userID int64, feedCreationRequest *model
subscription.WithClientResponse(response)
subscription.CheckedNow()

processor.ProcessFeedEntries(store, subscription, user)
processor.ProcessFeedEntries(store, subscription, user, true)

if storeErr := store.CreateFeed(subscription); storeErr != nil {
return nil, storeErr
Expand All @@ -104,7 +104,7 @@ func CreateFeed(store *storage.Storage, userID int64, feedCreationRequest *model
}

// RefreshFeed refreshes a feed.
func RefreshFeed(store *storage.Storage, userID, feedID int64) error {
func RefreshFeed(store *storage.Storage, userID, feedID int64, forceRefresh bool) error {
defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[RefreshFeed] feedID=%d", feedID))
user, storeErr := store.UserByID(userID)
if storeErr != nil {
Expand Down Expand Up @@ -173,10 +173,11 @@ func RefreshFeed(store *storage.Storage, userID, feedID int64) error {
}

originalFeed.Entries = updatedFeed.Entries
processor.ProcessFeedEntries(store, originalFeed, user)
processor.ProcessFeedEntries(store, originalFeed, user, forceRefresh)

// We don't update existing entries when the crawler is enabled (we crawl only inexisting entries).
if storeErr := store.RefreshFeedEntries(originalFeed.UserID, originalFeed.ID, originalFeed.Entries, !originalFeed.Crawler); storeErr != nil {
// We don't update existing entries when the crawler is enabled (we crawl only inexisting entries). Unless it is forced to refresh
updateExistingEntries := forceRefresh || !originalFeed.Crawler
if storeErr := store.RefreshFeedEntries(originalFeed.UserID, originalFeed.ID, originalFeed.Entries, updateExistingEntries); storeErr != nil {
originalFeed.WithError(storeErr.Error())
store.UpdateFeedError(originalFeed)
return storeErr
Expand Down
4 changes: 2 additions & 2 deletions reader/processor/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ var (
)

// ProcessFeedEntries downloads original web page for entries and apply filters.
func ProcessFeedEntries(store *storage.Storage, feed *model.Feed, user *model.User) {
func ProcessFeedEntries(store *storage.Storage, feed *model.Feed, user *model.User, forceRefresh bool) {
var filteredEntries model.Entries

// array used for bulk push
Expand All @@ -56,7 +56,7 @@ func ProcessFeedEntries(store *storage.Storage, feed *model.Feed, user *model.Us

url := getUrlFromEntry(feed, entry)
entryIsNew := !store.EntryURLExists(feed.ID, entry.URL)
if feed.Crawler && entryIsNew {
if feed.Crawler && (entryIsNew || forceRefresh) {
logger.Debug("[Processor] Crawling entry %q from feed %q", url, feed.FeedURL)

startTime := time.Now()
Expand Down
9 changes: 8 additions & 1 deletion template/templates/views/edit_feed.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ <h1 dir="auto">{{ .feed.Title }}</h1>
<a href="{{ route "feedEntries" "feedID" .feed.ID }}">{{ icon "entries" }}{{ t "menu.feed_entries" }}</a>
</li>
<li>
<a href="{{ route "refreshFeed" "feedID" .feed.ID }}">{{ icon "refresh" }}{{ t "menu.refresh_feed" }}</a>
<a href="#"
data-confirm="true"
data-label-question="{{ t "confirm.question.refresh" }}"
data-label-yes="{{ t "confirm.yes" }}"
data-label-no="{{ t "confirm.no" }}"
data-label-loading="{{ t "confirm.loading" }}"
data-url="{{ route "refreshFeed" "feedID" .feed.ID }}?forceRefresh=true"
data-no-action-url="{{ route "refreshFeed" "feedID" .feed.ID }}?forceRefresh=false">{{ icon "refresh" }}{{ t "menu.refresh_feed" }}</a>
</li>
</ul>
</section>
Expand Down
9 changes: 8 additions & 1 deletion template/templates/views/feed_entries.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ <h1 dir="auto">
</li>
{{ end }}
<li>
<a href="{{ route "refreshFeed" "feedID" .feed.ID }}">{{ icon "refresh" }}{{ t "menu.refresh_feed" }}</a>
<a href="#"
data-confirm="true"
data-label-question="{{ t "confirm.question.refresh" }}"
data-label-yes="{{ t "confirm.yes" }}"
data-label-no="{{ t "confirm.no" }}"
data-label-loading="{{ t "confirm.loading" }}"
data-url="{{ route "refreshFeed" "feedID" .feed.ID }}?forceRefresh=true"
data-no-action-url="{{ route "refreshFeed" "feedID" .feed.ID }}?forceRefresh=false">{{ icon "refresh" }}{{ t "menu.refresh_feed" }}</a>
</li>
<li>
<a href="{{ route "editFeed" "feedID" .feed.ID }}">{{ icon "edit" }}{{ t "menu.edit_feed" }}</a>
Expand Down
3 changes: 2 additions & 1 deletion ui/feed_refresh.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import (

func (h *handler) refreshFeed(w http.ResponseWriter, r *http.Request) {
feedID := request.RouteInt64Param(r, "feedID")
if err := feedHandler.RefreshFeed(h.store, request.UserID(r), feedID); err != nil {
forceRefresh := request.QueryBoolParam(r, "forceRefresh", false)
if err := feedHandler.RefreshFeed(h.store, request.UserID(r), feedID, forceRefresh); err != nil {
logger.Error("[UI:RefreshFeed] %v", err)
}

Expand Down
28 changes: 20 additions & 8 deletions ui/static/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -561,18 +561,22 @@ function handleConfirmationMessage(linkElement, callback) {
let containerElement = linkElement.parentNode;
let questionElement = document.createElement("span");

let yesElement = document.createElement("a");
yesElement.href = "#";
yesElement.appendChild(document.createTextNode(linkElement.dataset.labelYes));
yesElement.onclick = (event) => {
event.preventDefault();

function createLoadingElement() {
let loadingElement = document.createElement("span");
loadingElement.className = "loading";
loadingElement.appendChild(document.createTextNode(linkElement.dataset.labelLoading));

questionElement.remove();
containerElement.appendChild(loadingElement);
}

let yesElement = document.createElement("a");
yesElement.href = "#";
yesElement.appendChild(document.createTextNode(linkElement.dataset.labelYes));
yesElement.onclick = (event) => {
event.preventDefault();

createLoadingElement();

callback(linkElement.dataset.url, linkElement.dataset.redirectUrl);
};
Expand All @@ -582,8 +586,16 @@ function handleConfirmationMessage(linkElement, callback) {
noElement.appendChild(document.createTextNode(linkElement.dataset.labelNo));
noElement.onclick = (event) => {
event.preventDefault();
linkElement.style.display = "inline";
questionElement.remove();

const noActionUrl = linkElement.dataset.noActionUrl;
if (noActionUrl) {
createLoadingElement();

callback(noActionUrl, linkElement.dataset.redirectUrl);
} else {
linkElement.style.display = "inline";
questionElement.remove();
}
};

questionElement.className = "confirm";
Expand Down
4 changes: 3 additions & 1 deletion ui/static/js/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,11 @@ document.addEventListener("DOMContentLoaded", function () {
onClick("a[data-confirm]", (event) => handleConfirmationMessage(event.target, (url, redirectURL) => {
let request = new RequestBuilder(url);

request.withCallback(() => {
request.withCallback((response) => {
if (redirectURL) {
window.location.href = redirectURL;
} else if (response && response.redirected && response.url) {
window.location.href = response.url;
} else {
window.location.reload();
}
Expand Down
3 changes: 2 additions & 1 deletion ui/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ func Serve(router *mux.Router, store *storage.Storage, pool *worker.Pool) {
uiRouter.HandleFunc("/feeds/refresh", handler.refreshAllFeeds).Name("refreshAllFeeds").Methods(http.MethodGet)

// Individual feed pages.
uiRouter.HandleFunc("/feed/{feedID}/refresh", handler.refreshFeed).Name("refreshFeed").Methods(http.MethodGet)
uiRouter.HandleFunc("/feed/{feedID}/refresh", handler.refreshFeed).Name("refreshFeed").Methods(http.MethodGet, http.MethodPost)
uiRouter.HandleFunc("/feed/{feedID}/refresh", handler.refreshFeed).Queries("forceRefresh", "{forceRefresh:true|false}").Name("refreshFeed").Methods(http.MethodGet, http.MethodPost)
uiRouter.HandleFunc("/feed/{feedID}/edit", handler.showEditFeedPage).Name("editFeed").Methods(http.MethodGet)
uiRouter.HandleFunc("/feed/{feedID}/remove", handler.removeFeed).Name("removeFeed").Methods(http.MethodPost)
uiRouter.HandleFunc("/feed/{feedID}/update", handler.updateFeed).Name("updateFeed").Methods(http.MethodPost)
Expand Down
2 changes: 1 addition & 1 deletion worker/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (w *Worker) Run(c chan model.Job) {
logger.Debug("[Worker #%d] Received feed #%d for user #%d", w.id, job.FeedID, job.UserID)

startTime := time.Now()
refreshErr := feedHandler.RefreshFeed(w.store, job.UserID, job.FeedID)
refreshErr := feedHandler.RefreshFeed(w.store, job.UserID, job.FeedID, false)

if config.Opts.HasMetricsCollector() {
status := "success"
Expand Down

0 comments on commit 79c91d7

Please sign in to comment.