From 3a2778f28e987ec6dc5342eb1fa1c4d4d08512da Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 21 Jan 2012 09:54:35 -0500 Subject: [PATCH 01/15] Implemented wp.getTaxonomies and wp.getTaxonomy. --- tests/test_taxonomies.py | 39 ++++++++++++++++++++++++++ wordpress_xmlrpc/methods/taxonomies.py | 30 ++++++++++++++++++++ wordpress_xmlrpc/wordpress.py | 19 +++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 tests/test_taxonomies.py create mode 100644 wordpress_xmlrpc/methods/taxonomies.py diff --git a/tests/test_taxonomies.py b/tests/test_taxonomies.py new file mode 100644 index 0000000..2371794 --- /dev/null +++ b/tests/test_taxonomies.py @@ -0,0 +1,39 @@ +from nose.plugins.attrib import attr + +from tests import WordPressTestCase + +from wordpress_xmlrpc.methods import taxonomies +from wordpress_xmlrpc.wordpress import WordPressTaxonomy + + +class TestTaxonomies(WordPressTestCase): + + @attr('taxonomies') + def test_get_taxonomies(self): + taxs = self.client.call(taxonomies.GetTaxonomies()) + self.assert_list_of_classes(taxs, WordPressTaxonomy) + + @attr('taxonomies') + def test_get_taxonomy(self): + tax = self.client.call(taxonomies.GetTaxonomy('category')) + self.assertTrue(isinstance(tax, WordPressTaxonomy)) + + @attr('taxonomies') + def test_taxonomy_fields_match(self): + """ + Check that the fields returned by singular and plural versions are the same. + """ + tax1 = self.client.call(taxonomies.GetTaxonomy('category')) + tax2 = None + + # find category taxonomy in the list of all taxonomies + taxs = self.client.call(taxonomies.GetTaxonomies()) + for tax in taxs: + if tax.name == 'category': + tax2 = tax + break + self.assertTrue(tax2 is not None) + + # compare the two field-by-field + for field in tax1.definition.keys(): + self.assertEqual(getattr(tax1, field), getattr(tax2, field)) diff --git a/wordpress_xmlrpc/methods/taxonomies.py b/wordpress_xmlrpc/methods/taxonomies.py new file mode 100644 index 0000000..eb3701e --- /dev/null +++ b/wordpress_xmlrpc/methods/taxonomies.py @@ -0,0 +1,30 @@ +from wordpress_xmlrpc.base import * +from wordpress_xmlrpc.mixins import * +from wordpress_xmlrpc.wordpress import WordPressTaxonomy + + +class GetTaxonomies(AuthenticatedMethod): + """ + Retrieve the list of available taxonomies for the blog. + + Parameters: + None + + Returns: `list` of `WordPressTaxonomy` instances. + """ + method_name = 'wp.getTaxonomies' + results_class = WordPressTaxonomy + + +class GetTaxonomy(AuthenticatedMethod): + """ + Retrieve an individual taxonomy. + + Parameters: + `taxonomy_name`: name of the taxonomy + + Returns: `WordPressTaxonomy` instance. + """ + method_name = 'wp.getTaxonomy' + method_args = ('taxonomy_name',) + results_class = WordPressTaxonomy diff --git a/wordpress_xmlrpc/wordpress.py b/wordpress_xmlrpc/wordpress.py index 6a5865d..8e55012 100644 --- a/wordpress_xmlrpc/wordpress.py +++ b/wordpress_xmlrpc/wordpress.py @@ -217,3 +217,22 @@ class WordPressOption(WordPressBase): def __str__(self): return '%s="%s"' % (self.name, self.value) + + +class WordPressTaxonomy(WordPressBase): + definition = { + 'name': 'name', + 'labels': 'labels', + 'hierarchical': 'hierarchical', + 'public': 'public', + 'query_var': 'query_var', + 'rewrite': 'rewrite', + 'show_ui': 'show_ui', + 'show_tagcloud': 'show_tagcloud', + 'show_in_nav_menus': 'show_in_nav_menus', + 'cap': 'cap', + 'is_builtin': '_builtin' + } + + def __str__(self): + return self.name From 2f63d1bac3d221e95270235fd233c67838dc0c76 Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 21 Jan 2012 10:39:38 -0500 Subject: [PATCH 02/15] Implemented wp.getTerms, wp.getTerm, wp.newTerm, wp.editTerm, and wp.deleteTerm. --- tests/test_taxonomies.py | 71 ++++++++++++++++++++++++- wordpress_xmlrpc/methods/taxonomies.py | 72 +++++++++++++++++++++++++- wordpress_xmlrpc/wordpress.py | 17 ++++++ 3 files changed, 158 insertions(+), 2 deletions(-) diff --git a/tests/test_taxonomies.py b/tests/test_taxonomies.py index 2371794..e8df501 100644 --- a/tests/test_taxonomies.py +++ b/tests/test_taxonomies.py @@ -3,7 +3,7 @@ from tests import WordPressTestCase from wordpress_xmlrpc.methods import taxonomies -from wordpress_xmlrpc.wordpress import WordPressTaxonomy +from wordpress_xmlrpc.wordpress import WordPressTaxonomy, WordPressTerm class TestTaxonomies(WordPressTestCase): @@ -37,3 +37,72 @@ def test_taxonomy_fields_match(self): # compare the two field-by-field for field in tax1.definition.keys(): self.assertEqual(getattr(tax1, field), getattr(tax2, field)) + + @attr('taxonomies') + @attr('terms') + def test_get_terms(self): + terms = self.client.call(taxonomies.GetTerms('category')) + self.assert_list_of_classes(terms, WordPressTerm) + + @attr('taxonomies') + @attr('terms') + def test_get_term(self): + term = self.client.call(taxonomies.GetTerm('category', 1)) + self.assertTrue(isinstance(term, WordPressTerm)) + + @attr('taxonomies') + @attr('terms') + def test_term_lifecycle(self): + term = WordPressTerm() + term.name = 'Test Term' + term.taxonomy = 'category' + + # create the term + term_id = self.client.call(taxonomies.NewTerm(term)) + self.assertTrue(term_id) + term.term_id = term_id + + # re-fetch to verify + term2 = self.client.call(taxonomies.GetTerm(term.taxonomy, term.term_id)) + self.assertEqual(term.name, term2.name) + + # set a description and save + term.description = "My test term" + response = self.client.call(taxonomies.EditTerm(term.term_id, term)) + self.assertTrue(response) + + # re-fetch to verify + term3 = self.client.call(taxonomies.GetTerm(term.taxonomy, term.term_id)) + self.assertEqual(term.description, term3.description) + + # delete the term + response = self.client.call(taxonomies.DeleteTerm(term.taxonomy, term.term_id)) + self.assertTrue(response) + + @attr('taxonomies') + @attr('terms') + def test_term_parent_child(self): + parent = WordPressTerm() + parent.taxonomy = 'category' + parent.name = 'Test Parent Term' + + parent_id = self.client.call(taxonomies.NewTerm(parent)) + self.assertTrue(parent_id) + parent.term_id = parent_id + + child = WordPressTerm() + child.taxonomy = parent.taxonomy + child.name = 'Test Child Term' + child.parent = parent.term_id + + child_id = self.client.call(taxonomies.NewTerm(child)) + self.assertTrue(child_id) + child.term_id = child_id + + # re-fetch to verify + child2 = self.client.call(taxonomies.GetTerm(child.taxonomy, child.term_id)) + self.assertEqual(child.parent, int(child2.parent)) + + # cleanup + self.client.call(taxonomies.DeleteTerm(child.taxonomy, child.term_id)) + self.client.call(taxonomies.DeleteTerm(parent.taxonomy, parent.term_id)) diff --git a/wordpress_xmlrpc/methods/taxonomies.py b/wordpress_xmlrpc/methods/taxonomies.py index eb3701e..aa3e6fc 100644 --- a/wordpress_xmlrpc/methods/taxonomies.py +++ b/wordpress_xmlrpc/methods/taxonomies.py @@ -1,6 +1,6 @@ from wordpress_xmlrpc.base import * from wordpress_xmlrpc.mixins import * -from wordpress_xmlrpc.wordpress import WordPressTaxonomy +from wordpress_xmlrpc.wordpress import WordPressTaxonomy, WordPressTerm class GetTaxonomies(AuthenticatedMethod): @@ -28,3 +28,73 @@ class GetTaxonomy(AuthenticatedMethod): method_name = 'wp.getTaxonomy' method_args = ('taxonomy_name',) results_class = WordPressTaxonomy + + +class GetTerms(AuthenticatedMethod): + """ + Retrieve the list of available terms for a taxonomy. + + Parameters: + `taxonomy_name`: name of the taxonomy + + Returns: `list` of `WordPressTerm` instances. + """ + method_name = 'wp.getTerms' + method_args = ('taxonomy_name',) + results_class = WordPressTerm + + +class GetTerm(AuthenticatedMethod): + """ + Retrieve an individual term. + + Parameters: + `taxonomy_name`: name of the taxonomy + `term_id`: ID of the term + + Returns: `WordPressTerm` instance. + """ + method_name = 'wp.getTerm' + method_args = ('taxonomy_name', 'term_id') + results_class = WordPressTerm + + +class NewTerm(AuthenticatedMethod): + """ + Create new term. + + Parameters: + `term`: instance of `WordPressTerm` + + Returns: ID of newly-created term (an integer). + """ + method_name = 'wp.newTerm' + method_args = ('term',) + + +class EditTerm(AuthenticatedMethod): + """ + Edit an existing term. + + Parameters: + `term_id`: ID of the term to edit. + `content`: A `WordPressTerm` instance with the new values for the term. + + Returns: `True` on successful edit. + """ + method_name = 'wp.editTerm' + method_args = ('term_id', 'content') + + +class DeleteTerm(AuthenticatedMethod): + """ + Delete a term. + + Parameters: + `taxonomy_name`: name of the taxonomy + `term_id`: ID of the term to delete. + + Returns: `True` on successful deletion. + """ + method_name = 'wp.deleteTerm' + method_args = ('taxonomy_name', 'term_id') diff --git a/wordpress_xmlrpc/wordpress.py b/wordpress_xmlrpc/wordpress.py index 8e55012..9a357fb 100644 --- a/wordpress_xmlrpc/wordpress.py +++ b/wordpress_xmlrpc/wordpress.py @@ -236,3 +236,20 @@ class WordPressTaxonomy(WordPressBase): def __str__(self): return self.name + + +class WordPressTerm(WordPressBase): + definition = { + 'term_id': 'term_id', + 'group': 'term_group', + 'taxonomy': 'taxonomy', + 'taxonomy_id': 'term_taxonomy_id', + 'name': 'name', + 'slug': 'slug', + 'description': 'description', + 'parent': 'parent', + 'count': IntegerFieldMap('count') + } + + def __str__(self): + return self.name From 4f1aa4efc4b30951bc333ba7cbee3e4d64478027 Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 21 Jan 2012 14:09:23 -0500 Subject: [PATCH 03/15] Implemented wp.getPostTerms and wp.setPostTerms. --- wordpress_xmlrpc/methods/taxonomies.py | 51 ++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/wordpress_xmlrpc/methods/taxonomies.py b/wordpress_xmlrpc/methods/taxonomies.py index aa3e6fc..ed6c4d5 100644 --- a/wordpress_xmlrpc/methods/taxonomies.py +++ b/wordpress_xmlrpc/methods/taxonomies.py @@ -98,3 +98,54 @@ class DeleteTerm(AuthenticatedMethod): """ method_name = 'wp.deleteTerm' method_args = ('taxonomy_name', 'term_id') + + +class GetPostTerms(AuthenticatedMethod): + """ + Retrieve list of terms assigned to a blog post. + + Parameters: + `post_id`: ID of the blog post + `group_by_taxonomy`: `bool` specifying whether to return terms grouped by taxonomy name + in a `dict` or as a flat list of `WordPressTerm`s + + Returns: Depends on value of `group_by_taxonomy`: + True: `dict`, with taxonomy names as keys and `list` of `WordPressTerm` instances as values. + False: `list` of `WordPressTerm` instances. + """ + method_name = 'wp.getPostTerms' + method_args = ('post_id', 'group_by_taxonomy') + results_class = WordPressTerm + + def process_result(self, raw_result): + if not self.group_by_taxonomy: + # flat list, so normal processing + return super(GetPostTerms, self).process_result(raw_result) + else: + # dictionary of taxonomy/terms. process each value individually + result = {} + for taxonomy, terms in raw_result.items(): + result[taxonomy] = super(GetPostTerms, self).process_result(terms) + return result + + +class SetPostTerms(AuthenticatedMethod): + """ + Assign a set of terms to a blog post. + + Parameters: + `post_id`: ID of the blog post + `terms`: `dict` with taxonomy names as keys and `list` of term IDs as values + + Returns: `True` on successful category assignment. + + Example: + >>> client.call(SetPostTerms(15, { + 'category': [1, 4, 199], + 'post_tag': [6, 21, 39], + 'custom_tax': [384] + })) + True + """ + method_name = 'wp.setPostTerms' + method_args = ('post_id', 'terms',) From c2a623f20278dde9184a684bdcbfe3dec0092c6d Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 21 Jan 2012 14:49:50 -0500 Subject: [PATCH 04/15] Switched users.GetUserInfo method to use new wp.getUserInfo interface instead of old blogger.getUserInfo. --- wordpress_xmlrpc/methods/users.py | 5 ++--- wordpress_xmlrpc/wordpress.py | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/wordpress_xmlrpc/methods/users.py b/wordpress_xmlrpc/methods/users.py index 00d8976..69ec3f9 100644 --- a/wordpress_xmlrpc/methods/users.py +++ b/wordpress_xmlrpc/methods/users.py @@ -3,7 +3,7 @@ from wordpress_xmlrpc.wordpress import WordPressBlog, WordPressAuthor, WordPressUser -class GetUserInfo(BloggerApiMethodMixin, AuthenticatedMethod): +class GetUserInfo(AuthenticatedMethod): """ Retrieve information about the connected user. @@ -12,8 +12,7 @@ class GetUserInfo(BloggerApiMethodMixin, AuthenticatedMethod): Returns: instance of `WordPressUser` representing the user whose credentials are being used with the XML-RPC API. """ - method_name = 'blogger.getUserInfo' - requires_blog = False + method_name = 'wp.getUserInfo' results_class = WordPressUser diff --git a/wordpress_xmlrpc/wordpress.py b/wordpress_xmlrpc/wordpress.py index 9a357fb..a8dd276 100644 --- a/wordpress_xmlrpc/wordpress.py +++ b/wordpress_xmlrpc/wordpress.py @@ -152,11 +152,20 @@ def __str__(self): class WordPressUser(WordPressBase): definition = { - 'user_id': 'userid', + 'user_id': 'user_id', + 'username': 'username', 'nickname': 'nickname', 'url': 'url', - 'first_name': 'firstname', - 'last_name': 'lastname', + 'first_name': 'first_name', + 'last_name': 'last_name', + 'registered': DateTimeFieldMap('registered'), + 'bio': 'bio', + 'email': 'email', + 'nicename': 'nicename', + 'display_name': 'display_name', + 'capabilities': 'capabilities', + 'user_level': 'user_level', + 'user_contacts': 'user_contacts' } def __str__(self): From cb99c3ebf6be586571ad82756201953b1691bd00 Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 21 Jan 2012 15:25:02 -0500 Subject: [PATCH 05/15] Added support for optional method arguments. --- wordpress_xmlrpc/base.py | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/wordpress_xmlrpc/base.py b/wordpress_xmlrpc/base.py index 4388701..83c6403 100644 --- a/wordpress_xmlrpc/base.py +++ b/wordpress_xmlrpc/base.py @@ -52,7 +52,8 @@ class XmlrpcMethod(object): Properties: `method_name`: XML-RPC method name (e.g., 'wp.getUserInfo') - `method_args`: Tuple of method-specific parameters + `method_args`: Tuple of method-specific required parameters + `optional_args`: Tuple of method-specific optional parameters `args_start_position`: If greater than zero, this many dummy arguments will pad the beginning of the method argument list. `default_args_position`: The index in the `method_args` list at which the default arguments should be inserted. `results_class`: Python class which will convert an XML-RPC response dict into an object @@ -63,19 +64,31 @@ class XmlrpcMethod(object): `process_results`: Performs actions on the raw result from the XML-RPC response. """ method_name = None - method_args = None + method_args = tuple() + optional_args = tuple() args_start_position = 0 default_args_position = 0 results_class = None def __init__(self, *args): - if self.method_args: - if len(args) != len(self.method_args): - raise ValueError("Invalid number of parameters to %s" % self.method_name) + if self.method_args or self.optional_args: + if self.optional_args: + max_num_args = len(self.method_args) + len(self.optional_args) + if not ( len(self.method_args) <= len(args) <= max_num_args ): + raise ValueError("Invalid number of parameters to %s" % self.method_name) + else: + if len(args) != len(self.method_args): + raise ValueError("Invalid number of parameters to %s" % self.method_name) for i, arg_name in enumerate(self.method_args): setattr(self, arg_name, args[i]) + if self.optional_args: + for i, arg_name in enumerate(self.optional_args, start=len(self.method_args)): + if i >= len(args): + break + setattr(self, arg_name, args[i]) + def default_args(self, client): """ Builds set of method-non-specific arguments. @@ -90,14 +103,16 @@ def get_args(self, client): """ default_args = self.default_args(client) - if self.method_args: + if self.method_args or self.optional_args: + optional_args = getattr(self, 'optional_args', tuple()) args = [] - for arg in self.method_args: - obj = getattr(self, arg) - if hasattr(obj, 'struct'): - args.append(obj.struct) - else: - args.append(obj) + for arg in (self.method_args + optional_args): + if hasattr(self, arg): + obj = getattr(self, arg) + if hasattr(obj, 'struct'): + args.append(obj.struct) + else: + args.append(obj) args = args[:self.default_args_position] + list(default_args) + args[self.default_args_position:] else: args = default_args From 73d60e404ebef994f8380cceb54ea30e42bbe30d Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 21 Jan 2012 15:37:24 -0500 Subject: [PATCH 06/15] Implemented wp.getUsers and wp.getUser. --- wordpress_xmlrpc/methods/users.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/wordpress_xmlrpc/methods/users.py b/wordpress_xmlrpc/methods/users.py index 69ec3f9..e6451d3 100644 --- a/wordpress_xmlrpc/methods/users.py +++ b/wordpress_xmlrpc/methods/users.py @@ -41,3 +41,34 @@ class GetAuthors(AuthenticatedMethod): """ method_name = 'wp.getAuthors' results_class = WordPressAuthor + + +class GetUsers(AuthenticatedMethod): + """ + Retrieve list of users in the blog. + + Parameters: + `filter`: (optional) `dict` of filters to modify the query. Valid keys are 'number', 'offset', and 'role'. + `fields`: (optional) `list` of fields to return. Specific fields, or groups 'basic' or 'all'. + + Returns: `list` of `WordPressUser` instances. + """ + method_name = 'wp.getUsers' + optional_args = ('filter', 'fields') + results_class = WordPressUser + + +class GetUser(AuthenticatedMethod): + """ + Retrieve an individual user. + + Parameters: + `user_id`: ID of the user + `fields`: (optional) `list` of fields to return. Specific fields, or groups 'basic' or 'all'. + + Returns: `WordPressUser` instance. + """ + method_name = 'wp.getUser' + method_args = ('user_id',) + optional_args = ('fields',) + results_class = WordPressUser From e600cba67ae69ef21e33c9e0f5b3cb9c0319caa8 Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 21 Jan 2012 15:39:59 -0500 Subject: [PATCH 07/15] PEP8 whitespace fix. --- wordpress_xmlrpc/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wordpress_xmlrpc/base.py b/wordpress_xmlrpc/base.py index 83c6403..7c96af8 100644 --- a/wordpress_xmlrpc/base.py +++ b/wordpress_xmlrpc/base.py @@ -74,7 +74,7 @@ def __init__(self, *args): if self.method_args or self.optional_args: if self.optional_args: max_num_args = len(self.method_args) + len(self.optional_args) - if not ( len(self.method_args) <= len(args) <= max_num_args ): + if not (len(self.method_args) <= len(args) <= max_num_args): raise ValueError("Invalid number of parameters to %s" % self.method_name) else: if len(args) != len(self.method_args): From 9d38237f90144bcaa3e8e69d977beea6e122bf0a Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 21 Jan 2012 16:10:57 -0500 Subject: [PATCH 08/15] Implemented wp.newUser, wp.editUser, and wp.deleteUser. --- tests/test_users.py | 23 +++++++++++++++++ wordpress_xmlrpc/methods/users.py | 42 +++++++++++++++++++++++++++++++ wordpress_xmlrpc/wordpress.py | 2 ++ 3 files changed, 67 insertions(+) diff --git a/tests/test_users.py b/tests/test_users.py index f3cc8be..7f45512 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -23,3 +23,26 @@ def test_get_user_blogs(self): def test_get_authors(self): authors = self.client.call(users.GetAuthors()) self.assert_list_of_classes(authors, WordPressAuthor) + + @attr('users') + def test_user_lifecycle(self): + user = WordPressUser() + user.username = 'harrietsmith' + user.password = 'mysecretpassword' + user.email = 'harriet.smith@example.com' + user.role = 'subscriber' + user.last_name = 'Smith' + user_id = self.client.call(users.NewUser(user)) + self.assertTrue(user_id) + user.user_id = user_id + + user.first_name = 'Harriet' + response = self.client.call(users.EditUser(user.user_id, user)) + self.assertTrue(response) + + # re-fetch to confirm + user2 = self.client.call(users.GetUser(user.user_id)) + self.assertEqual(user.first_name, user2.first_name) + + response = self.client.call(users.DeleteUser(user.user_id)) + self.assertTrue(response) diff --git a/wordpress_xmlrpc/methods/users.py b/wordpress_xmlrpc/methods/users.py index e6451d3..afb66bd 100644 --- a/wordpress_xmlrpc/methods/users.py +++ b/wordpress_xmlrpc/methods/users.py @@ -72,3 +72,45 @@ class GetUser(AuthenticatedMethod): method_args = ('user_id',) optional_args = ('fields',) results_class = WordPressUser + + +class NewUser(AuthenticatedMethod): + """ + Create new user on the blog. + + Parameters: + `user`: A `WordPressUser` instance with at least `username`, `password`, and `email`. + `send_mail`: (optional) Send a confirmation email to the new user. + + Returns: ID of the newly-created blog user (an integer). + """ + method_name = 'wp.newUser' + method_args = ('user',) + optional_args = ('send_mail',) + + +class EditUser(AuthenticatedMethod): + """ + Edit an existing blog post. + + Parameters: + `user_id`: ID of the user to edit. + `user`: `WordPressUser` instance. + + Returns: `True` on successful edit. + """ + method_name = 'wp.editUser' + method_args = ('user_id', 'user') + + +class DeleteUser(AuthenticatedMethod): + """ + Delete a blog user. + + Parameters: + `user_id`: ID of the blog user to delete. + + Returns: `True` on successful deletion. + """ + method_name = 'wp.deleteUser' + method_args = ('user_id',) diff --git a/wordpress_xmlrpc/wordpress.py b/wordpress_xmlrpc/wordpress.py index a8dd276..ccb6998 100644 --- a/wordpress_xmlrpc/wordpress.py +++ b/wordpress_xmlrpc/wordpress.py @@ -154,6 +154,8 @@ class WordPressUser(WordPressBase): definition = { 'user_id': 'user_id', 'username': 'username', + 'password': 'password', + 'role': 'role', 'nickname': 'nickname', 'url': 'url', 'first_name': 'first_name', From 3d206a7cea5b36d09e7746295803d43620d59901 Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 21 Jan 2012 16:27:26 -0500 Subject: [PATCH 09/15] Implemented wp.getPostTypes and wp.getPostType. --- tests/test_posts.py | 12 +++++++++++- wordpress_xmlrpc/methods/posts.py | 29 ++++++++++++++++++++++++++++- wordpress_xmlrpc/wordpress.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/tests/test_posts.py b/tests/test_posts.py index 47de838..e7a4abc 100644 --- a/tests/test_posts.py +++ b/tests/test_posts.py @@ -3,7 +3,7 @@ from tests import WordPressTestCase from wordpress_xmlrpc.methods import posts -from wordpress_xmlrpc.wordpress import WordPressPost +from wordpress_xmlrpc.wordpress import WordPressPost, WordPressPostType class TestPosts(WordPressTestCase): @@ -58,3 +58,13 @@ def test_post_lifecycle(self): # delete the post response = self.client.call(posts.DeletePost(post_id)) self.assertTrue(response) + + @attr('post_types') + def test_get_post_types(self): + post_types = self.client.call(posts.GetPostTypes()) + self.assert_list_of_classes(post_types, WordPressPostType) + + @attr('post_types') + def test_get_post_type(self): + post_type = self.client.call(posts.GetPostType('post')) + self.assertTrue(isinstance(post_type, WordPressPostType)) diff --git a/wordpress_xmlrpc/methods/posts.py b/wordpress_xmlrpc/methods/posts.py index 9aee5b8..73e4148 100644 --- a/wordpress_xmlrpc/methods/posts.py +++ b/wordpress_xmlrpc/methods/posts.py @@ -1,6 +1,6 @@ from wordpress_xmlrpc.base import * from wordpress_xmlrpc.mixins import * -from wordpress_xmlrpc.wordpress import WordPressPost +from wordpress_xmlrpc.wordpress import WordPressPost, WordPressPostType class GetRecentPosts(AuthenticatedMethod): @@ -123,3 +123,30 @@ class PublishPost(AuthParamsOffsetMixin, AuthenticatedMethod): """ method_name = 'mt.publishPost' method_args = ('post_id',) + + +class GetPostTypes(AuthenticatedMethod): + """ + Retrieve a list of post types used by the blog. + + Parameters: + None + + Returns: `list` of `WordPressPostType` instances. + """ + method_name = 'wp.getPostTypes' + results_class = WordPressPostType + + +class GetPostType(AuthenticatedMethod): + """ + Retrieve an individual blog post type. + + Parameters: + `post_type_name`: Name of the blog post type to retrieve. + + Returns: `WordPressPostType` instance. + """ + method_name = 'wp.getPostType' + method_args = ('post_type_name',) + results_class = WordPressPostType diff --git a/wordpress_xmlrpc/wordpress.py b/wordpress_xmlrpc/wordpress.py index ccb6998..a00eb48 100644 --- a/wordpress_xmlrpc/wordpress.py +++ b/wordpress_xmlrpc/wordpress.py @@ -264,3 +264,31 @@ class WordPressTerm(WordPressBase): def __str__(self): return self.name + + +class WordPressPostType(WordPressBase): + definition = { + 'name': 'name', + 'label': 'label', + 'labels': 'labels', + 'cap': 'cap', + 'capability_type': 'capability_type', + 'description': 'description', + 'exclude_from_search': 'exclude_from_search', + 'has_archive': 'has_archive', + 'hierarchical': 'hierarchical', + 'menu_icon': 'menu_icon', + 'menu_position': 'menu_position', + 'public': 'public', + 'publicly_queryable': 'publicly_queryable', + 'query_var': 'query_var', + 'rewrite': 'rewrite', + 'show_in_menu': 'show_in_menu', + 'show_in_nav_menus': 'show_in_nav_menus', + 'show_ui': 'show_ui', + 'taxonomies': 'taxonomies', + 'is_builtin': '_builtin' + } + + def __str__(self): + return self.label From 9fec3837d9553b1828d2828b0daae963f9a9e60b Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 21 Jan 2012 16:38:13 -0500 Subject: [PATCH 10/15] Added support for wp.deleteUser's 'reassign_id' parameter. --- wordpress_xmlrpc/methods/users.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wordpress_xmlrpc/methods/users.py b/wordpress_xmlrpc/methods/users.py index afb66bd..6a9d99d 100644 --- a/wordpress_xmlrpc/methods/users.py +++ b/wordpress_xmlrpc/methods/users.py @@ -109,8 +109,10 @@ class DeleteUser(AuthenticatedMethod): Parameters: `user_id`: ID of the blog user to delete. + `reassign_id`: ID of the blog user to reassign this user's posts to. Returns: `True` on successful deletion. """ method_name = 'wp.deleteUser' method_args = ('user_id',) + optional_args = ('reassign_id',) From 54730aaf6b76aa32ef041301885ac5267889b409 Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 21 Jan 2012 16:43:56 -0500 Subject: [PATCH 11/15] Updated README with new methods for this branch. --- README.rst | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index df5bcdc..da7b373 100644 --- a/README.rst +++ b/README.rst @@ -17,7 +17,8 @@ NOTE: The XML-RPC API is disabled in WordPress by default. To enable, go to Settings->Writing->Remote Publishing and check the box for XML-RPC. -This library was developed against and tested on WordPress 3.2. +This branch of python-wordpress-xmlrpc is tested on trunk of +WordPress 3.4 with the wp-xmlrpc-modernization plugin installed. This library is only compatible with Python 2.x. Usage @@ -115,6 +116,9 @@ Available classes: * WordPressTag * WordPressMedia * WordPressOption +* WordPressTaxonomy +* WordPressTerm +* WordPressPostType XML-RPC Methods --------------- @@ -133,6 +137,8 @@ methods.posts * GetPostStatusList() * GetPostFormats() - requires WordPress 3.2 or newer * PublishPost(post_id) +* GetPostTypes() - requires wp-xmlrpc-modernization plugin +* GetPostType(post_type_name) - requires wp-xmlrpc-modernization plugin methods.pages ~~~~~~~~~~~~~ @@ -156,6 +162,19 @@ methods.categories * SetPostCategories(post_id, categories) * GetTags() +methods.taxonomies - requires wp-xmlrpc-modernization plugin +~~~~~~~~~~~~~~~~~~ + +* GetTaxonomies() +* GetTaxonomy(taxonomy_name) +* GetTerms(taxonomy_name) +* GetTerm(taxonomy_name, term_id) +* NewTerm(term) +* EditTerm(term_id, term) +* DeleteTerm(taxonomy_name, term_id) +* GetPostTerms(post_id, group_by_taxonomy) +* SetPostTerms(post_id, terms) + methods.comments ~~~~~~~~~~~~~~~~ @@ -173,6 +192,11 @@ methods.users * GetUserInfo() * GetUsersBlogs() * GetAuthors() +* GetUsers([filter, fields]) - requires wp-xmlrpc-modernization plugin +* GetUser(user_id[, fields]) - requires wp-xmlrpc-modernization plugin +* NewUser(user[, send_mail]) - requires wp-xmlrpc-modernization plugin +* EditUser(user_id, user) - requires wp-xmlrpc-modernization plugin +* DeleteUser(user_id[, reassign_id]) - requires wp-xmlrpc-modernization plugin methods.media ~~~~~~~~~~~~~ From 0a93933d3f90031f1bcd30d59449bae809b0aedd Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Fri, 20 Apr 2012 14:36:12 -0300 Subject: [PATCH 12/15] Expose the GMT version of date_created field on WordPressPost. This is a temporary fix for a user until the modernization branch is aligned with master branch's v2 changes. --- wordpress_xmlrpc/wordpress.py | 1 + 1 file changed, 1 insertion(+) diff --git a/wordpress_xmlrpc/wordpress.py b/wordpress_xmlrpc/wordpress.py index a00eb48..e4879d6 100644 --- a/wordpress_xmlrpc/wordpress.py +++ b/wordpress_xmlrpc/wordpress.py @@ -53,6 +53,7 @@ class WordPressPost(WordPressBase): 'id': 'postid', 'user': 'wp_author_id', 'date_created': DateTimeFieldMap('dateCreated'), + 'date_created_gmt': DateTimeFieldMap('date_created_gmt'), 'slug': 'wp_slug', 'post_status': 'post_status', 'title': 'title', From 1458f3c2558578cbfee4452ec002935ae404f845 Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 12 May 2012 17:35:08 -0400 Subject: [PATCH 13/15] Changed WordPressUser 'user_id' to 'id'. --- tests/test_users.py | 8 ++++---- wordpress_xmlrpc/wordpress.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_users.py b/tests/test_users.py index 7f45512..7f864db 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -34,15 +34,15 @@ def test_user_lifecycle(self): user.last_name = 'Smith' user_id = self.client.call(users.NewUser(user)) self.assertTrue(user_id) - user.user_id = user_id + user.id = user_id user.first_name = 'Harriet' - response = self.client.call(users.EditUser(user.user_id, user)) + response = self.client.call(users.EditUser(user.id, user)) self.assertTrue(response) # re-fetch to confirm - user2 = self.client.call(users.GetUser(user.user_id)) + user2 = self.client.call(users.GetUser(user.id)) self.assertEqual(user.first_name, user2.first_name) - response = self.client.call(users.DeleteUser(user.user_id)) + response = self.client.call(users.DeleteUser(user.id)) self.assertTrue(response) diff --git a/wordpress_xmlrpc/wordpress.py b/wordpress_xmlrpc/wordpress.py index 67eef96..ff0ebb3 100644 --- a/wordpress_xmlrpc/wordpress.py +++ b/wordpress_xmlrpc/wordpress.py @@ -170,7 +170,7 @@ def __str__(self): class WordPressUser(WordPressBase): definition = { - 'user_id': 'user_id', + 'id': 'user_id', 'username': 'username', 'password': 'password', 'role': 'role', From 379fd43f120a56d247b2a4f9581f0d63decdb3b6 Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Sat, 12 May 2012 17:41:17 -0400 Subject: [PATCH 14/15] Updated docs to cover plugin's users methods. --- docs/ref/methods.rst | 5 +++++ docs/ref/wordpress.rst | 11 +++++++++++ wordpress_xmlrpc/methods/users.py | 14 +++++++++----- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/docs/ref/methods.rst b/docs/ref/methods.rst index e53ad5c..555ea63 100644 --- a/docs/ref/methods.rst +++ b/docs/ref/methods.rst @@ -60,6 +60,11 @@ methods.users .. autoclass:: GetUserInfo() .. autoclass:: GetUsersBlogs() .. autoclass:: GetAuthors() + .. autoclass:: GetUsers([filter, fields]) + .. autoclass:: GetUser(user_id[, fields]) + .. autoclass:: NewUser(user) + .. autoclass:: EditUser(user_id, user) + .. autoclass:: DeleteUser(user_id[, reassign_id]) methods.media ------------- diff --git a/docs/ref/wordpress.rst b/docs/ref/wordpress.rst index 53a1a7a..027bb42 100644 --- a/docs/ref/wordpress.rst +++ b/docs/ref/wordpress.rst @@ -121,10 +121,21 @@ WordPressUser Basic representation of a WordPress user. * id + * username + * password + * role * nickname * url * first_name * last_name + * registered + * bio + * email + * nicename + * display_name + * capabilities + * user_level + * user_contacts WordPressComment ---------------- diff --git a/wordpress_xmlrpc/methods/users.py b/wordpress_xmlrpc/methods/users.py index 1da7f9b..5b9e36b 100644 --- a/wordpress_xmlrpc/methods/users.py +++ b/wordpress_xmlrpc/methods/users.py @@ -51,10 +51,14 @@ class GetUsers(AuthenticatedMethod): Retrieve list of users in the blog. Parameters: - `filter`: (optional) `dict` of filters to modify the query. Valid keys are 'number', 'offset', and 'role'. - `fields`: (optional) `list` of fields to return. Specific fields, or groups 'basic' or 'all'. + `filter`: optional `dict` of filters: + * `number` + * `offset` + * `role` + + `fields`: optional `list` of fields to return. Specific fields, or groups 'basic' or 'all'. - Returns: `list` of `WordPressUser` instances. + Returns: `list` of :class:`WordPressUser` instances. """ method_name = 'wp.getUsers' optional_args = ('filter', 'fields') @@ -69,7 +73,7 @@ class GetUser(AuthenticatedMethod): `user_id`: ID of the user `fields`: (optional) `list` of fields to return. Specific fields, or groups 'basic' or 'all'. - Returns: `WordPressUser` instance. + Returns: :class:`WordPressUser` instance. """ method_name = 'wp.getUser' method_args = ('user_id',) @@ -82,7 +86,7 @@ class NewUser(AuthenticatedMethod): Create new user on the blog. Parameters: - `user`: A `WordPressUser` instance with at least `username`, `password`, and `email`. + `user`: A :class:`WordPressUser` instance with at least `username`, `password`, and `email`. `send_mail`: (optional) Send a confirmation email to the new user. Returns: ID of the newly-created blog user (an integer). From e0b6aeac24878ee6b17dddf85758f73147d5936e Mon Sep 17 00:00:00 2001 From: Max Cutler Date: Tue, 3 Jul 2012 09:26:23 -0300 Subject: [PATCH 15/15] Removed erroneous mixins import statement. --- wordpress_xmlrpc/methods/users.py | 1 - 1 file changed, 1 deletion(-) diff --git a/wordpress_xmlrpc/methods/users.py b/wordpress_xmlrpc/methods/users.py index 5b9e36b..f63bf53 100644 --- a/wordpress_xmlrpc/methods/users.py +++ b/wordpress_xmlrpc/methods/users.py @@ -1,5 +1,4 @@ from wordpress_xmlrpc.base import * -from wordpress_xmlrpc.mixins import * from wordpress_xmlrpc.wordpress import WordPressBlog, WordPressAuthor, WordPressUser