Skip to content

Commit

Permalink
update: finalize url action, add autotag feature
Browse files Browse the repository at this point in the history
  • Loading branch information
abhijit-hota committed May 14, 2022
1 parent 7144860 commit eed234a
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 77 deletions.
8 changes: 4 additions & 4 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ func main() {
configRouter.GET("", handlers.GetConfig)
configRouter.PATCH("/save-offline", handlers.ToggleSaveOffline)

autotagRouter := configRouter.Group("/autotag-rule")
urlActionRouter := configRouter.Group("/url-action")
{
autotagRouter.POST("", handlers.UpdateAutotagRules)
autotagRouter.PUT("", handlers.UpdateAutotagRules)
autotagRouter.DELETE("", handlers.UpdateAutotagRules)
urlActionRouter.POST("", handlers.UpdateURLActions)
urlActionRouter.PUT("", handlers.UpdateURLActions)
urlActionRouter.DELETE("", handlers.UpdateURLActions)
}
}
router.Run()
Expand Down
14 changes: 11 additions & 3 deletions api/bingo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
should_save_offline = false

[[autotag_rule]]
url_pattern = "https://news.ycombinator.com"
tags = [3, 4]
[[url_action]]
pattern = "https://news.ycombinator.com"
match_detection = "starts_with"
should_save_offline = true
tags = [3, 2]

[[url_action]]
pattern = "https://github.com"
match_detection = "starts_with"
should_save_offline = false
tags = [4, 5]
5 changes: 5 additions & 0 deletions api/common/save_page.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package common

func SavePage(url string) {

}
15 changes: 7 additions & 8 deletions api/db/bookmark.model.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@ type Meta struct {
}

type Bookmark struct {
ID int64 `json:"id"`
Meta Meta `json:"meta"`
URL string `json:"url" binding:"required"`
Created int64 `json:"created"`
LastUpdated int64 `json:"last_updated"`
Tags []string `json:"tags"`
ID int64 `json:"id"`
Meta Meta `json:"meta"`
URL string `json:"url" binding:"required"`
Created int64 `json:"created,omitempty"`
LastUpdated int64 `json:"last_updated,omitempty"`
}

type Tag struct {
ID int64 `json:"id"`
Name string `json:"name" form:"name" binding:"required"`
Created int64 `json:"created" form:"created"`
LastUpdated int64 `json:"last_updated" form:"last_updated"`
Created int64 `json:"created,omitempty" form:"created"`
LastUpdated int64 `json:"last_updated,omitempty" form:"last_updated"`
}
124 changes: 84 additions & 40 deletions api/handlers/bookmarks.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,64 @@ import (
"api/utils"
"fmt"
"net/http"
"strconv"
"strings"
"time"

"github.com/PuerkitoBio/purell"
"github.com/gin-gonic/gin"
)

type BookmarkReq struct {
DB.Bookmark
Tags []int `json:"tags"`
}
type BookmarkRes struct {
DB.Bookmark
Tags []DB.Tag `json:"tags"`
}

func AddBookmark(ctx *gin.Context) {
var body DB.Bookmark
var body BookmarkReq

db := DB.GetDB()

if err := ctx.BindJSON(&body); err != nil {
return
}

link, err := purell.NormalizeURLString(body.URL, purell.FlagsSafe)
body.URL = link
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
body.URL = link

tx, err := db.Begin()
utils.Must(err)

stmt := "SELECT COUNT(*) FROM links WHERE url = ?"
existingCheck := tx.QueryRow(stmt, body.URL)
var urlExists int
existingCheck.Scan(&urlExists)

if urlExists != 0 {
body.Tags = []int{}
tx.Commit()

ctx.JSON(http.StatusBadRequest, gin.H{"message": "URL_ALREADY_PRESENT"})
return
}

if err := common.GetMetadata(body.URL, &body.Meta); err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}

tx, err := db.Begin()
utils.Must(err)

stmt := "INSERT INTO meta (title, description, favicon) VALUES (?, ?, ?)"
info, err := tx.Exec(stmt, body.Meta.Title, body.Meta.Description, body.Meta.Favicon)
metaID, _ := info.LastInsertId()
// TODO: do this parallely? but what about meta id?
stmt = "INSERT INTO meta (title, description, favicon) VALUES (?, ?, ?)"
metaExecinfo, err := tx.Exec(stmt, body.Meta.Title, body.Meta.Description, body.Meta.Favicon)
metaID, _ := metaExecinfo.LastInsertId()

if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid URL."})
Expand All @@ -50,56 +75,63 @@ func AddBookmark(ctx *gin.Context) {
body.LastUpdated = now

stmt = "INSERT OR IGNORE INTO links (url, meta_id, created, last_updated) VALUES (?, ?, ?, ?)"
info, err = tx.Exec(stmt, body.URL, metaID, now, now)
linkInsertionInfo, err := tx.Exec(stmt, body.URL, metaID, now, now)
utils.Must(err)

num, _ := info.RowsAffected()
if num == 0 {
body.Tags = []string{}
tx.Exec("DELETE FROM meta WHERE id = ?", metaID)
tx.Commit()
urlActions := utils.GetConfig().URLActions

ctx.JSON(http.StatusBadRequest, gin.H{"message": "URL_ALREADY_PRESENT"})
return
shouldSaveOffline := utils.GetConfig().ShouldSaveOffline
for _, urlAction := range urlActions {
if urlAction.Match(body.URL) {
body.Tags = append(body.Tags, urlAction.Tags...)
shouldSaveOffline = urlAction.ShouldSaveOffline
}
}

if shouldSaveOffline {
go common.SavePage(body.URL)
}
fmt.Println(444, body.Tags)
if len(body.Tags) == 0 {
body.Tags = []string{}
body.Tags = []int{}
tx.Commit()

ctx.JSON(http.StatusOK, body)
return
}

linkID, _ := info.LastInsertId()

statement, err := tx.Prepare("INSERT OR IGNORE INTO tags (name, created, last_updated) VALUES (?, ?, ?)")
utils.Must(err)
defer statement.Close()

for _, tag := range body.Tags {
statement.Exec(tag, now, now)
}

query := fmt.Sprintf("SELECT id FROM tags WHERE name IN (%s)", strings.TrimRight(strings.Repeat("?,", len(body.Tags)), ","))
tagIDs, err := tx.Query(query, utils.ToGenericArray(body.Tags)...)
query := fmt.Sprintf(
"SELECT id, name FROM tags WHERE id IN (%s)",
strings.TrimRight(strings.Repeat("?,", len(body.Tags)), ","),
)
statement, _ := tx.Prepare(query)
tagIDs, err := statement.Query(utils.ToGenericArray(body.Tags)...)
defer tagIDs.Close()
utils.Must(err)

statement, err = tx.Prepare("INSERT INTO links_tags (tag_id, link_id) VALUES (?, ?)")
utils.Must(err)
defer statement.Close()

linkID, _ := linkInsertionInfo.LastInsertId()
body.ID = linkID

var res BookmarkRes
res.Bookmark = body.Bookmark

for tagIDs.Next() {
var tagID int
tagIDs.Scan(&tagID)
statement.Exec(tagID, linkID)
var tag DB.Tag
tagIDs.Scan(&tag.ID, &tag.Name)
_, err := statement.Exec(tag.ID, linkID)
utils.Must(err)

fmt.Printf("%+v\n", tag)
res.Tags = append(res.Tags, tag)
}
err = tagIDs.Err()
utils.Must(err)

tx.Commit()
ctx.JSON(http.StatusOK, body)
ctx.JSON(http.StatusOK, res)
}

const (
Expand Down Expand Up @@ -136,7 +168,9 @@ func GetBookmarks(ctx *gin.Context) {
return
}

dbQuery := `SELECT links.id, links.url, links.created, links.last_updated, GROUP_CONCAT(IFNULL(tags.name,"")), meta.title, meta.favicon, meta.description
dbQuery := `SELECT links.id, links.url, links.created, links.last_updated,
GROUP_CONCAT(IFNULL(tags.id,"") || "=" || IFNULL(tags.name,"")),
meta.title, meta.favicon, meta.description
FROM links
LEFT JOIN meta ON meta.id = links.meta_id
LEFT JOIN links_tags ON links_tags.link_id = links.id
Expand All @@ -161,9 +195,9 @@ func GetBookmarks(ctx *gin.Context) {
utils.Must(err)
defer rows.Close()

bookmarks := make([]DB.Bookmark, 0)
bookmarks := make([]BookmarkRes, 0)
for rows.Next() {
var bm DB.Bookmark
var bm BookmarkRes
var tagStr string
err = rows.Scan(
&bm.ID,
Expand All @@ -176,16 +210,26 @@ func GetBookmarks(ctx *gin.Context) {
&bm.Meta.Description,
)
utils.Must(err)
if tagStr == "" {
bm.Tags = []string{}
if tagStr == "=" {
bm.Tags = []DB.Tag{}
} else {
bm.Tags = strings.Split(tagStr, ",")
keyVals := strings.Split(tagStr, ",")
for _, keyval := range keyVals {
str := strings.Split(keyval, "=")
tagId, _ := strconv.Atoi(str[0])

var tag DB.Tag
tag.ID = int64(tagId)
tag.Name = str[1]
bm.Tags = append(bm.Tags, tag)
}
}

bookmarks = append(bookmarks, bm)
}
err = rows.Err()
utils.Must(err)

ctx.JSON(http.StatusOK, bookmarks)
}

Expand Down
29 changes: 19 additions & 10 deletions api/handlers/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package handlers

import (
"api/utils"
"fmt"
"net/http"

"github.com/gin-gonic/gin"
Expand All @@ -20,10 +21,10 @@ func ToggleSaveOffline(ctx *gin.Context) {
ctx.JSON(http.StatusOK, cfg)
}

func UpdateAutotagRules(ctx *gin.Context) {
var autotag utils.AutoTagRule
func UpdateURLActions(ctx *gin.Context) {
var urlAction utils.URLAction

if err := ctx.ShouldBindJSON(&autotag); err != nil {
if err := ctx.ShouldBindJSON(&urlAction); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
Expand All @@ -32,21 +33,29 @@ func UpdateAutotagRules(ctx *gin.Context) {

switch ctx.Request.Method {
case "POST":
cfg.AutoTagRules = append(cfg.AutoTagRules, autotag)
if urlAction.MatchDetection == "" {
urlAction.MatchDetection = "starts_with"
}
if len(urlAction.Tags) == 0 {
urlAction.Tags = []int{}
}
fmt.Printf("%+v\n", urlAction)
cfg.URLActions = append(cfg.URLActions, urlAction)
break
case "PUT":
for index, rule := range cfg.AutoTagRules {
if rule.Pattern == autotag.Pattern {
cfg.AutoTagRules[index] = autotag
// TODO: Shift to merging logic
for index, rule := range cfg.URLActions {
if rule.Pattern == urlAction.Pattern {
cfg.URLActions[index] = urlAction
break
}
}
ctx.JSON(http.StatusNotModified, gin.H{"message": "No change"})
return
case "DELETE":
for index, rule := range cfg.AutoTagRules {
if rule.Pattern == autotag.Pattern {
cfg.AutoTagRules = utils.RemoveIndex(cfg.AutoTagRules, index)
for index, rule := range cfg.URLActions {
if rule.Pattern == urlAction.Pattern {
cfg.URLActions = utils.RemoveIndex(cfg.URLActions, index)
}
}
ctx.JSON(http.StatusNotModified, gin.H{"message": "No change"})
Expand Down
16 changes: 9 additions & 7 deletions api/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@

## Todo

- [x] Update /add route to support title, meta data, etc, auto fill missing data[1]
- [x] Update /add route to support title, meta data
- [x] Auto fill missing data configuration
- [x] Add support for tags
- [x] LinkTree
11
- [x] Config routes
- [x] Get
- [x] Update
- [ ] Save offline config
- [ ] Auto tag
- [x] Save offline config
- [x] Auto tag
- Match detection: https://bitwarden.com/help/uri-match-detection/
- [ ] Bookmark routes
- [x] all
Expand All @@ -29,10 +29,12 @@
- [x] sort
- [x] date
- [x] alphabetic title
- [ ] update bookmark
- [ ] edit url (refetch all metadata?)
- [x] edit tags
- [x] delete bookmark (also remove it from all tags)
- [x] update bookmark tags
- [x] individual
- [ ] bulk
- [x] delete
- [x] individual
- [ ] bulk
- [x] Tag routes
- [x] C
- [x] R
Expand Down
Loading

0 comments on commit eed234a

Please sign in to comment.