diff --git a/README.md b/README.md index dbe169f..2cd6651 100644 --- a/README.md +++ b/README.md @@ -2099,6 +2099,109 @@ corresponding to when the API was available for use. } ``` +* **modelFieldRename** + + Rename the field name of a given model. + + *Sample Request*: + ```json + { + "action": "modelFieldRename", + "version": 6, + "params": { + "modelName": "Basic", + "oldFieldName": "Front", + "newFieldName": "FrontRenamed" + } + } + ``` + + *Sample result*: + ```json + { + "result": null, + "error": null + } + ``` + +* **modelFieldReposition** + + Reposition the field within the field list of a given model. + + The value of `index` starts at 0. For example, an index of `0` puts the field in the first position, and an index of `2` puts the field in the third position. + + *Sample Request*: + ```json + { + "action": "modelFieldReposition", + "version": 6, + "params": { + "modelName": "Basic", + "fieldName": "Back", + "index": 0 + } + } + ``` + + *Sample result*: + ```json + { + "result": null, + "error": null + } + ``` + +* **modelFieldAdd** + + Creates a new field within a given model. + + Optionally, the `index` value can be provided, which works exactly the same as the index in `modelFieldReposition`. By default, the field is added to the end of the field list. + + *Sample Request*: + ```json + { + "action": "modelFieldAdd", + "version": 6, + "params": { + "modelName": "Basic", + "fieldName": "NewField", + "index": 0 + } + } + ``` + + *Sample result*: + ```json + { + "result": null, + "error": null + } + ``` + +* **modelFieldRemove** + + Deletes a field within a given model. + + *Sample Request*: + ```json + { + "action": "modelFieldRemove", + "version": 6, + "params": { + "modelName": "Basic", + "fieldName": "Front" + } + } + ``` + + *Sample result*: + ```json + { + "result": null, + "error": null + } + ``` + #### Note Actions * **addNote** diff --git a/plugin/__init__.py b/plugin/__init__.py index 93c92d0..4ff486b 100644 --- a/plugin/__init__.py +++ b/plugin/__init__.py @@ -1185,6 +1185,79 @@ class AnkiConnect: return updatedModels + @util.api() + def modelFieldRename(self, modelName, oldFieldName, newFieldName): + mm = self.collection().models + model = mm.byName(modelName) + if model is None: + raise Exception('model was not found: {}'.format(modelName)) + + fieldMap = mm.fieldMap(model) + if oldFieldName not in fieldMap: + raise Exception('field was not found in {}: {}'.format(modelName, oldFieldName)) + field = fieldMap[oldFieldName][1] + + mm.renameField(model, field, newFieldName) + + self.save_model(mm, model) + + + @util.api() + def modelFieldReposition(self, modelName, fieldName, index): + mm = self.collection().models + model = mm.byName(modelName) + if model is None: + raise Exception('model was not found: {}'.format(modelName)) + + fieldMap = mm.fieldMap(model) + if fieldName not in fieldMap: + raise Exception('field was not found in {}: {}'.format(modelName, fieldName)) + field = fieldMap[fieldName][1] + + mm.repositionField(model, field, index) + + self.save_model(mm, model) + + + @util.api() + def modelFieldAdd(self, modelName, fieldName, index=None): + mm = self.collection().models + model = mm.byName(modelName) + if model is None: + raise Exception('model was not found: {}'.format(modelName)) + + # only adds the field if it doesn't already exist + fieldMap = mm.fieldMap(model) + if fieldName not in fieldMap: + field = mm.newField(fieldName) + mm.addField(model, field) + + # repositions, even if the field already exists + if index is not None: + fieldMap = mm.fieldMap(model) + newField = fieldMap[fieldName][1] + mm.repositionField(model, newField, index) + + self.save_model(mm, model) + + + @util.api() + def modelFieldRemove(self, modelName, fieldName): + mm = self.collection().models + model = mm.byName(modelName) + if model is None: + raise Exception('model was not found: {}'.format(modelName)) + + fieldMap = mm.fieldMap(model) + if fieldName not in fieldMap: + raise Exception('field was not found in {}: {}'.format(modelName, fieldName)) + field = fieldMap[fieldName][1] + + mm.removeField(model, field) + + self.save_model(mm, model) + + @util.api() def deckNameFromId(self, deckId): deck = self.collection().decks.get(deckId) diff --git a/tests/test_models.py b/tests/test_models.py index f7e9131..7c5dbb7 100755 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -110,3 +110,60 @@ def test_findAndReplaceInModels(setup): assert ac.modelStyling(modelName="test_model") == { "css": "* {color: blue;}" } + + +class TestModelFieldNames: + def test_modelFieldRename(self, setup): + ac.modelFieldRename( + modelName="test_model", + oldFieldName="field1", + newFieldName="foo", + ) + + result = ac.modelFieldNames(modelName="test_model") + assert result == ["foo", "field2"] + + def test_modelFieldReposition(self, setup): + ac.modelFieldReposition( + modelName="test_model", + fieldName="field1", + index=2, + ) + + result = ac.modelFieldNames(modelName="test_model") + assert result == ["field2", "field1"] + + def test_modelFieldAdd(self, setup): + ac.modelFieldAdd( + modelName="test_model", + fieldName="Foo", + ) + + result = ac.modelFieldNames(modelName="test_model") + assert result == ["field1", "field2", "Foo"] + + def test_modelFieldAdd_with_index(self, setup): + ac.modelFieldAdd( + modelName="test_model", + fieldName="Foo", + index=1, + ) + + result = ac.modelFieldNames(modelName="test_model") + assert result == ["field1", "Foo", "field2"] + + def test_modelFieldRemove(self, setup): + # makes sure that the front template always has a field, + # and makes sure that the front template of the cards are not the same + ac.updateModelTemplates(model={ + "name": "test_model", + "templates": {"Card 1": {"Front": "{{field2}} {{field2}}", "Back": "foo"}} + }) + + ac.modelFieldRemove( + modelName="test_model", + fieldName="field1", + ) + + result = ac.modelFieldNames(modelName="test_model") + assert result == ["field2"]