Skip to content

Commit d70169b

Browse files
🎉 Live Preview
1 parent 12f029b commit d70169b

File tree

7 files changed

+106
-23
lines changed

7 files changed

+106
-23
lines changed

contentstack/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@
1818
__title__ = 'contentstack-python'
1919
__author__ = 'Contentstack'
2020
__status__ = 'debug'
21-
__version__ = '1.7.0'
21+
__version__ = '1.8.0'
2222
__endpoint__ = 'cdn.contentstack.io'
2323
__email__ = 'shailesh.mishra@contentstack.com'

contentstack/https_connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def get(self, url):
5858

5959
"""
6060
Here we create a response object, `response` which will store the request-response.
61-
We use requests.get method since we are sending a GET request.
61+
We use requests. Get method since we are sending a GET request.
6262
The four arguments we pass are url, verify(ssl), timeout, headers
6363
"""
6464
try:

contentstack/query.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
"""
22
Contentstack provides certain queries that you can use to fetch filtered results
33
"""
4+
45
import enum
56
import json
67
import logging
78
from urllib import parse
9+
10+
import deprecation
811
import empty
912

1013
from contentstack.basequery import BaseQuery
@@ -118,10 +121,15 @@ def tags(self, *tags):
118121
self.query_params["tags"] = ",".join(tags)
119122
return self
120123

124+
@deprecation.deprecated(
125+
deprecated_in="1.7.0",
126+
current_version='1.8.0',
127+
details="Use regex function instead")
121128
def search(self, value: str):
122129
"""
123130
This method provides only the entries matching
124131
the specified value.
132+
@Deprecated deprecated in 1.7.0, Use #regex instaead
125133
Arguments:
126134
value {str} -- value used to match or compare
127135
Raises:
@@ -314,4 +322,61 @@ def __execute_network_call(self):
314322
encoded_string = parse.urlencode(self.query_params, doseq=True)
315323
url = f'{self.base_url}?{encoded_string}'
316324
# url = '{}?{}'.format(self.base_url, encoded_string)
325+
if 'content_type_uid' in self.http_instance.live_preview and 'live_preview' in url:
326+
query_response = self.http_instance.get(url)
327+
return self._map_live_preview(query_response)
317328
return self.http_instance.get(url)
329+
330+
def _map_live_preview(self, query_response):
331+
_preview = self.http_instance.live_preview['resp'] # Gets Live Preview Stored Data From Dict
332+
if 'entries' in query_response:
333+
query_response = query_response['entries']
334+
for index, it in enumerate(query_response): # it in query_response:
335+
if isinstance(it, dict):
336+
if it['uid'] == _preview['uid']:
337+
# return self.merge_it(self.resp, _preview)
338+
merged = {**query_response[index], **_preview}
339+
return query_response
340+
# self._map_live_preview(query_response)
341+
# elif isinstance(query_response, list):
342+
# for obj in query_response:
343+
# self.iter_dict(obj,_preview['uid'])
344+
# pass
345+
else:
346+
return None
347+
348+
# def iter_dict(self, item, uid):
349+
# if isinstance(item, dict):
350+
# if item['uid'] == uid:
351+
# # return self.merge_it(self.resp, preview_response)
352+
# merged = {**query_response[index], **preview_response}
353+
# return merged
354+
# self._map_live_preview(query_response)
355+
356+
def merge_it(self, resp, lp_resp):
357+
resp.update(lp_resp)
358+
# merged
359+
merged = {**resp, **lp_resp}
360+
print(f"merged: {merged}")
361+
return resp
362+
363+
def deep_merge(self, resp, lp_resp):
364+
query_set = set(resp)
365+
live_set = set(lp_resp)
366+
store_keys = []
367+
for key in live_set.intersection(query_set): # Iterates for common keys between query & livePreview
368+
store_keys.append(key)
369+
if isinstance(resp[key], dict):
370+
# match keys and update value
371+
self.merge_it(resp[key], lp_resp[key])
372+
elif isinstance(resp[key], list):
373+
# match keys and update value
374+
for i in lp_resp[key]:
375+
if isinstance(resp[i], dict):
376+
self.merge_it(resp[key], lp_resp[key])
377+
resp.update({key: f"New Fake:{lp_resp[key]}"})
378+
resp.update({key: f"New Fake:{lp_resp[key]}"})
379+
380+
# name, myNames[name]
381+
print(f"new query resp: {resp}")
382+
print(f"store_keys {store_keys}")

contentstack/stack.py

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
from contentstack.https_connection import HTTPSConnection
1515
from contentstack.image_transform import ImageTransform
1616

17-
__author__ = "ishaileshmishra (ishaileshmishra@gmail.com)"
17+
__author__ = "ishaileshmishra (shailesh.mishra@contentstack.com)"
1818
__license__ = "MIT"
19-
__version__ = '1.7.0'
19+
__version__ = '1.8.0'
2020

2121
log = logging.getLogger(__name__)
2222
DEFAULT_HOST = 'cdn.contentstack.io'
@@ -79,13 +79,14 @@ def __init__(self, api_key: str, delivery_token: str, environment: str,
7979
**Example:**
8080
8181
>>> _strategy = Retry(total=5, backoff_factor=1, status_forcelist=[408, 429])
82+
>>> import contentstack
8283
>>> stack = contentstack.Stack("api_key", "delivery_token", "environment",
8384
live_preview={enable=True, authorization='your auth token'}, retry_strategy= _strategy)
8485
```
8586
"""
87+
logging.basicConfig(level=logging.DEBUG)
8688
if live_preview is None:
8789
live_preview = {'enable': False}
88-
logging.basicConfig(level=logging.DEBUG)
8990
self.headers = {}
9091
self._query_params = {}
9192
self.sync_param = {}
@@ -144,10 +145,6 @@ def _validate_stack(self):
144145
def _validate_live_preview(self):
145146
if isinstance(self.live_preview_dict, dict):
146147
if 'enable' in self.live_preview_dict and self.live_preview_dict['enable']:
147-
if 'authorization' not in self.live_preview_dict:
148-
raise PermissionError("management token is required")
149-
if 'host' not in self.live_preview_dict:
150-
raise PermissionError("host is required")
151148
self.headers['authorization'] = self.live_preview_dict['authorization']
152149
self.host = self.live_preview_dict['host']
153150
self.endpoint = f'https://{self.host}/{self.version}'
@@ -200,7 +197,7 @@ def content_type(self, content_type_uid=None):
200197
"""
201198
Content type defines the structure or schema of a page or a section
202199
of your web or mobile property.
203-
:param content_type_uid:
200+
param content_type_uid:
204201
:return: ContentType
205202
"""
206203
return ContentType(self.http_instance, content_type_uid)
@@ -209,7 +206,7 @@ def asset(self, uid):
209206
"""
210207
Assets refer to all the media files (images, videos, PDFs, audio files, and so on)
211208
uploaded in your Contentstack repository for future use.
212-
:param uid: asset_uid of the Asset
209+
param uid: asset_uid of the Asset
213210
:return: Asset
214211
215212
-----------------------------
@@ -242,7 +239,7 @@ def asset_query(self):
242239
def sync_init(self, content_type_uid=None, start_from=None, locale=None, publish_type=None):
243240
"""
244241
Set init to ‘true’ if you want to sync all the published entries and assets.
245-
This is usually used when the app does not have any content and you want to
242+
This is usually used when the app does not have any content, and you want to
246243
get all the content for the first time.\n
247244
248245
:param content_type_uid: (optional) content type UID. e.g., products
@@ -285,7 +282,7 @@ def pagination(self, pagination_token: str):
285282
paginated. It provides pagination token in the response.
286283
However, you do not have to use the pagination token
287284
manually to get the next batch.
288-
:param pagination_token:
285+
param pagination_token:
289286
:return: list of sync items
290287
------------------------------
291288
Example:
@@ -303,7 +300,7 @@ def sync_token(self, sync_token):
303300
to get the updated content next time. The sync token fetches
304301
only the content that was added
305302
after your last sync, and the details of the content that was deleted or updated.
306-
:param sync_token: sync_token
303+
param sync_token: sync_token
307304
:return: list of Sync Result
308305
------------------------------
309306
[Example]:
@@ -318,7 +315,7 @@ def sync_token(self, sync_token):
318315

319316
def __sync_request(self):
320317
r"""Sends a GET request.
321-
:param url URL for :class:`Request` object.
318+
param url is URL for :class:`Request` object.
322319
in the query string for the :class:`Request`.
323320
:param \*\*kwargs: Optional arguments that ``request`` takes.
324321
:return: :class:`Response <Response>` object
@@ -350,6 +347,27 @@ def image_transform(self, image_url, **kwargs):
350347
def live_preview_query(self, **kwargs):
351348
"""
352349
live_preview_query accepts key value pair objects to the query
353-
i.e hash and content_type_uid
350+
hash, content_type_uid and entry_uid
351+
Example:
352+
# def live_preview_query(**kwargs):
353+
# kwargs is a dict of the keyword args passed to the function
354+
for key, value in kwargs.iteritems():
355+
print "%s = %s" % (key, value)
356+
Uses:=>
357+
live_preview_query(
358+
host='api.contentstack.io',
359+
entry_uid='your_entry_uid',
360+
hash='hashcode'
361+
)
354362
"""
355363
self.live_preview_dict.update(kwargs)
364+
self._execute_management_api()
365+
return self
366+
367+
def _execute_management_api(self):
368+
_ct_uid = self.live_preview_dict.get("content_type_uid")
369+
_entry_uid = self.live_preview_dict.get("entry_uid")
370+
_url = f'{self.http_instance.endpoint}/content_types/{_ct_uid}/entries/{_entry_uid}'
371+
_resp = self.http_instance.get(_url)
372+
self.live_preview_dict['resp'] = _resp['entry']
373+
return self

contentstack/utility.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
Utils
33
contentstack
4-
Last modified by Shailesh Mishra on 06/08/20.
4+
Last modified by ishaileshmishra on 06/08/20.
55
Copyright 2019 Contentstack. All rights reserved.
66
"""
77

tests/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# pytest --html=tests/report/test-report.html
1+
# pytest --html=tests/report/test-report.html
22
# above command runs tests and test reports generates in tests/report location.
33
# nosetests --with-coverage --cover-html
44
# clean all the .pyc files
@@ -7,9 +7,7 @@
77
# pytest --cov=contentstack
88
# pytest -v --cov=contentstack --cov-report=html
99
# pytest --html=tests/report/test-report.html
10-
import unittest
1110
from unittest import TestLoader, TestSuite
12-
1311
from .test_assets import TestAsset
1412
from .test_entry import TestEntry
1513
from .test_query import TestQuery
@@ -25,5 +23,5 @@ def all_tests():
2523
test_module_stack,
2624
test_module_asset,
2725
test_module_entry,
28-
test_module_query
26+
test_module_query,
2927
])

tests/test_live_preview_config.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
ENVIRONMENT = config.ENVIRONMENT
1515
HOST = config.HOST
1616

17+
1718
class TestLivePreviewConfig(unittest.TestCase):
1819

1920
def setUp(self):
@@ -124,5 +125,6 @@ def test_branching(self):
124125
stack.content_type('product')
125126
self.assertEqual('dev_branch', stack.get_branch)
126127

127-
# if __name__ == '__main__':
128-
# unittest.main()
128+
129+
if __name__ == '__main__':
130+
unittest.main()

0 commit comments

Comments
 (0)