Skip to content
Permalink
Browse files

while trying to apply our updateBackupData to the new checklist and c…

…heckitem stuff we had to make some changes in it.

also, started tracking the board id on each backup row.
  • Loading branch information...
fiatjaf committed Jul 15, 2018
1 parent fd30618 commit aba74f6d6d675d4a572d59ba6345b38c30fea493
Showing with 192 additions and 69 deletions.
  1. +94 −28 allowed.go
  2. +28 −22 helpers.go
  3. +24 −0 postgres.sql
  4. +7 −5 types.go
  5. +39 −14 unallowed.go
@@ -5,56 +5,126 @@ import (
"time"

"github.com/jmoiron/sqlx/types"
"github.com/kr/pretty"
"github.com/lib/pq"
"github.com/rs/zerolog"
)

func onAllowed(logger zerolog.Logger, trello trelloClient, wh Webhook) {
b := wh.Action.Data.Board.Id

switch wh.Action.Type {
case "createCard", "copyCard", "convertToCardFromCheckItem", "moveCardToBoard":
err = saveBackupData(wh.Action.Data.Card.Id, wh.Action.Data.Card)
// if a card is moved from another tracked board to this board
// this will give time to the other webhook to delete everything from the backups
// table so we can recreate everything here.
time.Sleep(time.Second * 2)

saveBackupData(b, wh.Action.Data.Card.Id, wh.Action.Data.Card)
case "deleteCard", "moveCardFromBoard":
err = deleteBackupData(wh.Action.Data.Card.Id)
// delete card, checklists and checkitems
var card Card
fetchBackupData(wh.Action.Data.Card.Id, &card)
for _, idChecklist := range card.IdChecklists {
var checklist Checklist
fetchBackupData(idChecklist, &checklist)
for _, idCheckItem := range checklist.IdCheckItems {
deleteBackupData(b, idCheckItem)
}
}
deleteBackupData(b, wh.Action.Data.Card.Id)
case "updateCard":
var cardValues types.JSONText
cardValues, err = toJSONText(wh.Action.Data.Card)
if err != nil {
break
}

err = saveBackupData(wh.Action.Data.Card.Id, cardValues)
err = saveBackupData(b, wh.Action.Data.Card.Id, cardValues)
case "addMemberToCard":
err = updateBackupData(wh.Action.Data.Card.Id, wh.Action.Data.Card,
`'{"idMembers": []}' || $init || data`,
`jsonb_set(new.data, '{idMembers}', (new.data->'idMembers') || $arg)`,
err = updateBackupData(b, wh.Action.Data.Card.Id, wh.Action.Data.Card,
`'{"idMembers": []}'::jsonb || $init || data`,
`jsonb_set(data, '{idMembers}', (data->'idMembers') || $arg)`,
wh.Action.Data.IdMember,
)
case "removeMemberFromCard":
err = updateBackupData(wh.Action.Data.Card.Id, wh.Action.Data.Card,
`'{"idMembers": []}' || $init || data`,
`jsonb_set(new.data, '{idMembers}', (new.data->'idMembers') - ($arg::jsonb#>>'{}'))`,
err = updateBackupData(b, wh.Action.Data.Card.Id, wh.Action.Data.Card,
`'{"idMembers": []}'::jsonb || $init || data`,
`jsonb_set(data, '{idMembers}', (data->'idMembers') - ($arg::jsonb#>>'{}'))`,
wh.Action.Data.IdMember,
)
case "addLabelToCard":
saveBackupData(wh.Action.Data.Label.Id, wh.Action.Data.Label)
go saveBackupData(b, wh.Action.Data.Label.Id, wh.Action.Data.Label)

err = updateBackupData(wh.Action.Data.Card.Id, wh.Action.Data.Card,
`'{"idLabels": []}' || $init || data`,
`jsonb_set(new.data, '{idLabels}', (new.data->'idLabels') || $arg)`,
err = updateBackupData(b, wh.Action.Data.Card.Id, wh.Action.Data.Card,
`'{"idLabels": []}'::jsonb || $init || data`,
`jsonb_set(data, '{idLabels}', (data->'idLabels') || $arg)`,
wh.Action.Data.Label.Id,
)
case "removeLabelFromCard":
saveBackupData(wh.Action.Data.Label.Id, wh.Action.Data.Label)
go saveBackupData(b, wh.Action.Data.Label.Id, wh.Action.Data.Label)

err = updateBackupData(wh.Action.Data.Card.Id, wh.Action.Data.Card,
`'{"idLabels": []}' || $init || data`,
`jsonb_set(new.data, '{idLabels}', (new.data->'idLabels') - ($arg::jsonb#>>'{}'))`,
err = updateBackupData(b, wh.Action.Data.Card.Id, wh.Action.Data.Card,
`'{"idLabels": []}'::jsonb || $init || data`,
`jsonb_set(data, '{idLabels}', (data->'idLabels') - ($arg::jsonb#>>'{}'))`,
wh.Action.Data.Label.Id,
)
case "createLabel", "updateLabel":
saveBackupData(wh.Action.Data.Label.Id, wh.Action.Data.Label)
err = saveBackupData(b, wh.Action.Data.Label.Id, wh.Action.Data.Label)
case "deleteLabel":
err = deleteBackupData(wh.Action.Data.Label.Id)
err = deleteBackupData(b, wh.Action.Data.Label.Id)
case "addChecklistToCard":
// create checklist on database
go saveBackupData(b, wh.Action.Data.Checklist.Id, wh.Action.Data.Checklist)

// update card
err = updateBackupData(b, wh.Action.Data.Card.Id, wh.Action.Data.Card,
`'{"idChecklists": []}'::jsonb || $init || data`,
`jsonb_set(data, '{idChecklists}', (data->'idChecklists') || $arg)`,
wh.Action.Data.Checklist.Id,
)
case "updateChecklist":
err = saveBackupData(b, wh.Action.Data.Checklist.Id, wh.Action.Data.Checklist)
case "removeChecklistFromCard":
// delete checkitems and checklist
var checklist Checklist
fetchBackupData(wh.Action.Data.Checklist.Id, &checklist)
for _, idCheckItem := range checklist.IdCheckItems {
err = deleteBackupData(b, idCheckItem)
if err != nil {
pretty.Log(err)
}
}
deleteBackupData(b, wh.Action.Data.Checklist.Id)

// update card
err = updateBackupData(b, wh.Action.Data.Card.Id, wh.Action.Data.Card,
`'{"idChecklists": []}'::jsonb || $init || data`,
`jsonb_set(data, '{idChecklists}', (data->'idChecklists') - ($arg::jsonb#>>'{}'))`,
wh.Action.Data.Checklist.Id,
)
case "createCheckItem":
// create checkitem on database
go saveBackupData(b, wh.Action.Data.CheckItem.Id, wh.Action.Data.CheckItem)

// update checklist
err = updateBackupData(b, wh.Action.Data.Checklist.Id, wh.Action.Data.Checklist,
`'{"idCheckItems": []}'::jsonb || $init || data`,
`jsonb_set(data, '{idCheckItems}', (data->'idCheckItems') || $arg)`,
wh.Action.Data.CheckItem.Id,
)
case "updateCheckItem", "updateCheckItemStateOnCard":
err = saveBackupData(b, wh.Action.Data.CheckItem.Id, wh.Action.Data.CheckItem)
case "deleteCheckItem":
// delete checkitem
deleteBackupData(b, wh.Action.Data.CheckItem.Id)

// update checklist
err = updateBackupData(b, wh.Action.Data.Checklist.Id, wh.Action.Data.Checklist,
`'{"idCheckItems": []}'::jsonb || $init || data`,
`jsonb_set(data, '{idCheckItems}', (data->'idCheckItems') - ($arg::jsonb#>>'{}'))`,
wh.Action.Data.CheckItem.Id,
)
case "addAttachmentToCard":
primary := Attachment{
Name: wh.Action.Data.Attachment.Name,
@@ -82,26 +152,22 @@ func onAllowed(logger zerolog.Logger, trello trelloClient, wh Webhook) {
primary.Id = wh.Action.Data.Attachment.Id

// save the primary as a backup to the secondary
saveBackupData(secondary.Id, primary)
saveBackupData(b, secondary.Id, primary)

// and vice-versa
saveBackupData(primary.Id, secondary)
saveBackupData(b, primary.Id, secondary)
}
} else {
// just save the primary data as a backup to itself
saveBackupData(wh.Action.Data.Attachment.Id, primary)
saveBackupData(b, wh.Action.Data.Attachment.Id, primary)
}
case "deleteAttachmentFromCard":
err = deleteBackupData(wh.Action.Data.Attachment.Id)
err = deleteBackupData(b, wh.Action.Data.Attachment.Id)
}

if err != nil {
if perr, ok := err.(*pq.Error); ok {
log.Print(perr.Where)
log.Print(perr.Position)
log.Print(perr.Hint)
log.Print(perr.Column)
log.Print(perr.Message)
pretty.Log(perr)
}

logger.Warn().
@@ -110,22 +110,22 @@ func toJSONText(data interface{}) (v types.JSONText, err error) {
return
}

func saveBackupData(id string, data interface{}) (err error) {
func saveBackupData(boardId, id string, data interface{}) (err error) {
v, err := toJSONText(data)
if err != nil {
return
}

_, err = pg.Exec(`
INSERT INTO backups VALUES ($1, $2)
ON CONFLICT (id) DO UPDATE SET data = backups.data || $2
`, id, v)
INSERT INTO backups (id, board, data) VALUES ($1, $2, $3)
ON CONFLICT (id) DO UPDATE SET board = $2, data = backups.data || $3
`, id, boardId, v)
return
}

func updateBackupData(
id string, initData interface{},
preupdate, updatefun string, value interface{},
boardId, id string, initData interface{},
initialize, updatefun string, value interface{},
) (err error) {
d, err := toJSONText(initData)
if err != nil {
@@ -138,27 +138,33 @@ func updateBackupData(
}

updatefun = strings.Replace(
strings.Replace(updatefun, "$init", "$2", -1),
"$arg", "$3", -1)
strings.Replace(updatefun, "$init", "$3", -1),
"$arg", "$4", -1)

preupdate = strings.Replace(
strings.Replace(preupdate, "$init", "$2", -1),
"$arg", "$3", -1)
initialize = strings.Replace(
strings.Replace(initialize, "$init", "$3", -1),
"$arg", "$4", -1)

_, err = pg.Exec(`
WITH
ins AS (
INSERT INTO backups VALUES ($1, $2)
ON CONFLICT (id) DO NOTHING
init AS (
SELECT (`+initialize+`) AS data
FROM (
SELECT 0 AS idx, data FROM backups WHERE id = $1
UNION ALL
SELECT 1 AS idx, '{}'::jsonb AS data
) AS whatever
ORDER BY idx LIMIT 1
),
new AS (
SELECT (`+preupdate+`) AS data
FROM backups WHERE id = $1
SELECT (`+updatefun+`) AS data
FROM init
)
UPDATE backups SET data = `+updatefun+`
FROM new
WHERE id = $1
`, id, d, v)
INSERT INTO backups (id, board, data) VALUES ($1, $2, (SELECT data FROM new))
ON CONFLICT (id) DO UPDATE
SET data = (SELECT data FROM new),
board = $2
`, id, boardId, d, v)
return
}

@@ -176,7 +182,7 @@ func fetchBackupData(id string, data interface{}) (err error) {
return
}

func deleteBackupData(id string) (err error) {
_, err = pg.Exec(`DELETE FROM backups WHERE id = $1`, id)
func deleteBackupData(boardId, id string) (err error) {
_, err = pg.Exec(`DELETE FROM backups WHERE id = $1 AND board = $2`, id, boardId)
return
}
@@ -8,10 +8,34 @@ CREATE TABLE boards (

CREATE TABLE backups (
id text PRIMARY KEY,
board text,
data jsonb NOT NULL,

CHECK (id != '')
);

table boards;
table backups;
delete from backups;

WITH
init AS (
SELECT ('{"id":"5b4a910f0aa8cfb949529fb9","name":"Checklist"}' || '{"idCheckItems": []}'::jsonb || data) AS data
FROM (
SELECT 0 AS idx, data FROM backups WHERE id = '5b4a910f0aa8cfb949529fb9'
UNION ALL
SELECT 1 AS idx, '{}'::jsonb
) AS whatever
ORDER BY idx LIMIT 1
),
new AS (
SELECT jsonb_set(
data,
'{idCheckItems}',
data->'idCheckItems' || '"5b4a9232a495da35ccca80ea"'
) AS data
FROM init
)
INSERT INTO backups (id, board, data) VALUES ('5b4a910f0aa8cfb949529fb9', '5b1980e92c9e71f5e06ad718', (SELECT data FROM new))
ON CONFLICT (id) DO UPDATE
SET data = (SELECT data FROM new);
@@ -33,6 +33,8 @@ type Label struct {
type Card struct {
Id string `json:"id,omitempty"`
ShortLink string `json:"shortLink,omitempty"`
IdBoard string `json:"idBoard,omitempty"`
IdList string `json:"idList,omitempty"`
Name string `json:"name,omitempty"`
Desc string `json:"desc,omitempty"`
Due string `json:"due,omitempty"`
@@ -41,17 +43,17 @@ type Card struct {
IdAttachmentCover string `json:"idAttachmentCover,omitempty"`
IdMembers []string `json:"idMembers,omitempty"`
IdLabels []string `json:"idLabels,omitempty"`
IdChecklists []string `json:"idChecklists,omitempty"`
Checklists []Checklist `json:"checklists,omitempty"`
Attachments []Attachment `json:"attachments,omitempty"`
IdBoard string `json:"idBoard,omitempty"`
IdList string `json:"idList,omitempty"`
CustomFieldItems []CustomFieldItem `json:"customFieldItems,omitempty"`
}

type Checklist struct {
Id string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
CheckItems []CheckItem `json:"checkItems,omitempty"`
Id string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
CheckItems []CheckItem `json:"checkItems,omitempty"`
IdCheckItems []string `json:"idCheckItems,omitempty"`
}

type CheckItem struct {

0 comments on commit aba74f6

Please sign in to comment.
You can’t perform that action at this time.