Skip to content

Commit b8f1e1f

Browse files
author
dhermes@google.com
committed
Adding support for Content API Users Feed. (Issue 6295071)
1 parent 2e4e9d8 commit b8f1e1f

2 files changed

Lines changed: 113 additions & 38 deletions

File tree

src/gdata/contentforshopping/client.py

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
#!/usr/bin/python
23
#
34
# Copyright (C) 2010-2011 Google Inc.
@@ -15,26 +16,23 @@
1516
# limitations under the License.
1617

1718

18-
"""Extend the gdata client for the Content API for Shopping.
19-
20-
TODO:
21-
22-
1. Proper MCA Support.
23-
2. Add classes for datafeed functions instead of asking for raw XML.
24-
"""
19+
"""Extend the gdata client for the Content API for Shopping."""
2520

2621

2722
__author__ = 'afshar (Ali Afshar), dhermes (Daniel Hermes)'
2823

2924

30-
import atom.data
25+
import urllib
26+
3127
import gdata.client
3228
from gdata.contentforshopping.data import ClientAccount
3329
from gdata.contentforshopping.data import ClientAccountFeed
3430
from gdata.contentforshopping.data import DatafeedEntry
3531
from gdata.contentforshopping.data import DatafeedFeed
3632
from gdata.contentforshopping.data import ProductEntry
3733
from gdata.contentforshopping.data import ProductFeed
34+
from gdata.contentforshopping.data import UsersEntry
35+
from gdata.contentforshopping.data import UsersFeed
3836

3937

4038
CFS_VERSION = 'v1'
@@ -75,7 +73,7 @@ def _create_uri(self, account_id, resource, path=(), use_projection=True,
7573
segments = [CFS_URI, self.cfs_api_version, account_id, resource]
7674
if use_projection:
7775
segments.append(CFS_PROJECTION)
78-
segments.extend(path)
76+
segments.extend(urllib.quote(value) for value in path)
7977
result = '/'.join(segments)
8078

8179
request_params = []
@@ -482,3 +480,85 @@ def delete_client_account(self, client_account_id, account_id=None,
482480
return self.delete(uri, auth_token=auth_token)
483481

484482
DeleteClientAccount = delete_client_account
483+
484+
def get_users_feed(self, account_id=None, auth_token=None):
485+
"""Get the users feed for an account.
486+
487+
:param account_id: The Merchant Center Account ID. If ommitted the default
488+
Account ID will be used for this client
489+
:param auth_token: An object which sets the Authorization HTTP header in its
490+
modify_request method.
491+
"""
492+
493+
uri = self._create_uri(account_id, 'users', use_projection=False)
494+
return self.get_feed(uri, auth_token=auth_token, desired_class=UsersFeed)
495+
496+
GetUsersFeed = get_users_feed
497+
498+
def get_users_entry(self, user_email, account_id=None, auth_token=None):
499+
"""Get a users feed entry for an account.
500+
501+
:param user_email: Email of the user entry to be retrieved.
502+
:param account_id: The Merchant Center Account ID. If ommitted the default
503+
Account ID will be used for this client
504+
:param auth_token: An object which sets the Authorization HTTP header in its
505+
modify_request method.
506+
"""
507+
uri = self._create_uri(
508+
account_id, 'users', path=[user_email], use_projection=False)
509+
return self.get_entry(uri, auth_token=auth_token, desired_class=UsersEntry)
510+
511+
GetUsersEntry = get_users_entry
512+
513+
def insert_users_entry(self, entry, account_id=None, auth_token=None):
514+
"""Insert a users feed entry for an account.
515+
516+
:param entry: A :class:`gdata.contentforshopping.data.UsersEntry` with
517+
the required user data.
518+
:param account_id: The Merchant Center Account ID. If ommitted the default
519+
Account ID will be used for this client
520+
:param auth_token: An object which sets the Authorization HTTP header in its
521+
modify_request method.
522+
"""
523+
uri = self._create_uri(account_id, 'users', use_projection=False)
524+
return self.post(entry, uri=uri, auth_token=auth_token)
525+
526+
InsertUsersEntry = insert_users_entry
527+
528+
def update_users_entry(self, entry, account_id=None, auth_token=None):
529+
"""Update a users feed entry for an account.
530+
531+
:param entry: A :class:`gdata.contentforshopping.data.UsersEntry` with
532+
the required user data.
533+
:param account_id: The Merchant Center Account ID. If ommitted the default
534+
Account ID will be used for this client
535+
:param auth_token: An object which sets the Authorization HTTP header in its
536+
modify_request method.
537+
"""
538+
# Could also use entry.find_edit_link() but that is inconsistent
539+
# with the rest of the module
540+
user_email = entry.title.text
541+
uri = self._create_uri(
542+
account_id, 'users', path=[user_email], use_projection=False)
543+
return self.update(entry, uri=uri, auth_token=auth_token)
544+
545+
UpdateUsersEntry = update_users_entry
546+
547+
def delete_users_entry(self, entry, account_id=None, auth_token=None):
548+
"""Delete a users feed entry for an account.
549+
550+
:param entry: A :class:`gdata.contentforshopping.data.UsersEntry` with
551+
the required user data.
552+
:param account_id: The Merchant Center Account ID. If ommitted the default
553+
Account ID will be used for this client
554+
:param auth_token: An object which sets the Authorization HTTP header in its
555+
modify_request method.
556+
"""
557+
# Could also use entry.find_edit_link() but that is inconsistent
558+
# with the rest of the module
559+
user_email = entry.title.text
560+
uri = self._create_uri(
561+
account_id, 'users', path=[user_email], use_projection=False)
562+
return self.delete(uri, auth_token=auth_token)
563+
564+
DeleteUsersEntry = delete_users_entry

src/gdata/contentforshopping/data.py

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import gdata.data
2828

2929

30-
ATOM_NAMESPACE = 'http://www.w3.org/2005/Atom'
3130
GD_NAMESPACE = 'http://schemas.google.com/g/2005'
3231
GD_NAMESPACE_TEMPLATE = '{http://schemas.google.com/g/2005}%s'
3332
SC_NAMESPACE_TEMPLATE = ('{http://schemas.google.com/'
@@ -170,19 +169,6 @@ class ExcludedDestination(atom.core.XmlElement):
170169
_qname = SC_NAMESPACE_TEMPLATE % 'excluded_destination'
171170
dest = 'dest'
172171

173-
174-
class Status(atom.core.XmlElement):
175-
"""sc:status element
176-
177-
This element defines the status of an element in a particular destination. It
178-
has a destination and an actual status such as enlisted, review, or
179-
disapproved.
180-
"""
181-
_qname = SC_NAMESPACE_TEMPLATE % 'status'
182-
dest = 'dest'
183-
status = 'status'
184-
185-
186172
# Warning Attributes (to be used with app:control element)
187173

188174
class Code(atom.core.XmlElement):
@@ -271,7 +257,6 @@ class ProductControl(atom.data.Control):
271257
required_destination = [RequiredDestination]
272258
validate_destination = [ValidateDestination]
273259
excluded_destination = [ExcludedDestination]
274-
statuses = [Status]
275260
warnings = Warnings
276261

277262
# Content API for Shopping, product (scp) attributes
@@ -1108,20 +1093,7 @@ class ContentForShoppingError(atom.core.XmlElement):
11081093
code = ErrorCode
11091094
location = ErrorLocation
11101095
internal_reason = InternalReason
1111-
1112-
@property
1113-
def id(self):
1114-
"""Id for error element.
1115-
1116-
The namespace for the id element is different in batch requests than in
1117-
individual requests, so we need to consider either case.
1118-
"""
1119-
for element in self.GetElements():
1120-
if element.tag == 'id':
1121-
if element.namespace in (GD_NAMESPACE, ATOM_NAMESPACE):
1122-
return element.text
1123-
1124-
return None
1096+
id = atom.data.Id
11251097

11261098

11271099
class ContentForShoppingErrors(atom.core.XmlElement):
@@ -1268,3 +1240,26 @@ class ClientAccountFeed(gdata.data.GDFeed):
12681240
"""A multiclient account feed
12691241
"""
12701242
entry = [ClientAccount]
1243+
1244+
1245+
# Users Feed Classes
1246+
class Admin(atom.core.XmlElement):
1247+
"""sc:admin element"""
1248+
_qname = SC_NAMESPACE_TEMPLATE % 'admin'
1249+
1250+
1251+
class Permission(atom.core.XmlElement):
1252+
"""sc:permission element"""
1253+
_qname = SC_NAMESPACE_TEMPLATE % 'permission'
1254+
scope = 'scope'
1255+
1256+
1257+
class UsersEntry(gdata.data.GDEntry):
1258+
"""A User Management Feed entry."""
1259+
admin = Admin
1260+
permission = [Permission]
1261+
1262+
1263+
class UsersFeed(gdata.data.GDFeed):
1264+
"""A User Management Feed."""
1265+
entry = [UsersEntry]

0 commit comments

Comments
 (0)