273 lines
6.5 KiB
Go
273 lines
6.5 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"path/filepath"
|
|
"strconv"
|
|
"text/template"
|
|
|
|
"github.com/gin-contrib/multitemplate"
|
|
"github.com/gin-gonic/gin"
|
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
|
"github.com/spf13/viper"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
var baseHTML = filepath.Join("templates", "base.html")
|
|
var indexHTML = filepath.Join("templates", "index.html")
|
|
var newWatchHTML = filepath.Join("templates", "newWatch.html")
|
|
|
|
type Web struct {
|
|
//Bot *tgbotapi.BotAPI
|
|
db *gorm.DB
|
|
}
|
|
|
|
func (web Web) index(c *gin.Context) {
|
|
//msg := tgbotapi.NewMessage(viper.GetInt64("telegram.chat"), message)
|
|
//web.Bot.Send(msg)
|
|
watches := []Watch{}
|
|
web.db.Find(&watches)
|
|
c.HTML(http.StatusOK, "index", watches)
|
|
}
|
|
|
|
func (web Web) newWatch(c *gin.Context) {
|
|
c.HTML(http.StatusOK, "newWatch", gin.H{})
|
|
}
|
|
|
|
func (web Web) createWatch(c *gin.Context) {
|
|
var watch Watch
|
|
errMap, err := bindAndValidateWatch(&watch, c)
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "500", errMap)
|
|
return
|
|
}
|
|
web.db.Create(&watch)
|
|
c.Redirect(http.StatusSeeOther, fmt.Sprintf("/watch/view/%d", watch.ID))
|
|
}
|
|
|
|
func (web Web) deleteWatch(c *gin.Context) {
|
|
id, err := strconv.Atoi(c.PostForm("id"))
|
|
if err != nil {
|
|
c.Redirect(http.StatusSeeOther, "/watch/new")
|
|
return
|
|
}
|
|
|
|
web.db.Delete(&Watch{}, id)
|
|
c.Redirect(http.StatusSeeOther, "/")
|
|
}
|
|
|
|
type FilterDepth struct {
|
|
Filter Filter
|
|
Depth int
|
|
}
|
|
|
|
func (web Web) viewWatch(c *gin.Context) {
|
|
id := c.Param("id")
|
|
|
|
var watch Watch
|
|
web.db.Model(&Watch{}).First(&watch, id)
|
|
|
|
var filters []Filter
|
|
web.db.Model(&Filter{}).Find(&filters)
|
|
|
|
queuedFilters := []*Filter{}
|
|
filterMap := make(map[uint]*Filter)
|
|
for _, filter := range filters {
|
|
filterMap[filter.ID] = &filter
|
|
if filter.ParentID == nil {
|
|
queuedFilters = append(queuedFilters, &filter)
|
|
}
|
|
s, _ := json.MarshalIndent(filter, "", "\t")
|
|
fmt.Println(s)
|
|
}
|
|
|
|
for _, filter := range filterMap {
|
|
if filter.Parent != nil {
|
|
parent := filterMap[*filter.ParentID]
|
|
parent.Filters = append(parent.Filters, *filter)
|
|
}
|
|
}
|
|
|
|
nextFilters := []*Filter{}
|
|
bftFilters := []FilterDepth{}
|
|
depth := 0
|
|
for len(queuedFilters) > 0 {
|
|
for _, f1 := range queuedFilters {
|
|
bftFilters = append(bftFilters, FilterDepth{
|
|
Filter: *f1,
|
|
Depth: depth,
|
|
})
|
|
for _, f2 := range f1.Filters {
|
|
nextFilters = append(nextFilters, &f2)
|
|
}
|
|
}
|
|
log.Println(nextFilters)
|
|
queuedFilters = nextFilters
|
|
log.Println(queuedFilters)
|
|
nextFilters = []*Filter{}
|
|
log.Println(nextFilters)
|
|
depth += 1
|
|
}
|
|
|
|
c.HTML(http.StatusOK, "viewWatch", gin.H{
|
|
"Watch": watch,
|
|
"Filters": bftFilters,
|
|
"MaxDepth": depth,
|
|
})
|
|
}
|
|
|
|
func (web Web) createFilter(c *gin.Context) {
|
|
var filter Filter
|
|
errMap, err := bindAndValidateFilter(&filter, c)
|
|
if err != nil {
|
|
log.Print(err)
|
|
c.HTML(http.StatusBadRequest, "500", errMap)
|
|
return
|
|
}
|
|
web.db.Create(&filter)
|
|
c.Redirect(http.StatusSeeOther, "/group/edit")
|
|
}
|
|
|
|
func (web Web) updateFilter(c *gin.Context) {
|
|
var filterUpdate FilterUpdate
|
|
errMap, err := bindAndValidateFilterUpdate(&filterUpdate, c)
|
|
if err != nil {
|
|
log.Print(err)
|
|
c.HTML(http.StatusBadRequest, "500", errMap)
|
|
return
|
|
}
|
|
var filter Filter
|
|
web.db.First(&filter, filterUpdate.ID)
|
|
filter.Name = filterUpdate.Name
|
|
filter.Type = filterUpdate.Type
|
|
filter.Var1 = filterUpdate.From
|
|
filter.Var2 = &filterUpdate.To
|
|
web.db.Save(&filter)
|
|
c.Redirect(http.StatusSeeOther, "/group/edit/")
|
|
}
|
|
|
|
func (web Web) deleteFilter(c *gin.Context) {
|
|
id, err := strconv.Atoi(c.PostForm("filter_id"))
|
|
if err != nil {
|
|
c.Redirect(http.StatusSeeOther, "/watch/new")
|
|
return
|
|
}
|
|
|
|
group_id := c.PostForm("group_id")
|
|
web.db.Delete(&Filter{}, id)
|
|
c.Redirect(http.StatusSeeOther, "/group/edit/"+group_id)
|
|
}
|
|
|
|
func passiveBot(bot *tgbotapi.BotAPI) {
|
|
u := tgbotapi.NewUpdate(0)
|
|
u.Timeout = 60
|
|
updates := bot.GetUpdatesChan(u)
|
|
|
|
for update := range updates {
|
|
if update.Message != nil { // If we got a message
|
|
log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)
|
|
|
|
msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text)
|
|
msg.ReplyToMessageID = update.Message.MessageID
|
|
|
|
bot.Send(msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func render(w http.ResponseWriter, filename string, data interface{}) {
|
|
tmpl, err := template.ParseFiles(filename, baseHTML)
|
|
if err != nil {
|
|
log.Print(err)
|
|
http.Error(w, "Something went wrong", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err := tmpl.Execute(w, data); err != nil {
|
|
log.Print(err)
|
|
http.Error(w, "Something went wrong", http.StatusInternalServerError)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
viper.SetConfigName("config")
|
|
viper.SetConfigType("yaml")
|
|
viper.AddConfigPath(".")
|
|
viper.AutomaticEnv()
|
|
|
|
err := viper.ReadInConfig()
|
|
if err != nil {
|
|
log.Fatalln("Could not load config file")
|
|
}
|
|
|
|
db, _ := gorm.Open(sqlite.Open(viper.GetString("database.dsn")))
|
|
db.AutoMigrate(&Watch{}, &Filter{})
|
|
|
|
filters := []Filter{}
|
|
watch := Watch{
|
|
Name: "LG C2 42",
|
|
Interval: 60,
|
|
Filters: filters,
|
|
}
|
|
db.Create(&watch)
|
|
|
|
urlFilter := Filter{
|
|
WatchID: watch.ID,
|
|
ParentID: nil,
|
|
Parent: nil,
|
|
Name: "PriceWatch Fetch",
|
|
Type: "url",
|
|
Var1: "https://tweakers.net/pricewatch/1799060/lg-c2-42-inch-donkerzilveren-voet-zwart.html",
|
|
}
|
|
db.Create(&urlFilter)
|
|
|
|
xpathFilter := Filter{
|
|
WatchID: watch.ID,
|
|
Watch: watch,
|
|
ParentID: &urlFilter.ID,
|
|
Name: "price select",
|
|
Type: "xpath",
|
|
Var1: "//td[@class='shop-price']",
|
|
}
|
|
db.Create(&xpathFilter)
|
|
|
|
//bot, _ := tgbotapi.NewBotAPI(viper.GetString("telegram.token"))
|
|
|
|
//bot.Debug = true
|
|
|
|
//log.Printf("Authorized on account %s", bot.Self.UserName)
|
|
|
|
//go passiveBot(bot)
|
|
|
|
web := Web{
|
|
//bot,
|
|
db,
|
|
}
|
|
router := gin.Default()
|
|
|
|
router.Static("/static", "./static")
|
|
|
|
templates := multitemplate.NewRenderer()
|
|
templates.AddFromFiles("index", "templates/base.html", "templates/index.html")
|
|
templates.AddFromFiles("newWatch", "templates/base.html", "templates/newWatch.html")
|
|
templates.AddFromFiles("viewWatch", "templates/base.html", "templates/viewWatch.html")
|
|
templates.AddFromFiles("editGroup", "templates/base.html", "templates/editGroup.html")
|
|
|
|
templates.AddFromFiles("500", "templates/base.html", "templates/500.html")
|
|
router.HTMLRender = templates
|
|
|
|
router.GET("/", web.index)
|
|
router.GET("/watch/new", web.newWatch)
|
|
router.POST("/watch/create", web.createWatch)
|
|
router.POST("/watch/delete", web.deleteWatch)
|
|
router.GET("/watch/view/:id/", web.viewWatch)
|
|
router.POST("/filter/create/", web.createFilter)
|
|
router.POST("/filter/update/", web.updateFilter)
|
|
router.POST("/filter/delete/", web.deleteFilter)
|
|
|
|
router.Run("0.0.0.0:8080")
|
|
}
|