From accbc53e5d961d6a90cec1b0695e8bdb1b437142 Mon Sep 17 00:00:00 2001
From: Austin Siew <17107540+Aquafina-water-bottle@users.noreply.github.com>
Date: Thu, 13 Apr 2023 19:30:49 -0600
Subject: [PATCH 1/3] added modelTemplateRename, modelTemplateReposition,
modelTemplateAdd, modelTemplateRemove
---
README.md | 130 ++++++++++++++++++++++++++++++++++++++++++-
plugin/__init__.py | 79 ++++++++++++++++++++++----
tests/test_models.py | 56 +++++++++++++++++++
3 files changed, 254 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index 585e9ff..52c9adc 100644
--- a/README.md
+++ b/README.md
@@ -2630,6 +2630,134 @@ corresponding to when the API was available for use.
```
+#### `modelTemplateRename`
+
+* Renames a template in an existing model.
+
+
+ Sample request:
+
+ ```json
+ {
+ "action": "modelTemplateRename",
+ "version": 6,
+ "params": {
+ "modelName": "Basic",
+ "oldTemplateName": "Card 1",
+ "newTemplateName": "Card 1 renamed"
+ }
+ }
+ ```
+
+
+
+ Sample result:
+
+ ```json
+ {
+ "result": null,
+ "error": null
+ }
+ ```
+
+
+#### `modelTemplateReposition`
+
+* Repositions a template in an existing model.
+
+ The value of `index` starts at 0. For example, an index of `0` puts the template in the first position, and an index of `2` puts the template in the third position.
+
+
+ Sample request:
+
+ ```json
+ {
+ "action": "modelTemplateRemove",
+ "version": 6,
+ "params": {
+ "modelName": "Basic",
+ "templateName": "Card 1",
+ "index": 1
+ }
+ }
+ ```
+
+
+
+ Sample result:
+
+ ```json
+ {
+ "result": null,
+ "error": null
+ }
+ ```
+
+
+#### `modelTemplateAdd`
+
+* Adds a template to an existing model by name. If you want to update an existing template, use `updateModelTemplates`.
+
+
+ Sample request:
+
+ ```json
+ {
+ "action": "modelTemplateAdd",
+ "version": 6,
+ "params": {
+ "modelName": "Basic",
+ "template": {
+ "Name": "Card 3",
+ "Front": "Front html {{Field1}}",
+ "Back": "Back html {{Field2}}"
+ }
+ }
+ }
+ ```
+
+
+
+ Sample result:
+
+ ```json
+ {
+ "result": null,
+ "error": null
+ }
+ ```
+
+
+#### `modelTemplateRemove`
+
+* Removes a template from an existing model.
+
+
+ Sample request:
+
+ ```json
+ {
+ "action": "modelTemplateRemove",
+ "version": 6,
+ "params": {
+ "modelName": "Basic",
+ "templateName": "Card 1"
+ }
+ }
+ ```
+
+
+
+ Sample result:
+
+ ```json
+ {
+ "result": null,
+ "error": null
+ }
+ ```
+
+
#### `modelFieldRename`
* Rename the field name of a given model.
@@ -2644,7 +2772,7 @@ corresponding to when the API was available for use.
"params": {
"modelName": "Basic",
"oldFieldName": "Front",
- "newFieldName": "FrontRenamed"
+ "newFieldName": "Front2"
}
}
```
diff --git a/plugin/__init__.py b/plugin/__init__.py
index eaefc32..a30fca0 100644
--- a/plugin/__init__.py
+++ b/plugin/__init__.py
@@ -196,15 +196,20 @@ class AnkiConnect:
return model
- def getField(self, modelName, fieldName):
- model = self.getModel(modelName)
-
+ def getField(self, model, fieldName):
fieldMap = self.collection().models.fieldMap(model)
if fieldName not in fieldMap:
- raise Exception('field was not found in {}: {}'.format(modelName, fieldName))
+ raise Exception('field was not found in {}: {}'.format(model['name'], fieldName))
return fieldMap[fieldName][1]
+ def getTemplate(self, model, templateName):
+ for ankiTemplate in model['tmpls']:
+ if ankiTemplate['name'] == templateName:
+ return ankiTemplate
+ raise Exception('template was not found in {}: {}'.format(model['name'], templateName))
+
+
def startEditing(self):
self.window().requireReset()
@@ -1268,11 +1273,65 @@ class AnkiConnect:
return updatedModels
+ @util.api()
+ def modelTemplateRename(self, modelName, oldTemplateName, newTemplateName):
+ mm = self.collection().models
+ model = self.getModel(modelName)
+ ankiTemplate = self.getTemplate(model, oldTemplateName)
+
+ ankiTemplate['name'] = newTemplateName
+ self.save_model(mm, model)
+
+
+ @util.api()
+ def modelTemplateReposition(self, modelName, templateName, index):
+ mm = self.collection().models
+ model = self.getModel(modelName)
+ ankiTemplate = self.getTemplate(model, templateName)
+
+ mm.reposition_template(model, ankiTemplate, index)
+ self.save_model(mm, model)
+
+
+ @util.api()
+ def modelTemplateAdd(self, modelName, template):
+ # "Name", "Front", "Back" borrows from `createModel`
+ mm = self.collection().models
+ model = self.getModel(modelName)
+ name = template['Name']
+ qfmt = template['Front']
+ afmt = template['Back']
+
+ # updates the template if it already exists
+ for ankiTemplate in model['tmpls']:
+ if ankiTemplate['name'] == name:
+ ankiTemplate['qfmt'] = qfmt
+ ankiTemplate['afmt'] = afmt
+ return
+
+ ankiTemplate = mm.new_template(name)
+ ankiTemplate['qfmt'] = qfmt
+ ankiTemplate['afmt'] = afmt
+ mm.add_template(model, ankiTemplate)
+
+ self.save_model(mm, model)
+
+
+ @util.api()
+ def modelTemplateRemove(self, modelName, templateName):
+ mm = self.collection().models
+ model = self.getModel(modelName)
+ ankiTemplate = self.getTemplate(model, templateName)
+
+ mm.remove_template(model, ankiTemplate)
+ self.save_model(mm, model)
+
+
@util.api()
def modelFieldRename(self, modelName, oldFieldName, newFieldName):
mm = self.collection().models
model = self.getModel(modelName)
- field = self.getField(modelName, oldFieldName)
+ field = self.getField(model, oldFieldName)
mm.renameField(model, field, newFieldName)
@@ -1283,7 +1342,7 @@ class AnkiConnect:
def modelFieldReposition(self, modelName, fieldName, index):
mm = self.collection().models
model = self.getModel(modelName)
- field = self.getField(modelName, fieldName)
+ field = self.getField(model, fieldName)
mm.repositionField(model, field, index)
@@ -1314,7 +1373,7 @@ class AnkiConnect:
def modelFieldRemove(self, modelName, fieldName):
mm = self.collection().models
model = self.getModel(modelName)
- field = self.getField(modelName, fieldName)
+ field = self.getField(model, fieldName)
mm.removeField(model, field)
@@ -1325,7 +1384,7 @@ class AnkiConnect:
def modelFieldSetFont(self, modelName, fieldName, font):
mm = self.collection().models
model = self.getModel(modelName)
- field = self.getField(modelName, fieldName)
+ field = self.getField(model, fieldName)
if not isinstance(font, str):
raise Exception('font should be a string: {}'.format(font))
@@ -1339,7 +1398,7 @@ class AnkiConnect:
def modelFieldSetFontSize(self, modelName, fieldName, fontSize):
mm = self.collection().models
model = self.getModel(modelName)
- field = self.getField(modelName, fieldName)
+ field = self.getField(model, fieldName)
if not isinstance(fontSize, int):
raise Exception('fontSize should be an integer: {}'.format(fontSize))
@@ -1353,7 +1412,7 @@ class AnkiConnect:
def modelFieldSetDescription(self, modelName, fieldName, description):
mm = self.collection().models
model = self.getModel(modelName)
- field = self.getField(modelName, fieldName)
+ field = self.getField(model, fieldName)
if not isinstance(description, str):
raise Exception('description should be a string: {}'.format(description))
diff --git a/tests/test_models.py b/tests/test_models.py
index bf8aa97..c3db38e 100755
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -132,6 +132,62 @@ def test_findAndReplaceInModels(setup):
}
+class TestModelTemplates:
+ def test_modelTemplateRename(self, setup):
+ ac.modelTemplateRename(
+ modelName="test_model",
+ oldTemplateName="Card 1",
+ newTemplateName="Card 1 Renamed",
+ )
+
+ result = ac.modelTemplates(modelName="test_model")
+ assert result == {
+ "Card 1 Renamed": {"Front": "{{field1}}", "Back": "{{field2}}"},
+ "Card 2": {"Front": "{{field2}}", "Back": "{{field1}}"}
+ }
+
+ def test_modelTemplateReposition(self, setup):
+ # There currently isn't a way to test for order, so this is just a
+ # smoke test for now
+ ac.modelTemplateReposition(
+ modelName="test_model",
+ templateName="Card 1",
+ index=1,
+ )
+
+ def test_modelTemplateAdd(self, setup):
+ # There currently isn't a way to test for order, so this is just a
+ # smoke test for now
+ ac.modelTemplateAdd(
+ modelName="test_model",
+ template={
+ "Name": "Card 3",
+ "Front": "{{field1}} Card 3",
+ "Back": "{{field2}}",
+ }
+ )
+
+ result = ac.modelTemplates(modelName="test_model")
+ assert result == {
+ "Card 1": {"Front": "{{field1}}", "Back": "{{field2}}"},
+ "Card 2": {"Front": "{{field2}}", "Back": "{{field1}}"},
+ "Card 3": {"Front": "{{field1}} Card 3", "Back": "{{field2}}"},
+ }
+
+ def test_modelTemplateRemove(self, setup):
+ # There currently isn't a way to test for order, so this is just a
+ # smoke test for now
+ ac.modelTemplateRemove(
+ modelName="test_model",
+ templateName="Card 2"
+ )
+
+ result = ac.modelTemplates(modelName="test_model")
+ assert result == {
+ "Card 1": {"Front": "{{field1}}", "Back": "{{field2}}"},
+ }
+
+
class TestModelFieldNames:
def test_modelFieldRename(self, setup):
ac.modelFieldRename(
From 918d4de72abb46a704e304e050237c52a0fdd021 Mon Sep 17 00:00:00 2001
From: Austin Siew <17107540+Aquafina-water-bottle@users.noreply.github.com>
Date: Thu, 13 Apr 2023 20:33:18 -0600
Subject: [PATCH 2/3] fixed accidental change in README
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 52c9adc..4785900 100644
--- a/README.md
+++ b/README.md
@@ -2772,7 +2772,7 @@ corresponding to when the API was available for use.
"params": {
"modelName": "Basic",
"oldFieldName": "Front",
- "newFieldName": "Front2"
+ "newFieldName": "FrontRenamed"
}
}
```
From fc63bdaa1753a099ca33da115146d8174c3c57eb Mon Sep 17 00:00:00 2001
From: Austin Siew <17107540+Aquafina-water-bottle@users.noreply.github.com>
Date: Thu, 13 Apr 2023 20:36:07 -0600
Subject: [PATCH 3/3] removed unnecessary comments in test_models.py
---
tests/test_models.py | 4 ----
1 file changed, 4 deletions(-)
diff --git a/tests/test_models.py b/tests/test_models.py
index c3db38e..1cda36a 100755
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -156,8 +156,6 @@ class TestModelTemplates:
)
def test_modelTemplateAdd(self, setup):
- # There currently isn't a way to test for order, so this is just a
- # smoke test for now
ac.modelTemplateAdd(
modelName="test_model",
template={
@@ -175,8 +173,6 @@ class TestModelTemplates:
}
def test_modelTemplateRemove(self, setup):
- # There currently isn't a way to test for order, so this is just a
- # smoke test for now
ac.modelTemplateRemove(
modelName="test_model",
templateName="Card 2"