aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assets_src/js/like.js75
-rw-r--r--modules/likes/likes.go153
-rw-r--r--views/includes/like.html4
-rw-r--r--views/pages/list.html4
4 files changed, 4 insertions, 232 deletions
diff --git a/assets_src/js/like.js b/assets_src/js/like.js
index a438182..03b15a1 100644
--- a/assets_src/js/like.js
+++ b/assets_src/js/like.js
@@ -11,81 +11,12 @@ async function updateLikeCount(el) {
11 11
12 const count = await ajax.get(`/api/likes/count?id=${contentId}&type=${type}`, {}); 12 const count = await ajax.get(`/api/likes/count?id=${contentId}&type=${type}`, {});
13 13
14 dom.firstChild(el, e => e.classList.contains('like-count')).textContent = count; 14 el.textContent = count;
15}
16
17async function isLikedByCurrentUser(el) {
18 const type = parseInt(el.getAttribute('content-type'), 10);
19 const contentId = parseInt(el.getAttribute('content-id'), 10);
20 const userId = parseInt(el.getAttribute('update-with'), 10);
21
22 if (isNaN(type) || isNaN(contentId) || isNaN(userId)) {
23 return;
24 }
25
26 const b = await ajax.get(`/api/likes/liked_by?id=${contentId}&type=${type}&user=${userId}`, {});
27
28 console.log(b);
29 return b === 'true';
30}
31
32async function updateLikeByCurrentUser(el, to) {
33 const type = parseInt(el.getAttribute('content-type'), 10);
34 const contentId = parseInt(el.getAttribute('content-id'), 10);
35 const userId = parseInt(el.getAttribute('update-with'), 10);
36
37 if (isNaN(type) || isNaN(contentId) || isNaN(userId)) {
38 return;
39 }
40
41 updateLikeClass(el, to);
42
43 if (to) {
44 await ajax.put('/api/likes', `id=${contentId}&type=${type}&user=${userId}`, {
45 headers: {
46 'Content-Type': 'application/x-www-form-urlencoded',
47 }
48 });
49 } else {
50 await ajax.del('/api/likes', `id=${contentId}&type=${type}&user=${userId}`, {
51 headers: {
52 'Content-Type': 'application/x-www-form-urlencoded',
53 }
54 });
55 }
56 const cont = dom.firstChild(el, e => e.classList.contains('like-count'));
57
58 cont.textContent = parseInt(cont.textContent, 10) + (to ? 1 : -1);
59}
60
61function updateLikeClass(el, to) {
62 el.classList.toggle('liked', to);
63} 15}
64 16
65dom.ready(() => { 17dom.ready(() => {
66 dom.withClass('like-div') 18 dom.withClass('like-count')
67 .forEach(async el => { 19 .forEach(el => {
68 updateLikeCount(el); 20 updateLikeCount(el);
69
70 const userId = parseInt(el.getAttribute('update-with'), 10);
71
72 let liked = await isLikedByCurrentUser(el);
73 updateLikeClass(el, liked);
74 if (!isNaN(userId)) {
75 el.addEventListener('click', async () => {
76 liked = !liked;
77 await updateLikeByCurrentUser(el, liked);
78 });
79 const cap = dom.firstChild(el, e => e.classList.contains('like-caption'));
80 if (cap) {
81 el.addEventListener('mouseover', () => {
82 cap.textContent = liked ? 'nicht mehr approven' : 'approven!';
83 });
84 el.addEventListener('mouseout', () => cap.textContent = 'approven');
85 }
86 } else {
87 el.classList.add('disabled');
88 }
89
90 }); 21 });
91}); 22});
diff --git a/modules/likes/likes.go b/modules/likes/likes.go
index 80f632b..949cba2 100644
--- a/modules/likes/likes.go
+++ b/modules/likes/likes.go
@@ -2,14 +2,11 @@ package likes
2 2
3import ( 3import (
4 "fmt" 4 "fmt"
5 "io/ioutil"
6 "log" 5 "log"
7 "net/http" 6 "net/http"
8 "net/url"
9 "strconv" 7 "strconv"
10 8
11 "fagott.pw/charakterin" 9 "fagott.pw/charakterin"
12 "fagott.pw/grilist/cache"
13 "fagott.pw/grilist/grilist" 10 "fagott.pw/grilist/grilist"
14 "fagott.pw/grilist/modules/lists" 11 "fagott.pw/grilist/modules/lists"
15 12
@@ -18,7 +15,6 @@ import (
18 15
19type Module struct { 16type Module struct {
20 g *grilist.Grilist 17 g *grilist.Grilist
21 c *cache.Cache
22 lists *lists.Module 18 lists *lists.Module
23} 19}
24 20
@@ -37,11 +33,7 @@ func (m *Module) Init(g *grilist.Grilist) {
37 log.Fatal("tags: lists module not found") 33 log.Fatal("tags: lists module not found")
38 } 34 }
39 m.lists = gm.(*lists.Module) 35 m.lists = gm.(*lists.Module)
40 m.c = cache.New()
41 m.g.Router.GET("/api/likes/count", m.getLikeCount) 36 m.g.Router.GET("/api/likes/count", m.getLikeCount)
42 m.g.Router.GET("/api/likes/liked_by", m.isLikedBy)
43 m.g.Router.PUT("/api/likes", m.addLike)
44 m.g.Router.DELETE("/api/likes", m.removeLike)
45} 37}
46 38
47func (m *Module) Interface() interface{} { 39func (m *Module) Interface() interface{} {
@@ -76,148 +68,3 @@ func (m *Module) getLikeCount(w http.ResponseWriter, r *http.Request, p httprout
76 w.WriteHeader(200) 68 w.WriteHeader(200)
77 w.Write([]byte(fmt.Sprintf("%d", res))) 69 w.Write([]byte(fmt.Sprintf("%d", res)))
78} 70}
79func (m *Module) isLikedBy(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
80 params := r.URL.Query()
81
82 contentId, err := strconv.Atoi(params.Get("id"))
83 if err != nil {
84 http.Error(w, "invalid content id", http.StatusBadRequest)
85 return
86 }
87 contentType, err := strconv.Atoi(params.Get("type"))
88 if err != nil {
89 http.Error(w, "invalid content type", http.StatusBadRequest)
90 return
91 }
92 userId, err := strconv.Atoi(params.Get("user"))
93 if err != nil {
94 http.Error(w, "invalid user id", http.StatusBadRequest)
95 return
96 }
97
98 var res int
99 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 {
100 http.Error(w, "pq error", http.StatusInternalServerError)
101 log.Printf("error getting like by user: %s", err)
102 return
103 }
104
105 w.WriteHeader(200)
106 w.Write([]byte(fmt.Sprintf("%t", res > 0)))
107}
108func (m *Module) addLike(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
109 user, _ := m.g.Charakterin.GetUserFromRequest(r)
110
111 if user == nil {
112 http.Error(w, "403", http.StatusForbidden)
113 return
114 }
115
116 params, err := readBody(r)
117 if err != nil {
118 log.Println(err)
119 http.Error(w, "invalid body", http.StatusBadRequest)
120 return
121 }
122
123 contentId, err := strconv.Atoi(params.Get("id"))
124 if err != nil {
125 log.Println(err)
126 http.Error(w, "invalid content id", http.StatusBadRequest)
127 return
128 }
129 contentType, err := strconv.Atoi(params.Get("type"))
130 if err != nil {
131 log.Println(err)
132 http.Error(w, "invalid content type", http.StatusBadRequest)
133 return
134 }
135 userId, err := strconv.Atoi(params.Get("user"))
136 if err != nil {
137 http.Error(w, "invalid user id", http.StatusBadRequest)
138 return
139 }
140 if user.ID != userId {
141 http.Error(w, "403", http.StatusForbidden)
142 return
143 }
144
145 lists := m.lists.GetUserLists(user, false)
146 for _, list := range lists {
147 if list.Owner.ID == user.ID {
148 http.Error(w, "403", http.StatusForbidden)
149 return
150 }
151 }
152
153 _, 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)
154 if err != nil {
155 http.Error(w, "pq error", http.StatusInternalServerError)
156 log.Printf("error add like: %s", err)
157 return
158 }
159
160 w.WriteHeader(200)
161}
162
163func (m *Module) removeLike(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
164 user, _ := m.g.Charakterin.GetUserFromRequest(r)
165
166 if user == nil {
167 http.Error(w, "403", http.StatusForbidden)
168 return
169 }
170
171 params, err := readBody(r)
172 if err != nil {
173 log.Println(err)
174 http.Error(w, "invalid body", http.StatusBadRequest)
175 return
176 }
177
178 contentId, err := strconv.Atoi(params.Get("id"))
179 if err != nil {
180 log.Println(err)
181 http.Error(w, "invalid content id", http.StatusBadRequest)
182 return
183 }
184 contentType, err := strconv.Atoi(params.Get("type"))
185 if err != nil {
186 log.Println(err)
187 http.Error(w, "invalid content type", http.StatusBadRequest)
188 return
189 }
190 userId, err := strconv.Atoi(params.Get("user"))
191 if err != nil {
192 http.Error(w, "invalid user id", http.StatusBadRequest)
193 return
194 }
195 if user.ID != userId {
196 http.Error(w, "403", http.StatusForbidden)
197 return
198 }
199
200 _, err = m.g.DB.Exec(`DELETE FROM grilist.likes WHERE content = $1 AND "user" = $2 AND type = $3`, contentId, userId, contentType)
201 if err != nil {
202 http.Error(w, "pq error", http.StatusInternalServerError)
203 log.Printf("error add like: %s", err)
204 return
205 }
206
207 w.WriteHeader(200)
208}
209
210func readBody(r *http.Request) (url.Values, error) {
211 defer r.Body.Close()
212 data, err := ioutil.ReadAll(r.Body)
213 if err != nil {
214 return nil, err
215 }
216
217 values, err := url.ParseQuery(string(data))
218 if err != nil {
219 return nil, err
220 }
221
222 return values, nil
223}
diff --git a/views/includes/like.html b/views/includes/like.html
index 4399999..226aaff 100644
--- a/views/includes/like.html
+++ b/views/includes/like.html
@@ -1,5 +1,3 @@
1{{ define "like" }} 1{{ define "like" }}
2<div class="like-div btn purple lighten-4" {{ if .User }}update-with="{{ .User.ID }}"{{ end }} content-type={{ .ContentType }} content-id={{ .ContentID }}> 2<span class="like-count" content-type={{ .ContentType }} content-id={{ .ContentID }}></span> Likes
3 <span class="like-count"></span> <span class="like-caption">approven</span>
4</div>
5{{ end }} 3{{ end }}
diff --git a/views/pages/list.html b/views/pages/list.html
index 6d4d112..3c95548 100644
--- a/views/pages/list.html
+++ b/views/pages/list.html
@@ -35,11 +35,7 @@
35 </div> 35 </div>
36 </div>{{ end }} 36 </div>{{ end }}
37 <blockquote>{{ $list.Description }}</blockquote><br /> 37 <blockquote>{{ $list.Description }}</blockquote><br />
38 {{ if isSameUser $user $list.Owner }}
39 {{ template "like" (map "ContentType" 0 "ContentID" $list.ID) }} 38 {{ template "like" (map "ContentType" 0 "ContentID" $list.ID) }}
40 {{ else }}
41 {{ template "like" (map "ContentType" 0 "ContentID" $list.ID "User" $user) }}
42 {{ end }}
43 <div class="row"> 39 <div class="row">
44 <div class="col s12 {{ if ($user) and eq $user.ID $list.Owner.ID }}l8{{ end }}"> 40 <div class="col s12 {{ if ($user) and eq $user.ID $list.Owner.ID }}l8{{ end }}">
45 <ul id="gril-list" class="gril-list"> 41 <ul id="gril-list" class="gril-list">