From 0f62ade5a05c755f18fd4d16a2a280b7870b08b7 Mon Sep 17 00:00:00 2001 From: jan Date: Mon, 14 Nov 2016 18:46:52 +0100 Subject: likes funktionieren diff --git a/assets_src/js/like.js b/assets_src/js/like.js index 03b15a1..feae345 100644 --- a/assets_src/js/like.js +++ b/assets_src/js/like.js @@ -11,12 +11,81 @@ async function updateLikeCount(el) { const count = await ajax.get(`/api/likes/count?id=${contentId}&type=${type}`, {}); - el.textContent = count; + dom.firstChild(el, e => e.classList.contains('like-count')).textContent = count; +} + +async function isLikedByCurrentUser(el) { + const type = parseInt(el.getAttribute('content-type'), 10); + const contentId = parseInt(el.getAttribute('content-id'), 10); + const userId = parseInt(el.getAttribute('update-with'), 10); + + if (isNaN(type) || isNaN(contentId) || isNaN(userId)) { + return; + } + + const b = await ajax.get(`/api/likes/liked_by?id=${contentId}&type=${type}&user=${userId}`, {}); + + console.log(b); + return b === 'true'; +} + +async function updateLikeByCurrentUser(el, to) { + const type = parseInt(el.getAttribute('content-type'), 10); + const contentId = parseInt(el.getAttribute('content-id'), 10); + const userId = parseInt(el.getAttribute('update-with'), 10); + + if (isNaN(type) || isNaN(contentId) || isNaN(userId)) { + return; + } + + updateLikeClass(el, to); + + if (to) { + await ajax.put('/api/likes', `id=${contentId}&type=${type}&user=${userId}`, { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + } + }); + } else { + await ajax.del('/api/likes', `id=${contentId}&type=${type}&user=${userId}`, { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + } + }); + } + const cont = dom.firstChild(el, e => e.classList.contains('like-count')); + + cont.textContent = parseInt(cont.textContent, 10) + (to ? 1 : -1); +} + +function updateLikeClass(el, to) { + el.classList.toggle('liked', to); } dom.ready(() => { - dom.withClass('like-count') - .forEach(el => { + dom.withClass('like-div') + .forEach(async el => { updateLikeCount(el); + + const userId = parseInt(el.getAttribute('update-with'), 10); + + let liked = await isLikedByCurrentUser(el); + updateLikeClass(el, liked); + if (!isNaN(userId)) { + el.addEventListener('click', async () => { + liked = !liked; + await updateLikeByCurrentUser(el, liked); + }); + const cap = dom.firstChild(el, e => e.classList.contains('like-caption')); + if (cap) { + el.addEventListener('mouseover', () => { + cap.textContent = `${liked ? 'nicht mehr ' : ''}geil finden`; + }); + el.addEventListener('mouseout', () => cap.textContent = 'Finden das geil'); + } + } else { + el.classList.add('disabled'); + } + }); }); diff --git a/modules/likes/likes.go b/modules/likes/likes.go index 949cba2..4d69d7b 100644 --- a/modules/likes/likes.go +++ b/modules/likes/likes.go @@ -2,11 +2,14 @@ package likes import ( "fmt" + "io/ioutil" "log" "net/http" + "net/url" "strconv" "fagott.pw/charakterin" + "fagott.pw/grilist/cache" "fagott.pw/grilist/grilist" "fagott.pw/grilist/modules/lists" @@ -15,6 +18,7 @@ import ( type Module struct { g *grilist.Grilist + c *cache.Cache lists *lists.Module } @@ -33,7 +37,11 @@ func (m *Module) Init(g *grilist.Grilist) { log.Fatal("tags: lists module not found") } m.lists = gm.(*lists.Module) + m.c = cache.New() m.g.Router.GET("/api/likes/count", m.getLikeCount) + m.g.Router.GET("/api/likes/liked_by", m.isLikedBy) + m.g.Router.PUT("/api/likes", m.addLike) + m.g.Router.DELETE("/api/likes", m.removeLike) } func (m *Module) Interface() interface{} { @@ -68,3 +76,115 @@ func (m *Module) getLikeCount(w http.ResponseWriter, r *http.Request, p httprout w.WriteHeader(200) w.Write([]byte(fmt.Sprintf("%d", res))) } +func (m *Module) isLikedBy(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + params := r.URL.Query() + + contentId, err := strconv.Atoi(params.Get("id")) + if err != nil { + http.Error(w, "invalid content id", http.StatusBadRequest) + return + } + contentType, err := strconv.Atoi(params.Get("type")) + if err != nil { + http.Error(w, "invalid content type", http.StatusBadRequest) + return + } + userId, err := strconv.Atoi(params.Get("user")) + if err != nil { + http.Error(w, "invalid user id", http.StatusBadRequest) + return + } + + var res int + if err := m.g.DB.QueryRow(`SELECT COUNT(*) FROM grilist.likes WHERE content = $1 AND type = $2 AND "user" = $3`, contentId, contentType, userId).Scan(&res); err != nil { + http.Error(w, "pq error", http.StatusInternalServerError) + log.Printf("error getting like by user: %s", err) + return + } + + w.WriteHeader(200) + w.Write([]byte(fmt.Sprintf("%t", res > 0))) +} +func (m *Module) addLike(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + params, err := readBody(r) + if err != nil { + log.Println(err) + http.Error(w, "invalid body", http.StatusBadRequest) + return + } + + contentId, err := strconv.Atoi(params.Get("id")) + if err != nil { + log.Println(err) + http.Error(w, "invalid content id", http.StatusBadRequest) + return + } + contentType, err := strconv.Atoi(params.Get("type")) + if err != nil { + log.Println(err) + http.Error(w, "invalid content type", http.StatusBadRequest) + return + } + userId, err := strconv.Atoi(params.Get("user")) + if err != nil { + http.Error(w, "invalid user id", http.StatusBadRequest) + return + } + + _, err = m.g.DB.Exec(`INSERT INTO grilist.likes(content, "user", type) SELECT $1, $2, $3 WHERE NOT EXISTS (SELECT * FROM grilist.likes WHERE content = $1 AND "user" = $2 AND type = $3)`, contentId, userId, contentType) + if err != nil { + http.Error(w, "pq error", http.StatusInternalServerError) + log.Printf("error add like: %s", err) + return + } + + w.WriteHeader(200) +} + +func (m *Module) removeLike(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + params, err := readBody(r) + if err != nil { + http.Error(w, "invalid body", http.StatusBadRequest) + return + } + + contentId, err := strconv.Atoi(params.Get("id")) + if err != nil { + http.Error(w, "invalid content id", http.StatusBadRequest) + return + } + contentType, err := strconv.Atoi(params.Get("type")) + if err != nil { + http.Error(w, "invalid content type", http.StatusBadRequest) + return + } + userId, err := strconv.Atoi(params.Get("user")) + if err != nil { + http.Error(w, "invalid user id", http.StatusBadRequest) + return + } + + _, err = m.g.DB.Exec(`DELETE FROM grilist.likes WHERE content = $1 AND "user" = $2 AND type = $3`, contentId, userId, contentType) + if err != nil { + http.Error(w, "pq error", http.StatusInternalServerError) + log.Printf("error add like: %s", err) + return + } + + w.WriteHeader(200) +} + +func readBody(r *http.Request) (url.Values, error) { + defer r.Body.Close() + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, err + } + + values, err := url.ParseQuery(string(data)) + if err != nil { + return nil, err + } + + return values, nil +} diff --git a/views/includes/like.html b/views/includes/like.html index 226aaff..bfb9576 100644 --- a/views/includes/like.html +++ b/views/includes/like.html @@ -1,3 +1,5 @@ {{ define "like" }} - Likes +
+ +
{{ end }} diff --git a/views/pages/list.html b/views/pages/list.html index 3c95548..3676241 100644 --- a/views/pages/list.html +++ b/views/pages/list.html @@ -35,7 +35,7 @@ {{ end }}
{{ $list.Description }}

- {{ template "like" (map "ContentType" 0 "ContentID" $list.ID) }} + {{ template "like" (map "ContentType" 0 "ContentID" $list.ID "User" $user) }}
    -- cgit v0.10.1