Skip to content
This repository has been archived by the owner on Dec 31, 2023. It is now read-only.

Commit

Permalink
Merge pull request #380 from Aquafina-water-bottle/updateNote
Browse files Browse the repository at this point in the history
Update note
  • Loading branch information
FooSoft committed Apr 1, 2023
2 parents bf5c73b + ed508ba commit 3c98885
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 2 deletions.
118 changes: 117 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3058,7 +3058,7 @@ corresponding to when the API was available for use.

#### `updateNoteFields`

* Modify the fields of an exist note. You can also include audio, video, or picture files which will be added to the note with an
* Modify the fields of an existing note. You can also include audio, video, or picture files which will be added to the note with an
optional `audio`, `video`, or `picture` property. Please see the documentation for `addNote` for an explanation of objects in the `audio`, `video`, or `picture` array.

> **Warning**:
Expand Down Expand Up @@ -3105,6 +3105,122 @@ corresponding to when the API was available for use.
```
</details>

#### `updateNote`

* Modify the fields and/or tags of an existing note.
In other words, combines `updateNoteFields` and `updateNoteTags`.
Please see their documentation for an explanation of all properties.

Either `fields` or `tags` property can be omitted without affecting the other.
Thus valid requests to `updateNoteFields` also work with `updateNote`.
The note must have the `fields` property in order to update the optional audio, video, or picture objects.

If neither `fields` nor `tags` are provided, the method will fail.
Fields are updated first and are not rolled back if updating tags fails.
Tags are not updated if updating fields fails.

> **Warning**
> You must not be viewing the note that you are updating on your Anki browser, otherwise
> the fields will not update. See [this issue](https://github.com/FooSoft/anki-connect/issues/82)
> for further details.
<details>
<summary><i>Sample request:</i></summary>

```json
{
"action": "updateNote",
"version": 6,
"params": {
"note": {
"id": 1514547547030,
"fields": {
"Front": "new front content",
"Back": "new back content"
},
"tags": ["new", "tags"]
}
}
}
```

</details>

<details>
<summary><i>Sample result:</i></summary>

```json
{
"result": null,
"error": null
}
```

</details>

#### `updateNoteTags`

* Set a note's tags by note ID. Old tags will be removed.

<details>
<summary><i>Sample request:</i></summary>

```json
{
"action": "updateNoteTags",
"version": 6,
"params": {
"note": 1483959289817,
"tags": ["european-languages"]
}
}
```

</details>

<details>
<summary><i>Sample result:</i></summary>

```json
{
"result": null,
"error": null
}
```

</details>

#### `getNoteTags`

* Get a note's tags by note ID.

<details>
<summary><i>Sample request:</i></summary>

```json
{
"action": "getNoteTags",
"version": 6,
"params": {
"note": 1483959289817
}
}
```

</details>

<details>
<summary><i>Sample result:</i></summary>

```json
{
"result": ["european-languages"],
"error": null
}
```

</details>

#### `addTags`

* Adds tags to notes by note ID.
Expand Down
31 changes: 31 additions & 0 deletions plugin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,37 @@ def updateNoteFields(self, note):
self.stopEditing()


@util.api()
def updateNote(self, note):
updated = False
if 'fields' in note.keys():
self.updateNoteFields(note)
updated = True
if 'tags' in note.keys():
self.updateNoteTags(note['id'], note['tags'])
updated = True
if not updated:
raise Exception('Must provide a "fields" or "tags" property.')


@util.api()
def updateNoteTags(self, note, tags):
if type(tags) == str:
tags = [tags]
if type(tags) != list or not all([type(t) == str for t in tags]):
raise Exception('Must provide tags as a list of strings')

for old_tag in self.getNoteTags(note):
self.removeTags([note], old_tag)
for new_tag in tags:
self.addTags([note], new_tag)


@util.api()
def getNoteTags(self, note):
return self.getNote(note).tags


@util.api()
def addTags(self, notes, tags, add=True):
self.startEditing()
Expand Down
23 changes: 22 additions & 1 deletion tests/test_notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ def test_clearUnusedTags(self, setup):
ac.clearUnusedTags()
assert ac.getTags() == ["tag1"]

def test_updateNoteTags_and_getNoteTags(self, setup):
ac.updateNoteTags(note=setup.note1_id, tags="footag")
assert ac.getNoteTags(note=setup.note1_id) == ["footag"]
ac.updateNoteTags(note=setup.note1_id, tags=["foo", "bar", "baz"])
assert len(ac.getNoteTags(note=setup.note1_id)) == 3


class TestUpdateNoteFields:
def test_updateNoteFields(self, setup):
Expand All @@ -107,12 +113,27 @@ def test_updateNoteFields(self, setup):
notes_info = ac.notesInfo(notes=[setup.note1_id])
assert notes_info[0]["fields"]["field2"]["value"] == "bar"

def test_updateNoteFields_will_note_update_invalid_notes(self, setup):
def test_updateNoteFields_will_not_update_invalid_notes(self, setup):
bad_note = {"id": 123, "fields": make_note()["fields"]}
with pytest.raises(NotFoundError):
ac.updateNoteFields(note=bad_note)


class TestUpdateNote:
def test_updateNote(self, setup):
new_fields = {"field1": "frontbar", "field2": "backbar"}
new_tags = ["foobar"]
good_note = {"id": setup.note1_id, "fields": new_fields, "tags": new_tags}
ac.updateNote(note=good_note)
notes_info = ac.notesInfo(notes=[setup.note1_id])
assert notes_info[0]["fields"]["field2"]["value"] == "backbar"
assert notes_info[0]["tags"] == ["foobar"]

def test_updateNote_requires_either_fields_or_tags(self, setup):
with pytest.raises(Exception, match="ust provide"):
ac.updateNote(note={"id": setup.note1_id})


class TestCanAddNotes:
foo_bar_notes = [make_note(front="foo"), make_note(front="bar")]

Expand Down

0 comments on commit 3c98885

Please sign in to comment.