This is an automated email from the git hooks/post-receive script. New commit to branch bow-v2-go in repository bow. See https://gitlab.nuiton.org/chorem/bow.git commit cdb36a9cbfa901ff7e6f3f5057107be420aeab6f Author: Benjamin <poussin@codelutin.com> Date: Tue Jan 26 01:20:22 2021 +0100 ajout de la visulisation de l'historique --- migrate/001_init_schema.sql | 1 - migrate/007_create_index_pageHistory.sql | 9 +++++ pkg/constant/const.go | 5 +++ pkg/http/pageHistoryResource.go | 41 ++++++++++++++++++++ pkg/http/router.go | 1 + pkg/repository/bookmarkRepository.go | 6 ++- pkg/repository/pageHistoryRepository.go | 28 ++++++++++++++ pkg/utils/html.go | 14 +++++-- run-dev | 1 + web/src/components/Bookmark.vue | 2 +- web/src/router/index.js | 13 +++++++ web/src/views/PageHistory.vue | 65 ++++++++++++++++++++++++++++++++ 12 files changed, 179 insertions(+), 7 deletions(-) diff --git a/migrate/001_init_schema.sql b/migrate/001_init_schema.sql index 0d1b79d..28c576e 100644 --- a/migrate/001_init_schema.sql +++ b/migrate/001_init_schema.sql @@ -5,7 +5,6 @@ CREATE EXTENSION IF NOT EXISTS "pgcrypto"; CREATE EXTENSION IF NOT EXISTS "pg_trgm"; CREATE EXTENSION IF NOT EXISTS "citext"; --- CREATE EXTENSION IF NOT EXISTS "btree_gist"; -- fonction a utilise pour les recherches dans les tableaux de text (ex: where text(tags) ilike '%adm%') CREATE OR REPLACE FUNCTION text(text[]) diff --git a/migrate/007_create_index_pageHistory.sql b/migrate/007_create_index_pageHistory.sql new file mode 100644 index 0000000..35d520a --- /dev/null +++ b/migrate/007_create_index_pageHistory.sql @@ -0,0 +1,9 @@ +-- creation d'un index pour retrouver le plus vite possible un historique le plus proche d'une date pour une url + +CREATE EXTENSION IF NOT EXISTS "btree_gist"; + +CREATE INDEX pageHistory_url_createdate_idx ON pageHistory USING gist (creationdate, uri); + +---- create above / drop below ---- + +DROP INDEX pageHistory_url_createdate_idx; diff --git a/pkg/constant/const.go b/pkg/constant/const.go index f005ddc..e63b564 100644 --- a/pkg/constant/const.go +++ b/pkg/constant/const.go @@ -105,6 +105,11 @@ First query parameter name first result */ const First = "first" +/* +Date use to specify pageHistory date +*/ +const Date = "date" + /* Save string action to save bookmark */ diff --git a/pkg/http/pageHistoryResource.go b/pkg/http/pageHistoryResource.go new file mode 100644 index 0000000..6e42ebb --- /dev/null +++ b/pkg/http/pageHistoryResource.go @@ -0,0 +1,41 @@ +package http + +import ( + "io" + "net/http" + "time" + + "github.com/gorilla/mux" + "gitlab.chorem.org/chorem/bow/pkg/constant" + "gitlab.chorem.org/chorem/bow/pkg/model" + "gitlab.chorem.org/chorem/bow/pkg/repository" + "gitlab.chorem.org/chorem/bow/pkg/utils" +) + +func getPageHistory(w http.ResponseWriter, r *http.Request) { + currentUser := r.Context().Value(constant.User).(model.BowUser) + id := mux.Vars(r)["id"] + + queryParams := r.URL.Query() + dateAsString := queryParams.Get(constant.Date) + + date, err := time.Parse(time.RFC3339, dateAsString) + if err != nil { + date = time.Now() + } + + utils.LogDebug("getPageHistory query: ", queryParams) + json, err := repository.GetPageHistory(currentUser, id, date) + if err != nil { + if utils.Is404(err) { + // on a rien retrouve, on renvoie un objet vide + json = "{}" + } else { + utils.Throw(w, err) + return + } + } + + w.Header().Add("Content-Type", "application/json") + io.WriteString(w, json) +} diff --git a/pkg/http/router.go b/pkg/http/router.go index dd988bb..b48a26f 100644 --- a/pkg/http/router.go +++ b/pkg/http/router.go @@ -80,6 +80,7 @@ func Start(bowPublicURL string, addr string) { s.HandleFunc("/bookmarks/{id}", updateBookmark).Methods(http.MethodPut, http.MethodOptions) s.HandleFunc("/bookmarks/{id}/visit", addOneVisit).Methods(http.MethodGet, http.MethodPost, http.MethodOptions) s.HandleFunc("/bookmarks/{id}/authenticationinfo", updateBookmarkAuthenticationInfo).Methods(http.MethodPut, http.MethodOptions) + s.HandleFunc("/bookmarks/{id}/history", getPageHistory).Methods(http.MethodGet, http.MethodOptions) s.HandleFunc("/opensearch", doActions).Methods(http.MethodGet, http.MethodPost, http.MethodOptions).Queries(constant.Action, "{ask}") s.HandleFunc("/opensearch", doSuggestion).Methods(http.MethodGet, http.MethodPost, http.MethodOptions).Queries(constant.Suggestion, "{ask}") diff --git a/pkg/repository/bookmarkRepository.go b/pkg/repository/bookmarkRepository.go index 4a5f783..29c7de6 100644 --- a/pkg/repository/bookmarkRepository.go +++ b/pkg/repository/bookmarkRepository.go @@ -117,7 +117,10 @@ func BookmarkJSON(currentUser model.BowUser, id string, uri string, tags []strin BookmarkByIDJSON retourne le bookmark au format json */ func BookmarkByIDJSON(currentUser model.BowUser, id string) (string, error) { - q := &query{sql: `select json_agg(b.*, i.favicon, i.miniscreenshot, i.screenshot) as result from bookmark b left join pageInfo i on b.uri=i.uri where b.id=$1`} + q := &query{sql: `WITH + __query AS (select b.*, i.favicon, i.miniscreenshot, i.screenshot from bookmark b left join pageInfo i on b.uri=i.uri where b.id=$1) + select json_agg(q.*) as result from __query q; + `} result, err := q.QueryString(currentUser, id) if err != nil { @@ -281,6 +284,7 @@ func UpdateBookmark(currentUser model.BowUser, bookmark model.Bookmark) error { } go collectPageInfo(bookmark.URI) + go createPageHistory(bookmark.URI) return err } diff --git a/pkg/repository/pageHistoryRepository.go b/pkg/repository/pageHistoryRepository.go index 2aec9ed..5831c37 100644 --- a/pkg/repository/pageHistoryRepository.go +++ b/pkg/repository/pageHistoryRepository.go @@ -40,3 +40,31 @@ func CreatePageHistory(uri string, content string) string { return id } + +// GetPageHistory retourne une page d'historique spécifique (date), on retourne la date plus petit si date n'est pas trouvée +func GetPageHistory(currentUser model.BowUser, id string, date time.Time) (string, error) { + var result string + var err error + + maxResult := currentUser.MaxResult + if maxResult == 0 || maxResult > 1000 { + maxResult = 100 + } + + utils.LogDebug("search page history uri: %v, date: '%v'", id, date) + + q := &query{sql: `WITH + __url AS (select uri from bookmark where id=$1), + __info AS (select min(creationdate) as first, max(creationdate) as last, count(creationdate) as count from pageHistory p, __url where p.uri = __url.uri), + __data AS (select p.uri, content, creationdate, LEAD(creationdate) OVER (ORDER BY creationdate) AS next, LAG(creationdate) OVER (ORDER BY creationdate) AS prev from pageHistory p, __url where p.uri=__url.uri order by creationdate <-> $2 limit 1) + select row_to_json(v) from (select * from __data, __info) v + `} + result, err = q.QueryString(currentUser, id, date) + + if err != nil { + return "", utils.NewHTTPError500(err, currentUser) + } + + return result, nil + +} diff --git a/pkg/utils/html.go b/pkg/utils/html.go index af41767..1c16940 100644 --- a/pkg/utils/html.go +++ b/pkg/utils/html.go @@ -1,7 +1,7 @@ package utils import ( - "io/ioutil" + "encoding/json" "log" "net/http" "net/url" @@ -25,11 +25,17 @@ func GetHTML(uri string) string { } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { + // body, err := ioutil.ReadAll(resp.Body) + // if err != nil { + // log.Printf("[error] %v\n", err) + // return "" + // } + + var html string + if err := json.NewDecoder(resp.Body).Decode(&html); err != nil { log.Printf("[error] %v\n", err) return "" } - return string(body) + return html } diff --git a/run-dev b/run-dev index d4c59a6..e4e20d8 100755 --- a/run-dev +++ b/run-dev @@ -6,4 +6,5 @@ export SECRET_KEY="AZERTYUIOPQSDFGHJKLMWXCVBN" export BOW_PUBLIC_URL="http://localhost:8000" export BOW_FAVICON_URL="http://localhost:8080/icon?size=16..24..32&url={url}" export BOW_SCREENSHOT_URL="http://localhost:7171?url={url}" +export BOW_HTML_EXTRACTOR_URL="http://localhost:40100/api/v1/call?url={url}" go run cmd/bow/main.go diff --git a/web/src/components/Bookmark.vue b/web/src/components/Bookmark.vue index 65348f8..0dd83d1 100644 --- a/web/src/components/Bookmark.vue +++ b/web/src/components/Bookmark.vue @@ -45,7 +45,7 @@ <!-- <span>{{ bookmark.authenticationinfo }}</span> faire afficher une popup de modification de l'objet auth--> <AuthenticationInfo v-if="bookmark.authenticationinfo" :authenticationinfo="bookmark.authenticationinfo"></AuthenticationInfo> - <BookmarkDate :creationDate="date" :updateDate="bookmark.updatedate"></BookmarkDate> + <a :href="'/history/' + bookmark.id + '?date=' + date"><BookmarkDate :creationDate="date" :updateDate="bookmark.updatedate"></BookmarkDate></a> <!-- <span>{{ bookmark.lang }}</span> --> <!-- <span>{{ bookmark.owner }}</span> si mon id n'est pas le meme alors c'est le bookmark d'un autre partage par un group --> </div> diff --git a/web/src/router/index.js b/web/src/router/index.js index ad2c665..b34f223 100644 --- a/web/src/router/index.js +++ b/web/src/router/index.js @@ -4,6 +4,7 @@ import Login from '../views/Login.vue' import Preferences from '../views/Preferences.vue' import Home from '../views/Home.vue' import BookmarkEdit from '../views/BookmarkEdit.vue' +import PageHistory from '../views/PageHistory.vue' Vue.use(VueRouter) @@ -55,6 +56,18 @@ const routes = [ lang: route.query.lang }) }, + { + path: '/history/:id', + name: 'History', + component: PageHistory, + meta: { + requiresAuth: true + }, + props: (route) => ({ + id: route.params.id, + date: route.query.date + }) + }, { path: '/about', name: 'About', diff --git a/web/src/views/PageHistory.vue b/web/src/views/PageHistory.vue new file mode 100644 index 0000000..4d58dba --- /dev/null +++ b/web/src/views/PageHistory.vue @@ -0,0 +1,65 @@ +<template> + <div class="page-history"> + <div><a href="">{{ history.first }}</a> <a href="">{{ history.prev }}</a> <a href="">{{ history.next }}</a> <a href="">{{ history.last }}</a></div> + <div> + <BookmarkDate :creationDate="history.creationdate"></BookmarkDate> + <LinkCount + class="bookmark-uri" + :bookmarkId="id" + :link="history.uri"> + {{ history.uri }} + </LinkCount> + </div> + <Description :description="history.content"></Description> + </div> +</template> + +<script> +import { Component, Prop, Vue } from 'vue-property-decorator' +import BookmarkDate from '@/components/common/BookmarkDate' +import Description from '@/components/bookmark/Description' +import LinkCount from '@/components/bookmark/LinkCount' + +@Component({ + name: 'PageHistory', + props: [ + 'id', + 'date' + ], + components: { + BookmarkDate, + Description, + LinkCount + } +}) +class PageHistory extends Vue { + @Prop id + @Prop date + + history = {} + + fetchHistory() { + let searchParams = new URLSearchParams() + this.date && searchParams.append('date', this.date) + this.$fetch.get(`/bookmarks/${this.id}/history?${searchParams.toString()}`).then( + data => { + this.history = data + }, + err => { + console.log("Can't fetch history", err) + } + ) + } + + + beforeMount() { + console.log('beforeMounted page history') + this.fetchHistory() + } +} + +export default PageHistory +</script> + +<style lang="less" scoped> +</style> \ No newline at end of file -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.