mirror of
https://github.com/dnote/dnote
synced 2026-03-14 14:35:50 +01:00
Use actions package and add view command (#95)
* Use actions package * Add view command * Upgrade dependencies * Bump * Check update less frequently * Simplify doc
This commit is contained in:
parent
3148d3705b
commit
50cfd9923d
22 changed files with 720 additions and 246 deletions
107
COMMANDS.md
107
COMMANDS.md
|
|
@ -1,13 +1,12 @@
|
|||
# Commands
|
||||
|
||||
* [add](#dnote-add)
|
||||
* [edit](#dnote-edit)
|
||||
* [remove](#dnote-remove)
|
||||
* [ls](#dnote-ls)
|
||||
* [cat](#dnote-cat)
|
||||
* [upgrade](#dnote-upgrade)
|
||||
* [login](#dnote-login)
|
||||
* [sync](#dnote-sync)
|
||||
- [add](#dnote-add)
|
||||
- [view](#dnote-view)
|
||||
- [edit](#dnote-edit)
|
||||
- [remove](#dnote-remove)
|
||||
- [upgrade](#dnote-upgrade)
|
||||
- [login](#dnote-login)
|
||||
- [sync](#dnote-sync)
|
||||
|
||||
## dnote add
|
||||
|
||||
|
|
@ -15,17 +14,31 @@ _alias: a, n, new_
|
|||
|
||||
Add a new note to a book.
|
||||
|
||||
### `dnote add [book name]`
|
||||
```bash
|
||||
# Launch a text editor to add a new note to the specified book.
|
||||
$ dnote add linux
|
||||
|
||||
Launch a text editor to add a new note to the specified book.
|
||||
# Write a new note with a content to the specified book.
|
||||
$ dnote add linux -c "find - recursively walk the directory"
|
||||
```
|
||||
|
||||
### `dnote add [book name] -c "[content]"`
|
||||
## dnote view
|
||||
|
||||
Write a new note with a content to the specified book.
|
||||
_alias: v_
|
||||
|
||||
e.g.
|
||||
- List books or notes.
|
||||
- View a note detail.
|
||||
|
||||
$ dnote add linux -c "find - recursively walk the directory"
|
||||
```bash
|
||||
# List all books.
|
||||
$ dnote view
|
||||
|
||||
# List all notes in a book.
|
||||
$ dnote view golang
|
||||
|
||||
# See details of a note
|
||||
$ dnote view golang 12
|
||||
```
|
||||
|
||||
## dnote edit
|
||||
|
||||
|
|
@ -33,17 +46,13 @@ _alias: e_
|
|||
|
||||
Edit a note
|
||||
|
||||
### `dnote edit [book name] [note index]`
|
||||
```bash
|
||||
# Launch a text editor to edit a note with the given index.
|
||||
$ dnote edit linux 1
|
||||
|
||||
Launch a text editor to edit a note with the given index.
|
||||
|
||||
### `dnote edit [book name] [note index] -c "[note content]"`
|
||||
|
||||
Edit a note with the given index in the specified book with a content.
|
||||
|
||||
e.g
|
||||
|
||||
$ dnote edit linux 1 "New Content"
|
||||
# Edit a note with the given index in the specified book with a content.
|
||||
$ dnote edit linux 1 "New Content"
|
||||
```
|
||||
|
||||
## dnote remove
|
||||
|
||||
|
|
@ -51,49 +60,13 @@ _alias: d_
|
|||
|
||||
Remove either a note or a book
|
||||
|
||||
### `dnote remove [book name] [index]`
|
||||
```bash
|
||||
# Remove the note with `index` in the specified book.
|
||||
$ dnote remove JS 1
|
||||
|
||||
Removes the note with `index` in the specified book.
|
||||
|
||||
### `dnote remove -b [book name]`
|
||||
|
||||
Removes the book with the `book name`.
|
||||
|
||||
e.g
|
||||
|
||||
$ dnote remove JS 1
|
||||
$ dnote remove -b JS
|
||||
|
||||
## dnote ls
|
||||
|
||||
_alias: l, notes_
|
||||
|
||||
List books or notes
|
||||
|
||||
### `dnote ls`
|
||||
|
||||
List all books.
|
||||
|
||||
### `dnote ls [book name]`
|
||||
|
||||
List all notes in the book.
|
||||
|
||||
e.g
|
||||
|
||||
$ dnote ls
|
||||
$ dnote ls golang
|
||||
|
||||
## dnote cat
|
||||
|
||||
_alias: c_
|
||||
|
||||
See details of a note
|
||||
|
||||
### `dnote cat [book name] [note index]`
|
||||
|
||||
e.g
|
||||
|
||||
$ dnote cat golang 12
|
||||
# Remove the book with the `book name`.
|
||||
$ dnote remove -b JS
|
||||
```
|
||||
|
||||
## dnote upgrade
|
||||
|
||||
|
|
@ -103,6 +76,8 @@ Upgrade the Dnote if newer release is available
|
|||
|
||||
_Dnote Cloud only_
|
||||
|
||||
_alias: s_
|
||||
|
||||
Sync notes with Dnote cloud
|
||||
|
||||
## dnote login
|
||||
|
|
|
|||
60
Gopkg.lock
generated
60
Gopkg.lock
generated
|
|
@ -2,80 +2,120 @@
|
|||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:97242fd82dcd5574a59c31685652a4de519934674a9fa21159604fdd5a005e7c"
|
||||
name = "github.com/dnote/actions"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "e646839669907194077733897c26ce2bb9856896"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e988ed0ca0d81f4d28772760c02ee95084961311291bdfefc1b04617c178b722"
|
||||
name = "github.com/fatih/color"
|
||||
packages = ["."]
|
||||
revision = "507f6050b8568533fb3f5504de8e5205fa62a114"
|
||||
version = "v1.6.0"
|
||||
pruneopts = ""
|
||||
revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9f100ae40cada79ca20c068dc8510ad2d8decc49d84f27f9a45892cef3504557"
|
||||
name = "github.com/google/go-github"
|
||||
packages = ["github"]
|
||||
revision = "0c3b302de2a6de84a2511db47ea1bb2ff8146830"
|
||||
pruneopts = ""
|
||||
revision = "d7732128a00e8e95e8fe896017da18ee20b2180d"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9abc49f39e3e23e262594bb4fb70abf74c0c99e94f99153f43b143805e850719"
|
||||
name = "github.com/google/go-querystring"
|
||||
packages = ["query"]
|
||||
pruneopts = ""
|
||||
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9ea83adf8e96d6304f394d40436f2eb44c1dc3250d223b74088cc253a6cd0a1c"
|
||||
name = "github.com/mattn/go-colorable"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||
version = "v0.0.9"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:78229b46ddb7434f881390029bd1af7661294af31f6802e0e1bedaad4ab0af3c"
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7365acd48986e205ccb8652cc746f09c8b7876030d53710ea6ef7d0bd0dcd7ca"
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6b55df4b0517a459af9d3879c99330af4367adcf45f3d0d37ded80a6272ae057"
|
||||
name = "github.com/satori/go.uuid"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "879c5887cd475cd7864858769793b2ceb0d44feb"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a1403cc8a94b8d7956ee5e9694badef0e7b051af289caad1cf668331e3ffa4f6"
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = ["."]
|
||||
revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b"
|
||||
version = "v0.0.1"
|
||||
pruneopts = ""
|
||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0a52bcb568386d98f4894575d53ce3e456f56471de6897bb8b9de13c33d9340e"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
|
||||
version = "v1.0.0"
|
||||
pruneopts = ""
|
||||
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:7a5f7a1206de6b90f67cb465e489eac3298e95afa7262813b542df4fab38952f"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
|
||||
pruneopts = ""
|
||||
revision = "4910a1d54f876d7b22162a85f4d066d3ee649450"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "287cf08546ab5e7e37d55a84f7ed3fd1db036de5"
|
||||
pruneopts = ""
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "78f6d9536359b04aae8697ac22a2f0284223dea0c28a3c5287122dca041e0ef6"
|
||||
input-imports = [
|
||||
"github.com/dnote/actions",
|
||||
"github.com/fatih/color",
|
||||
"github.com/google/go-github/github",
|
||||
"github.com/pkg/errors",
|
||||
"github.com/satori/go.uuid",
|
||||
"github.com/spf13/cobra",
|
||||
"gopkg.in/yaml.v2",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
|
|||
12
README.md
12
README.md
|
|
@ -20,8 +20,8 @@ On Windows, download [binary](https://github.com/dnote/cli/releases).
|
|||
|
||||
Write technical notes without getting distracted from programming. The reasons are:
|
||||
|
||||
* We forget exponentially unless we write down what we learn and come back.
|
||||
* Ideas cannot be grokked unless we can put them down in clear words.
|
||||
- We forget exponentially unless we write down what we learn and come back.
|
||||
- Ideas cannot be grokked unless we can put them down in clear words.
|
||||
|
||||
## Examples
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ $ dnote add linux -c "find - recursively walk the directory"
|
|||
- See the notes in a book
|
||||
|
||||
```
|
||||
$ dnote ls linux
|
||||
$ dnote view linux
|
||||
• on book linux
|
||||
(0) find - recursively walk the directory
|
||||
```
|
||||
|
|
@ -45,9 +45,9 @@ Please refer to [commands](/COMMANDS.md).
|
|||
|
||||
## Links
|
||||
|
||||
* [Dnote](https://dnote.io)
|
||||
* [Dnote Cloud](https://dnote.io/cloud)
|
||||
* [Browser Extension](https://github.com/dnote/browser-extension)
|
||||
- [Dnote](https://dnote.io)
|
||||
- [Dnote Cloud](https://dnote.io/cloud)
|
||||
- [Browser Extension](https://github.com/dnote/browser-extension)
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@ var example = `
|
|||
dnote cat javascript 2
|
||||
`
|
||||
|
||||
var deprecationWarning = `and "view" will replace it in v0.5.0.
|
||||
|
||||
Run "dnote view --help" for more information.
|
||||
`
|
||||
|
||||
func preRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 2 {
|
||||
return errors.New("Incorrect number of arguments")
|
||||
|
|
@ -27,18 +32,19 @@ func preRun(cmd *cobra.Command, args []string) error {
|
|||
|
||||
func NewCmd(ctx infra.DnoteCtx) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "cat <book name> <note index>",
|
||||
Aliases: []string{"c"},
|
||||
Short: "See a note",
|
||||
Example: example,
|
||||
RunE: newRun(ctx),
|
||||
PreRunE: preRun,
|
||||
Use: "cat <book name> <note index>",
|
||||
Aliases: []string{"c"},
|
||||
Short: "See a note",
|
||||
Example: example,
|
||||
RunE: NewRun(ctx),
|
||||
PreRunE: preRun,
|
||||
Deprecated: deprecationWarning,
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newRun(ctx infra.DnoteCtx) core.RunEFunc {
|
||||
func NewRun(ctx infra.DnoteCtx) core.RunEFunc {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
dnote, err := core.GetDnote(ctx)
|
||||
if err != nil {
|
||||
|
|
|
|||
20
cmd/ls/ls.go
20
cmd/ls/ls.go
|
|
@ -20,6 +20,11 @@ var example = `
|
|||
dnote ls javascript
|
||||
`
|
||||
|
||||
var deprecationWarning = `and "view" will replace it in v0.5.0.
|
||||
|
||||
Run "dnote view --help" for more information.
|
||||
`
|
||||
|
||||
func preRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) > 1 {
|
||||
return errors.New("Incorrect number of argument")
|
||||
|
|
@ -30,18 +35,19 @@ func preRun(cmd *cobra.Command, args []string) error {
|
|||
|
||||
func NewCmd(ctx infra.DnoteCtx) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "ls <book name?>",
|
||||
Aliases: []string{"l", "notes"},
|
||||
Short: "List all notes",
|
||||
Example: example,
|
||||
RunE: newRun(ctx),
|
||||
PreRunE: preRun,
|
||||
Use: "ls <book name?>",
|
||||
Aliases: []string{"l", "notes"},
|
||||
Short: "List all notes",
|
||||
Example: example,
|
||||
RunE: NewRun(ctx),
|
||||
PreRunE: preRun,
|
||||
Deprecated: deprecationWarning,
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newRun(ctx infra.DnoteCtx) core.RunEFunc {
|
||||
func NewRun(ctx infra.DnoteCtx) core.RunEFunc {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
dnote, err := core.GetDnote(ctx)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/dnote/actions"
|
||||
"github.com/dnote/cli/core"
|
||||
"github.com/dnote/cli/infra"
|
||||
"github.com/dnote/cli/log"
|
||||
|
|
@ -32,8 +33,8 @@ func NewCmd(ctx infra.DnoteCtx) *cobra.Command {
|
|||
}
|
||||
|
||||
type responseData struct {
|
||||
Actions []core.Action `json:"actions"`
|
||||
Bookmark int `json:"bookmark"`
|
||||
Actions []actions.Action `json:"actions"`
|
||||
Bookmark int `json:"bookmark"`
|
||||
}
|
||||
|
||||
type syncPayload struct {
|
||||
|
|
@ -120,7 +121,7 @@ func newRun(ctx infra.DnoteCtx) core.RunEFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func getPayload(actions []core.Action, timestamp infra.Timestamp) (*bytes.Buffer, error) {
|
||||
func getPayload(actions []actions.Action, timestamp infra.Timestamp) (*bytes.Buffer, error) {
|
||||
compressedActions, err := compressActions(actions)
|
||||
if err != nil {
|
||||
return &bytes.Buffer{}, errors.Wrap(err, "Failed to compress actions")
|
||||
|
|
@ -140,7 +141,7 @@ func getPayload(actions []core.Action, timestamp infra.Timestamp) (*bytes.Buffer
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func compressActions(actions []core.Action) ([]byte, error) {
|
||||
func compressActions(actions []actions.Action) ([]byte, error) {
|
||||
b, err := json.Marshal(&actions)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshal actions into JSON")
|
||||
|
|
|
|||
59
cmd/view/view.go
Normal file
59
cmd/view/view.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package view
|
||||
|
||||
import (
|
||||
"github.com/dnote/cli/core"
|
||||
"github.com/dnote/cli/infra"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/dnote/cli/cmd/cat"
|
||||
"github.com/dnote/cli/cmd/ls"
|
||||
)
|
||||
|
||||
var example = `
|
||||
* View all books
|
||||
dnote view
|
||||
|
||||
* List notes in a book
|
||||
dnote view javascript
|
||||
|
||||
* View a particular note in a book
|
||||
dnote view javascript 0
|
||||
`
|
||||
|
||||
func preRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) > 2 {
|
||||
return errors.New("Incorrect number of argument")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewCmd(ctx infra.DnoteCtx) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "view <book name?> <note index?>",
|
||||
Aliases: []string{"v"},
|
||||
Short: "List books, notes or view a content",
|
||||
Example: example,
|
||||
RunE: newRun(ctx),
|
||||
PreRunE: preRun,
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newRun(ctx infra.DnoteCtx) core.RunEFunc {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
var run core.RunEFunc
|
||||
|
||||
if len(args) <= 1 {
|
||||
run = ls.NewRun(ctx)
|
||||
} else if len(args) == 2 {
|
||||
run = cat.NewRun(ctx)
|
||||
} else {
|
||||
return errors.New("Incorrect number of arguments")
|
||||
}
|
||||
|
||||
return run(cmd, args)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,54 +4,41 @@ import (
|
|||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/dnote/actions"
|
||||
"github.com/dnote/cli/infra"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
var (
|
||||
ActionAddNote = "add_note"
|
||||
ActionRemoveNote = "remove_note"
|
||||
ActionEditNote = "edit_note"
|
||||
ActionAddBook = "add_book"
|
||||
ActionRemoveBook = "remove_book"
|
||||
)
|
||||
|
||||
type Action struct {
|
||||
UUID string `json:"uuid"`
|
||||
Schema int `json:"schema"`
|
||||
Type string `json:"type"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
func LogActionAddNote(ctx infra.DnoteCtx, noteUUID, bookName, content string, timestamp int64) error {
|
||||
b, err := json.Marshal(AddNoteData{
|
||||
b, err := json.Marshal(actions.AddNoteDataV2{
|
||||
NoteUUID: noteUUID,
|
||||
BookName: bookName,
|
||||
Content: content,
|
||||
// TODO: support adding a public note
|
||||
Public: false,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to marshal data into JSON")
|
||||
}
|
||||
|
||||
action := Action{
|
||||
action := actions.Action{
|
||||
UUID: uuid.NewV4().String(),
|
||||
Schema: 1,
|
||||
Type: ActionAddNote,
|
||||
Schema: 2,
|
||||
Type: actions.ActionAddNote,
|
||||
Data: b,
|
||||
Timestamp: timestamp,
|
||||
}
|
||||
|
||||
if err := LogAction(ctx, action); err != nil {
|
||||
return errors.Wrapf(err, "Failed to log action type %s", ActionAddNote)
|
||||
return errors.Wrapf(err, "Failed to log action type %s", actions.ActionAddNote)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LogActionRemoveNote(ctx infra.DnoteCtx, noteUUID, bookName string) error {
|
||||
b, err := json.Marshal(RemoveNoteData{
|
||||
b, err := json.Marshal(actions.RemoveNoteDataV1{
|
||||
NoteUUID: noteUUID,
|
||||
BookName: bookName,
|
||||
})
|
||||
|
|
@ -59,23 +46,23 @@ func LogActionRemoveNote(ctx infra.DnoteCtx, noteUUID, bookName string) error {
|
|||
return errors.Wrap(err, "Failed to marshal data into JSON")
|
||||
}
|
||||
|
||||
action := Action{
|
||||
action := actions.Action{
|
||||
UUID: uuid.NewV4().String(),
|
||||
Schema: 1,
|
||||
Type: ActionRemoveNote,
|
||||
Type: actions.ActionRemoveNote,
|
||||
Data: b,
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
|
||||
if err := LogAction(ctx, action); err != nil {
|
||||
return errors.Wrapf(err, "Failed to log action type %s", ActionRemoveNote)
|
||||
return errors.Wrapf(err, "Failed to log action type %s", actions.ActionRemoveNote)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LogActionEditNote(ctx infra.DnoteCtx, noteUUID, bookName, content string, ts int64) error {
|
||||
b, err := json.Marshal(EditNoteData{
|
||||
b, err := json.Marshal(actions.EditNoteDataV1{
|
||||
NoteUUID: noteUUID,
|
||||
FromBook: bookName,
|
||||
Content: content,
|
||||
|
|
@ -84,60 +71,60 @@ func LogActionEditNote(ctx infra.DnoteCtx, noteUUID, bookName, content string, t
|
|||
return errors.Wrap(err, "Failed to marshal data into JSON")
|
||||
}
|
||||
|
||||
action := Action{
|
||||
action := actions.Action{
|
||||
UUID: uuid.NewV4().String(),
|
||||
Schema: 1,
|
||||
Type: ActionEditNote,
|
||||
Schema: 2,
|
||||
Type: actions.ActionEditNote,
|
||||
Data: b,
|
||||
Timestamp: ts,
|
||||
}
|
||||
|
||||
if err := LogAction(ctx, action); err != nil {
|
||||
return errors.Wrapf(err, "Failed to log action type %s", ActionEditNote)
|
||||
return errors.Wrapf(err, "Failed to log action type %s", actions.ActionEditNote)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LogActionAddBook(ctx infra.DnoteCtx, name string) error {
|
||||
b, err := json.Marshal(AddBookData{
|
||||
b, err := json.Marshal(actions.AddBookDataV1{
|
||||
BookName: name,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to marshal data into JSON")
|
||||
}
|
||||
|
||||
action := Action{
|
||||
action := actions.Action{
|
||||
UUID: uuid.NewV4().String(),
|
||||
Schema: 1,
|
||||
Type: ActionAddBook,
|
||||
Type: actions.ActionAddBook,
|
||||
Data: b,
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
|
||||
if err := LogAction(ctx, action); err != nil {
|
||||
return errors.Wrapf(err, "Failed to log action type %s", ActionAddBook)
|
||||
return errors.Wrapf(err, "Failed to log action type %s", actions.ActionAddBook)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LogActionRemoveBook(ctx infra.DnoteCtx, name string) error {
|
||||
b, err := json.Marshal(RemoveBookData{BookName: name})
|
||||
b, err := json.Marshal(actions.RemoveBookDataV1{BookName: name})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to marshal data into JSON")
|
||||
}
|
||||
|
||||
action := Action{
|
||||
action := actions.Action{
|
||||
UUID: uuid.NewV4().String(),
|
||||
Schema: 1,
|
||||
Type: ActionRemoveBook,
|
||||
Type: actions.ActionRemoveBook,
|
||||
Data: b,
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
|
||||
if err := LogAction(ctx, action); err != nil {
|
||||
return errors.Wrapf(err, "Failed to log action type %s", ActionRemoveBook)
|
||||
return errors.Wrapf(err, "Failed to log action type %s", actions.ActionRemoveBook)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
17
core/core.go
17
core/core.go
|
|
@ -9,6 +9,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dnote/actions"
|
||||
"github.com/dnote/cli/infra"
|
||||
"github.com/dnote/cli/utils"
|
||||
"github.com/pkg/errors"
|
||||
|
|
@ -18,7 +19,7 @@ import (
|
|||
|
||||
const (
|
||||
// Version is the current version of dnote
|
||||
Version = "0.3.1"
|
||||
Version = "0.4.0"
|
||||
|
||||
// TimestampFilename is the name of the file containing upgrade info
|
||||
TimestampFilename = "timestamps"
|
||||
|
|
@ -67,7 +68,7 @@ func InitActionFile(ctx infra.DnoteCtx) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
b, err := json.Marshal(&[]Action{})
|
||||
b, err := json.Marshal(&[]actions.Action{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to get initial action content")
|
||||
}
|
||||
|
|
@ -277,7 +278,7 @@ func WriteConfig(ctx infra.DnoteCtx, config infra.Config) error {
|
|||
|
||||
// LogAction appends the action to the action log and updates the last_action
|
||||
// timestamp
|
||||
func LogAction(ctx infra.DnoteCtx, action Action) error {
|
||||
func LogAction(ctx infra.DnoteCtx, action actions.Action) error {
|
||||
actions, err := ReadActionLog(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to read the action log")
|
||||
|
|
@ -298,10 +299,10 @@ func LogAction(ctx infra.DnoteCtx, action Action) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func WriteActionLog(ctx infra.DnoteCtx, actions []Action) error {
|
||||
func WriteActionLog(ctx infra.DnoteCtx, ats []actions.Action) error {
|
||||
path := GetActionPath(ctx)
|
||||
|
||||
d, err := json.Marshal(actions)
|
||||
d, err := json.Marshal(ats)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to marshal newly generated actions to JSON")
|
||||
}
|
||||
|
|
@ -315,7 +316,7 @@ func WriteActionLog(ctx infra.DnoteCtx, actions []Action) error {
|
|||
}
|
||||
|
||||
func ClearActionLog(ctx infra.DnoteCtx) error {
|
||||
var content []Action
|
||||
var content []actions.Action
|
||||
|
||||
if err := WriteActionLog(ctx, content); err != nil {
|
||||
return errors.Wrap(err, "Failed to write action log")
|
||||
|
|
@ -336,8 +337,8 @@ func ReadActionLogContent(ctx infra.DnoteCtx) ([]byte, error) {
|
|||
}
|
||||
|
||||
// ReadActionLog returns the action log content
|
||||
func ReadActionLog(ctx infra.DnoteCtx) ([]Action, error) {
|
||||
var ret []Action
|
||||
func ReadActionLog(ctx infra.DnoteCtx) ([]actions.Action, error) {
|
||||
var ret []actions.Action
|
||||
|
||||
b, err := ReadActionLogContent(ctx)
|
||||
if err != nil {
|
||||
|
|
|
|||
145
core/reducer.go
145
core/reducer.go
|
|
@ -4,39 +4,14 @@ import (
|
|||
"encoding/json"
|
||||
"sort"
|
||||
|
||||
"github.com/dnote/actions"
|
||||
"github.com/dnote/cli/infra"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type AddNoteData struct {
|
||||
NoteUUID string `json:"note_uuid"`
|
||||
BookName string `json:"book_name"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type EditNoteData struct {
|
||||
NoteUUID string `json:"note_uuid"`
|
||||
FromBook string `json:"from_book"`
|
||||
ToBook string `json:"to_book"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type RemoveNoteData struct {
|
||||
NoteUUID string `json:"note_uuid"`
|
||||
BookName string `json:"book_name"`
|
||||
}
|
||||
|
||||
type AddBookData struct {
|
||||
BookName string `json:"book_name"`
|
||||
}
|
||||
|
||||
type RemoveBookData struct {
|
||||
BookName string `json:"book_name"`
|
||||
}
|
||||
|
||||
// ReduceAll reduces all actions
|
||||
func ReduceAll(ctx infra.DnoteCtx, actions []Action) error {
|
||||
for _, action := range actions {
|
||||
func ReduceAll(ctx infra.DnoteCtx, ats []actions.Action) error {
|
||||
for _, action := range ats {
|
||||
if err := Reduce(ctx, action); err != nil {
|
||||
return errors.Wrap(err, "Failed to reduce action")
|
||||
}
|
||||
|
|
@ -47,19 +22,19 @@ func ReduceAll(ctx infra.DnoteCtx, actions []Action) error {
|
|||
|
||||
// Reduce transitions the local dnote state by consuming the action returned
|
||||
// from the server
|
||||
func Reduce(ctx infra.DnoteCtx, action Action) error {
|
||||
func Reduce(ctx infra.DnoteCtx, action actions.Action) error {
|
||||
var err error
|
||||
|
||||
switch action.Type {
|
||||
case ActionAddNote:
|
||||
case actions.ActionAddNote:
|
||||
err = handleAddNote(ctx, action)
|
||||
case ActionRemoveNote:
|
||||
case actions.ActionRemoveNote:
|
||||
err = handleRemoveNote(ctx, action)
|
||||
case ActionEditNote:
|
||||
case actions.ActionEditNote:
|
||||
err = handleEditNote(ctx, action)
|
||||
case ActionAddBook:
|
||||
case actions.ActionAddBook:
|
||||
err = handleAddBook(ctx, action)
|
||||
case ActionRemoveBook:
|
||||
case actions.ActionRemoveBook:
|
||||
err = handleRemoveBook(ctx, action)
|
||||
default:
|
||||
return errors.Errorf("Unsupported action %s", action.Type)
|
||||
|
|
@ -72,8 +47,8 @@ func Reduce(ctx infra.DnoteCtx, action Action) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func handleAddNote(ctx infra.DnoteCtx, action Action) error {
|
||||
var data AddNoteData
|
||||
func handleAddNote(ctx infra.DnoteCtx, action actions.Action) error {
|
||||
var data actions.AddNoteDataV1
|
||||
err := json.Unmarshal(action.Data, &data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to parse the action data")
|
||||
|
|
@ -117,8 +92,8 @@ func handleAddNote(ctx infra.DnoteCtx, action Action) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func handleRemoveNote(ctx infra.DnoteCtx, action Action) error {
|
||||
var data RemoveNoteData
|
||||
func handleRemoveNote(ctx infra.DnoteCtx, action actions.Action) error {
|
||||
var data actions.RemoveNoteDataV1
|
||||
err := json.Unmarshal(action.Data, &data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to parse the action data")
|
||||
|
|
@ -146,8 +121,8 @@ func handleRemoveNote(ctx infra.DnoteCtx, action Action) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func handleEditNote(ctx infra.DnoteCtx, action Action) error {
|
||||
var data EditNoteData
|
||||
func handleEditNoteV1(ctx infra.DnoteCtx, action actions.Action) error {
|
||||
var data actions.EditNoteDataV1
|
||||
err := json.Unmarshal(action.Data, &data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to parse the action data")
|
||||
|
|
@ -205,8 +180,90 @@ func handleEditNote(ctx infra.DnoteCtx, action Action) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func handleAddBook(ctx infra.DnoteCtx, action Action) error {
|
||||
var data AddBookData
|
||||
func handleEditNoteV2(ctx infra.DnoteCtx, action actions.Action) error {
|
||||
var data actions.EditNoteDataV2
|
||||
err := json.Unmarshal(action.Data, &data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to parse the action data")
|
||||
}
|
||||
|
||||
dnote, err := GetDnote(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to get dnote")
|
||||
}
|
||||
|
||||
fromBook, ok := dnote[data.FromBook]
|
||||
if !ok {
|
||||
return errors.Errorf("Origin book with a name %s is not found", data.FromBook)
|
||||
}
|
||||
|
||||
if data.ToBook == nil {
|
||||
for idx, note := range fromBook.Notes {
|
||||
if note.UUID == data.NoteUUID {
|
||||
if data.Content != nil {
|
||||
note.Content = *data.Content
|
||||
}
|
||||
if data.Public != nil {
|
||||
note.Public = *data.Public
|
||||
}
|
||||
|
||||
note.EditedOn = action.Timestamp
|
||||
dnote[fromBook.Name].Notes[idx] = note
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Change the book
|
||||
toBook := *data.ToBook
|
||||
|
||||
dstBook, ok := dnote[toBook]
|
||||
if !ok {
|
||||
return errors.Errorf("Destination book with a name %s is not found", toBook)
|
||||
}
|
||||
|
||||
var index int
|
||||
var note infra.Note
|
||||
|
||||
// Find the note
|
||||
for idx := range fromBook.Notes {
|
||||
note = fromBook.Notes[idx]
|
||||
|
||||
if note.UUID == data.NoteUUID {
|
||||
index = idx
|
||||
}
|
||||
}
|
||||
|
||||
if data.Content != nil {
|
||||
note.Content = *data.Content
|
||||
}
|
||||
if data.Public != nil {
|
||||
note.Public = *data.Public
|
||||
}
|
||||
note.EditedOn = action.Timestamp
|
||||
|
||||
dnote[fromBook.Name] = GetUpdatedBook(dnote[fromBook.Name], append(fromBook.Notes[:index], fromBook.Notes[index+1:]...))
|
||||
dnote[toBook] = GetUpdatedBook(dnote[toBook], append(dstBook.Notes, note))
|
||||
}
|
||||
|
||||
err = WriteDnote(ctx, dnote)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to write dnote")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleEditNote(ctx infra.DnoteCtx, action actions.Action) error {
|
||||
if action.Schema == 1 {
|
||||
return handleEditNoteV1(ctx, action)
|
||||
} else if action.Schema == 2 {
|
||||
return handleEditNoteV2(ctx, action)
|
||||
}
|
||||
|
||||
return errors.Errorf("Unsupported schema version for editing note: %d", action.Schema)
|
||||
}
|
||||
|
||||
func handleAddBook(ctx infra.DnoteCtx, action actions.Action) error {
|
||||
var data actions.AddBookDataV1
|
||||
err := json.Unmarshal(action.Data, &data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to parse the action data")
|
||||
|
|
@ -238,8 +295,8 @@ func handleAddBook(ctx infra.DnoteCtx, action Action) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func handleRemoveBook(ctx infra.DnoteCtx, action Action) error {
|
||||
var data RemoveBookData
|
||||
func handleRemoveBook(ctx infra.DnoteCtx, action actions.Action) error {
|
||||
var data actions.RemoveBookDataV1
|
||||
err := json.Unmarshal(action.Data, &data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to parse the action data")
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/dnote/actions"
|
||||
"github.com/dnote/cli/testutils"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
|
@ -17,13 +18,13 @@ func TestReduceAddNote(t *testing.T) {
|
|||
testutils.WriteFile(ctx, "../testutils/fixtures/dnote4.json", "dnote")
|
||||
|
||||
// Execute
|
||||
b, err := json.Marshal(&AddNoteData{
|
||||
b, err := json.Marshal(&actions.AddNoteDataV1{
|
||||
Content: "new content",
|
||||
BookName: "js",
|
||||
NoteUUID: "06896551-8a06-4996-89cc-0d866308b0f6",
|
||||
})
|
||||
action := Action{
|
||||
Type: ActionAddNote,
|
||||
action := actions.Action{
|
||||
Type: actions.ActionAddNote,
|
||||
Data: b,
|
||||
Timestamp: 1517629805,
|
||||
}
|
||||
|
|
@ -60,13 +61,13 @@ func TestReduceAddNote_SortByAddedOn(t *testing.T) {
|
|||
testutils.WriteFile(ctx, "../testutils/fixtures/dnote3.json", "dnote")
|
||||
|
||||
// Execute
|
||||
b, err := json.Marshal(&AddNoteData{
|
||||
b, err := json.Marshal(&actions.AddNoteDataV1{
|
||||
Content: "new content",
|
||||
BookName: "js",
|
||||
NoteUUID: "06896551-8a06-4996-89cc-0d866308b0f6",
|
||||
})
|
||||
action := Action{
|
||||
Type: ActionAddNote,
|
||||
action := actions.Action{
|
||||
Type: actions.ActionAddNote,
|
||||
Data: b,
|
||||
Timestamp: 1515199944,
|
||||
}
|
||||
|
|
@ -106,12 +107,12 @@ func TestReduceRemoveNote(t *testing.T) {
|
|||
testutils.WriteFile(ctx, "../testutils/fixtures/dnote3.json", "dnote")
|
||||
|
||||
// Execute
|
||||
b, err := json.Marshal(&RemoveNoteData{
|
||||
b, err := json.Marshal(&actions.RemoveNoteDataV1{
|
||||
BookName: "js",
|
||||
NoteUUID: "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f",
|
||||
})
|
||||
action := Action{
|
||||
Type: ActionRemoveNote,
|
||||
action := actions.Action{
|
||||
Type: actions.ActionRemoveNote,
|
||||
Data: b,
|
||||
Timestamp: 1517629805,
|
||||
}
|
||||
|
|
@ -146,14 +147,15 @@ func TestReduceEditNote(t *testing.T) {
|
|||
testutils.WriteFile(ctx, "../testutils/fixtures/dnote3.json", "dnote")
|
||||
|
||||
// Execute
|
||||
b, err := json.Marshal(&EditNoteData{
|
||||
b, err := json.Marshal(&actions.EditNoteDataV1{
|
||||
FromBook: "js",
|
||||
NoteUUID: "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f",
|
||||
Content: "updated content",
|
||||
})
|
||||
action := Action{
|
||||
Type: ActionEditNote,
|
||||
action := actions.Action{
|
||||
Type: actions.ActionEditNote,
|
||||
Data: b,
|
||||
Schema: 1,
|
||||
Timestamp: 1517629805,
|
||||
}
|
||||
err = Reduce(ctx, action)
|
||||
|
|
@ -191,15 +193,16 @@ func TestReduceEditNote_changeBook(t *testing.T) {
|
|||
testutils.WriteFile(ctx, "../testutils/fixtures/dnote3.json", "dnote")
|
||||
|
||||
// Execute
|
||||
b, err := json.Marshal(&EditNoteData{
|
||||
b, err := json.Marshal(&actions.EditNoteDataV1{
|
||||
FromBook: "js",
|
||||
ToBook: "linux",
|
||||
NoteUUID: "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f",
|
||||
Content: "updated content",
|
||||
})
|
||||
action := Action{
|
||||
Type: ActionEditNote,
|
||||
action := actions.Action{
|
||||
Type: actions.ActionEditNote,
|
||||
Data: b,
|
||||
Schema: 1,
|
||||
Timestamp: 1517629805,
|
||||
}
|
||||
err = Reduce(ctx, action)
|
||||
|
|
@ -233,6 +236,141 @@ func TestReduceEditNote_changeBook(t *testing.T) {
|
|||
testutils.AssertEqual(t, otherBook.Notes[1].EditedOn, int64(1517629805), "edited note edited_on mismatch")
|
||||
}
|
||||
|
||||
func TestReduceEditNote_V2_Content(t *testing.T) {
|
||||
// Setup
|
||||
ctx := testutils.InitCtx("../tmp")
|
||||
|
||||
testutils.SetupTmp(ctx)
|
||||
defer testutils.ClearTmp(ctx)
|
||||
testutils.WriteFile(ctx, "../testutils/fixtures/dnote3.json", "dnote")
|
||||
|
||||
// Execute
|
||||
b := json.RawMessage(`{"note_uuid": "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "from_book": "js", "content": "updated content"}`)
|
||||
|
||||
action := actions.Action{
|
||||
Type: actions.ActionEditNote,
|
||||
Data: b,
|
||||
Schema: 2,
|
||||
Timestamp: 1517629805,
|
||||
}
|
||||
err := Reduce(ctx, action)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to process action"))
|
||||
}
|
||||
|
||||
// Test
|
||||
dnote, err := GetDnote(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
||||
}
|
||||
|
||||
targetBook := dnote["js"]
|
||||
otherBook := dnote["linux"]
|
||||
|
||||
testutils.AssertEqual(t, len(dnote), 2, "number of books mismatch")
|
||||
testutils.AssertEqual(t, len(targetBook.Notes), 2, "target book notes length mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[0].UUID, "43827b9a-c2b0-4c06-a290-97991c896653", "remaining note uuid mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[0].Content, "Booleans have toString()", "remaining note content mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[1].UUID, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "edited note uuid mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[1].Content, "updated content", "edited note content mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[1].EditedOn, int64(1517629805), "edited note edited_on mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[1].Public, false, "edited note public mismatch")
|
||||
testutils.AssertEqual(t, len(otherBook.Notes), 1, "other book notes length mismatch")
|
||||
testutils.AssertEqual(t, otherBook.Notes[0].UUID, "3e065d55-6d47-42f2-a6bf-f5844130b2d2", "other book remaining note uuid mismatch")
|
||||
testutils.AssertEqual(t, otherBook.Notes[0].Content, "wc -l to count words", "other book remaining note content mismatch")
|
||||
}
|
||||
|
||||
func TestReduceEditNote_V2_public(t *testing.T) {
|
||||
// Setup
|
||||
ctx := testutils.InitCtx("../tmp")
|
||||
|
||||
testutils.SetupTmp(ctx)
|
||||
defer testutils.ClearTmp(ctx)
|
||||
testutils.WriteFile(ctx, "../testutils/fixtures/dnote3.json", "dnote")
|
||||
|
||||
// Execute
|
||||
b := json.RawMessage(`{"note_uuid": "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "from_book": "js", "public": true}`)
|
||||
|
||||
action := actions.Action{
|
||||
Type: actions.ActionEditNote,
|
||||
Data: b,
|
||||
Schema: 2,
|
||||
Timestamp: 1517629805,
|
||||
}
|
||||
err := Reduce(ctx, action)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to process action"))
|
||||
}
|
||||
|
||||
// Test
|
||||
dnote, err := GetDnote(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
||||
}
|
||||
|
||||
targetBook := dnote["js"]
|
||||
otherBook := dnote["linux"]
|
||||
|
||||
testutils.AssertEqual(t, len(dnote), 2, "number of books mismatch")
|
||||
testutils.AssertEqual(t, len(targetBook.Notes), 2, "target book notes length mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[0].UUID, "43827b9a-c2b0-4c06-a290-97991c896653", "remaining note uuid mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[0].Content, "Booleans have toString()", "remaining note content mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[1].UUID, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "edited note uuid mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[1].Content, "Date object implements mathematical comparisons", "edited note content mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[1].EditedOn, int64(1517629805), "edited note edited_on mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[1].Public, true, "edited note public mismatch")
|
||||
testutils.AssertEqual(t, len(otherBook.Notes), 1, "other book notes length mismatch")
|
||||
testutils.AssertEqual(t, otherBook.Notes[0].UUID, "3e065d55-6d47-42f2-a6bf-f5844130b2d2", "other book remaining note uuid mismatch")
|
||||
testutils.AssertEqual(t, otherBook.Notes[0].Content, "wc -l to count words", "other book remaining note content mismatch")
|
||||
}
|
||||
|
||||
func TestReduceEditNote_V2_changeBook(t *testing.T) {
|
||||
// Setup
|
||||
ctx := testutils.InitCtx("../tmp")
|
||||
|
||||
testutils.SetupTmp(ctx)
|
||||
defer testutils.ClearTmp(ctx)
|
||||
testutils.WriteFile(ctx, "../testutils/fixtures/dnote3.json", "dnote")
|
||||
|
||||
// Execute
|
||||
b := json.RawMessage(`{"note_uuid": "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "from_book": "js", "to_book": "linux", "content": "updated content"}`)
|
||||
action := actions.Action{
|
||||
Type: actions.ActionEditNote,
|
||||
Data: b,
|
||||
Schema: 2,
|
||||
Timestamp: 1517629805,
|
||||
}
|
||||
err := Reduce(ctx, action)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to process action"))
|
||||
}
|
||||
|
||||
// Test
|
||||
dnote, err := GetDnote(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
||||
}
|
||||
|
||||
targetBook := dnote["js"]
|
||||
otherBook := dnote["linux"]
|
||||
|
||||
if len(targetBook.Notes) != 1 {
|
||||
t.Fatalf("target book length mismatch. Got %d", len(targetBook.Notes))
|
||||
}
|
||||
if len(otherBook.Notes) != 2 {
|
||||
t.Fatalf("other book length mismatch. Got %d", len(targetBook.Notes))
|
||||
}
|
||||
|
||||
testutils.AssertEqual(t, len(dnote), 2, "number of books mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[0].UUID, "43827b9a-c2b0-4c06-a290-97991c896653", "remaining note uuid mismatch")
|
||||
testutils.AssertEqual(t, targetBook.Notes[0].Content, "Booleans have toString()", "remaining note content mismatch")
|
||||
testutils.AssertEqual(t, otherBook.Notes[0].UUID, "3e065d55-6d47-42f2-a6bf-f5844130b2d2", "other book remaining note uuid mismatch")
|
||||
testutils.AssertEqual(t, otherBook.Notes[0].Content, "wc -l to count words", "other book remaining note content mismatch")
|
||||
testutils.AssertEqual(t, otherBook.Notes[1].UUID, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "edited note uuid mismatch")
|
||||
testutils.AssertEqual(t, otherBook.Notes[1].Content, "updated content", "edited note content mismatch")
|
||||
testutils.AssertEqual(t, otherBook.Notes[1].EditedOn, int64(1517629805), "edited note edited_on mismatch")
|
||||
}
|
||||
|
||||
func TestReduceAddBook(t *testing.T) {
|
||||
// Setup
|
||||
ctx := testutils.InitCtx("../tmp")
|
||||
|
|
@ -242,9 +380,9 @@ func TestReduceAddBook(t *testing.T) {
|
|||
testutils.WriteFile(ctx, "../testutils/fixtures/dnote4.json", "dnote")
|
||||
|
||||
// Execute
|
||||
b, err := json.Marshal(&AddBookData{BookName: "new_book"})
|
||||
action := Action{
|
||||
Type: ActionAddBook,
|
||||
b, err := json.Marshal(&actions.AddBookDataV1{BookName: "new_book"})
|
||||
action := actions.Action{
|
||||
Type: actions.ActionAddBook,
|
||||
Data: b,
|
||||
Timestamp: 1517629805,
|
||||
}
|
||||
|
|
@ -274,9 +412,9 @@ func TestReduceRemoveBook(t *testing.T) {
|
|||
testutils.WriteFile(ctx, "../testutils/fixtures/dnote3.json", "dnote")
|
||||
|
||||
// Execute
|
||||
b, err := json.Marshal(&RemoveBookData{BookName: "linux"})
|
||||
action := Action{
|
||||
Type: ActionRemoveBook,
|
||||
b, err := json.Marshal(&actions.RemoveBookDataV1{BookName: "linux"})
|
||||
action := actions.Action{
|
||||
Type: actions.ActionRemoveBook,
|
||||
Data: b,
|
||||
Timestamp: 1517629805,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ type Note struct {
|
|||
Content string `json:"content"`
|
||||
AddedOn int64 `json:"added_on"`
|
||||
EditedOn int64 `json:"edited_on"`
|
||||
Public bool `json:"public"`
|
||||
}
|
||||
|
||||
// Timestamp holds time information
|
||||
|
|
|
|||
2
main.go
2
main.go
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/dnote/cli/cmd/edit"
|
||||
"github.com/dnote/cli/cmd/login"
|
||||
"github.com/dnote/cli/cmd/ls"
|
||||
"github.com/dnote/cli/cmd/view"
|
||||
"github.com/dnote/cli/cmd/remove"
|
||||
"github.com/dnote/cli/cmd/sync"
|
||||
"github.com/dnote/cli/cmd/upgrade"
|
||||
|
|
@ -46,6 +47,7 @@ func main() {
|
|||
root.Register(version.NewCmd(ctx))
|
||||
root.Register(upgrade.NewCmd(ctx))
|
||||
root.Register(cat.NewCmd(ctx))
|
||||
root.Register(view.NewCmd(ctx))
|
||||
|
||||
if err := root.Execute(); err != nil {
|
||||
log.Errorf("%s\n", err.Error())
|
||||
|
|
|
|||
67
main_test.go
67
main_test.go
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/dnote/actions"
|
||||
"github.com/dnote/cli/core"
|
||||
"github.com/dnote/cli/infra"
|
||||
"github.com/dnote/cli/testutils"
|
||||
|
|
@ -97,22 +98,22 @@ func TestAdd_NewBook_ContentFlag(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
||||
}
|
||||
actions, err := core.ReadActionLog(ctx)
|
||||
actionSlice, err := core.ReadActionLog(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to read actions"))
|
||||
}
|
||||
|
||||
if len(actions) != 2 {
|
||||
t.Fatalf("action log length mismatch. got %d", len(actions))
|
||||
if len(actionSlice) != 2 {
|
||||
t.Fatalf("action log length mismatch. got %d", len(actionSlice))
|
||||
}
|
||||
|
||||
book := dnote["js"]
|
||||
note := book.Notes[0]
|
||||
bookAction := actions[0]
|
||||
noteAction := actions[1]
|
||||
bookAction := actionSlice[0]
|
||||
noteAction := actionSlice[1]
|
||||
|
||||
var noteActionData core.AddNoteData
|
||||
var bookActionData core.AddBookData
|
||||
var noteActionData actions.AddNoteDataV1
|
||||
var bookActionData actions.AddBookDataV1
|
||||
err = json.Unmarshal(bookAction.Data, &bookActionData)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to unmarshal the action data: %s", err)
|
||||
|
|
@ -122,10 +123,10 @@ func TestAdd_NewBook_ContentFlag(t *testing.T) {
|
|||
log.Fatalf("Failed to unmarshal the action data: %s", err)
|
||||
}
|
||||
|
||||
testutils.AssertEqual(t, bookAction.Type, core.ActionAddBook, "bookAction type mismatch")
|
||||
testutils.AssertEqual(t, bookAction.Type, actions.ActionAddBook, "bookAction type mismatch")
|
||||
testutils.AssertNotEqual(t, bookActionData.BookName, "", "bookAction data note_uuid mismatch")
|
||||
testutils.AssertNotEqual(t, bookAction.Timestamp, 0, "bookAction timestamp mismatch")
|
||||
testutils.AssertEqual(t, noteAction.Type, core.ActionAddNote, "noteAction type mismatch")
|
||||
testutils.AssertEqual(t, noteAction.Type, actions.ActionAddNote, "noteAction type mismatch")
|
||||
testutils.AssertEqual(t, noteActionData.Content, "foo", "noteAction data name mismatch")
|
||||
testutils.AssertNotEqual(t, noteActionData.NoteUUID, nil, "noteAction data note_uuid mismatch")
|
||||
testutils.AssertNotEqual(t, noteActionData.BookName, "", "noteAction data note_uuid mismatch")
|
||||
|
|
@ -154,22 +155,22 @@ func TestAdd_ExistingBook_ContentFlag(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
||||
}
|
||||
actions, err := core.ReadActionLog(ctx)
|
||||
actionSlice, err := core.ReadActionLog(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to read actions"))
|
||||
}
|
||||
|
||||
book := dnote["js"]
|
||||
action := actions[0]
|
||||
action := actionSlice[0]
|
||||
|
||||
var actionData core.AddNoteData
|
||||
var actionData actions.AddNoteDataV1
|
||||
err = json.Unmarshal(action.Data, &actionData)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to unmarshal the action data: %s", err)
|
||||
}
|
||||
|
||||
testutils.AssertEqual(t, len(actions), 1, "There should be 1 action")
|
||||
testutils.AssertEqual(t, action.Type, core.ActionAddNote, "action type mismatch")
|
||||
testutils.AssertEqual(t, len(actionSlice), 1, "There should be 1 action")
|
||||
testutils.AssertEqual(t, action.Type, actions.ActionAddNote, "action type mismatch")
|
||||
testutils.AssertEqual(t, actionData.Content, "foo", "action data name mismatch")
|
||||
testutils.AssertNotEqual(t, actionData.NoteUUID, "", "action data note_uuid mismatch")
|
||||
testutils.AssertEqual(t, actionData.BookName, "js", "action data book_name mismatch")
|
||||
|
|
@ -199,22 +200,22 @@ func TestEdit_ContentFlag(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
||||
}
|
||||
actions, err := core.ReadActionLog(ctx)
|
||||
actionSlice, err := core.ReadActionLog(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to read actions"))
|
||||
}
|
||||
|
||||
book := dnote["js"]
|
||||
action := actions[0]
|
||||
action := actionSlice[0]
|
||||
|
||||
var actionData core.EditNoteData
|
||||
var actionData actions.EditNoteDataV1
|
||||
err = json.Unmarshal(action.Data, &actionData)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to unmarshal the action data: %s", err)
|
||||
}
|
||||
|
||||
testutils.AssertEqual(t, len(actions), 1, "There should be 1 action")
|
||||
testutils.AssertEqual(t, action.Type, core.ActionEditNote, "action type mismatch")
|
||||
testutils.AssertEqual(t, len(actionSlice), 1, "There should be 1 action")
|
||||
testutils.AssertEqual(t, action.Type, actions.ActionEditNote, "action type mismatch")
|
||||
testutils.AssertEqual(t, actionData.Content, "foo bar", "action data name mismatch")
|
||||
testutils.AssertEqual(t, actionData.FromBook, "js", "action data from_book mismatch")
|
||||
testutils.AssertEqual(t, actionData.NoteUUID, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "action data note_uuis mismatch")
|
||||
|
|
@ -270,27 +271,27 @@ func TestRemoveNote(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
||||
}
|
||||
actions, err := core.ReadActionLog(ctx)
|
||||
actionSlice, err := core.ReadActionLog(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to read actions"))
|
||||
}
|
||||
|
||||
if len(actions) != 1 {
|
||||
t.Fatalf("action log length mismatch. got %d", len(actions))
|
||||
if len(actionSlice) != 1 {
|
||||
t.Fatalf("action log length mismatch. got %d", len(actionSlice))
|
||||
}
|
||||
|
||||
book := dnote["js"]
|
||||
otherBook := dnote["linux"]
|
||||
action := actions[0]
|
||||
action := actionSlice[0]
|
||||
|
||||
var actionData core.RemoveNoteData
|
||||
var actionData actions.RemoveNoteDataV1
|
||||
err = json.Unmarshal(action.Data, &actionData)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to unmarshal the action data: %s", err)
|
||||
}
|
||||
|
||||
testutils.AssertEqual(t, len(actions), 1, "There should be 1 action")
|
||||
testutils.AssertEqual(t, action.Type, core.ActionRemoveNote, "action type mismatch")
|
||||
testutils.AssertEqual(t, len(actionSlice), 1, "There should be 1 action")
|
||||
testutils.AssertEqual(t, action.Type, actions.ActionRemoveNote, "action type mismatch")
|
||||
testutils.AssertEqual(t, actionData.NoteUUID, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "action data note_uuid mismatch")
|
||||
testutils.AssertEqual(t, actionData.BookName, "js", "action data book_name mismatch")
|
||||
testutils.AssertNotEqual(t, action.Timestamp, 0, "action timestamp mismatch")
|
||||
|
|
@ -343,26 +344,26 @@ func TestRemoveBook(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
||||
}
|
||||
actions, err := core.ReadActionLog(ctx)
|
||||
actionSlice, err := core.ReadActionLog(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to read actions"))
|
||||
}
|
||||
|
||||
if len(actions) != 1 {
|
||||
t.Fatalf("action log length mismatch. got %d", len(actions))
|
||||
if len(actionSlice) != 1 {
|
||||
t.Fatalf("action log length mismatch. got %d", len(actionSlice))
|
||||
}
|
||||
|
||||
book := dnote["linux"]
|
||||
action := actions[0]
|
||||
action := actionSlice[0]
|
||||
|
||||
var actionData core.RemoveBookData
|
||||
var actionData actions.RemoveBookDataV1
|
||||
err = json.Unmarshal(action.Data, &actionData)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to unmarshal the action data: %s", err)
|
||||
}
|
||||
|
||||
testutils.AssertEqual(t, len(actions), 1, "There should be 1 action")
|
||||
testutils.AssertEqual(t, action.Type, core.ActionRemoveBook, "action type mismatch")
|
||||
testutils.AssertEqual(t, len(actionSlice), 1, "There should be 1 action")
|
||||
testutils.AssertEqual(t, action.Type, actions.ActionRemoveBook, "action type mismatch")
|
||||
testutils.AssertEqual(t, actionData.BookName, "js", "action data name mismatch")
|
||||
testutils.AssertNotEqual(t, action.Timestamp, 0, "action timestamp mismatch")
|
||||
testutils.AssertEqual(t, len(dnote), 1, "There should be 1 book")
|
||||
|
|
|
|||
37
migrate/fixtures/6-post-dnote.json
Normal file
37
migrate/fixtures/6-post-dnote.json
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"css": {
|
||||
"name": "css",
|
||||
"notes": [
|
||||
{
|
||||
"uuid": "a7206776-cc2f-4439-995d-1d5c934c7758",
|
||||
"content": "asdf",
|
||||
"added_on": 1534888848,
|
||||
"edited_on": 0,
|
||||
"public": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"js": {
|
||||
"name": "js",
|
||||
"notes": [
|
||||
{
|
||||
"uuid": "d3eb7b64-cf51-48e3-935e-211be1af63fa",
|
||||
"content": "blah",
|
||||
"added_on": 1534888872,
|
||||
"edited_on": 0,
|
||||
"public": false
|
||||
},
|
||||
{
|
||||
"uuid": "16463315-1a89-4f82-ab25-06a384ef98b1",
|
||||
"content": "blah blah edited",
|
||||
"added_on": 1534888875,
|
||||
"edited_on": 1534888884,
|
||||
"public": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"linux": {
|
||||
"name": "linux",
|
||||
"notes": []
|
||||
}
|
||||
}
|
||||
34
migrate/fixtures/6-pre-dnote.json
Normal file
34
migrate/fixtures/6-pre-dnote.json
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"css": {
|
||||
"name": "css",
|
||||
"notes": [
|
||||
{
|
||||
"uuid": "a7206776-cc2f-4439-995d-1d5c934c7758",
|
||||
"content": "asdf",
|
||||
"added_on": 1534888848,
|
||||
"edited_on": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"js": {
|
||||
"name": "js",
|
||||
"notes": [
|
||||
{
|
||||
"uuid": "d3eb7b64-cf51-48e3-935e-211be1af63fa",
|
||||
"content": "blah",
|
||||
"added_on": 1534888872,
|
||||
"edited_on": 0
|
||||
},
|
||||
{
|
||||
"uuid": "16463315-1a89-4f82-ab25-06a384ef98b1",
|
||||
"content": "blah blah edited",
|
||||
"added_on": 1534888875,
|
||||
"edited_on": 1534888884
|
||||
}
|
||||
]
|
||||
},
|
||||
"linux": {
|
||||
"name": "linux",
|
||||
"notes": []
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ const (
|
|||
migrationV3
|
||||
migrationV4
|
||||
migrationV5
|
||||
migrationV6
|
||||
)
|
||||
|
||||
var migrationSequence = []int{
|
||||
|
|
@ -34,6 +35,7 @@ var migrationSequence = []int{
|
|||
migrationV3,
|
||||
migrationV4,
|
||||
migrationV5,
|
||||
migrationV6,
|
||||
}
|
||||
|
||||
type schema struct {
|
||||
|
|
@ -89,6 +91,8 @@ func performMigration(ctx infra.DnoteCtx, migrationID int) error {
|
|||
migrationError = migrateToV4(ctx)
|
||||
case migrationV5:
|
||||
migrationError = migrateToV5(ctx)
|
||||
case migrationV6:
|
||||
migrationError = migrateToV6(ctx)
|
||||
default:
|
||||
return errors.Errorf("Unrecognized migration id %d", migrationID)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dnote/cli/testutils"
|
||||
|
|
@ -292,3 +293,34 @@ func TestMigrateToV5(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateToV6(t *testing.T) {
|
||||
ctx := testutils.InitCtx("../tmp")
|
||||
|
||||
// set up
|
||||
testutils.SetupTmp(ctx)
|
||||
testutils.WriteFile(ctx, "./fixtures/6-pre-dnote.json", "dnote")
|
||||
defer testutils.ClearTmp(ctx)
|
||||
|
||||
// execute
|
||||
if err := migrateToV6(ctx); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to migrate").Error())
|
||||
}
|
||||
|
||||
// test
|
||||
b := testutils.ReadFile(ctx, "dnote")
|
||||
var got migrateToV6PostDnote
|
||||
if err := json.Unmarshal(b, &got); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to unmarshal the result into Dnote").Error())
|
||||
}
|
||||
|
||||
b = testutils.ReadFileAbs("./fixtures/6-post-dnote.json")
|
||||
var expected migrateToV6PostDnote
|
||||
if err := json.Unmarshal(b, &expected); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "Failed to unmarshal the result into Dnote").Error())
|
||||
}
|
||||
|
||||
if ok := reflect.DeepEqual(expected, got); !ok {
|
||||
t.Errorf("Payload does not match.\nActual: %+v\nExpected: %+v", got, expected)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,3 +262,56 @@ func migrateToV5(ctx infra.DnoteCtx) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// migrateToV6 adds a 'public' field to notes
|
||||
func migrateToV6(ctx infra.DnoteCtx) error {
|
||||
notePath := fmt.Sprintf("%s/dnote", ctx.DnoteDir)
|
||||
|
||||
b, err := ioutil.ReadFile(notePath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to read the note file")
|
||||
}
|
||||
|
||||
var preDnote migrateToV6PreDnote
|
||||
postDnote := migrateToV6PostDnote{}
|
||||
|
||||
err = json.Unmarshal(b, &preDnote)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to unmarshal existing dnote into JSON")
|
||||
}
|
||||
|
||||
for bookName, book := range preDnote {
|
||||
var notes = make([]migrateToV6PostNote, 0, len(book.Notes))
|
||||
public := false
|
||||
for _, note := range book.Notes {
|
||||
newNote := migrateToV6PostNote{
|
||||
UUID: note.UUID,
|
||||
Content: note.Content,
|
||||
AddedOn: note.AddedOn,
|
||||
EditedOn: note.EditedOn,
|
||||
Public: &public,
|
||||
}
|
||||
|
||||
notes = append(notes, newNote)
|
||||
}
|
||||
|
||||
b := migrateToV6PostBook{
|
||||
Name: bookName,
|
||||
Notes: notes,
|
||||
}
|
||||
|
||||
postDnote[bookName] = b
|
||||
}
|
||||
|
||||
d, err := json.MarshalIndent(postDnote, "", " ")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to marshal new dnote into JSON")
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(notePath, d, 0644)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to write the new dnote into the file")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,3 +104,29 @@ var (
|
|||
migrateToV5ActionAddBook = "add_book"
|
||||
migrateToV5ActionRemoveBook = "remove_book"
|
||||
)
|
||||
|
||||
// v6
|
||||
type migrateToV6PreNote struct {
|
||||
UUID string `json:"uuid"`
|
||||
Content string `json:"content"`
|
||||
AddedOn int64 `json:"added_on"`
|
||||
EditedOn int64 `json:"edited_on"`
|
||||
}
|
||||
type migrateToV6PostNote struct {
|
||||
UUID string `json:"uuid"`
|
||||
Content string `json:"content"`
|
||||
AddedOn int64 `json:"added_on"`
|
||||
EditedOn int64 `json:"edited_on"`
|
||||
// Make a pointer to test absent values
|
||||
Public *bool `json:"public"`
|
||||
}
|
||||
type migrateToV6PreBook struct {
|
||||
Name string `json:"name"`
|
||||
Notes []migrateToV6PreNote `json:"notes"`
|
||||
}
|
||||
type migrateToV6PostBook struct {
|
||||
Name string `json:"name"`
|
||||
Notes []migrateToV6PostNote `json:"notes"`
|
||||
}
|
||||
type migrateToV6PreDnote map[string]migrateToV6PreBook
|
||||
type migrateToV6PostDnote map[string]migrateToV6PostBook
|
||||
|
|
|
|||
|
|
@ -56,6 +56,20 @@ func ReadFile(ctx infra.DnoteCtx, filename string) []byte {
|
|||
return b
|
||||
}
|
||||
|
||||
func ReadFileAbs(filename string) []byte {
|
||||
fp, err := filepath.Abs(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadFile(fp)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func SetupTmp(ctx infra.DnoteCtx) {
|
||||
if err := os.MkdirAll(ctx.DnoteDir, 0755); err != nil {
|
||||
panic(err)
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// upgradeInterval is 7 days
|
||||
var upgradeInterval int64 = 86400 * 7
|
||||
// upgradeInterval is 3 weeks
|
||||
var upgradeInterval int64 = 86400 * 7 * 3
|
||||
|
||||
// getAsset finds the asset to download from the liast of assets in a release
|
||||
func getAsset(release *github.RepositoryRelease) *github.ReleaseAsset {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue