Skip to content
Merged

Next #28

Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# this file is *not* meant to cover or endorse the use of GitHub Actions, but rather to
# help make automated releases for this project

name: Release

on:
release:
types: [created]

jobs:
build-and-publish:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: '3.x'
- name: Install build dependencies
run: python -m pip install -U setuptools wheel build
- name: Build
run: python -m build .
- name: Publish
uses: pypa/gh-action-pypi-publish@master
with:
password: ${{ secrets.pypi_password }}
skip_existing: true
11 changes: 11 additions & 0 deletions .talismanrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
fileignoreconfig:

- filename: tests/config/default.yml.enc
checksum: f05423216fcfe17716c01932e7a87775a029ec4f1fb1314bfdf0697527e67038
- filename: tests/test_contentstack.py
Expand All @@ -9,4 +10,14 @@ fileignoreconfig:
checksum: 704f1cffd452d226e7447213fcb6a3fed7b01f0661aa27d4f7657b8a36eb3d28
- filename: contentstack_management/core/client.py
checksum: 7a1210ec269e05af414e7753758d8b261c157349e24df4fef047810fef8741c9
- filename: tests/test_organizations.py
checksum: a9ee8e15a00474ab16920da1a9cb7f96f9a0e40f945406506ed1e46030758025
- filename: tests/test_users.py
checksum: 55b60bc69e941184bf16697cec82f5e14369460259729bbbd62437e019e6ab60
- filename: contentstack_management/core/client.py
checksum: 1bec47304a29a7c482f530e3ac283e8ddd8fa96f99153833feac5a6513d726df
- filename: .github/workflows/release.yml
checksum: d2ea9ae192ae0f1b75ff2b68b6bcd9d40eb86d589fb2177535b93194d69a9e0e
- filename: tests/test_user_session.py
checksum: f5000644a471e6ac4ee5bfcb5cfc73762e53fa97980951063f787a83e97244f9
version: ""
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# CHANGELOG

1 change: 1 addition & 0 deletions CODEOWNERS.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @contentstack/security-admin @contentstack/sdk-admin
7 changes: 7 additions & 0 deletions INSTALL.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

To install the package simply run the below command on your terminal:

python setup.py install

Don't forget to file bugs and let me know about them.
Also, don't hesitate to ask for new features. Happy coding.
1 change: 1 addition & 0 deletions contentstack_management/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""The __init__.py file that contains modules that need to import"""


from contentstack_management import contentstack

__title__ = 'contentstack-cms'
Expand Down
1 change: 1 addition & 0 deletions contentstack_management/contentstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def user_agents(headers):
name=contentstack_management.__package__,
version=contentstack_management.__version__
), 'os': str(__platform())})

package = f"contentstack-management-python/{contentstack_management.__version__}"
return {'User-Agent': str(headers), "X-User-Agent": package, 'Content-Type': 'application/json' }

Expand Down
7 changes: 6 additions & 1 deletion contentstack_management/core/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ..organizations.organizations import Organization
from ..users.user import User
from ..stack.stack import Stack

from ..user_session.user_session import UserSession

class ApiClient:
Expand Down Expand Up @@ -96,7 +97,9 @@ def _call_request(self, method, url_path, headers=None, params=None, data=None,

if response.status_code >= 400:
if self.errors:

return (response)

elif retries > 1:
retries -= 1
else:
Expand All @@ -113,6 +116,7 @@ def _call_request(self, method, url_path, headers=None, params=None, data=None,
return None



def login(self, email=None, password=None):
if email is None or email == '':
raise PermissionError(
Expand Down Expand Up @@ -144,6 +148,7 @@ def login(self, email=None, password=None):
return response
return response.status_code


def logout(self):
url = "user-session"
self.headers['authtoken'] = self.auth_token
Expand All @@ -166,4 +171,4 @@ def stack(self, api_key = None):
'You are not permitted to the stack without valid api key')
return Stack(self.endpoint, self.auth_token, self.headers,self.api_client, api_key)


104 changes: 104 additions & 0 deletions contentstack_management/core/http_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"""This class takes a base URL as an argument when it's initialized,
which is the endpoint for the RESTFUL API that we'll be interacting with.
The create(), read(), update(), and delete() methods each correspond to
the CRUD operations that can be performed on the API """

import requests
import json


class HttpClient:
"""
This class takes a base URL as an argument when it's initialized,
which is the endpoint for the RESTFUL API that
we'll be interacting with. The create(), read(), update(), and delete()
methods each correspond to the CRUD
operations that can be performed on the API """

def __init__(self, endpoint):
#init method
self.url="user"
self.endpoint = endpoint
self.failure_retry = 0
self.exceptions = True
self.errors = True



def get(self, url, headers=None, params=None):
"""
Perform an HTTP GET request with the specified URL and parameters.

:param url: The URL to send the request to.
:param headers: Optional dictionary of headers to include in the request.
:param params: Optional dictionary of URL parameters to include in the request.
:return: The response from the server.
"""
return self._call_request('GET', url, headers=headers, params=params)

def put(self, url, headers=None, params=None, data=None, json=None):
"""
Perform an HTTP PUT request with the specified URL and parameters.

:param url: The URL to send the request to.
:param headers: Optional dictionary of headers to include in the request.
:param params: Optional dictionary of URL parameters to include in the request.
:param data: Optional dictionary, list of tuples, or bytes to include in the body of the request.
:param json: Optional JSON data to include in the body of the request.
:return: The response from the server.
"""
return self._call_request('PUT', url, headers=headers, params=params, data=data, json=json)

def post(self, url, headers=None, params=None, data=None, json=None):
"""
Perform an HTTP POST request with the specified URL and parameters.

:param url: The URL to send the request to.
:param headers: Optional dictionary of headers to include in the request.
:param params: Optional dictionary of URL parameters to include in the request.
:param data: Optional dictionary, list of tuples, or bytes to include in the body of the request.
:param json: Optional JSON data to include in the body of the request.
:return: The response from the server.
"""
return self._call_request('POST', url, headers=headers, params=params, data=data, json=json)

def delete(self, url, headers=None, params=None):
"""
Perform an HTTP DELETE request with the specified URL and parameters.

:param url: The URL to send the request to.
:param headers: Optional dictionary of headers to include in the request.
:param params: Optional dictionary of URL parameters to include in the request.
:return: The response from the server.
"""
return self._call_request('DELETE', url, headers=headers, params=params)



def _call_request(self, method, url_path, headers=None, params=None, data=None, json=None):
url = f"{self.endpoint}/{url_path}"
retries = self.failure_retry + 1

while retries > 0:
try:
response = requests.request(method, url, data=data, headers=headers, params=params, json=json)

if response.status_code >= 400:
if self.errors:
raise Exception(f"API returned an error: {response.text}")
elif retries > 1:
retries -= 1
else:
return None
else:
return response.json()

except Exception as e:
if self.exceptions:
raise e
elif retries > 1:
retries -= 1
else:
return None


9 changes: 8 additions & 1 deletion contentstack_management/organizations/organizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import contentstack_management


class Organization:
"""
This class takes a base URL as an argument when it's initialized,
Expand All @@ -23,15 +24,18 @@ def get(self):
return self.api_client.get(url, headers = self.headers)



def get_organization(self, organization_uid):
url = f"organizations/{organization_uid}"
self.headers['authtoken'] = self.authtoken
return self.api_client.get(url, headers = self.headers)


def get_organization_roles(self, organization_uid):
url = f"organizations/{organization_uid}/roles"
self.headers['authtoken'] = self.authtoken
return self.api_client.get(url, headers = self.headers)


def organization_add_users(self, organization_uid):
url = f"organizations/{organization_uid}/share"
Expand All @@ -42,13 +46,16 @@ def transfer_organizations_ownership(self, organization_uid, data):
url = f"organizations/{organization_uid}/transfer-ownership"
self.headers['authtoken'] = self.authtoken
return self.api_client.post(url, headers = self.headers, data=data)


def organization_stacks(self, organization_uid):
url = f"organizations/{organization_uid}/stacks"
self.headers['authtoken'] = self.authtoken
return self.api_client.get(url, headers = self.headers)


def organization_logs(self, organization_uid):
url = f"organizations/{organization_uid}/logs"
self.headers['authtoken'] = self.authtoken
return self.api_client.get(url, headers = self.headers)
return self.api_client.get(url, headers = self.headers)

2 changes: 2 additions & 0 deletions contentstack_management/stack/stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import contentstack_management



class Stack:
"""
This class takes a base URL as an argument when it's initialized,
Expand All @@ -33,3 +34,4 @@ def fetch(self):
return self.api_client.get(url, headers = self.headers)



2 changes: 2 additions & 0 deletions contentstack_management/user_session/user_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import urllib.request
import contentstack_management


class UserSession:
"""
This class takes a base URL as an argument when it's initialized,
Expand Down Expand Up @@ -49,6 +50,7 @@ def login(self):
rfc2109=False,
))
return response

return response

def logout(self):
Expand Down
1 change: 1 addition & 0 deletions contentstack_management/users/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import contentstack_management



class User:
"""
This class takes a base URL as an argument when it's initialized,
Expand Down
9 changes: 9 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "contentstack-management",
"version": "0.0.1",
"developer": "sunil-lakshman",
"license": "MIT",
"author": { "name": "sunil-lakshman", "email": "sunil.lakshman@contentstack.com" },
"homepage": "www.contentstack.com",
"readme": "./readme"
}
21 changes: 21 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
twython~=3.9.1
setuptools~=62.1.0
urllib3~=1.26.2
contentstack-utils
python-dateutil==2.8.2
requests==2.27.1
coverage==6.3.2
tox==3.25.0
virtualenv==20.14.1
Sphinx==4.5.0
sphinxcontrib-websupport==1.2.4
pip~=22.0.4
build~=0.7.0
wheel~=0.37.1
py~=1.11.0
lxml~=4.8.0
utils~=1.0.1
keyring~=23.5.0
docutils==0.16
pyparsing~=3.0.8
config~=0.5.1
45 changes: 45 additions & 0 deletions tests/test_user_session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import unittest
import requests
import os

from contentstack_management import contentstack

class UserSessionTests(unittest.TestCase):

@classmethod
def setUpClass(cls):
# Retrieve secret credentials from environment variables
cls.username = os.environ.get('API_USERNAME')
cls.password = os.environ.get('API_PASSWORD')

def test_successful_get_request(self):
response = requests.get('https://api.example.com/data')
self.assertEqual(response.status_code, 200)
# Additional assertions to validate the response content

def test_invalid_url(self):
response = requests.get('https://api.example.com/invalid')
self.assertEqual(response.status_code, 404)
# Additional assertions for error handling

def test_request_timeout(self):
response = requests.get('https://api.example.com/slow', timeout=2)
self.assertEqual(response.status_code, 408)
# Additional assertions for handling timeouts

def test_request_headers(self):
headers = {'User-Agent': 'My User Agent'}
response = requests.get('https://api.example.com/data', headers=headers)
self.assertEqual(response.status_code, 200)
# Additional assertions for validating headers in response

def test_authentication(self):
credentials = (self.username, self.password)
response = requests.get('https://api.example.com/data', auth=credentials)
self.assertEqual(response.status_code, 200)
# Additional assertions for successful authentication



if __name__ == '__main__':
unittest.main()
Loading