Skip to content

Conversation

@autoreleasefool
Copy link
Contributor

See: https://developer.box.com/v2.0/reference#recent-item-object

Use the Client to retrieve a user's recently accessed items on Box.

RecentItem class allows the translator to correctly instantiate the item returned by the API, which has the field type='recent_item'. This provides some additional fields, and access to the underlying File/Folder as the property RecentItem.item

@boxcla
Copy link

boxcla commented Jul 5, 2017

Verified that @josephroque has signed the CLA. Thanks for the pull request!

response_object=response,
)

@api_call
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears this endpoint uses marker based paging, not limit/offset.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 waiting on #212 to rebase

`Iterable` of `unicode`
:returns:
A list of the user's recently accessed items.
:rtype:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this returns a list of RecentItem, right?

The index at which to start returning items.
:type offset:
`int`
:param fields:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention that the fields apply to the recent item object, not to the underlying file or folder.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, these do apply to the underlying file or folder. I'll mention that. The recent_item type always has the same fields, but returns the 'mini' file/folder format by default, so this is to request more fields. It's similarly unclear in the API documentation, but that is what it does in practice. I'll update this to be more clear.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, cool.

A list of the user's recently accessed items.
:rtype:
`list` of :class:`Item`
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be self.get_url('recent_items')

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything else in the file follows the format used here. Should I still change it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to you, I guess. Most of the other things in this file predate being able to use self.get_url

item = item_class(
session=self._session,
object_id=item_json['id'],
object_id=item_json['id'] if 'id' in item_json else None,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that RecentItem is not a subclass of BaseObject because most of the functionality provided by BaseObject does not apply to to recent items (o way to GET individual recent items, no way to update). Finally, recent items from the API do not have unique IDs associated with them, so there's no way to get item_json['id']

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can do something like this:

item_class = self._translator.translate(item_json['type'])
kwargs = {}
if issubclass(item_class, BaseEndpoint):
    kwargs['session'] = self._session
if issubclass(item_class, BaseObject):
    kwargs['object_id'] = item_json['id'] if 'id' in item_json else None
item = item_class(response_object=item_json, **kwargs)

It's not great, but it should work, for now. Eventually we'll make something nicer than this for #140 .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is what's going to be necessary - solves the **kwargs in RecentItem as well.

response_object=response,
)

@api_call
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add **kwargs, and pass that to MarkerBasedObjectCollection. And then remove return_full_pages=True below, since that's a decision that the client, not the SDK, should make.

Depending on your personal preference, you could remove limit, marker, and fields, and leave them all for **kwargs. Or you can leave it as-is.

limit=limit,
fields=fields,
marker=marker,
return_full_pages=True,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if this is necessary, I believe it defaults to False.

response_object=item,
)

def get_url(self, *args):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed? As you said, this isn't a BaseObject, so we'll never be calling API endpoints for this object.


_item_type = 'recent_item'

def __init__(self, session, response_object=None, **kwargs):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't accept **kwargs unless we're willing to do something with it.

Doing this is just a hack around the fact that we're passing object_id to it..

We should solve that problem a different way.

And if we remove **kwargs, then you can actually just remove this method override altogether, since it isn't doing anything other than calling super.

item = item_class(
session=self._session,
object_id=item_json['id'],
object_id=item_json['id'] if 'id' in item_json else None,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can do something like this:

item_class = self._translator.translate(item_json['type'])
kwargs = {}
if issubclass(item_class, BaseEndpoint):
    kwargs['session'] = self._session
if issubclass(item_class, BaseObject):
    kwargs['object_id'] = item_json['id'] if 'id' in item_json else None
item = item_class(response_object=item_json, **kwargs)

It's not great, but it should work, for now. Eventually we'll make something nicer than this for #140 .

def marker_id():
return 'marker_1'


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this break if it is a module fixture? Because the Mock will retain its call spec between tests if we do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This user_response object was pre-existing, git just reports me as adding it. I added the lines above, with the @pytext.fixture from there. So for the comment on scope below, I followed suit from this line you're commenting on here. Additionally, I believe most of these fixtures are used in a read-only sense, so reuse of them in the tests is inconsequential.

return mock_network_response


@pytest.fixture(scope='module')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this doesn't seem like something that should be module scoped.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above

'entries': [
{'type': 'recent_item', 'item': {'type': 'file', 'id': file_id}}
],
'next_marker': marker_id,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Providing a next_marker implies that there are more results coming. So if you try paging, it'll try to make a second API call, which doesn't seem like what you want.

"item": {"type": "file", "id": mock_object_id}
})
assert recent_item['type'] == 'recent_item'
assert recent_item.item.object_id == mock_object_id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also assert recent_item.item.session is mock_box_session?

response_object=response,
)

@api_call
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In docstring, document that **kwargs are passed to MarkerBasedObjectCollection.

We could also call this **collection_kwargs or **paging_kwargs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, I was going to do this, but noticed it wasn't done that way somewhere else, so I thought it might be like, a standard.

@jmoldow jmoldow merged commit ea32ba5 into box:master Jul 20, 2017
mattwiller pushed a commit that referenced this pull request Jun 28, 2018
See: https://developer.box.com/v2.0/reference#recent-item-object

Use the Client to retrieve a user's recently accessed items on Box.

`RecentItem` class allows the translator to correctly instantiate the item returned by the API, which has the field `type='recent_item'`. This provides some additional fields, and access to the underlying File/Folder as the property `RecentItem.item`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants