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 a4eecce4f3e35b66fdd8e6e77efbc92ed427d1f6 Author: Benjamin <poussin@codelutin.com> Date: Wed Apr 22 00:27:39 2020 +0200 debug d'ajout de la recherche/suggestion dans la barre du navigateur --- README.md | 12 +++ cmd/bow/main.go | 4 +- doc/implementation.md | 2 + pkg/constant/const.go | 5 + pkg/http/actionResource.go | 87 ---------------- pkg/http/opensearchResource.go | 186 +++++++++++++++++++++++++++++++++++ pkg/http/router.go | 10 +- pkg/http/userResource.go | 57 ++++++----- pkg/repository/bookmarkRepository.go | 7 +- pkg/utils/jwt.go | 11 +-- web/.env | 1 + web/public/index.html | 2 +- web/public/opensearch.xml | 11 --- 13 files changed, 255 insertions(+), 140 deletions(-) diff --git a/README.md b/README.md new file mode 100644 index 0000000..792aab1 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +== to start back + +# Postgresql database must be start +export DATABASE_URL="postgres://dbuser:xxxxxxxx@localhost:5432/bow" +export BOW_PUBLIC_URL="http://localhost:8000" + +go run cmd/bow/main.go + +== to start front + +cd web +yarn serve diff --git a/cmd/bow/main.go b/cmd/bow/main.go index aa296b9..78cd526 100644 --- a/cmd/bow/main.go +++ b/cmd/bow/main.go @@ -12,6 +12,8 @@ import ( func main() { databaseURL := os.Getenv("DATABASE_URL") secretKey := os.Getenv("SECRET_KEY") + bowPublicURL := os.Getenv("BOW_PUBLIC_URL") + if secretKey == "" { // for dev only secretKey = "AZERTYUIOPQSDFGHJKLMWXCVBN" @@ -35,5 +37,5 @@ func main() { addr := ":8000" log.Println("Start web server", addr) - http.Start(addr) + http.Start(bowPublicURL, addr) } diff --git a/doc/implementation.md b/doc/implementation.md index fbbe2e9..2289e98 100644 --- a/doc/implementation.md +++ b/doc/implementation.md @@ -1,5 +1,7 @@ TODO: table d'historique d'authentification TODO: faire des tests de perf entre TEXT[] et jsonb qui stockerait que des chaines +TODO: suggestion du add affiche le format (doc) et propose des bookmarks ayant la meme url +TODO: generation du opensearch.xml par le back avec generation d'un token jwt plus petit (seulement l'id) pour les suggesions qui ne recoivent pas les cookies == Creation d'un compte diff --git a/pkg/constant/const.go b/pkg/constant/const.go index df4069b..b55f6ba 100644 --- a/pkg/constant/const.go +++ b/pkg/constant/const.go @@ -41,6 +41,11 @@ Action query parameter name for tags search */ const Action = "action" +/* +Action query parameter name for tags search +*/ +const Suggestion = "suggestion" + /* Tags query parameter name for tags search */ diff --git a/pkg/http/actionResource.go b/pkg/http/actionResource.go deleted file mode 100644 index 631f9be..0000000 --- a/pkg/http/actionResource.go +++ /dev/null @@ -1,87 +0,0 @@ -package http - -import ( - "fmt" - "net/http" - "strings" - - "gitlab.chorem.org/chorem/bow/pkg/constant" - "gitlab.chorem.org/chorem/bow/pkg/model" -) - -func getOrEmpty(args []string, i int) string { - result := "" - if len(args) > i { - result = args[i] - } - - return result -} - -var actions = map [string]func(w http.ResponseWriter, r *http.Request, ask string) { - constant.Save: func(w http.ResponseWriter, r *http.Request, ask string) { - args := strings.Split(ask, "|") - uri := getOrEmpty(args, 0) - description := getOrEmpty(args, 1) - tags := getOrEmpty(args, 2) - privatealias := getOrEmpty(args, 3) - publicalias := getOrEmpty(args, 4) - lang := getOrEmpty(args, 5) - - // FIXME parametrer l'url - url := fmt.Sprintf("http://localhost:8080/edit/new?uri=%s&description=%s&tags=%s&privatealias=%s&publicalias=%s&lang=%s", uri, description, tags, privatealias, publicalias, lang) - http.Redirect(w, r, url, http.StatusFound) - }, - constant.RedirectAlias: func(w http.ResponseWriter, r *http.Request, ask string) { - // TODO recherche dans les alias prives - http.Redirect(w, r, "TODO", http.StatusFound) - }, - constant.SuggestionAlias: func(w http.ResponseWriter, r *http.Request, ask string) { - // renvoyer les couple alias/uri/description? pour l'affichage en suggest - //http.Redirect(w, r, uri, http.StatusFound) - }, - constant.SearchFulltext: func(w http.ResponseWriter, r *http.Request, ask string) { - url := fmt.Sprintf("http://localhost:8080/?fulltext=%s", ask) - http.Redirect(w, r, url, http.StatusFound) - }, - constant.SuggestionFulltext: func(w http.ResponseWriter, r *http.Request, ask string) { - // renvoyer les couple uri/description? pour l'affichage en suggest - //http.Redirect(w, r, uri, http.StatusFound) - }, - constant.SearchTag: func(w http.ResponseWriter, r *http.Request, ask string) { - url := fmt.Sprintf("http://localhost:8080/?tags=%s", ask) - http.Redirect(w, r, url, http.StatusFound) - }, - constant.SuggestionTag: func(w http.ResponseWriter, r *http.Request, ask string) { - // renvoyer les couple uri/description? pour l'affichage en suggest - //http.Redirect(w, r, uri, http.StatusFound) - }} - -func doActions(w http.ResponseWriter, r *http.Request) { - currentUser := r.Context().Value(constant.User).(model.BowUser) - - query := r.URL.Query() - ask := query.Get(constant.Action) - - // l'action a faire - var todo string - for _, a := range currentUser.Actions { - prefix := a.Prefix - if prefix == "" { - todo = a.Action - } else if strings.HasPrefix(ask, prefix) { - todo = a.Action - ask = ask[len(prefix):] - break - } - } - - toCall := actions[todo] - if toCall != nil { - toCall(w, r, ask) - } else { - uri := strings.Replace(todo, "{searchTerms}", ask, -1) - http.Redirect(w, r, uri, http.StatusFound) - } - -} diff --git a/pkg/http/opensearchResource.go b/pkg/http/opensearchResource.go new file mode 100644 index 0000000..8a7e98c --- /dev/null +++ b/pkg/http/opensearchResource.go @@ -0,0 +1,186 @@ +package http + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "net/http" + "strings" + + "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 opensearchFile(w http.ResponseWriter, r *http.Request) { + currentUser := r.Context().Value(constant.User).(model.BowUser) + + token, err := utils.JwtGenerate(currentUser) + if err != nil { + utils.Throw(w, utils.NewHTTPError500(err, currentUser)) + return + } + + log.Println("URL ", r.URL.EscapedPath(), "path", r.URL.Path, "raw", r.URL.Hostname(), "end") + self := BowPublicURL + r.URL.EscapedPath() + fileContent := fmt.Sprintf(`<?xml version="1.0" encoding="utf-8"?> +<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/"> + <ShortName>Bow</ShortName> + <Description>Search with Bow</Description> + <InputEncoding>UTF-8</InputEncoding> + <LongName>Bow Search</LongName> + <Image height="16" width="16">data:image/x-icon;base64,R0lGODlhEAAQAMMCAAAAAP97AP////+9hP/nxv+cQsbGxoSEhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAUAAAgALAAAAAAQABAAAARHEIE5kbWUhr0rFmA2ccAFhJIJdNJwlqnZEaUXYwB97Xe+wryUbxUA8nwY1lEnM7ZqsiKuAKxKTwYn7Ic9OIXFiTeIu353lQgAOw==</Image> + <Url type="text/html" method="get" template="%[1]s"> + <Param name="action" value="{searchTerms}"/> + </Url> + <Url type="application/x-suggestions+json" template="%[1]s"> + <Param name="suggestion" value="{searchTerms}"/> + <Param name="bow-token" value="%[2]s"/> + </Url> + <Url type="application/opensearchdescription+xml" rel="self" template="%[1]s" /> + <moz:SearchForm>%[3]s</moz:SearchForm> +</OpenSearchDescription>`, self, token, BowPublicURL) + + w.Header().Add("Content-Type", "application/opensearchdescription+xml") + io.WriteString(w, fileContent) +} + +func getOrEmpty(args []string, i int) string { + result := "" + if len(args) > i { + result = args[i] + } + + return result +} + +func prependPrefix(prefix string, result string) string { + if prefix == "" { + return result + } + result = strings.ReplaceAll(result, "[\"", "[\""+prefix) + result = strings.ReplaceAll(result, ",\"", ",\""+prefix) + result = strings.ReplaceAll(result, ", \"", ", \""+prefix) + return result +} + +var actions = map[string]func(w http.ResponseWriter, r *http.Request, currentUser model.BowUser, prefix string, ask string){ + constant.Save: func(w http.ResponseWriter, r *http.Request, currentUser model.BowUser, prefix string, ask string) { + args := strings.Split(ask, "|") + uri := getOrEmpty(args, 0) + description := getOrEmpty(args, 1) + tags := getOrEmpty(args, 2) + privatealias := getOrEmpty(args, 3) + publicalias := getOrEmpty(args, 4) + lang := getOrEmpty(args, 5) + + // FIXME parametrer l'url + url := fmt.Sprintf("http://localhost:8080/edit/new?uri=%s&description=%s&tags=%s&privatealias=%s&publicalias=%s&lang=%s", uri, description, tags, privatealias, publicalias, lang) + http.Redirect(w, r, url, http.StatusFound) + }, + constant.RedirectAlias: func(w http.ResponseWriter, r *http.Request, currentUser model.BowUser, prefix string, ask string) { + // TODO recherche dans les alias prives + http.Redirect(w, r, "TODO", http.StatusFound) + }, + constant.SuggestionAlias: func(w http.ResponseWriter, r *http.Request, currentUser model.BowUser, prefix string, ask string) { + // renvoyer les couple alias/uri/description? pour l'affichage en suggest + //http.Redirect(w, r, uri, http.StatusFound) + }, + constant.SearchFulltext: func(w http.ResponseWriter, r *http.Request, currentUser model.BowUser, prefix string, ask string) { + url := fmt.Sprintf("http://localhost:8080/?fulltext=%s", ask) + http.Redirect(w, r, url, http.StatusFound) + }, + constant.SuggestionFulltext: func(w http.ResponseWriter, r *http.Request, currentUser model.BowUser, prefix string, ask string) { + // renvoyer les couple uri/description? pour l'affichage en suggest + //http.Redirect(w, r, uri, http.StatusFound) + }, + constant.SearchTag: func(w http.ResponseWriter, r *http.Request, currentUser model.BowUser, prefix string, ask string) { + url := fmt.Sprintf("http://localhost:8080/?tags=%s", ask) + http.Redirect(w, r, url, http.StatusFound) + }, + constant.SuggestionTag: func(w http.ResponseWriter, r *http.Request, currentUser model.BowUser, prefix string, ask string) { + // ["la saisie actuelle",["tableau de suggestion"],["tableau de description des suggetions"], ["tableau d'url si la suggesion est selection"]] + result, err := repository.TagsJSON(currentUser, ask, true) + if err != nil { + utils.Throw(w, utils.NewHTTPError500(err, currentUser)) + return + } + s := fmt.Sprintf("[\"%s\",%s", ask, result[1:]) + s = prependPrefix(prefix, s) + log.Println("Suggest", s) + io.WriteString(w, s) + }} + +func getAction(currentUser model.BowUser, ask string) model.Action { + var result model.Action + for _, a := range currentUser.Actions { + prefix := a.Prefix + if prefix == "" { + result = a + } else if strings.HasPrefix(ask, prefix) { + result = a + break + } + } + return result +} + +func doActions(w http.ResponseWriter, r *http.Request) { + currentUser := r.Context().Value(constant.User).(model.BowUser) + + ask := mux.Vars(r)["ask"] + actionTodo := getAction(currentUser, ask) + todo := actionTodo.Action + ask = ask[len(actionTodo.Prefix):] + + toCall := actions[todo] + if toCall != nil { + toCall(w, r, currentUser, actionTodo.Prefix, ask) + } else { + uri := strings.ReplaceAll(todo, "{searchTerms}", ask) + http.Redirect(w, r, uri, http.StatusFound) + } +} + +func doSuggestion(w http.ResponseWriter, r *http.Request) { + currentUser := r.Context().Value(constant.User).(model.BowUser) + + ask := mux.Vars(r)["ask"] + actionTodo := getAction(currentUser, ask) + todo := actionTodo.Suggest + ask = ask[len(actionTodo.Prefix):] + + toCall := actions[todo] + if toCall != nil { + toCall(w, r, currentUser, actionTodo.Prefix, ask) + } else { + uri := strings.ReplaceAll(todo, "{searchTerms}", ask) + log.Println("get suggestion from ", uri) + resp, err := http.Get(uri) + if err != nil { + utils.Throw(w, utils.NewHTTPError500(err, currentUser)) + return + } + + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + utils.Throw(w, utils.NewHTTPError500(err, currentUser)) + return + } + + result := string(body) + if resp.StatusCode >= 400 { + utils.Throw(w, utils.NewHTTPError(fmt.Sprintf("Can't retrieve suggestion: %s", result), currentUser, resp.StatusCode)) + return + } + + result = prependPrefix(actionTodo.Prefix, result) + log.Println("Suggest", result) + io.WriteString(w, result) + } + +} diff --git a/pkg/http/router.go b/pkg/http/router.go index da1f5f7..ab47931 100644 --- a/pkg/http/router.go +++ b/pkg/http/router.go @@ -16,10 +16,14 @@ import ( "github.com/gorilla/mux" ) +var BowPublicURL string + /* Start web server */ -func Start(addr string) { +func Start(bowPublicURL string, addr string) { + BowPublicURL = bowPublicURL + router := mux.NewRouter() router.Use(logAll) // router.Use(mux.CORSMethodMiddleware(router)) @@ -54,7 +58,9 @@ func Start(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("/action", doActions).Methods(http.MethodGet, http.MethodPost, 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}") + s.HandleFunc("/opensearch", opensearchFile).Methods(http.MethodGet, http.MethodOptions) srv := &http.Server{ Handler: router, diff --git a/pkg/http/userResource.go b/pkg/http/userResource.go index 4de850a..33399ef 100644 --- a/pkg/http/userResource.go +++ b/pkg/http/userResource.go @@ -48,7 +48,14 @@ func createAuth(w http.ResponseWriter, r *http.Request) { return } - token, err := utils.JwtGenerate(userJSON) // si on ajoute plus d'info sensible dans le token, il faudra le chiffrer + var user model.BowUser + err = json.Unmarshal([]byte(userJSON), &user) + if err != nil { + utils.Throw(w, utils.NewHTTPError500(err, pseudoUser)) + return + } + + token, err := utils.JwtGenerate(user) // si on ajoute plus d'info sensible dans le token, il faudra le chiffrer if err != nil { utils.Throw(w, err) return @@ -86,10 +93,10 @@ func checkLogin(id string, email string, password string) string { GetUser return all information on user (info, config, auth) */ func getUser(w http.ResponseWriter, r *http.Request) { - currentUserID := r.Context().Value(constant.User).(model.BowUser) + currentUser := r.Context().Value(constant.User).(model.BowUser) id := mux.Vars(r)["id"] - json, err := repository.UserJSON(currentUserID, id) + json, err := repository.UserJSON(currentUser, id) if err != nil { utils.Throw(w, err) return @@ -124,12 +131,12 @@ func createUser(w http.ResponseWriter, r *http.Request) { } func deleteUser(w http.ResponseWriter, r *http.Request) { - currentUserID := r.Context().Value(constant.User).(model.BowUser) + currentUser := r.Context().Value(constant.User).(model.BowUser) id := mux.Vars(r)["id"] log.Println("deleteUser", id) - err := repository.DeleteUser(currentUserID, id) + err := repository.DeleteUser(currentUser, id) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -141,7 +148,7 @@ updateUserPassword body: {"password": "xxxx", "oldPassword": "yyyy"} */ func updateUserPassword(w http.ResponseWriter, r *http.Request) { - currentUserID := r.Context().Value(constant.User).(model.BowUser) + currentUser := r.Context().Value(constant.User).(model.BowUser) id := mux.Vars(r)["id"] log.Println("updateUserPassword", id) @@ -153,7 +160,7 @@ func updateUserPassword(w http.ResponseWriter, r *http.Request) { return } - err = repository.UpdateUserPassword(currentUserID, id, data["password"], data["oldPassword"], false) + err = repository.UpdateUserPassword(currentUser, id, data["password"], data["oldPassword"], false) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -166,7 +173,7 @@ body: {"name": "for application toto", "expiration": 1586081695000} return: {"token": "uuid"} */ func addUserToken(w http.ResponseWriter, r *http.Request) { - currentUserID := r.Context().Value(constant.User).(model.BowUser) + currentUser := r.Context().Value(constant.User).(model.BowUser) id := mux.Vars(r)["id"] @@ -179,7 +186,7 @@ func addUserToken(w http.ResponseWriter, r *http.Request) { log.Println("addUserToken", id, data.Name, data.Expiration) - token, err := repository.AddUserToken(currentUserID, id, data.Name, data.Expiration) + token, err := repository.AddUserToken(currentUser, id, data.Name, data.Expiration) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -194,7 +201,7 @@ body: {"name": "for application toto", "expiration": 1586081695000} return: {"token": "uuid"} */ func addUserUnconfirmedEmail(w http.ResponseWriter, r *http.Request) { - currentUserID := r.Context().Value(constant.User).(model.BowUser) + currentUser := r.Context().Value(constant.User).(model.BowUser) id := mux.Vars(r)["id"] @@ -207,7 +214,7 @@ func addUserUnconfirmedEmail(w http.ResponseWriter, r *http.Request) { log.Println("addUserUnconfirmedEmail", id) - token, err := repository.AddUserUnconfirmedEmail(currentUserID, id, data.Email) + token, err := repository.AddUserUnconfirmedEmail(currentUser, id, data.Email) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -219,7 +226,7 @@ func addUserUnconfirmedEmail(w http.ResponseWriter, r *http.Request) { } func updateUserAuthenticationInfo(w http.ResponseWriter, r *http.Request) { - currentUserID := r.Context().Value(constant.User).(model.BowUser) + currentUser := r.Context().Value(constant.User).(model.BowUser) id := mux.Vars(r)["id"] var auth model.AuthenticationInfo @@ -231,7 +238,7 @@ func updateUserAuthenticationInfo(w http.ResponseWriter, r *http.Request) { log.Println("updateUserAuthenticationInfo", id, auth) - err = repository.UpdateUserAuthenticationInfo(currentUserID, id, auth) + err = repository.UpdateUserAuthenticationInfo(currentUser, id, auth) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -239,7 +246,7 @@ func updateUserAuthenticationInfo(w http.ResponseWriter, r *http.Request) { } func updateUserActions(w http.ResponseWriter, r *http.Request) { - currentUserID := r.Context().Value(constant.User).(model.BowUser) + currentUser := r.Context().Value(constant.User).(model.BowUser) id := mux.Vars(r)["id"] var actions []model.Action @@ -251,7 +258,7 @@ func updateUserActions(w http.ResponseWriter, r *http.Request) { log.Println("updateUserActions", id, actions) - err = repository.UpdateUserActions(currentUserID, id, actions) + err = repository.UpdateUserActions(currentUser, id, actions) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -259,7 +266,7 @@ func updateUserActions(w http.ResponseWriter, r *http.Request) { } func updateUserAutoScreenshot(w http.ResponseWriter, r *http.Request) { - currentUserID := r.Context().Value(constant.User).(model.BowUser) + currentUser := r.Context().Value(constant.User).(model.BowUser) id := mux.Vars(r)["id"] @@ -272,7 +279,7 @@ func updateUserAutoScreenshot(w http.ResponseWriter, r *http.Request) { log.Println("updateUserAutoScreenshot", id, data) - err = repository.UpdateUserAutoScreenshot(currentUserID, id, data["autoscreenshot"]) + err = repository.UpdateUserAutoScreenshot(currentUser, id, data["autoscreenshot"]) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -280,7 +287,7 @@ func updateUserAutoScreenshot(w http.ResponseWriter, r *http.Request) { } func updateUserAutoFavicon(w http.ResponseWriter, r *http.Request) { - currentUserID := r.Context().Value(constant.User).(model.BowUser) + currentUser := r.Context().Value(constant.User).(model.BowUser) id := mux.Vars(r)["id"] @@ -293,7 +300,7 @@ func updateUserAutoFavicon(w http.ResponseWriter, r *http.Request) { log.Println("updateUserAutoFavicon", id, data) - err = repository.UpdateUserAutoFavicon(currentUserID, id, data["autofavicon"]) + err = repository.UpdateUserAutoFavicon(currentUser, id, data["autofavicon"]) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -301,7 +308,7 @@ func updateUserAutoFavicon(w http.ResponseWriter, r *http.Request) { } func updateUserMaxTagInCloud(w http.ResponseWriter, r *http.Request) { - currentUserID := r.Context().Value(constant.User).(model.BowUser) + currentUser := r.Context().Value(constant.User).(model.BowUser) id := mux.Vars(r)["id"] @@ -314,7 +321,7 @@ func updateUserMaxTagInCloud(w http.ResponseWriter, r *http.Request) { log.Println("updateUserMaxTagInCloud", id, data) - err = repository.UpdateUserMaxTagInCloud(currentUserID, id, data["maxtagincloud"]) + err = repository.UpdateUserMaxTagInCloud(currentUser, id, data["maxtagincloud"]) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -322,7 +329,7 @@ func updateUserMaxTagInCloud(w http.ResponseWriter, r *http.Request) { } func updateUserMaxResult(w http.ResponseWriter, r *http.Request) { - currentUserID := r.Context().Value(constant.User).(model.BowUser) + currentUser := r.Context().Value(constant.User).(model.BowUser) id := mux.Vars(r)["id"] @@ -335,7 +342,7 @@ func updateUserMaxResult(w http.ResponseWriter, r *http.Request) { log.Println("updateUserMaxResult", id, data) - err = repository.UpdateUserMaxResult(currentUserID, id, data["maxresult"]) + err = repository.UpdateUserMaxResult(currentUser, id, data["maxresult"]) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return @@ -343,12 +350,12 @@ func updateUserMaxResult(w http.ResponseWriter, r *http.Request) { } func confirmUserEmail(w http.ResponseWriter, r *http.Request) { - currentUserID := r.Context().Value(constant.User).(model.BowUser) + currentUser := r.Context().Value(constant.User).(model.BowUser) id := mux.Vars(r)["id"] token := mux.Vars(r)["token"] - err := repository.ConfirmUserEmail(currentUserID, id, token) + err := repository.ConfirmUserEmail(currentUser, id, token) if err != nil { http.Error(w, fmt.Sprintf("%s", err), 400) return diff --git a/pkg/repository/bookmarkRepository.go b/pkg/repository/bookmarkRepository.go index 6afaef2..68987a3 100644 --- a/pkg/repository/bookmarkRepository.go +++ b/pkg/repository/bookmarkRepository.go @@ -59,14 +59,15 @@ func BookmarkJSON(currentUser model.BowUser, id string, uri string, tags string, } /* -TagsJSON retourne le bookmark au format json +TagsJSON retourne la liste des tags qui match le filtre +le format de retour est celui d'opensearch */ func TagsJSON(currentUser model.BowUser, filter string, withCount bool) (string, error) { var q *query if withCount { - q = &query{sql: `WITH __all AS (select unnest(tags) as tag from bookmark), __some AS (select tag, count(tag) from __all where tag ilike $1 group by tag order by 2 desc) select json_agg(a) from __some a;`} + q = &query{sql: `WITH __all AS (select unnest(tags) as tag from bookmark), __some AS (select tag, count(tag) from __all where tag ilike $1 group by tag order by 2 desc) select '[' || json_agg(a.tag) || ', ' || json_agg(a.count) || ']' as suggestion from __some a;`} } else { - q = &query{sql: `WITH __all AS (select distinct unnest(tags) as tag from bookmark order by 1), __some AS (select * from __all where tag ilike $1) select json_agg(tag) from __some;`} + q = &query{sql: `WITH __all AS (select distinct unnest(tags) as tag from bookmark order by 1), __some AS (select * from __all where tag ilike $1) select json_agg(tag) as suggestion from __some;`} } substring := fmt.Sprintf("%%%s%%", filter) // to do like, with must have many % :) result, err := q.QueryString(currentUser, substring) diff --git a/pkg/utils/jwt.go b/pkg/utils/jwt.go index 2dca08e..30d7f02 100644 --- a/pkg/utils/jwt.go +++ b/pkg/utils/jwt.go @@ -1,8 +1,6 @@ package utils import ( - "encoding/json" - "github.com/brianvoe/sjwt" "gitlab.chorem.org/chorem/bow/pkg/model" ) @@ -61,14 +59,7 @@ func JwtVerify(token string) (model.BowUser, error) { /* JwtGenerate generate JWT token from information in parameter */ -func JwtGenerate(userJSON string) (string, error) { - var user model.BowUser - - err := json.Unmarshal([]byte(userJSON), &user) - if err != nil { - return "", NewHTTPError500(err, user) - } - +func JwtGenerate(user model.BowUser) (string, error) { claims, err := sjwt.ToClaims(user) if err != nil { return "", NewHTTPError500(err, user) diff --git a/web/.env b/web/.env new file mode 100644 index 0000000..4023d13 --- /dev/null +++ b/web/.env @@ -0,0 +1 @@ +VUE_APP_BOW_PUBLIC_URL=http://localhost:8000 diff --git a/web/public/index.html b/web/public/index.html index 4703ad2..f3fd181 100644 --- a/web/public/index.html +++ b/web/public/index.html @@ -5,7 +5,7 @@ <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="icon" href="<%= BASE_URL %>favicon.png"> - <link title="bow" type="application/opensearchdescription+xml" rel="search" href="/opensearch.xml"> + <link title="bow" type="application/opensearchdescription+xml" rel="search" href="<%= VUE_APP_BOW_PUBLIC_URL %>/api/v1/opensearch"> <title>Bow - <%= htmlWebpackPlugin.options.title %></title> </head> <body> diff --git a/web/public/opensearch.xml b/web/public/opensearch.xml deleted file mode 100644 index d51563f..0000000 --- a/web/public/opensearch.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/"> - <ShortName>Bow</ShortName> - <Description>Search with Bow</Description> - <InputEncoding>UTF-8</InputEncoding> - <LongName>Bow Search</LongName> - <Image height="16" width="16">data:image/x-icon;base64,R0lGODlhEAAQAMMCAAAAAP97AP////+9hP/nxv+cQsbGxoSEhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAUAAAgALAAAAAAQABAAAARHEIE5kbWUhr0rFmA2ccAFhJIJdNJwlqnZEaUXYwB97Xe+wryUbxUA8nwY1lEnM7ZqsiKuAKxKTwYn7Ic9OIXFiTeIu353lQgAOw==</Image> - <Url type="text/html" method="get" template="https://localhost:8000/api/v1/action?action={searchTerms}"/> - <Url type="application/x-suggestions+json" template="https://localhost:8000/api/v1/action?suggestion={searchTerms}"/> - <moz:SearchForm>https://bow.chorem.org/bow/</moz:SearchForm> -</OpenSearchDescription> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.