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" "github.com/julienschmidt/httprouter" ) type Module struct { g *grilist.Grilist c *cache.Cache lists *lists.Module } func New() *Module { return &Module{} } func (m *Module) Name() string { return "Likes" } func (m *Module) Init(g *grilist.Grilist) { m.g = g gm, ok := g.Modules["Lists"] if !ok { 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{} { return m } func (m *Module) ProvideDashboardData(user *charakterin.User) []grilist.DashboardCategory { return make([]grilist.DashboardCategory, 0) } func (m *Module) getLikeCount(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 id", http.StatusBadRequest) return } var res int if err := m.g.DB.QueryRow(`SELECT COUNT(*) FROM grilist.likes WHERE content = $1 AND type = $2`, contentId, contentType).Scan(&res); err != nil { http.Error(w, "pq error", http.StatusInternalServerError) log.Printf("error getting like count: %s", err) return } 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) { user, _ := m.g.Charakterin.GetUserFromRequest(r) if user == nil { http.Error(w, "403", http.StatusForbidden) return } 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 } if user.ID != userId { http.Error(w, "403", http.StatusForbidden) return } lists := m.lists.GetUserLists(user, false) for _, list := range lists { if list.Owner.ID == user.ID { http.Error(w, "403", http.StatusForbidden) 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) { user, _ := m.g.Charakterin.GetUserFromRequest(r) if user == nil { http.Error(w, "403", http.StatusForbidden) return } 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 } if user.ID != userId { http.Error(w, "403", http.StatusForbidden) 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 }