From ba1c6b93356189afd2493cdc4b88d21c68633e8b Mon Sep 17 00:00:00 2001 From: Musilah Date: Thu, 10 Aug 2023 19:14:34 +0300 Subject: [PATCH 01/31] Fix sdk-py Signed-off-by: Musilah --- examples/examples.py | 680 ++++++++++++++++++++++--------------------- mainflux/users.py | 7 +- 2 files changed, 345 insertions(+), 342 deletions(-) diff --git a/examples/examples.py b/examples/examples.py index 19f2f24..c82c42c 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -15,22 +15,26 @@ """To start working with the Mainflux system, you need to create a user account""" mf_resp = mfsdk.users.create( - user={"email": "", "password": ""} + user={"credentials": {"identity": "example8@example.com", "secret": "12345678"}} ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) + + """To log in to the Mainflux system, you need to create a user token""" mf_resp = mfsdk.users.login( - user={"email": "", "password": ""} + user={ "identity" : "example8@example.com", "secret": "12345678"} ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) + +''' """You can always check the user entity that is logged in by entering the user ID and token""" mf_resp = mfsdk.users.get(id="", token="") @@ -38,339 +42,339 @@ print(mf_resp.value) else: print(mf_resp.error.message) - -"""Updating user entities in the database""" -mf_resp = mfsdk.users.update( - user_token="", user={"metadata": {"foo": "bar"}} -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""You can get all users in the database by calling the get_all () function""" -mf_resp = mfsdk.users.get_all( - query_params={"offset": 1, "limit": 5}, admin_token="" -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -mf_resp = mfsdk.users.disable(user_id="", admin_token="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - - -mf_resp = mfsdk.users.enable(user_id="", admin_token="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Changing the user password can be done by calling -the update password function""" -mf_resp = mfsdk.users.update_password( - old_password="", password="", - user_token="" -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""To create a thing, you need the thing name and a user token""" -mf_resp = mfsdk.things.create( - thing={"name": ""}, token="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""You can create multiple things at once -by entering a series of things structures and a user token""" -mf_resp = mfsdk.things.create_bulk( - things=[{"name": ""}, {"name": ""}], - token="", -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""You can get thing information by entering the thing ID and user token""" -mf_resp = mfsdk.things.get(token="", thing_id="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""You can get all things in the database by calling the get_all () function""" -mf_resp = mfsdk.things.get_all( - query_params={"offset": 1, "limit": 5}, token="" -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Updating a thing entity in a database""" -mf_resp = mfsdk.things.update( - thing_id="", token="", thing={"name": ""} -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - - -"You can get all thing connected to channel" -mf_resp = mfsdk.things.get_by_channel( - channel_id="", - query_params={"offset": 1, "limit": 5}, - token="", -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""To delete a thing you need a thing ID and a user token""" -mf_resp = mfsdk.things.delete(thing_id="", token="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Connect thing to channel""" -mf_resp = mfsdk.things.connect( - channel_id="", thing_id="", token="" -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Disconnect thing from channel""" -mf_resp = mfsdk.things.disconnect( - channel_id="", thing_id="", token="" -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Connect things to channels""" -mf_resp = mfsdk.things.connects( - channel_ids=["", ""], - thing_ids=["", ""], - token="", -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Disconnect things from channels""" -mf_resp = mfsdk.things.disconnects( - channel_ids=["", ""], - thing_ids=["", ""], - token="", -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""To create a channel, you need a channel and a token""" -mf_resp = mfsdk.channels.create( - channel={"name": "channel_name"}, token="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""As with things, you can create multiple channels at once""" -mf_resp = mfsdk.channels.create_bulk( - channels=[{"name": ""}, {"name": ""}], - token="", -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Update channel entities in the database""" -mf_resp = mfsdk.channels.update( - channel_id="", - token="", - channel={"name": ""}, -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""You can get channel information by entering the channel ID and user token""" -mf_resp = mfsdk.channels.get(token="", channel_id="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""You can get all channels in the database by calling the get_all () -function""" -mf_resp = mfsdk.channels.get_all( - query_params={"offset": 1, "limit": 5}, token="" -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""A list of all the channels to which a given thing is connected""" -mf_resp = mfsdk.channels.get_by_thing( - thing_id="", query_params={"offset": 1, "limit": 5}, - token="" -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Identifies thing when given thing key""" -mf_resp = mfsdk.channels.identify_thing(thing_key="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Delete channels from the database""" -mf_resp = mfsdk.channels.delete( - channel_id="", token="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""To create a group, you need the group name and a user token""" -mf_resp = mfsdk.groups.create( - group={"name": "group_name"}, token="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""You can get group information by entering the group ID and token""" -mf_resp = mfsdk.groups.get(group_id="", token="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Group update""" -mf_resp = mfsdk.groups.update( - group_id="", token="", group={""} -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""You can get groups in the database by calling the get_all () function""" -mf_resp = mfsdk.groups.get_all( - token="", query_params={"offset": 1, "limit": 5} -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Assign user, thing or channel to a group""" -mf_resp = mfsdk.groups.assign( - group_id="", - token="", - members_ids=["" | "" | ""], - member_type='<"users" | "things" | "channels">', -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Unassign""" -mf_resp = mfsdk.groups.unassign( - group_id="", - token="", - members_ids=["" | "" | ""], -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Get list of children from group""" -mf_resp = mfsdk.groups.children( - group_id="", token="", - query_params={"offset": 0, "limit": 5} -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Get list of parents from group""" -mf_resp = mfsdk.groups.parents( - group_id="", token="", - query_params={"offset": 0, "limit": 5} -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Get list of members from group""" -mf_resp = mfsdk.groups.members( - member_id="", token="", - query_params={"offset": 0, "limit": 5} -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Get list of memberships from member""" -mf_resp = mfsdk.groups.memberships( - group_id="", - token="", - query_params={"offset": 0, "limit": 5}, -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Delete group from the database""" -mf_resp = mfsdk.groups.delete(group_id="", token="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Sends message via HTTP protocol""" -mf_resp = mfsdk.messages.send( - channel_id="", msg="", thing_key="" -) -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) - -"""Reads messages from database for a given channel""" -mf_resp = mfsdk.messages.read(channel_id="", token="") -if mf_resp.error.status == 0: - print(mf_resp.value) -else: - print(mf_resp.error.message) +''' +# """Updating user entities in the database""" +# mf_resp = mfsdk.users.update( +# user_token="", user={"metadata": {"foo": "bar"}} +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """You can get all users in the database by calling the get_all () function""" +# mf_resp = mfsdk.users.get_all( +# query_params={"offset": 1, "limit": 5}, admin_token="" +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# mf_resp = mfsdk.users.disable(user_id="", admin_token="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + + +# mf_resp = mfsdk.users.enable(user_id="", admin_token="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Changing the user password can be done by calling +# the update password function""" +# mf_resp = mfsdk.users.update_password( +# old_password="", password="", +# user_token="" +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """To create a thing, you need the thing name and a user token""" +# mf_resp = mfsdk.things.create( +# thing={"name": ""}, token="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """You can create multiple things at once +# by entering a series of things structures and a user token""" +# mf_resp = mfsdk.things.create_bulk( +# things=[{"name": ""}, {"name": ""}], +# token="", +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """You can get thing information by entering the thing ID and user token""" +# mf_resp = mfsdk.things.get(token="", thing_id="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """You can get all things in the database by calling the get_all () function""" +# mf_resp = mfsdk.things.get_all( +# query_params={"offset": 1, "limit": 5}, token="" +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Updating a thing entity in a database""" +# mf_resp = mfsdk.things.update( +# thing_id="", token="", thing={"name": ""} +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + + +# "You can get all thing connected to channel" +# mf_resp = mfsdk.things.get_by_channel( +# channel_id="", +# query_params={"offset": 1, "limit": 5}, +# token="", +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """To delete a thing you need a thing ID and a user token""" +# mf_resp = mfsdk.things.delete(thing_id="", token="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Connect thing to channel""" +# mf_resp = mfsdk.things.connect( +# channel_id="", thing_id="", token="" +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Disconnect thing from channel""" +# mf_resp = mfsdk.things.disconnect( +# channel_id="", thing_id="", token="" +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Connect things to channels""" +# mf_resp = mfsdk.things.connects( +# channel_ids=["", ""], +# thing_ids=["", ""], +# token="", +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Disconnect things from channels""" +# mf_resp = mfsdk.things.disconnects( +# channel_ids=["", ""], +# thing_ids=["", ""], +# token="", +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """To create a channel, you need a channel and a token""" +# mf_resp = mfsdk.channels.create( +# channel={"name": "channel_name"}, token="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """As with things, you can create multiple channels at once""" +# mf_resp = mfsdk.channels.create_bulk( +# channels=[{"name": ""}, {"name": ""}], +# token="", +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Update channel entities in the database""" +# mf_resp = mfsdk.channels.update( +# channel_id="", +# token="", +# channel={"name": ""}, +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """You can get channel information by entering the channel ID and user token""" +# mf_resp = mfsdk.channels.get(token="", channel_id="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """You can get all channels in the database by calling the get_all () +# function""" +# mf_resp = mfsdk.channels.get_all( +# query_params={"offset": 1, "limit": 5}, token="" +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """A list of all the channels to which a given thing is connected""" +# mf_resp = mfsdk.channels.get_by_thing( +# thing_id="", query_params={"offset": 1, "limit": 5}, +# token="" +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Identifies thing when given thing key""" +# mf_resp = mfsdk.channels.identify_thing(thing_key="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Delete channels from the database""" +# mf_resp = mfsdk.channels.delete( +# channel_id="", token="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """To create a group, you need the group name and a user token""" +# mf_resp = mfsdk.groups.create( +# group={"name": "group_name"}, token="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """You can get group information by entering the group ID and token""" +# mf_resp = mfsdk.groups.get(group_id="", token="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Group update""" +# mf_resp = mfsdk.groups.update( +# group_id="", token="", group={""} +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """You can get groups in the database by calling the get_all () function""" +# mf_resp = mfsdk.groups.get_all( +# token="", query_params={"offset": 1, "limit": 5} +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Assign user, thing or channel to a group""" +# mf_resp = mfsdk.groups.assign( +# group_id="", +# token="", +# members_ids=["" | "" | ""], +# member_type='<"users" | "things" | "channels">', +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Unassign""" +# mf_resp = mfsdk.groups.unassign( +# group_id="", +# token="", +# members_ids=["" | "" | ""], +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Get list of children from group""" +# mf_resp = mfsdk.groups.children( +# group_id="", token="", +# query_params={"offset": 0, "limit": 5} +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Get list of parents from group""" +# mf_resp = mfsdk.groups.parents( +# group_id="", token="", +# query_params={"offset": 0, "limit": 5} +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Get list of members from group""" +# mf_resp = mfsdk.groups.members( +# member_id="", token="", +# query_params={"offset": 0, "limit": 5} +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Get list of memberships from member""" +# mf_resp = mfsdk.groups.memberships( +# group_id="", +# token="", +# query_params={"offset": 0, "limit": 5}, +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Delete group from the database""" +# mf_resp = mfsdk.groups.delete(group_id="", token="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Sends message via HTTP protocol""" +# mf_resp = mfsdk.messages.send( +# channel_id="", msg="", thing_key="" +# ) +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) + +# """Reads messages from database for a given channel""" +# mf_resp = mfsdk.messages.read(channel_id="", token="") +# if mf_resp.error.status == 0: +# print(mf_resp.value) +# else: +# print(mf_resp.error.message) diff --git a/mainflux/users.py b/mainflux/users.py index 2761866..601aab8 100644 --- a/mainflux/users.py +++ b/mainflux/users.py @@ -23,21 +23,20 @@ def create(self, user: dict): errors.users["create"], http_resp.status_code ) else: - location = http_resp.headers.get("location") - mf_resp.value = location.split("/")[2] + mf_resp.value = http_resp.json() return mf_resp def login(self, user: dict): """Generates an access token when provided with proper credentials.""" mf_resp = response.Response() - http_resp = requests.post(self.url + "/tokens", json=user) + http_resp = requests.post(self.url + "/users/tokens/issue", json=user) if http_resp.status_code != 201: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.users["login"], http_resp.status_code ) else: - mf_resp.value = http_resp.json()["token"] + mf_resp.value = http_resp.json() return mf_resp def get(self, user_id: str, token: str): From 9be50d707c7cf4c5d8c95116b929064398b68cda Mon Sep 17 00:00:00 2001 From: Musilah Date: Fri, 11 Aug 2023 18:36:46 +0300 Subject: [PATCH 02/31] Test user service Signed-off-by: Musilah --- mainflux/users.py | 54 ++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/mainflux/users.py b/mainflux/users.py index 601aab8..0dcd154 100644 --- a/mainflux/users.py +++ b/mainflux/users.py @@ -7,16 +7,20 @@ class Users: - users_endpoint = "users" + USERS_ENDPOINT = "users" def __init__(self, url: str): - self.url = url + self.URL = url - def create(self, user: dict): + def create(self, user: dict, token: str = ""): """Registers new user account given email and password. New account will be uniquely identified by its email address.""" mf_resp = response.Response() - http_resp = requests.post(self.url + "/users", json=user) + http_resp = requests.post( + self.URL + "/users", + json=user, + headers=utils.construct_header(token, utils.CTJSON), + ) if http_resp.status_code != 201: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( @@ -29,7 +33,7 @@ def create(self, user: dict): def login(self, user: dict): """Generates an access token when provided with proper credentials.""" mf_resp = response.Response() - http_resp = requests.post(self.url + "/users/tokens/issue", json=user) + http_resp = requests.post(self.URL + "/users/tokens/issue", json=user) if http_resp.status_code != 201: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( @@ -43,7 +47,7 @@ def get(self, user_id: str, token: str): """Gets a user information""" mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.users_endpoint + "/" + user_id, + self.URL + "/" + self.USERS_ENDPOINT + "/" + user_id, headers=utils.construct_header(token, utils.CTJSON), ) if http_resp.status_code != 200: @@ -58,7 +62,7 @@ def get(self, user_id: str, token: str): def get_all(self, query_params: dict, admin_token: str): """Retrieves a list of users""" http_resp = requests.get( - self.url + "/" + self.users_endpoint, + self.URL + "/" + self.USERS_ENDPOINT, headers=utils.construct_header(admin_token, utils.CTJSON), params=query_params, ) @@ -75,8 +79,8 @@ def get_all(self, query_params: dict, admin_token: str): def update(self, user: dict, user_token: str): """Updates info on currently logged in user. Info is updated using authorization user_token""" - http_resp = requests.put( - self.url + "/" + self.users_endpoint, + http_resp = requests.patch( + self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"], headers=utils.construct_header(user_token, utils.CTJSON), data=json.dumps(user), ) @@ -86,50 +90,56 @@ def update(self, user: dict, user_token: str): mf_resp.error.message = errors.handle_error( errors.users["update"], http_resp.status_code ) + else: + mf_resp.value = http_resp.json() return mf_resp - def update_password( - self, old_password: str, password: str, user_token: str - ): + def update_password(self, old_secret: str, new_secret: str, user_token: str): """Changes user password""" - payload = {"old_password": old_password, "password": password} + payload = {"old_secret": old_secret, "new_secret": new_secret} http_resp = requests.patch( - self.url + "/password", + self.URL + "/" + self.USERS_ENDPOINT + "/secret", headers=utils.construct_header(user_token, utils.CTJSON), json=payload, ) mf_resp = response.Response() - if http_resp.status_code != 201: + if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.users["update"], http_resp.status_code ) + else: + mf_resp.value = "OK" return mf_resp - def enable(self, user_id: str, admin_token: str): + def enable(self, user_id: str, user_token: str): """Enables a disabled user account for a given user ID.""" mf_resp = response.Response() http_resp = requests.post( - self.url + "/" + self.users_endpoint + "/" + user_id + "/enable", - headers=utils.construct_header(admin_token, utils.CTJSON), + self.URL + "/" + self.USERS_ENDPOINT + "/" + user_id + "/enable", + headers=utils.construct_header(user_token, utils.CTJSON), ) if http_resp.status_code != 204: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.users["enable"], http_resp.status_code ) + else: + mf_resp.value = http_resp.json() return mf_resp - def disable(self, user_id: str, admin_token: str): + def disable(self, user_id: str, user_token: str): """Disables an enabled user account for a given user ID.""" mf_resp = response.Response() http_resp = requests.post( - self.url + "/" + self.users_endpoint + "/" + user_id + "/disable", - headers=utils.construct_header(admin_token, utils.CTJSON), + self.URL + "/" + self.USERS_ENDPOINT + "/" + user_id + "/disable", + headers=utils.construct_header(user_token, utils.CTJSON), ) - if http_resp.status_code != 204: + if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.users["disable"], http_resp.status_code ) + else: + mf_resp.value = http_resp.json() return mf_resp From 476621a6ab14b79bff353495cd8ca1757f2d1371 Mon Sep 17 00:00:00 2001 From: Musilah Date: Wed, 16 Aug 2023 20:28:53 +0300 Subject: [PATCH 03/31] Fix things, channels and groups Signed-off-by: Musilah --- README.md | 2 +- docs/users.md | 22 +- examples/examples.py | 517 ++++++++++++++++++++++------------------- mainflux/channels.py | 30 ++- mainflux/errors.py | 4 +- mainflux/groups.py | 21 +- mainflux/keys.py | 60 ----- mainflux/things.py | 69 +++--- mainflux/users.py | 4 +- tests/test_channels.py | 61 ++--- tests/test_keys.py | 47 ---- tests/test_things.py | 191 +++++++++------ tests/test_users.py | 132 +++++++++-- 13 files changed, 614 insertions(+), 546 deletions(-) delete mode 100644 mainflux/keys.py delete mode 100644 tests/test_keys.py diff --git a/README.md b/README.md index 05d9daa..1bfb126 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Official documentation for the SDK is hosted at [here](https://github.com/mainfl ```sh pip install lazydocs requests python3 setup.py install -lazydocs --src-base-url="https://github.com/mainflux/sdk-py/blob/main/" --overview-file="README.md" lib +lazydocs --src-base-url="https://github.com/mainflux/sdk-py/blob/main/" --overview-file="README.md" mainflux ``` Please note that lazydocs requires Python version 3.5 or higher. diff --git a/docs/users.md b/docs/users.md index 622c303..7a98b1f 100644 --- a/docs/users.md +++ b/docs/users.md @@ -40,38 +40,38 @@ __init__(url: str) ### method `create` ```python -create(user: dict) +create(user: dict, token: str = '') ``` Registers new user account given email and password. New account will be uniquely identified by its email address. --- - + ### method `disable` ```python -disable(user_id: str, admin_token: str) +disable(user_id: str, user_token: str) ``` Disables an enabled user account for a given user ID. --- - + ### method `enable` ```python -enable(user_id: str, admin_token: str) +enable(user_id: str, user_token: str) ``` Enables a disabled user account for a given user ID. --- - + ### method `get` @@ -83,7 +83,7 @@ Gets a user information --- - + ### method `get_all` @@ -95,7 +95,7 @@ Retrieves a list of users --- - + ### method `login` @@ -107,7 +107,7 @@ Generates an access token when provided with proper credentials. --- - + ### method `update` @@ -119,12 +119,12 @@ Updates info on currently logged in user. Info is updated using authorization us --- - + ### method `update_password` ```python -update_password(old_password: str, password: str, user_token: str) +update_password(old_secret: str, new_secret: str, user_token: str) ``` Changes user password diff --git a/examples/examples.py b/examples/examples.py index c82c42c..4d432ed 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -4,294 +4,321 @@ mfsdk = sdk.SDK( users_url=default_url, - things_url=default_url, + things_url=default_url + ":9000", reader_url=default_url + ":9204", http_adapter_url=default_url, certs_url=default_url + ":8204", bootstrap_url=default_url + ":8202", auth_url=default_url, ) - +''' """To start working with the Mainflux system, you need to create a user account""" mf_resp = mfsdk.users.create( - user={"credentials": {"identity": "example8@example.com", "secret": "12345678"}} + user={"credentials": {"identity": "example23@example.com", "secret": "12345678"}}, + token="", ) if mf_resp.error.status == 0: print(mf_resp.value) else: - print(mf_resp.error.message) - - + print(mf_resp.error.message) """To log in to the Mainflux system, you need to create a user token""" mf_resp = mfsdk.users.login( - user={ "identity" : "example8@example.com", "secret": "12345678"} + user={ "identity" : "example23@example.com", "secret": "12345678"} ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) - - +''' ''' """You can always check the user entity that is logged in by entering the user ID and token""" -mf_resp = mfsdk.users.get(id="", token="") +mf_resp = mfsdk.users.get(user_id="0f047968-b170-4dd4-85f5-6e03e1b3798e", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE3NTIxOTcsImlhdCI6MTY5MTc1MTI5NywiaWRlbnRpdHkiOiJleGFtcGxlMTJAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiIwZjA0Nzk2OC1iMTcwLTRkZDQtODVmNS02ZTAzZTFiMzc5OGUiLCJ0eXBlIjoiYWNjZXNzIn0.REa8wv-veZm2fpAeLe3jO9SMYMnyPrcT07YTmx4M_lOE3wYYal26HYp8RHd6z3Igy7ccadSKiqaygyvrpkMLzw") if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) ''' -# """Updating user entities in the database""" -# mf_resp = mfsdk.users.update( -# user_token="", user={"metadata": {"foo": "bar"}} -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - -# """You can get all users in the database by calling the get_all () function""" -# mf_resp = mfsdk.users.get_all( -# query_params={"offset": 1, "limit": 5}, admin_token="" -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - -# mf_resp = mfsdk.users.disable(user_id="", admin_token="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - - -# mf_resp = mfsdk.users.enable(user_id="", admin_token="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - -# """Changing the user password can be done by calling -# the update password function""" -# mf_resp = mfsdk.users.update_password( -# old_password="", password="", -# user_token="" -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - -# """To create a thing, you need the thing name and a user token""" -# mf_resp = mfsdk.things.create( -# thing={"name": ""}, token="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - -# """You can create multiple things at once -# by entering a series of things structures and a user token""" -# mf_resp = mfsdk.things.create_bulk( -# things=[{"name": ""}, {"name": ""}], -# token="", -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - -# """You can get thing information by entering the thing ID and user token""" -# mf_resp = mfsdk.things.get(token="", thing_id="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +''' +"""Updating user entities in the database""" +user = { + "id": "", + "name": "", + "metadata": { + "foo": "bar" + } +} +mf_resp = mfsdk.users.update( + user_token="", user=user +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) +''' +''' +"""You can get all users in the database by calling the get_all () function""" +mf_resp = mfsdk.users.get_all( + query_params={"offset": 0, "limit": 5}, + admin_token="", +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) +''' +''' +mf_resp = mfsdk.users.disable(user_id="46c266a8-084d-4863-b013-9d27be7617e5", user_token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE4MTIxMjQsImlhdCI6MTY5MTc1ODEyNCwiaWRlbnRpdHkiOiJleGFtcGxlMTVAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiJhZTE4ZjZiZS01OTJmLTQ1NjAtOGIxNy1jMmUxYmYyNzNhYWUiLCJ0eXBlIjoiYWNjZXNzIn0.SO3Z6-mNbYFEuJDlO1E477nQblg0UR6r0C7aR8jhRcTpDA62isovYjXhdoDdjPrRrDb7K1hHSHrxHhMFPiYz7w") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """You can get all things in the database by calling the get_all () function""" -# mf_resp = mfsdk.things.get_all( -# query_params={"offset": 1, "limit": 5}, token="" -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +mf_resp = mfsdk.users.enable(user_id="46c266a8-084d-4863-b013-9d27be7617e5", user_token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE4MTIxMjQsImlhdCI6MTY5MTc1ODEyNCwiaWRlbnRpdHkiOiJleGFtcGxlMTVAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiJhZTE4ZjZiZS01OTJmLTQ1NjAtOGIxNy1jMmUxYmYyNzNhYWUiLCJ0eXBlIjoiYWNjZXNzIn0.SO3Z6-mNbYFEuJDlO1E477nQblg0UR6r0C7aR8jhRcTpDA62isovYjXhdoDdjPrRrDb7K1hHSHrxHhMFPiYz7w") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """Updating a thing entity in a database""" -# mf_resp = mfsdk.things.update( -# thing_id="", token="", thing={"name": ""} -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""Changing the user password can be done by calling +the update password function""" +''' +""" +mf_resp = mfsdk.users.update_password( + old_secret="", secret="", + user_token="" +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) +""" +''' +"""To create a thing, you need the thing name and a user token""" +mf_resp = mfsdk.things.create( + thing={"name": "thing1"}, token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# "You can get all thing connected to channel" -# mf_resp = mfsdk.things.get_by_channel( -# channel_id="", -# query_params={"offset": 1, "limit": 5}, -# token="", -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""You can create multiple things at once +by entering a series of things structures and a user token""" +mf_resp = mfsdk.things.create_bulk( + things=[{"name": "thing_8"}, {"name": "thing_9"}, {"name": "thing_10"}], + token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ", +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """To delete a thing you need a thing ID and a user token""" -# mf_resp = mfsdk.things.delete(thing_id="", token="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""You can get thing information by entering the thing ID and user token""" +mf_resp = mfsdk.things.get(token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ", thing_id="6d591627-8657-43af-bfaa-79047b5f8ec3") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """Connect thing to channel""" -# mf_resp = mfsdk.things.connect( -# channel_id="", thing_id="", token="" -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""You can get all things in the database by calling the get_all () function""" +mf_resp = mfsdk.things.get_all( + query_params={"offset": 0, "limit": 5}, token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ" +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """Disconnect thing from channel""" -# mf_resp = mfsdk.things.disconnect( -# channel_id="", thing_id="", token="" -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""Updating a thing entity in a database""" +mf_resp = mfsdk.things.update( + thing_id="6d591627-8657-43af-bfaa-79047b5f8ec3", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ", thing={"name": "thing_1"} +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """Connect things to channels""" -# mf_resp = mfsdk.things.connects( -# channel_ids=["", ""], -# thing_ids=["", ""], -# token="", -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"You can get all thing connected to channel" +mf_resp = mfsdk.things.get_by_channel( + channel_id="", + query_params={"offset": 1, "limit": 5}, + token="", +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """Disconnect things from channels""" -# mf_resp = mfsdk.things.disconnects( -# channel_ids=["", ""], -# thing_ids=["", ""], -# token="", -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""To disable a thing you need a thing ID and a user token""" +mf_resp = mfsdk.things.disable(thing_id="2ad76a79-640b-44c3-ab1c-3894d4013391", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """To create a channel, you need a channel and a token""" -# mf_resp = mfsdk.channels.create( -# channel={"name": "channel_name"}, token="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""Connect thing to channel""" +mf_resp = mfsdk.things.connect( + channel_id="2b7ff10e-9294-47a9-a66b-e8f7de7c5a8b", thing_id="6d591627-8657-43af-bfaa-79047b5f8ec3", action="m_read", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ" +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """As with things, you can create multiple channels at once""" -# mf_resp = mfsdk.channels.create_bulk( -# channels=[{"name": ""}, {"name": ""}], -# token="", -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""Disconnect thing from channel""" +mf_resp = mfsdk.things.disconnect( + channel_id="2b7ff10e-9294-47a9-a66b-e8f7de7c5a8b", thing_id="6d591627-8657-43af-bfaa-79047b5f8ec3", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ" +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """Update channel entities in the database""" -# mf_resp = mfsdk.channels.update( -# channel_id="", -# token="", -# channel={"name": ""}, -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""Connect things to channels""" +mf_resp = mfsdk.things.connects( + thing_ids=["769c8d58-bc7e-4003-8e5b-84301534ba7f", "a937d27a-b0aa-4e4f-a85e-bb95bf0ac1bf"], + channel_ids=["6a4c094d-b192-4e7b-837f-6d2a2bae12d5"], + action="m_read", + token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ", +) -# """You can get channel information by entering the channel ID and user token""" -# mf_resp = mfsdk.channels.get(token="", channel_id="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """You can get all channels in the database by calling the get_all () -# function""" -# mf_resp = mfsdk.channels.get_all( -# query_params={"offset": 1, "limit": 5}, token="" -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""Disconnect things from channels""" +mf_resp = mfsdk.things.disconnects( + thing_ids=["", ""], + channel_ids=["", ""], + token="", +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """A list of all the channels to which a given thing is connected""" -# mf_resp = mfsdk.channels.get_by_thing( -# thing_id="", query_params={"offset": 1, "limit": 5}, -# token="" -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""To create a channel, you need a channel and a token""" +mf_resp = mfsdk.channels.create( + channel={"name": "channel_3"}, token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """Identifies thing when given thing key""" -# mf_resp = mfsdk.channels.identify_thing(thing_key="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""As with things, you can create multiple channels at once""" +mf_resp = mfsdk.channels.create_bulk( + channels=[{"name": "channel_6"}, {"name": "channel_7"}], + token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ", +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Update channel entities in the database""" +mf_resp = mfsdk.channels.update( + channel_id="2b7ff10e-9294-47a9-a66b-e8f7de7c5a8b", + token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ", + channel={"name": "channel_3"}, +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) +''' +''' +"""You can get channel information by entering the channel ID and user token""" +mf_resp = mfsdk.channels.get(token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ", channel_id="2b7ff10e-9294-47a9-a66b-e8f7de7c5a8b") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """Delete channels from the database""" -# mf_resp = mfsdk.channels.delete( -# channel_id="", token="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""You can get all channels in the database by calling the get_all () +function""" +mf_resp = mfsdk.channels.get_all( + query_params={"offset": 0, "limit": 5}, token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ" +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """To create a group, you need the group name and a user token""" -# mf_resp = mfsdk.groups.create( -# group={"name": "group_name"}, token="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""A list of all the channels to which a given thing is connected""" +mf_resp = mfsdk.channels.get_by_thing( + thing_id="2ad76a79-640b-44c3-ab1c-3894d4013391", query_params={"offset": 0, "limit": 5}, + token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ" +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) -# """You can get group information by entering the group ID and token""" -# mf_resp = mfsdk.groups.get(group_id="", token="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) -# """Group update""" -# mf_resp = mfsdk.groups.update( -# group_id="", token="", group={""} -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""Identifies thing when given thing key""" +mf_resp = mfsdk.channels.identify_thing(thing_key="a0c5471a-b7a6-4337-81af-b6113f41d898", user_token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + -# """You can get groups in the database by calling the get_all () function""" -# mf_resp = mfsdk.groups.get_all( -# token="", query_params={"offset": 1, "limit": 5} -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""Delete channels from the database""" +mf_resp = mfsdk.channels.disable( + channel_id="2b7ff10e-9294-47a9-a66b-e8f7de7c5a8b", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) +''' +''' +"""To create a group, you need the group name and a user token""" +mf_resp = mfsdk.groups.create( + group={"name": "group_2"}, token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) +"""You can get group information by entering the group ID and token""" +mf_resp = mfsdk.groups.get(group_id="1705dbd3-e542-4a38-8bef-aa7c33bdcf2d", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) +''' +''' +"""Group update""" +#group= { +# "name": "group_1", +# "description": "", +# "metadata": { +# "role": "general" +# } +#} +mf_resp = mfsdk.groups.update( + + group_id="1705dbd3-e542-4a38-8bef-aa7c33bdcf2d", token="yJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ", group={"name: group_nat"} +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) +''' +''' +"""You can get groups in the database by calling the get_all () function""" +mf_resp = mfsdk.groups.get_all( + token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ", query_params={"offset": 0, "limit": 5} +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) +''' # """Assign user, thing or channel to a group""" # mf_resp = mfsdk.groups.assign( # group_id="", @@ -355,14 +382,14 @@ # print(mf_resp.value) # else: # print(mf_resp.error.message) - -# """Delete group from the database""" -# mf_resp = mfsdk.groups.delete(group_id="", token="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - +''' +"""Delete group from the database""" +mf_resp = mfsdk.groups.disable(group_id="29474bea-a8d6-4e5c-9336-5de0c8ca9aaf", user_token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) +''' # """Sends message via HTTP protocol""" # mf_resp = mfsdk.messages.send( # channel_id="", msg="", thing_key="" diff --git a/mainflux/channels.py b/mainflux/channels.py index d979584..972f353 100644 --- a/mainflux/channels.py +++ b/mainflux/channels.py @@ -3,6 +3,7 @@ from mainflux import response from mainflux import errors from mainflux import utils +from mainflux import things class Channels: @@ -27,8 +28,7 @@ def create(self, channel: dict, token: str): errors.channels["create"], http_resp.status_code ) else: - location = http_resp.headers.get("location") - mf_resp.value = location.split("/")[2] + mf_resp.value = http_resp.json() return mf_resp def create_bulk(self, channels: list, token: str): @@ -66,12 +66,11 @@ def get(self, channel_id: str, token: str): def get_all(self, query_params: dict, token: str): """Gets all channels from database""" - url = self.url + "/" + self.channels_endpoint mf_resp = response.Response() http_resp = requests.get( - url, + self.url + "/" + self.channels_endpoint, headers=utils.construct_header(token, utils.CTJSON), - params=query_params + params=query_params, ) if http_resp.status_code != 200: mf_resp.error.status = 1 @@ -86,13 +85,7 @@ def get_by_thing(self, thing_id: str, query_params: dict, token: str): """Gets all channels to which a specific thing is connected to""" mf_resp = response.Response() http_resp = requests.get( - self.url - + "/" - + self.things_endpoint - + "/" - + thing_id - + "/" - + self.channels_endpoint, + self.url + "/" + self.things_endpoint + "/" + thing_id + "/" + self.channels_endpoint, headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -120,14 +113,15 @@ def update(self, channel_id: str, channel: dict, token: str): ) return mf_resp - def delete(self, channel_id: str, token: str): + def disable(self, channel_id: str, token: str): """Deletes a channel entity from database""" - http_resp = requests.delete( - self.url + "/" + self.channels_endpoint + "/" + channel_id, + http_resp = requests.post( + self.url + "/" + self.channels_endpoint + "/" + channel_id + "/disable", headers=utils.construct_header(token, utils.CTJSON), ) + print(http_resp.request.url) mf_resp = response.Response() - if http_resp.status_code != 204: + if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.channels["delete"], http_resp.status_code @@ -137,8 +131,10 @@ def delete(self, channel_id: str, token: str): def identify_thing(self, thing_key: str): """Validates thing's key and returns it's ID if key is valid""" http_resp = requests.post( - self.url + "/" + self.identify_endpoint, json={"token": thing_key} + self.url + "/" + self.identify_endpoint, + headers=utils.construct_header(utils.ThingPrefix + thing_key, utils.CTJSON), ) + print(http_resp.request.url) mf_resp = response.Response() if http_resp.status_code != 200: mf_resp.error.status = 1 diff --git a/mainflux/errors.py b/mainflux/errors.py index 959c6f7..44b19ab 100644 --- a/mainflux/errors.py +++ b/mainflux/errors.py @@ -20,7 +20,7 @@ def handle_error(error_dict, status_code): users = { "create": { - 409: "Failed due to using an existing email address.", + 409: "Failed due to using an existing identity.", }, "login": { 409: "Failed due to using an existing email address.", @@ -66,7 +66,7 @@ def handle_error(error_dict, status_code): 400: "Failed due to malformed thing's ID.", }, "connect": { - + 400: "A non-existent entity request." }, "disconnect": { 400: "Failed due to malformed query parameters.", diff --git a/mainflux/groups.py b/mainflux/groups.py index 3e63042..1b99dd7 100644 --- a/mainflux/groups.py +++ b/mainflux/groups.py @@ -25,8 +25,7 @@ def create(self, group: dict, token: str): errors.groups["create"], http_resp.status_code ) else: - location = http_resp.headers.get("location") - mf_resp.value = location.split("/")[2] + mf_resp.value = http_resp.json() return mf_resp def get(self, group_id: str, token: str): @@ -86,7 +85,7 @@ def children(self, group_id: str, query_params: dict, token: str): mf_resp = response.Response() http_resp = requests.get( self.url + "/" + self.groups_endpoint + "/" + group_id + - "children", + "/children", headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -112,6 +111,8 @@ def update(self, group_id: str, group: dict, token: str): mf_resp.error.message = errors.handle_error( errors.groups["update"], http_resp.status_code ) + else: + mf_resp.value = http_resp.json() return mf_resp def members(self, group_id: str, query_params: dict, token: str): @@ -179,17 +180,17 @@ def unassign(self, group_id: str, token: str, members_ids): ) return mf_resp - def delete(self, group_id: str, token: str): - """Deletes a group entity from database""" - http_resp = requests.delete( - self.url + "/" + self.groups_endpoint + "/" + group_id, - headers=utils.construct_header(token, utils.CTJSON), + def disable(self, group_id: str, user_token: str): + """Disables a group entity from database""" + http_resp = requests.post( + self.url + "/" + self.groups_endpoint + "/" + group_id + "/disable", + headers=utils.construct_header(user_token, utils.CTJSON), ) mf_resp = response.Response() - if http_resp.status_code != 204: + if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( - errors.groups["delete"], http_resp.status_code + errors.groups["disable"], http_resp.status_code ) return mf_resp diff --git a/mainflux/keys.py b/mainflux/keys.py deleted file mode 100644 index acc7e4c..0000000 --- a/mainflux/keys.py +++ /dev/null @@ -1,60 +0,0 @@ -import requests - -from mainflux import response -from mainflux import errors -from mainflux import utils - - -class Keys: - keys_endpoint = "keys" - - def __init__(self, url: str): - self.url = url - - def issue(self, duration: str, token: str): - """Generates a new API key""" - payload = {"type": 2, "duration": duration} - mf_resp = response.Response() - http_resp = requests.post( - self.url + "/" + self.keys_endpoint, - json=payload, - headers=utils.construct_header(token, utils.CTJSON), - ) - if http_resp.status_code != 201: - mf_resp.error.status = 1 - mf_resp.error.message = errors.handle_error( - errors.things["create"], http_resp.status_code - ) - else: - mf_resp.value = http_resp.json() - return mf_resp - - def get_key_details(self, key_id: str, token: str): - """Gets API key details for the given key""" - mf_resp = response.Response() - http_resp = requests.get( - self.url + "/" + self.keys_endpoint + "/" + key_id, - headers=utils.construct_header(token, utils.CTJSON), - ) - if http_resp.status_code != 200: - mf_resp.error.status = 1 - mf_resp.error.message = errors.handle_error( - errors.things["create"], http_resp.status_code - ) - else: - mf_resp.value = http_resp.json() - return mf_resp - - def revoke(self, key_id: str, token: str): - """Revoke API key identified by the given ID.""" - mf_resp = response.Response() - http_resp = requests.delete( - self.url + "/" + self.keys_endpoint + "/" + key_id, - headers=utils.construct_header(token, utils.CTJSON), - ) - if http_resp.status_code != 204: - mf_resp.error.status = 1 - mf_resp.error.message = errors.handle_error( - errors.things["delete"], http_resp.status_code - ) - return mf_resp diff --git a/mainflux/things.py b/mainflux/things.py index 0884da0..13c83cd 100644 --- a/mainflux/things.py +++ b/mainflux/things.py @@ -6,19 +6,19 @@ class Things: - things_endpoint = "things" - connect_endpoint = "connect" - disconnect_endpoint = "disconnect" - identify_endpoint = "identify" + THINGS_ENDPOINT = "things" + CONNECT_ENDPOINT = "connect" + DISCONNECT_ENDPOINT = "disconnect" + IDENTIFY_ENDPOINT= "identify" def __init__(self, url: str): - self.url = url + self.URL = url def create(self, thing: dict, token: str): """Creates thing entity in the database""" mf_resp = response.Response() http_resp = requests.post( - self.url + "/" + self.things_endpoint, + self.URL + "/" + self.THINGS_ENDPOINT, json=thing, headers=utils.construct_header(token, utils.CTJSON), ) @@ -28,19 +28,18 @@ def create(self, thing: dict, token: str): errors.things["create"], http_resp.status_code ) else: - location = http_resp.headers.get("location") - mf_resp.value = location.split("/")[2] + mf_resp.value = http_resp.json() return mf_resp def create_bulk(self, things: list, token: str): """Creates multiple things in a bulk""" mf_resp = response.Response() http_resp = requests.post( - self.url + "/" + self.things_endpoint + "/bulk", + self.URL + "/" + self.THINGS_ENDPOINT + "/bulk", json=things, headers=utils.construct_header(token, utils.CTJSON), ) - if http_resp.status_code != 201: + if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.things["create_bulk"], http_resp.status_code @@ -53,7 +52,7 @@ def get(self, thing_id: str, token: str): """Gets a thing entity for a logged-in user""" mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.things_endpoint + "/" + thing_id, + self.URL + "/" + self.THINGS_ENDPOINT + "/" + thing_id, headers=utils.construct_header(token, utils.CTJSON), ) if http_resp.status_code != 200: @@ -69,7 +68,7 @@ def get_all(self, query_params: dict, token: str): """Gets all things from database""" mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.things_endpoint, + self.URL + "/" + self.THINGS_ENDPOINT, headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -86,7 +85,7 @@ def get_by_channel(self, channel_id: str, query_params: dict, token: str): """Gets all things to which a specific thing is connected to""" mf_resp = response.Response() http_resp = requests.get( - self.url + "/channels/" + channel_id + "/" + self.things_endpoint, + self.URL + "/channels/" + channel_id + "/" + self.THINGS_ENDPOINT, headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -101,8 +100,8 @@ def get_by_channel(self, channel_id: str, query_params: dict, token: str): def update(self, thing_id: str, thing: dict, token: str): """Updates thing entity""" - http_resp = requests.put( - self.url + "/" + self.things_endpoint + "/" + thing_id, + http_resp = requests.patch( + self.URL + "/" + self.THINGS_ENDPOINT + "/" + thing_id, json=thing, headers=utils.construct_header(token, utils.CTJSON), ) @@ -114,28 +113,29 @@ def update(self, thing_id: str, thing: dict, token: str): ) return mf_resp - def delete(self, thing_id: str, token: str): + def disable(self, thing_id: str, token: str): """Deletes a thing entity from database""" - http_resp = requests.delete( - self.url + "/" + self.things_endpoint + "/" + thing_id, + http_resp = requests.post( + self.URL + "/" + self.THINGS_ENDPOINT + "/" + thing_id + "/disable", headers=utils.construct_header(token, utils.CTJSON), ) mf_resp = response.Response() - if http_resp.status_code != 204: + if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.things["delete"], http_resp.status_code ) return mf_resp - def connects(self, thing_ids: list, channel_ids: list, token: str): + def connects(self, thing_ids: list, channel_ids: list, actions: list, token: str): """Connects thing and channel""" - payload = {"channel_ids": channel_ids, "thing_ids": thing_ids} + payload = {"subjects": thing_ids, "objects": channel_ids, "actions": actions} http_resp = requests.post( - self.url + "/" + self.connect_endpoint, + self.URL + "/connect", headers=utils.construct_header(token, utils.CTJSON), json=payload, ) + print(http_resp.request.url) mf_resp = response.Response() if http_resp.status_code != 201: mf_resp.error.status = 1 @@ -148,12 +148,13 @@ def connects(self, thing_ids: list, channel_ids: list, token: str): def disconnects(self, thing_ids: list, channel_ids: list, token: str): """Disconnect thing and channel""" - payload = {"thing_ids": thing_ids, "channel_ids": channel_ids} - http_resp = requests.delete( - self.url + "/" + self.disconnect_endpoint, + payload = {"subjects": thing_ids, "objects": channel_ids} + http_resp = requests.post( + self.URL + "/disconnect", headers=utils.construct_header(token, utils.CTJSON), json=payload, ) + print(http_resp.request.url) mf_resp = response.Response() if http_resp.status_code != 204: mf_resp.error.status = 1 @@ -162,14 +163,17 @@ def disconnects(self, thing_ids: list, channel_ids: list, token: str): ) return mf_resp - def connect(self, thing_id: str, channel_id: str, token: str): + def connect(self, thing_id: str, channel_id: str, action: str, token: str): """Connects thing and channel""" - http_resp = requests.put( - self.url + "/channels/" + channel_id + "/things/" + thing_id, + payload= {"subject": thing_id, "object": channel_id, "action": action} + http_resp = requests.post( + self.URL + "/policies", headers=utils.construct_header(token, utils.CTJSON), + json= payload, ) + print(http_resp.request.url) mf_resp = response.Response() - if http_resp.status_code != 200: + if http_resp.status_code != 201: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.things["connect"], http_resp.status_code @@ -180,10 +184,13 @@ def connect(self, thing_id: str, channel_id: str, token: str): def disconnect(self, thing_id: str, channel_id: str, token: str): """Disconnect thing and channel""" - http_resp = requests.delete( - self.url + "/channels/" + channel_id + "/things/" + thing_id, + payload = {"subject": thing_id, "object": channel_id} + http_resp = requests.post( + self.URL + "/disconnect", headers=utils.construct_header(token, utils.CTJSON), + json=payload, ) + print(http_resp.request.url) mf_resp = response.Response() if http_resp.status_code != 204: mf_resp.error.status = 1 diff --git a/mainflux/users.py b/mainflux/users.py index 0dcd154..70fcae6 100644 --- a/mainflux/users.py +++ b/mainflux/users.py @@ -59,11 +59,11 @@ def get(self, user_id: str, token: str): mf_resp.value = http_resp.json() return mf_resp - def get_all(self, query_params: dict, admin_token: str): + def get_all(self, query_params: dict, user_token: str): """Retrieves a list of users""" http_resp = requests.get( self.URL + "/" + self.USERS_ENDPOINT, - headers=utils.construct_header(admin_token, utils.CTJSON), + headers=utils.construct_header(user_token, utils.CTJSON), params=query_params, ) mf_resp = response.Response() diff --git a/tests/test_channels.py b/tests/test_channels.py index 7ed9cf7..40f6e18 100644 --- a/tests/test_channels.py +++ b/tests/test_channels.py @@ -5,7 +5,21 @@ s = sdk.SDK() -channel = {"channel_name": "channel"} +channel ={ + "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + "name": "channelName", + "owner_id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + "parent_id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + "description": "long channel description", + "metadata": { + "role": "general" + }, + "path": "bb7edb32-2eac-4aad-aebe-ed96fe073879.bb7edb32-2eac-4aad-aebe-ed96fe073879", + "level": 2, + "created_at": "2019-11-26 13:31:52", + "updated_at": "2019-11-26 13:31:52", + "status": "enabled" +} channel_id = "123-456-789" channel_id1 = "123-223-333" thing_id = "332-665-998" @@ -16,11 +30,10 @@ def test_create_channel(requests_mock): - requests_mock.register_uri( - "POST", url + "/channels", headers={"location": "/channels/" + channel_id}, status_code=201) + requests_mock.register_uri( "POST", url + "/channels", headers={"location": "/channels/" + channel_id}, json=channel, status_code=201) r = s.channels.create(channel=channel, token=token) assert r.error.status == 0 - assert channel_id == r.value + assert channel == r.value def test_create_channel_entity_exist(requests_mock): @@ -32,56 +45,49 @@ def test_create_channel_entity_exist(requests_mock): def test_create_bulk_channels(requests_mock): - requests_mock.register_uri("POST", url + "/channels/bulk", json=[ - channel_id, channel_id1], headers={"location": "/channels/channel_ids"}, status_code=201) + requests_mock.register_uri("POST", url + "/channels/bulk", json=[channel_id, channel_id1], headers={"location": "/channels/channel_ids"}, status_code=201) r = s.channels.create_bulk(channel_id, token=token) assert r.error.status == 0 assert [channel_id, channel_id1] == r.value def test_create_bulk_channels_server_error(requests_mock): - requests_mock.register_uri("POST", url + "/channels/bulk", json=[ - channel_id, channel_id1], headers={"location": "/channels/channel_ids"}, status_code=500) + requests_mock.register_uri("POST", url + "/channels/bulk", json=[channel_id, channel_id1], headers={"location": "/channels/channel_ids"}, status_code=500) r = s.channels.create_bulk(channel_id, token=token) assert r.error.status == 1 assert r.error.message == "Unexpected server-side error occurred." def test_get_channel(requests_mock): - requests_mock.register_uri( - "GET", url + "/channels/" + channel_id, json=channel, status_code=200) + requests_mock.register_uri("GET", url + "/channels/" + channel_id, json=channel, status_code=200) r = s.channels.get(channel_id=channel_id, token=token) assert r.error.status == 0 assert channel == r.value def test_get_channel_bad_token(requests_mock): - requests_mock.register_uri( - "GET", url + "/channels/" + channel_id, json=channel, status_code=401) + requests_mock.register_uri("GET", url + "/channels/" + channel_id, json=channel, status_code=401) r = s.channels.get(channel_id=channel_id, token=token) assert r.error.status == 1 assert r.error.message == "Missing or invalid access token provided." def test_get_all_channels(requests_mock): - requests_mock.register_uri( - "GET", url + "/channels", json=[channel_id, channel_id1], status_code=200) + requests_mock.register_uri("GET", url + "/channels", json=[channel_id, channel_id1], status_code=200) r = s.channels.get_all(token=token, query_params=params) assert r.error.status == 0 assert [channel_id, channel_id1] == r.value def test_get_all_channels_channel_does_not_exist(requests_mock): - requests_mock.register_uri( - "GET", url + "/channels", json=[channel_id, channel_id1], status_code=404) + requests_mock.register_uri("GET", url + "/channels", json=[channel_id, channel_id1], status_code=404) r = s.channels.get_all(token=token, query_params=params) assert r.error.status == 1 assert r.error.message == "Channel does not exist." def test_get_by_thing(requests_mock): - requests_mock.register_uri("GET", url + "/things/" + thing_id + "/channels", json=channel_id, - headers={"Authorization": "/channels/" + channel_id + "/things"}, status_code=200) + requests_mock.register_uri("GET", url + "/things/" + thing_id + "/channels", json=channel_id, headers={"Authorization": "/channels/" + channel_id + "/things"}, status_code=200) r = s.channels.get_by_thing( thing_id=thing_id, query_params=params, token=token) assert r.error.status == 0 @@ -89,8 +95,7 @@ def test_get_by_thing(requests_mock): def test_get_by_thing_does_not_exist(requests_mock): - requests_mock.register_uri("GET", url + "/things/" + thing_id + "/channels", json=channel_id, - headers={"Authorization": "/channels/" + channel_id + "/things"}, status_code=404) + requests_mock.register_uri("GET", url + "/things/" + thing_id + "/channels", json=channel_id, headers={"Authorization": "/channels/" + channel_id + "/things"}, status_code=404) r = s.channels.get_by_thing( thing_id=thing_id, query_params=params, token=token) assert r.error.status == 1 @@ -98,31 +103,27 @@ def test_get_by_thing_does_not_exist(requests_mock): def test_update_channel(requests_mock): - requests_mock.register_uri( - "PUT", url + "/channels/" + channel_id, json=json.dumps(channel), status_code=200) + requests_mock.register_uri("PUT", url + "/channels/" + channel_id, json=json.dumps(channel), status_code=200) r = s.channels.update(channel_id=channel_id, token=token, channel=channel) assert r.error.status == 0 def test_update_channel_does_not_exist(requests_mock): - requests_mock.register_uri( - "PUT", url + "/channels/" + channel_id, json=json.dumps(channel), status_code=404) + requests_mock.register_uri("PUT", url + "/channels/" + channel_id, json=json.dumps(channel), status_code=404) r = s.channels.update(channel_id=channel_id, token=token, channel=channel) assert r.error.status == 1 assert r.error.message == "Channel does not exist." def test_delete_channel(requests_mock): - requests_mock.register_uri( - "DELETE", url + "/channels/" + channel_id, status_code=204) - r = s.channels.delete(channel_id=channel_id, token=token) + requests_mock.register_uri("POST", url + "/channels/" + channel_id + "/disable", status_code=200) + r = s.channels.disable(channel_id=channel_id, token=token) assert r.error.status == 0 def test_delete_channel_malformed_channel_id(requests_mock): - requests_mock.register_uri( - "DELETE", url + "/channels/" + channel_id, status_code=400) - r = s.channels.delete(channel_id=channel_id, token=token) + requests_mock.register_uri("POST", url + "/channels/" + channel_id + "/disable", status_code=400) + r = s.channels.disable(channel_id=channel_id, token=token) assert r.error.status == 1 assert r.error.message == "Failed due to malformed channel's ID." diff --git a/tests/test_keys.py b/tests/test_keys.py deleted file mode 100644 index 8a1910c..0000000 --- a/tests/test_keys.py +++ /dev/null @@ -1,47 +0,0 @@ -from mainflux import sdk - -import json, requests_mock - -s = sdk.SDK() - -token = "9a8b7c6d5e4f3g21" -duration_params = {"type":2, "duration":10000} -key_id = "123-456-789" -url = "http://localhost" -params = None - - -def test_issue(requests_mock): - requests_mock.register_uri("POST", url + "/keys", json=token, status_code=201) - r = s.keys.issue(token=token, duration=duration_params) - assert r.error.status == 0 - assert token == r.value - -def test_create_existing_key(requests_mock): - requests_mock.register_uri("POST", url + "/keys", status_code=409) - r = s.keys.issue(token=token, duration=duration_params) - assert r.error.status == 1 - assert r.error.message == "Entity already exist." - -def test_get_key_details(requests_mock): - requests_mock.register_uri("GET", url + "/keys/" + key_id, json=key_id, status_code=200) - r = s.keys.get_key_details(token=token, key_id=key_id) - assert r.error.status == 0 - assert key_id == r.value - -def test_get_key_details_missing_token(requests_mock): - requests_mock.register_uri("GET", url + "/keys/" + key_id, json=key_id, status_code=403) - r = s.keys.get_key_details(token=token, key_id=key_id) - assert r.error.status == 1 - assert r.error.message == "Missing or invalid access token provided." - -def test_revoke(requests_mock): - requests_mock.register_uri("DELETE", url + "/keys/" + key_id, status_code=204) - r = s.keys.revoke(token=token, key_id=key_id) - assert r.error.status == 0 - -def test_revoke_bad_key(requests_mock): - requests_mock.register_uri("DELETE", url + "/keys/" + key_id, status_code=403) - r = s.keys.revoke(token=token, key_id=key_id) - assert r.error.status == 1 - assert r.error.message == "Missing or invalid access token provided." diff --git a/tests/test_things.py b/tests/test_things.py index 88d1fa6..b46b1cc 100644 --- a/tests/test_things.py +++ b/tests/test_things.py @@ -5,172 +5,229 @@ s = sdk.SDK() -thing = {"name": "thing"} -things = [{"name": "thing1"}, {"name": "thing2"}] +thing = { + "id": "35ad0272-94bb-4701-9785-ff32334327a0", + "name": "thing", + "tags": [ + "tag1", + "tag2" + ], + "owner": "edc876eb-27e2-4bc9-8599-4faf21d2a12f", + "credentials": { + "identity": "thingidentity", + "secret": "f002d93b-fa40-435e-b9d9-37f991e47e9f" + }, + "metadata": { + "domain": "example.com" + }, + "status": "enabled", + "created_at": "2019-11-26 13:31:52", + "updated_at": "2019-11-26 13:31:52" +} +things = [{ + "id": "4e5532c0-cf92-4ef3-ab7b-65ee30151c99", + "name": "thing1", + "tags": [ + "tag1", + "tag2" + ], + "owner": "edc876eb-27e2-4bc9-8599-4faf21d2a12f", + "credentials": { + "identity": "thingidentity", + "secret": "47749f5e-1e32-4834-9a1d-2d38871d4e1e" + }, + "metadata": { + "domain": "example.com" + }, + "status": "enabled", + "created_at": "2019-11-26 13:31:52", + "updated_at": "2019-11-26 13:31:52" +}, { + "id": "53ed347d-f277-4e2b-9ee1-442389ad1a9a", + "name": "thing2", + "tags": [ + "tag1", + "tag2" + ], + "owner": "edc876eb-27e2-4bc9-8599-4faf21d2a12f", + "credentials": { + "identity": "thingidentity", + "secret": "566eff24-0b55-4033-9ab1-b4df0d9a3266" + }, + "metadata": { + "domain": "example.com" + }, + "status": "enabled", + "created_at": "2019-11-26 13:31:52", + "updated_at": "2019-11-26 13:31:52" +}] thing_id = "123-456-789" thing_id1 = "123-223-333" channel_id = "654-654-654" channel_id1 = "654-654-654" -token = "9a8b7c6d5e4f3g21" +token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" url = "http://localhost" params = None - +policies= { + "policies": [ + { + "owner_id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + "subject": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + "object": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + "actions": [ + "m_write", + "g_add" + ], + "created_at": "2019-11-26 13:31:52", + "updated_at": "2019-11-26 13:31:52" + } + ], + "total": 1, + "offset": 0, + "limit": 10 +} def test_create_thing(requests_mock): - requests_mock.register_uri( - "POST", url + "/things", headers={"location": "/things/" + thing_id}, status_code=201) + requests_mock.register_uri("POST", url + "/things", headers={"location": "/things/" + thing["id"]}, json=thing, status_code=201) r = s.things.create(thing=thing, token=token) assert r.error.status == 0 - assert thing_id == r.value + assert thing == r.value def test_create_existing_thing(requests_mock): - requests_mock.register_uri( - "POST", url + "/things", headers={"location": "/things/" + thing_id}, status_code=409) + requests_mock.register_uri("POST", url + "/things", headers={"location": "/things/" + thing_id}, status_code=409) r = s.things.create(thing=thing, token=token) assert r.error.status == 1 assert r.error.message == "Entity already exist." def test_create_bulk_things(requests_mock): - requests_mock.register_uri("POST", url + "/things/bulk", json=[ - thing_id, thing_id1], headers={"location": "/things/" + thing_id}, status_code=201) + requests_mock.register_uri("POST", url + "/things/bulk", json=things, status_code=200) r = s.things.create_bulk(things=things, token=token) assert r.error.status == 0 - assert [thing_id, thing_id1] == r.value + assert things == r.value def test_create_bulk_things_missing_token(requests_mock): - requests_mock.register_uri("POST", url + "/things/bulk", json=[ - thing_id, thing_id1], headers={"location": "/things/" + thing_id}, status_code=401) + requests_mock.register_uri("POST", url + "/things/bulk", json=[thing_id, thing_id1], headers={"location": "/things/" + thing_id}, status_code=401) r = s.things.create_bulk(things=things, token=token) assert r.error.status == 1 assert r.error.message == "Missing or invalid access token provided." def test_get_thing(requests_mock): - requests_mock.register_uri( - "GET", url + "/things/" + thing_id, json=thing, status_code=200) + requests_mock.register_uri("GET", url + "/things/" + thing_id, json=thing, status_code=200) r = s.things.get(thing_id=thing_id, token=token) assert r.error.status == 0 assert thing == r.value def test_get_thing_malformed_query(requests_mock): - requests_mock.register_uri( - "GET", url + "/things/" + thing_id, json=thing, status_code=400) + requests_mock.register_uri("GET", url + "/things/" + thing_id, json=thing, status_code=400) r = s.things.get(thing_id=thing_id, token=token) assert r.error.status == 1 assert r.error.message == "Failed due to malformed query parameters." def test_get_all_things(requests_mock): - requests_mock.register_uri( - "GET", url + "/things", json=[thing_id, thing_id1], status_code=200) + requests_mock.register_uri("GET", url + "/things", json=[thing_id, thing_id1], status_code=200) r = s.things.get_all(token=token, query_params=params) assert r.error.status == 0 assert [thing_id, thing_id1] == r.value def test_get_all_thing_does_not_exist(requests_mock): - requests_mock.register_uri( - "GET", url + "/things", json=[thing_id, thing_id1], status_code=404) + requests_mock.register_uri("GET", url + "/things", json=[thing_id, thing_id1], status_code=404) r = s.things.get_all(token=token, query_params=params) assert r.error.status == 1 assert r.error.message == "Thing does not exist." def test_get_by_channel(requests_mock): - requests_mock.register_uri("GET", url + "/channels/" + channel_id + "/things", json=channel_id, - headers={"Authorization": "/channels/" + channel_id + "/things"}, status_code=200) - r = s.things.get_by_channel( - channel_id=channel_id, query_params=params, token=token) + requests_mock.register_uri("GET", url + "/channels/" + channel_id + "/things", json=channel_id, headers={"Authorization": "/channels/" + channel_id + "/things"}, status_code=200) + r = s.things.get_by_channel(channel_id=channel_id, query_params=params, token=token) assert r.error.status == 0 assert channel_id == r.value def test_get_by_channel_missing_token(requests_mock): - requests_mock.register_uri("GET", url + "/channels/" + channel_id + "/things", json=channel_id, - headers={"Authorization": "/channels/" + channel_id + "/things"}, status_code=401) - r = s.things.get_by_channel( - channel_id=channel_id, query_params=params, token=token) + requests_mock.register_uri("GET", url + "/channels/" + channel_id + "/things", json=channel_id, headers={"Authorization": "/channels/" + channel_id + "/things"}, status_code=401) + r = s.things.get_by_channel(channel_id=channel_id, query_params=params, token=token) assert r.error.status == 1 assert r.error.message == "Missing or invalid access token provided." def test_update_thing(requests_mock): - requests_mock.register_uri( - "PUT", url + "/things/" + thing_id, json=json.dumps(thing), status_code=200) - r = s.things.update(thing_id=thing_id, token=token, thing=thing) + requests_mock.register_uri("PATCH", url + "/things/" + thing["id"], json=thing, status_code=200) + r = s.things.update(thing_id=thing["id"], token=token, thing=thing) assert r.error.status == 0 def test_update_thing_bad_json(requests_mock): - requests_mock.register_uri( - "PUT", url + "/things/" + thing_id, json=json.dumps(thing), status_code=400) - r = s.things.update(thing_id=thing_id, token=token, thing=thing) + requests_mock.register_uri("PATCH", url + "/things/" + thing["id"], json=thing, status_code=400) + r = s.things.update(thing_id=thing["id"], token=token, thing=thing) assert r.error.status == 1 assert r.error.message == "Failed due to malformed JSON." -def test_delete_thing(requests_mock): - requests_mock.register_uri( - "DELETE", url + "/things/" + thing_id, status_code=204) - r = s.things.delete(thing_id=thing_id, token=token) +def test_disable_thing(requests_mock): + requests_mock.register_uri("POST", url + "/things/" + thing["id"] + "/disable", status_code=200) + r = s.things.disable(thing_id=thing["id"], token=token) assert r.error.status == 0 -def test_delete_bad_thing_id(requests_mock): - requests_mock.register_uri( - "DELETE", url + "/things/" + thing_id, status_code=400) - r = s.things.delete(thing_id=thing_id, token=token) +def test_disable_bad_thing_id(requests_mock): + requests_mock.register_uri("POST", url + "/things/" + thing["id"] + "/disable", status_code=400) + r = s.things.disable(thing_id=thing["id"], token=token) assert r.error.status == 1 assert r.error.message == "Failed due to malformed thing's ID." def test_connect_thing(requests_mock): - requests_mock.register_uri( - "PUT", url + "/channels/" + channel_id + "/things/"+thing_id, json=[channel_id, thing_id], status_code=200) - r = s.things.connect(channel_id=channel_id, thing_id=thing_id, token=token) + requests_mock.register_uri("POST", url + "/policies", status_code=201) + r = s.things.connect(channel_id=channel_id, thing_id=thing_id, token=token, action=["m_read"]) assert r.error.status == 0 assert r.value == "connected" +def test_connects_things(requests_mock): + requests_mock.register_uri("POST", url + "/connect", json=policies, status_code=201) + r = s.things.connects(channel_ids=[channel_id], thing_ids=[thing_id, thing_id1], token=token, actions=["m_read"]) + assert r.error.status == 0 + +def test_connects_things_non_existing_entity(requests_mock): + requests_mock.register_uri("POST", url + "/connect", status_code=400) + r = s.things.connects(channel_ids=[channel_id], thing_ids=[thing_id, thing_id1], token=token, actions=["m_read"]) + assert r.error.status == 1 + assert r.error.message == "A non-existent entity request." def test_connect_non_existing_entity(requests_mock): - requests_mock.register_uri( - "PUT", url + "/channels/" + channel_id + "/things/"+thing_id, json=[channel_id, thing_id], status_code=404) - r = s.things.connect(channel_id=channel_id, thing_id=thing_id, token=token) + requests_mock.register_uri("POST", url + "/policies", status_code=404) + r = s.things.connect(channel_id=channel_id, thing_id=thing_id, token=token, action="m_read") assert r.error.status == 1 assert r.error.message == "A non-existent entity request." def test_disconnect_thing(requests_mock): - requests_mock.register_uri( - "DELETE", url + "/channels/" + channel_id + "/things/" + thing_id, status_code=204) - r = s.things.disconnect(channel_id=channel_id, - thing_id=thing_id, token=token) + requests_mock.register_uri("POST", url + "/disconnect", status_code=204) + r = s.things.disconnect(channel_id=channel_id, thing_id=thing_id, token=token) assert r.error.status == 0 - + def test_disconnect_thing_or_channel_does_not_exist(requests_mock): - requests_mock.register_uri( - "DELETE", url + "/channels/" + channel_id + "/things/" + thing_id, status_code=404) - r = s.things.disconnect(channel_id=channel_id, - thing_id=thing_id, token=token) + requests_mock.register_uri("POST", url + "/disconnect", status_code=404) + r = s.things.disconnect(channel_id=channel_id, thing_id=thing_id, token=token) assert r.error.status == 1 assert r.error.message == "Channel or thing does not exist." def test_disconnects(requests_mock): - requests_mock.register_uri("DELETE", url + "/disconnect", status_code=200) - r = s.things.disconnects(channel_ids=[channel_id], thing_ids=[ - thing_id, thing_id1], token=token) - assert r.error.status == 1 + requests_mock.register_uri("POST", url + "/disconnect", status_code=204) + r = s.things.disconnects(channel_ids=[channel_id], thing_ids=[thing_id, thing_id1], token=token) + assert r.error.status == 0 def test_disconnects_bad_json(requests_mock): - requests_mock.register_uri("DELETE", url + "/disconnect", status_code=400) - r = s.things.disconnects(channel_ids=[channel_id], thing_ids=[ - thing_id, thing_id1], token=token) + requests_mock.register_uri("POST", url + "/disconnect", status_code=404) + r = s.things.disconnects(channel_ids=[channel_id], thing_ids=[thing_id, thing_id1], token=token) assert r.error.status == 1 - assert r.error.message == "Failed due to malformed query parameters." + assert r.error.message == "Channel or thing does not exist." diff --git a/tests/test_users.py b/tests/test_users.py index 9aafe74..7041cc4 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -3,32 +3,94 @@ import json, requests_mock s = sdk.SDK() -user = {"email": "test@email.com", "password": "12345678"} -user1 = {"email": "test1@email.com", "password": "12345678"} -user2 = {"email": "test2@email.com", "password": "12345678"} -old_password = {"old_password": "12345678"} -password = {"password": "dsa"} +user = { + "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + "name": "userName", + "tags": [ + "tag1", + "tag2" + ], + "owner": "aa68f94c-de36-48dd-9c53-d8ac8b12d86b", + "credentials": { + "identity": "test@email.com" + }, + "metadata": { + "domain": "example.com" + }, + "status": "enabled", + "created_at": "2019-11-26 13:31:52", + "updated_at": "2019-11-26 13:31:52" +} +user1 = { + "id": "1d36ac54-9bb7-4079-a46b-63c34f7fc678", + "name": "userName1", + "tags": [ + "tag1", + "tag2" + ], + "owner": "aa68f94c-de36-48dd-9c53-d8ac8b12d86b", + "credentials": { + "identity": "test1@email.com" + }, + "metadata": { + "domain": "example.com" + }, + "status": "enabled", + "created_at": "2019-11-26 13:31:52", + "updated_at": "2019-11-26 13:31:52" +} + +user2 = { + "id": "e2c769b8-8b8c-4886-8b19-e155c4d363e6", + "name": "userName", + "tags": [ + "tag1", + "tag2" + ], + "owner": "aa68f94c-de36-48dd-9c53-d8ac8b12d86b", + "credentials": { + "identity": "test2@email.com" + }, + "metadata": { + "domain": "example.com" + }, + "status": "enabled", + "created_at": "2019-11-26 13:31:52", + "updated_at": "2019-11-26 13:31:52" +} +old_secret = {"old_secret": "12345678"} +new_secret = {"new_secret": "dsa"} user_id = "123-456" -token = "9a8b7c6d5e4f3g21" +token = { + "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", + "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", + "access_type": "access" +} url = "http://localhost" def test_create_user(requests_mock): - requests_mock.register_uri("POST", url + "/users", headers={"location": "/users/" + user_id}, status_code=201) + requests_mock.register_uri("POST", url + "/users", headers={"location": "/users/" + user_id}, json=user, status_code=201) r = s.users.create(user=user) assert r.error.status == 0 - assert user_id == r.value - + assert user == r.value +def test_create_user_bad_user(requests_mock): + requests_mock.register_uri("POST", url + "/users", headers={"location": "/users/" + user_id}, status_code=409) + r = s.users.create(user=user) + assert r.error.status == 1 + assert r.error.message == "Failed due to using an existing identity." + + def test_login_user(requests_mock): - requests_mock.register_uri("POST", url + "/tokens", json={"token": token}, status_code=201) + requests_mock.register_uri("POST", url + "/users/tokens/issue", json=token, status_code=201) r = s.users.login(user=user) assert r.error.status == 0 assert token == r.value def test_login_user_bad_email(requests_mock): - requests_mock.register_uri("POST", url + "/tokens", status_code=409) + requests_mock.register_uri("POST", url + "/users/tokens/issue", status_code=409) r = s.users.login(user=user) assert r.error.status == 1 assert r.error.message == "Failed due to using an existing email address." @@ -36,53 +98,77 @@ def test_login_user_bad_email(requests_mock): def test_get_user(requests_mock): requests_mock.register_uri("GET", url + "/users/" + user_id, json=user, status_code=200) - r = s.users.get(user_id=user_id, token=token) + r = s.users.get(user_id=user_id, token=token["access_token"]) assert r.error.status == 0 assert user == r.value def test_get_user_bad_token(requests_mock): requests_mock.register_uri("GET", url + "/users/" + user_id, json=user, status_code=401) - r = s.users.get(user_id=user_id, token=token) + r = s.users.get(user_id=user_id, token=token["access_token"]) assert r.error.status == 1 assert r.error.message == "Missing or invalid access token provided." def test_get_all_users(requests_mock): requests_mock.register_uri("GET", url + "/users", json=[user, user2], status_code=200) - r = s.users.get_all(admin_token=token, query_params=None) + r = s.users.get_all(query_params=None, user_token=token["access_token"]) assert r.error.status == 0 assert [user, user2] == r.value def test_get_all_user_bad_request(requests_mock): requests_mock.register_uri("GET", url + "/users" , json=user, status_code=422) - r = s.users.get_all(admin_token=token, query_params=None) + r = s.users.get_all(query_params=None, user_token=token["access_token"]) assert r.error.status == 1 assert r.error.message == "Database can't process request." def test_update_user(requests_mock): - requests_mock.register_uri("PUT", url + "/users", json=json.dumps(user1), status_code=200) - r = s.users.update(user=user, user_token=token) + requests_mock.register_uri("PATCH", url + "/users/" + user["id"], json=user, status_code=200) + r = s.users.update(user=user, user_token=token["access_token"]) assert r.error.status == 0 def test_non_existing_user_update(requests_mock): - requests_mock.register_uri("PUT", url + "/users", json=json.dumps(user1), status_code=404) - r = s.users.update(user=user, user_token=token) + requests_mock.register_uri("PATCH",url + "/users/" + user["id"], json=user, status_code=404) + r = s.users.update(user=user, user_token=token["access_token"]) assert r.error.status == 1 assert r.error.message == "Failed due to non existing user." def test_update_user_password(requests_mock): - requests_mock.register_uri("PATCH", url + "/password", status_code=201) - r = s.users.update_password(old_password=old_password, password=password, user_token=token) + requests_mock.register_uri("PATCH", url + "/users" + "/secret", status_code=200) + r = s.users.update_password(old_secret=old_secret, new_secret=new_secret, user_token=token["access_token"]) assert r.error.status == 0 def test_update_user_password_bad_token(requests_mock): - requests_mock.register_uri("PATCH", url + "/password", status_code=415) - r = s.users.update_password(old_password=old_password, password=password, user_token=token) + requests_mock.register_uri("PATCH",url + "/users" + "/secret", status_code=415) + r = s.users.update_password(old_secret=old_secret, new_secret=new_secret, user_token=token["access_token"]) assert r.error.status == 1 assert r.error.message == "Missing or invalid content type." + +def test_enable_user(requests_mock): + requests_mock.register_uri("POST", url + "/users/" + user["id"] + "/enable", json=user, status_code=204) + r = s.users.enable(user_id=user["id"], user_token= token["access_token"]) + assert r.error.status == 0 + assert user == r.value + +def test_disable_user(requests_mock): + requests_mock.register_uri("POST", url + "/users/" + user["id"] + "/disable", json=user, status_code=200) + r = s.users.disable(user_id=user["id"], user_token= token["access_token"]) + assert r.error.status == 0 + assert user == r.value + +def test_enable_user_bad_user(requests_mock): + requests_mock.register_uri("POST", url + "/users/" + user["id"] + "/enable", json=user, status_code=404) + r = s.users.enable(user_id=user["id"], user_token= token["access_token"]) + assert r.error.status == 1 + assert r.error.message == "Failed due to non existing user." + +def test_disable_user_bad_user(requests_mock): + requests_mock.register_uri("POST", url + "/users/" + user["id"] + "/disable", json=user, status_code=404) + r = s.users.disable(user_id=user["id"], user_token= token["access_token"]) + assert r.error.status == 1 + assert r.error.message == "Failed due to non existing user." \ No newline at end of file From 0dd8d622d6c1457523c814b9287189ae0c84d28f Mon Sep 17 00:00:00 2001 From: Musilah Date: Mon, 21 Aug 2023 12:02:47 +0300 Subject: [PATCH 04/31] Support latest OS version and 2 python versions Signed-off-by: Musilah --- .github/workflows/python-testing.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-testing.yml b/.github/workflows/python-testing.yml index 30463e3..c0e1223 100644 --- a/.github/workflows/python-testing.yml +++ b/.github/workflows/python-testing.yml @@ -15,8 +15,8 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.5, 3.6, 3.7, 3.8] - os: [windows-2022, windows-2019, ubuntu-18.04, ubuntu-20.04, macos-10.15, macos-11] + python-version: [3.7, 3.9] + os: [windows-2022, ubuntu-22.04, macos-11] steps: - name: Checkout code uses: actions/checkout@v2 From f4f59168d5d097507fb995a7b5f9a285a478ef61 Mon Sep 17 00:00:00 2001 From: Musilah Date: Mon, 21 Aug 2023 12:11:30 +0300 Subject: [PATCH 05/31] Fix Tests Signed-off-by: Musilah --- examples/examples.py | 185 +++++++++++++++++++++---------------------- mainflux/errors.py | 2 +- mainflux/groups.py | 37 ++++----- mainflux/messages.py | 1 + mainflux/sdk.py | 2 - tests/test_groups.py | 59 +++++++++----- 6 files changed, 149 insertions(+), 137 deletions(-) diff --git a/examples/examples.py b/examples/examples.py index 4d432ed..036f3ca 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -15,7 +15,7 @@ """To start working with the Mainflux system, you need to create a user account""" mf_resp = mfsdk.users.create( - user={"credentials": {"identity": "example23@example.com", "secret": "12345678"}}, + user={"credentials": {"identity": "example25@example.com", "secret": "12345678"}}, token="", ) if mf_resp.error.status == 0: @@ -25,7 +25,7 @@ """To log in to the Mainflux system, you need to create a user token""" mf_resp = mfsdk.users.login( - user={ "identity" : "example23@example.com", "secret": "12345678"} + user={ "identity" : "example20@example.com", "secret": "12345678"} ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -161,7 +161,7 @@ """Connect thing to channel""" mf_resp = mfsdk.things.connect( - channel_id="2b7ff10e-9294-47a9-a66b-e8f7de7c5a8b", thing_id="6d591627-8657-43af-bfaa-79047b5f8ec3", action="m_read", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ" + channel_id="6a4c094d-b192-4e7b-837f-6d2a2bae12d5", thing_id="769c8d58-bc7e-4003-8e5b-84301534ba7f", action="m_write", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMzI1ODUsImlhdCI6MTY5MjI3ODU4NSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.hAJllwSCLDOqJseCKkTtw4qI9EyuBat6qaLGsvdsU-OGVS6-VkkK6boiDQ-_Men9CT6oUpzzTmW3e0dRF72j3g" ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -170,7 +170,7 @@ """Disconnect thing from channel""" mf_resp = mfsdk.things.disconnect( - channel_id="2b7ff10e-9294-47a9-a66b-e8f7de7c5a8b", thing_id="6d591627-8657-43af-bfaa-79047b5f8ec3", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ" + channel_id="2b7ff10e-9294-47a9-a66b-e8f7de7c5a8b", thing_id="6d591627-8657-43af-bfaa-79047b5f8ec3", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMzI1ODUsImlhdCI6MTY5MjI3ODU4NSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.hAJllwSCLDOqJseCKkTtw4qI9EyuBat6qaLGsvdsU-OGVS6-VkkK6boiDQ-_Men9CT6oUpzzTmW3e0dRF72j3g" ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -278,7 +278,7 @@ ''' """To create a group, you need the group name and a user token""" mf_resp = mfsdk.groups.create( - group={"name": "group_2"}, token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ") + group={"name": "group_D", "parent_id": "d6198103-4724-427e-b052-e6ad544c8864"}, token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIyNjk5MzEsImlhdCI6MTY5MjIxNTkzMSwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.vDHq7AOvppvknsKPdAxnGjsErUZ25_gAbZJ1zom3QqZ1sNAoPPU5AyVor-EgMeq1yvhggh8wzLx-9TSK6pQcCA") if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -293,16 +293,12 @@ ''' ''' """Group update""" -#group= { -# "name": "group_1", -# "description": "", -# "metadata": { -# "role": "general" -# } -#} +group={ + "id": "75b2f10c-b903-4205-8af5-9d672be26d63", + "name": "group_15" +} mf_resp = mfsdk.groups.update( - - group_id="1705dbd3-e542-4a38-8bef-aa7c33bdcf2d", token="yJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ", group={"name: group_nat"} + token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIyNjk5MzEsImlhdCI6MTY5MjIxNTkzMSwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.vDHq7AOvppvknsKPdAxnGjsErUZ25_gAbZJ1zom3QqZ1sNAoPPU5AyVor-EgMeq1yvhggh8wzLx-9TSK6pQcCA", group= group ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -318,90 +314,91 @@ print(mf_resp.value) else: print(mf_resp.error.message) -''' -# """Assign user, thing or channel to a group""" -# mf_resp = mfsdk.groups.assign( -# group_id="", -# token="", -# members_ids=["" | "" | ""], -# member_type='<"users" | "things" | "channels">', -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - -# """Unassign""" -# mf_resp = mfsdk.groups.unassign( -# group_id="", -# token="", -# members_ids=["" | "" | ""], -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - -# """Get list of children from group""" -# mf_resp = mfsdk.groups.children( -# group_id="", token="", -# query_params={"offset": 0, "limit": 5} -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - -# """Get list of parents from group""" -# mf_resp = mfsdk.groups.parents( -# group_id="", token="", -# query_params={"offset": 0, "limit": 5} -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - -# """Get list of members from group""" -# mf_resp = mfsdk.groups.members( -# member_id="", token="", -# query_params={"offset": 0, "limit": 5} -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - -# """Get list of memberships from member""" -# mf_resp = mfsdk.groups.memberships( -# group_id="", -# token="", -# query_params={"offset": 0, "limit": 5}, -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) -''' + + +"""Assign user, thing or channel to a group""" +mf_resp = mfsdk.groups.assign( + group_id="d6198103-4724-427e-b052-e6ad544c8864", + token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMjEyNzgsImlhdCI6MTY5MjI2NzI3OCwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.o5l7GX9OXrTr_st-gc1FNPwf7Kx-7FYrO7JUfXOUIL9GR0lKqBuwOLHpQav_8RCWmO1EFsiRzo1hsWRE1BKoXA", + members_ids="9c398baf-5520-48ed-86de-572be9405d5b", + member_type=["g_update"], +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Unassign""" +mf_resp = mfsdk.groups.unassign( + group_id="d6198103-4724-427e-b052-e6ad544c8864", + token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMjEyNzgsImlhdCI6MTY5MjI2NzI3OCwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.o5l7GX9OXrTr_st-gc1FNPwf7Kx-7FYrO7JUfXOUIL9GR0lKqBuwOLHpQav_8RCWmO1EFsiRzo1hsWRE1BKoXA", + members_ids="9c398baf-5520-48ed-86de-572be9405d5b", +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Get list of children from group""" +mf_resp = mfsdk.groups.children( + group_id="75b2f10c-b903-4205-8af5-9d672be26d63", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIyNjk5MzEsImlhdCI6MTY5MjIxNTkzMSwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.vDHq7AOvppvknsKPdAxnGjsErUZ25_gAbZJ1zom3QqZ1sNAoPPU5AyVor-EgMeq1yvhggh8wzLx-9TSK6pQcCA", + query_params={"offset": 0, "limit": 5} +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Get list of parents from group""" +mf_resp = mfsdk.groups.parents( + group_id="b7cbb7c3-39af-4577-bae9-f83f3674b364", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIyNjk5MzEsImlhdCI6MTY5MjIxNTkzMSwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.vDHq7AOvppvknsKPdAxnGjsErUZ25_gAbZJ1zom3QqZ1sNAoPPU5AyVor-EgMeq1yvhggh8wzLx-9TSK6pQcCA", + query_params={"offset": 0, "limit": 5} +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Get list of members from group""" +mf_resp = mfsdk.groups.members( + group_id="d6198103-4724-427e-b052-e6ad544c8864", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMjEyNzgsImlhdCI6MTY5MjI2NzI3OCwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.o5l7GX9OXrTr_st-gc1FNPwf7Kx-7FYrO7JUfXOUIL9GR0lKqBuwOLHpQav_8RCWmO1EFsiRzo1hsWRE1BKoXA", + query_params={"offset": 0, "limit": 5} +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Get list of memberships from member""" +mf_resp = mfsdk.groups.memberships( + member_id="9c398baf-5520-48ed-86de-572be9405d5b", + token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMjEyNzgsImlhdCI6MTY5MjI2NzI3OCwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.o5l7GX9OXrTr_st-gc1FNPwf7Kx-7FYrO7JUfXOUIL9GR0lKqBuwOLHpQav_8RCWmO1EFsiRzo1hsWRE1BKoXA", + query_params={"offset": 0, "limit": 5}, +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + """Delete group from the database""" mf_resp = mfsdk.groups.disable(group_id="29474bea-a8d6-4e5c-9336-5de0c8ca9aaf", user_token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Sends message via HTTP protocol""" +mf_resp = mfsdk.messages.send( + channel_id="6a4c094d-b192-4e7b-837f-6d2a2bae12d5", msg="Hello", thing_key="a0c5471a-b7a6-4337-81af-b6113f41d898" +) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) ''' -# """Sends message via HTTP protocol""" -# mf_resp = mfsdk.messages.send( -# channel_id="", msg="", thing_key="" -# ) -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) - -# """Reads messages from database for a given channel""" -# mf_resp = mfsdk.messages.read(channel_id="", token="") -# if mf_resp.error.status == 0: -# print(mf_resp.value) -# else: -# print(mf_resp.error.message) +"""Reads messages from database for a given channel""" +mf_resp = mfsdk.messages.read(channel_id="6a4c094d-b192-4e7b-837f-6d2a2bae12d5", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMzI1ODUsImlhdCI6MTY5MjI3ODU4NSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.hAJllwSCLDOqJseCKkTtw4qI9EyuBat6qaLGsvdsU-OGVS6-VkkK6boiDQ-_Men9CT6oUpzzTmW3e0dRF72j3g") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) diff --git a/mainflux/errors.py b/mainflux/errors.py index 44b19ab..ff2f131 100644 --- a/mainflux/errors.py +++ b/mainflux/errors.py @@ -138,7 +138,7 @@ def handle_error(error_dict, status_code): 400: "Failed due to malformed query parameters.", 404: "Group does not exist.", }, - "delete": { + "disable": { 400: "Failed due to malformed query parameters.", 404: "Group does not exist.", }, diff --git a/mainflux/groups.py b/mainflux/groups.py index 1b99dd7..b8154a9 100644 --- a/mainflux/groups.py +++ b/mainflux/groups.py @@ -1,4 +1,5 @@ import requests +import json from mainflux import response from mainflux import errors @@ -84,8 +85,7 @@ def children(self, group_id: str, query_params: dict, token: str): """Gets children for a specific group from database""" mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.groups_endpoint + "/" + group_id + - "/children", + self.url + "/" + self.groups_endpoint + "/" + group_id + "/children", headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -102,9 +102,10 @@ def update(self, group_id: str, group: dict, token: str): """Updates group entity""" http_resp = requests.put( self.url + "/" + self.groups_endpoint + "/" + group_id, - json=group, + data= json.dumps(group), headers=utils.construct_header(token, utils.CTJSON), ) + print(http_resp) mf_resp = response.Response() if http_resp.status_code != 200: mf_resp.error.status = 1 @@ -118,8 +119,7 @@ def update(self, group_id: str, group: dict, token: str): def members(self, group_id: str, query_params: dict, token: str): """Get list of members ID's from group""" http_resp = requests.get( - self.url + "/" + self.groups_endpoint + "/" + group_id + - "/members", + self.url + "/" + self.groups_endpoint + "/" + group_id + "/members", headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -129,32 +129,36 @@ def members(self, group_id: str, query_params: dict, token: str): mf_resp.error.message = errors.handle_error( errors.groups["members"], http_resp.status_code ) + else: + mf_resp.value = http_resp.json() return mf_resp def memberships(self, member_id: str, query_params: dict, token: str): """Get list of members ID's from group""" http_resp = requests.get( - self.url + "/members/" + member_id + "/" + self.groups_endpoint, + self.url + "/users" + "/" + member_id + "/memberships", headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) + print(http_resp.request.url) mf_resp = response.Response() if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.groups["members"], http_resp.status_code ) + else: + mf_resp.value = http_resp.json() return mf_resp - def assign(self, group_id: str, members_ids, member_type: str, token: str): + def assign(self, group_id: str, members_ids: str, member_type: dict, token: str): """Assign""" - payload = {"type": member_type, "members": members_ids} + payload = {"Object": group_id, "Subject": members_ids, "Actions": member_type} mf_resp = response.Response() http_resp = requests.post( - self.url + "/" + self.groups_endpoint + "/" + group_id + - "/members", + self.url + "/users/policies", headers=utils.construct_header(token, utils.CTJSON), - json=payload, + json= payload, ) if http_resp.status_code != 200: mf_resp.error.status = 1 @@ -164,12 +168,11 @@ def assign(self, group_id: str, members_ids, member_type: str, token: str): return mf_resp def unassign(self, group_id: str, token: str, members_ids): - """Assign""" - payload = {"members": members_ids} + """Unassign""" + payload = {"Object": group_id, "Subject": members_ids} mf_resp = response.Response() http_resp = requests.delete( - self.url + "/" + self.groups_endpoint + "/" + group_id + - "/members", + self.url + "/users/policies" + "/" + members_ids + "/" + group_id, headers=utils.construct_header(token, utils.CTJSON), json=payload, ) @@ -194,9 +197,7 @@ def disable(self, group_id: str, user_token: str): ) return mf_resp - def share_groups( - self, token: str, user_group_id: str, thing_group_id: str - ): + def share_groups(self, token: str, user_group_id: str, thing_group_id: str): """Adds access rights on thing groups to the user group""" mf_resp = response.Response() http_resp = requests.post( diff --git a/mainflux/messages.py b/mainflux/messages.py index 0791e60..ce403c0 100644 --- a/mainflux/messages.py +++ b/mainflux/messages.py @@ -25,6 +25,7 @@ def send(self, channel_id: str, msg: dict, thing_key: str): headers=utils.construct_header( utils.ThingPrefix + thing_key, utils.CTJSON), ) + print(http_resp) if http_resp.status_code != 202: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( diff --git a/mainflux/sdk.py b/mainflux/sdk.py index e3a5b6e..5e9c0f0 100644 --- a/mainflux/sdk.py +++ b/mainflux/sdk.py @@ -3,7 +3,6 @@ from mainflux import messages from mainflux import channels from mainflux import groups -from mainflux import keys from mainflux import boostrap from mainflux import certs @@ -30,7 +29,6 @@ def __init__( ) self.channels = channels.Channels(things_url) self.groups = groups.Groups(auth_url) - self.keys = keys.Keys(auth_url) self.bootstrap = boostrap.Bootstrap(bootstrap_url) self.certs = certs.Certs(certs_url) self.version_url = things_url diff --git a/tests/test_groups.py b/tests/test_groups.py index 68f1bb1..2c550b5 100644 --- a/tests/test_groups.py +++ b/tests/test_groups.py @@ -1,12 +1,27 @@ from mainflux import sdk -import json, requests_mock +import requests_mock s = sdk.SDK() channel_id = "654-559-774" members = {"members": channel_id, "type": "channels"} -group = {"group_name": "group"} +members_ids ="4e5532c0-cf92-4ef3-ab7b-65ee30151c99" +group ={ + "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + "name": "groupName", + "owner_id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + "parent_id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", + "description": "long group description", + "metadata": { + "role": "general" + }, + "path": "bb7edb32-2eac-4aad-aebe-ed96fe073879.bb7edb32-2eac-4aad-aebe-ed96fe073879", + "level": 2, + "created_at": "2019-11-26 13:31:52", + "updated_at": "2019-11-26 13:31:52", + "status": "enabled" +} group_id = "888-888-888" group_id1 = "989-787-686" thing_group_id = "868-464-262" @@ -15,10 +30,10 @@ def test_create_group(requests_mock): - requests_mock.register_uri("POST", url + "/groups", headers={"location": "/groups/" + group_id}, status_code=201) + requests_mock.register_uri("POST", url + "/groups", headers={"location": "/groups/" + group_id}, json=group, status_code=201) r = s.groups.create(group=group, token=token) assert r.error.status == 0 - assert group_id == r.value + assert group == r.value def test_create_group_existing_email_address(requests_mock): @@ -57,20 +72,20 @@ def test_get_all_groups_malformed_query(requests_mock): def test_update_group(requests_mock): - requests_mock.register_uri("PUT", url + "/groups/" + group_id, json=json.dumps(group), status_code=200) - r = s.groups.update(group_id=group_id, token=token, group=group) + requests_mock.register_uri("PUT", url + "/groups/" + group_id, json=group, status_code=200) + r = s.groups.update(group_id=group_id, group=group, token=token) assert r.error.status == 0 def test_update_group_sverver_error(requests_mock): - requests_mock.register_uri("PUT", url + "/groups/" + group_id, json=json.dumps(group), status_code=500) - r = s.groups.update(group_id=group_id, token=token, group=group) + requests_mock.register_uri("PUT", url + "/groups/" + group_id, json=group, status_code=500) + r = s.groups.update(group_id=group_id, group=group, token=token) assert r.error.status == 1 assert r.error.message == "Unexpected server-side error occurred." def test_members(requests_mock): - requests_mock.register_uri("GET", url + "/groups/" + group_id + "/members", status_code=200) + requests_mock.register_uri("GET", url + "/groups/" + group_id + "/members",json=group_id, status_code=200) r = s.groups.members(group_id=group_id, query_params=None, token=token) assert r.error.status == 0 @@ -83,40 +98,40 @@ def test_members_bad_content_type(requests_mock): def test_assign(requests_mock): - requests_mock.register_uri("POST", url + "/groups/" + group_id + "/members", status_code=200) - r = s.groups.assign(group_id=group_id, token=token, members_ids=members, member_type="things") + requests_mock.register_uri("POST", url + "/users/policies" , status_code=200) + r = s.groups.assign(group_id=group_id, token=token, members_ids=members, member_type= ["m_read"]) assert r.error.status == 0 def test_assign_malformed_json(requests_mock): - requests_mock.register_uri("POST", url + "/groups/" + group_id + "/members", status_code=400) - r = s.groups.assign(group_id=group_id, token=token, members_ids=members, member_type="things") + requests_mock.register_uri("POST", url + "/users/policies", status_code=400) + r = s.groups.assign(group_id=group_id, token=token, members_ids=members, member_type= ["m_read"]) assert r.error.status == 1 assert r.error.message == "Failed due to malformed JSON." def test_unassign(requests_mock): - requests_mock.register_uri("DELETE", url + "/groups/" + group_id + "/members", status_code=204) - r = s.groups.unassign(group_id=group_id, token=token, members_ids=members) + requests_mock.register_uri("DELETE", url + "/users/policies" + "/" + members_ids + "/" + group_id, json=group, status_code=204) + r = s.groups.unassign(group_id=group_id, members_ids=members_ids, token=token) assert r.error.status == 0 - + def test_unassign_bad_token(requests_mock): - requests_mock.register_uri("DELETE", url + "/groups/" + group_id + "/members", status_code=403) - r = s.groups.unassign(group_id=group_id, token=token, members_ids=members) + requests_mock.register_uri("DELETE", url + "/users/policies" + "/" + members_ids + "/" + group_id, status_code=403) + r = s.groups.unassign(group_id=group_id, token=token, members_ids=members_ids) assert r.error.status == 1 assert r.error.message == "Missing or invalid access token provided." def test_delete_group(requests_mock): - requests_mock.register_uri("DELETE", url + "/groups/" + group_id, status_code=204) - r = s.groups.delete(group_id=group_id, token=token) + requests_mock.register_uri("POST", url + "/groups/" + group_id + "/disable", status_code=200) + r = s.groups.disable(group_id=group_id, user_token=token) assert r.error.status == 0 def test_delete_group_does_not_exist(requests_mock): - requests_mock.register_uri("DELETE", url + "/groups/" + group_id, status_code=404) - r = s.groups.delete(group_id=group_id, token=token) + requests_mock.register_uri("POST", url + "/groups/" + group_id + "/disable", status_code=404) + r = s.groups.disable(group_id=group_id, user_token=token) assert r.error.status == 1 assert r.error.message == "Group does not exist." From f27b0f3dbc29556a93f32d3108e240c7a80e7578 Mon Sep 17 00:00:00 2001 From: Musilah Date: Mon, 21 Aug 2023 12:15:04 +0300 Subject: [PATCH 06/31] Add Docs Signed-off-by: Musilah --- docs/README.md | 2 -- docs/channels.md | 18 +++++------ docs/groups.md | 30 +++++++++---------- docs/keys.md | 77 ------------------------------------------------ docs/messages.md | 2 +- docs/sdk.md | 6 ++-- docs/things.md | 26 ++++++++-------- docs/users.md | 2 +- 8 files changed, 42 insertions(+), 121 deletions(-) delete mode 100644 docs/keys.md diff --git a/docs/README.md b/docs/README.md index 00ece48..674d4b5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,7 +9,6 @@ - [`channels`](./channels.md#module-channels) - [`errors`](./errors.md#module-errors) - [`groups`](./groups.md#module-groups) -- [`keys`](./keys.md#module-keys) - [`messages`](./messages.md#module-messages) - [`response`](./response.md#module-response) - [`sdk`](./sdk.md#module-sdk) @@ -23,7 +22,6 @@ - [`certs.Certs`](./certs.md#class-certs) - [`channels.Channels`](./channels.md#class-channels) - [`groups.Groups`](./groups.md#class-groups) -- [`keys.Keys`](./keys.md#class-keys) - [`messages.Messages`](./messages.md#class-messages) - [`response.Error`](./response.md#class-error) - [`response.Response`](./response.md#class-response) diff --git a/docs/channels.md b/docs/channels.md index 0f30e84..c1be396 100644 --- a/docs/channels.md +++ b/docs/channels.md @@ -11,14 +11,14 @@ --- - + ## class `Channels` - + ### method `__init__` @@ -35,7 +35,7 @@ __init__(url: str) --- - + ### method `create` @@ -59,12 +59,12 @@ Creates multiple channels in a bulk --- - + -### method `delete` +### method `disable` ```python -delete(channel_id: str, token: str) +disable(channel_id: str, token: str) ``` Deletes a channel entity from database @@ -95,7 +95,7 @@ Gets all channels from database --- - + ### method `get_by_thing` @@ -107,7 +107,7 @@ Gets all channels to which a specific thing is connected to --- - + ### method `identify_thing` @@ -119,7 +119,7 @@ Validates thing's key and returns it's ID if key is valid --- - + ### method `update` diff --git a/docs/groups.md b/docs/groups.md index 7474a36..fc739fb 100644 --- a/docs/groups.md +++ b/docs/groups.md @@ -11,14 +11,14 @@ --- - + ## class `Groups` - + ### method `__init__` @@ -35,12 +35,12 @@ __init__(url: str) --- - + ### method `assign` ```python -assign(group_id: str, members_ids, member_type: str, token: str) +assign(group_id: str, members_ids: str, member_type: dict, token: str) ``` Assign @@ -59,7 +59,7 @@ Gets children for a specific group from database --- - + ### method `create` @@ -71,15 +71,15 @@ Creates group entity in the database --- - + -### method `delete` +### method `disable` ```python -delete(group_id: str, token: str) +disable(group_id: str, user_token: str) ``` -Deletes a group entity from database +Disables a group entity from database --- @@ -107,7 +107,7 @@ Gets all groups from database --- - + ### method `members` @@ -119,7 +119,7 @@ Get list of members ID's from group --- - + ### method `memberships` @@ -143,7 +143,7 @@ Gets parents for a specific group from database --- - + ### method `share_groups` @@ -155,7 +155,7 @@ Adds access rights on thing groups to the user group --- - + ### method `unassign` @@ -163,11 +163,11 @@ Adds access rights on thing groups to the user group unassign(group_id: str, token: str, members_ids) ``` -Assign +Unassign --- - + ### method `update` diff --git a/docs/keys.md b/docs/keys.md deleted file mode 100644 index 666e350..0000000 --- a/docs/keys.md +++ /dev/null @@ -1,77 +0,0 @@ - - - - -# module `keys` - - - - - - ---- - - - -## class `Keys` - - - - - - -### method `__init__` - -```python -__init__(url: str) -``` - - - - - - - - ---- - - - -### method `get_key_details` - -```python -get_key_details(key_id: str, token: str) -``` - -Gets API key details for the given key - ---- - - - -### method `issue` - -```python -issue(duration: str, token: str) -``` - -Generates a new API key - ---- - - - -### method `revoke` - -```python -revoke(key_id: str, token: str) -``` - -Revoke API key identified by the given ID. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/docs/messages.md b/docs/messages.md index 607309f..308b16c 100644 --- a/docs/messages.md +++ b/docs/messages.md @@ -35,7 +35,7 @@ __init__(adapter_url: str, reader_url: str) --- - + ### method `read` diff --git a/docs/sdk.md b/docs/sdk.md index 04e26c7..14ba5eb 100644 --- a/docs/sdk.md +++ b/docs/sdk.md @@ -14,14 +14,14 @@ --- - + ## class `SDK` - + ### method `__init__` @@ -46,7 +46,7 @@ __init__( --- - + ### method `version` diff --git a/docs/things.md b/docs/things.md index 2c2e712..8605b50 100644 --- a/docs/things.md +++ b/docs/things.md @@ -35,24 +35,24 @@ __init__(url: str) --- - + ### method `connect` ```python -connect(thing_id: str, channel_id: str, token: str) +connect(thing_id: str, channel_id: str, action: str, token: str) ``` Connects thing and channel --- - + ### method `connects` ```python -connects(thing_ids: list, channel_ids: list, token: str) +connects(thing_ids: list, channel_ids: list, actions: list, token: str) ``` Connects thing and channel @@ -71,7 +71,7 @@ Creates thing entity in the database --- - + ### method `create_bulk` @@ -83,19 +83,19 @@ Creates multiple things in a bulk --- - + -### method `delete` +### method `disable` ```python -delete(thing_id: str, token: str) +disable(thing_id: str, token: str) ``` Deletes a thing entity from database --- - + ### method `disconnect` @@ -119,7 +119,7 @@ Disconnect thing and channel --- - + ### method `get` @@ -131,7 +131,7 @@ Gets a thing entity for a logged-in user --- - + ### method `get_all` @@ -143,7 +143,7 @@ Gets all things from database --- - + ### method `get_by_channel` @@ -155,7 +155,7 @@ Gets all things to which a specific thing is connected to --- - + ### method `update` diff --git a/docs/users.md b/docs/users.md index 7a98b1f..ff5d96f 100644 --- a/docs/users.md +++ b/docs/users.md @@ -88,7 +88,7 @@ Gets a user information ### method `get_all` ```python -get_all(query_params: dict, admin_token: str) +get_all(query_params: dict, user_token: str) ``` Retrieves a list of users From 3eb02193aedd34893a8af78c54ed4c37b0d075be Mon Sep 17 00:00:00 2001 From: Musilah Date: Mon, 21 Aug 2023 16:57:12 +0300 Subject: [PATCH 07/31] Fix Certs Signed-off-by: Musilah --- mainflux/certs.py | 42 ++++++++++++++++++++--------- mainflux/errors.py | 8 +++++- tests/test_certs.py | 66 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 tests/test_certs.py diff --git a/mainflux/certs.py b/mainflux/certs.py index 23fee28..9063717 100644 --- a/mainflux/certs.py +++ b/mainflux/certs.py @@ -6,20 +6,15 @@ class Certs: - certs_endpoint = "configs" + certs_endpoint = "certs" def __init__(self, url: str): self.url = url - def issue( - self, thing_id: str, key_bits: int, key_type: str, valid: str, - token: str - ): + def issue(self, thing_id: str, valid: str, token: str): payload = { "thing_id": thing_id, - "key_bits": key_bits, - "key_type": key_type, "ttl": valid, } mf_resp = response.Response() @@ -34,22 +29,40 @@ def issue( errors.certs["issue"], http_resp.status_code ) else: - location = http_resp.headers.get("location") - mf_resp.value = location.split("/")[2] + mf_resp.value = http_resp.json() return mf_resp - def view(self, thing_id: str, token: str): - """Generates an access token when provided with proper credentials.""" + def view_by_thing(self, thing_id: str, token: str): + """Retrieves a list of certificates' serial IDs for a given thing ID.""" mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.certs_endpoint + "/" + thing_id, + self.url + "/serials" + "/" + thing_id, headers=utils.construct_header(token, utils.CTJSON), ) if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( - errors.certs["view"], http_resp.status_code + errors.certs["view_by_thing"], http_resp.status_code ) + else: + mf_resp.value = http_resp.json() + return mf_resp + + def view_by_serial(self, cert_id: str, token: str): + """Retrieves a certificate for a given cert ID.""" + mf_resp = response.Response() + http_resp = requests.get( + self.url + "/" + self.certs_endpoint + "/" + cert_id, + headers=utils.construct_header(token, utils.CTJSON), + ) + print(http_resp.url) + if http_resp.status_code != 200: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.certs["view_by_serial"], http_resp.status_code + ) + else: + mf_resp.value = http_resp.json() return mf_resp def revoke(self, thing_id: str, token: str): @@ -59,9 +72,12 @@ def revoke(self, thing_id: str, token: str): self.url + "/" + self.certs_endpoint + "/" + thing_id, headers=utils.construct_header(token, utils.CTJSON), ) + if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.certs["revoke"], http_resp.status_code ) + else: + mf_resp.value = "DELETED" return mf_resp diff --git a/mainflux/errors.py b/mainflux/errors.py index ff2f131..002008a 100644 --- a/mainflux/errors.py +++ b/mainflux/errors.py @@ -160,7 +160,13 @@ def handle_error(error_dict, status_code): } } certs = { - "view": { + "issue": { + 401: "Missing or invalid access token provided.", + }, + "view_by_thing": { + 404: "Failed to retrieve corresponding certificate.", + }, + "view_by_serial": { 404: "Failed to retrieve corresponding certificate.", }, "revoke": { diff --git a/tests/test_certs.py b/tests/test_certs.py new file mode 100644 index 0000000..7bc6dd7 --- /dev/null +++ b/tests/test_certs.py @@ -0,0 +1,66 @@ +from mainflux import sdk + +import json +import requests_mock + +s= sdk.SDK() + +certs= { + "cert_serial": "22:16:df:60:c2:99:bc:c4:9b:1d:fd:71:5e:e9:07:d9:1b:3c:85:1d", + "client_cert": "-----BEGIN CERTIFICATE-----\nMIIEATCCAumgAwIBAgIUIhbfYMKZvMSbHf1xXukH2Rs8hR0wDQYJKoZIhvcNAQEL\nBQAwLjEsMCoGA1UEAxMjbWFpbmZsdXguY29tIEludGVybWVkaWF0ZSBBdXRob3Jp\ndHkwHhcNMjMwODIxMTAwMjE5WhcNMjMwOTIwMTAwMjQ4WjAvMS0wKwYDVQQDEyRj\nODkyMzViNy0xZDU0LTQyY2YtODdlYi0yNDgzMWY3NDE0ZTEwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDL2AXzhrmzqOVfqGQA9evsqM0n5BjL3F3FCo2q\n1vMVq8HrCmJ1qXk1h6coz5KILiloLET5PFALFqwHByBzNAg0IZUbTTTh8YuUtiq+\nbnRa2MOZZzQtXB1T6tPkAtcxdJ+H3j0eEIAbYh4DJiq8l1NmU0siCaFLHJ+pwJr5\ndGwGgWOW3sotrUvN9vVsXM41SgxJOeps765/lKQjSxTdhEERLsu6pQ+68K1WNYKg\npCO9kB2Dmu3jtoV34kMyhg1ptaegztEFrSgA8bSIsR4X19itIR5ku4jZb6pnmPcM\nBwHJlJXTl9zdzSC4MXOdb8aOXEROTsVuFGn5fnZ9OWDWXeEhAgMBAAGjggEUMIIB\nEDAOBgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC\nMB0GA1UdDgQWBBSmppsLhLCf6N44sY6Np7/k+z//tzAfBgNVHSMEGDAWgBRXKFnr\nLL2mS5RUzzlVZHJup20WfTA7BggrBgEFBQcBAQQvMC0wKwYIKwYBBQUHMAKGH2h0\ndHA6Ly92YXVsdDo4MjAwL3YxL3BraV9pbnQvY2EwLwYDVR0RBCgwJoIkYzg5MjM1\nYjctMWQ1NC00MmNmLTg3ZWItMjQ4MzFmNzQxNGUxMDEGA1UdHwQqMCgwJqAkoCKG\nIGh0dHA6Ly92YXVsdDo4MjAwL3YxL3BraV9pbnQvY3JsMA0GCSqGSIb3DQEBCwUA\nA4IBAQCZla9Opcq6RQqnCoih9VCg3JbU0PmpfeM+2LtWziH51PyeIOxB5b244SPe\nUtLzSv4lAB6tsq4aYx67n7suiv1E50E9xOXtVq1s/yO/bhvR2NIQL3bFc61ZGW3C\nVetPdSfESwXqi5jdWcacs+F66ZFEza3fFYLgl7D8Bdd3i9hKlgK7pWDrhcDpgwMA\nabIRbQ4nuCyf8OVeklCUfbilRrvESrWIy9r0PjViZbJDFIFEs9uEvBUFcDokzJqY\nzVH1+pduYw7x5JzJy/cK8TGX3JdKK7Y058jnSrO3ZkW4uKQ3bCWD5kB0wNanrp+a\nfD1NTEQ0etWwdlylVx4JjtwA4T1k\n-----END CERTIFICATE-----", + "client_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEoQIBAAKCAQEAy9gF84a5s6jlX6hkAPXr7KjNJ+QYy9xdxQqNqtbzFavB6wpi\ndal5NYenKM+SiC4paCxE+TxQCxasBwcgczQINCGVG0004fGLlLYqvm50WtjDmWc0\nLVwdU+rT5ALXMXSfh949HhCAG2IeAyYqvJdTZlNLIgmhSxyfqcCa+XRsBoFjlt7K\nLa1Lzfb1bFzONUoMSTnqbO+uf5SkI0sU3YRBES7LuqUPuvCtVjWCoKQjvZAdg5rt\n47aFd+JDMoYNabWnoM7RBa0oAPG0iLEeF9fYrSEeZLuI2W+qZ5j3DAcByZSV05fc\n3c0guDFznW/GjlxETk7FbhRp+X52fTlg1l3hIQIDAQABAoIBACOiqz+sgNBgqWC0\nrm7gjxL7W4oqvQ7+gkING0EPfMWAFlGBqj7Jls/93AItb39xGnoEqzYrDg8yMna0\nDz80jG6YpFl2gNUzBeTEh+psotiy5lbuDNgVL2dZORu2R2p06eK1vleAKPUgjQCd\n7oCzr7fGve7AYjsgUOU7L5yGdtAYBLL4nu6XfMC9kWxHKwVMhWSRSZO4gr83Yhld\nsHrlLlSMYciuXWSZSMGvFTQc3jj8tyq9TqMTysqgbM++6E4KyzATwW2DsoiiMAPl\n/2wyG1GxsNHreeSxxAFQw4NhxY5ud34jYi6NNpR2u2kaa17eFD/YVyMTn+9gyugc\nuFt0tjECgYEA5CYve2BhowU6kSUx0055Kf1mD24MpGo29tKzR98m9Rc045iUMwdc\n51skrTjdVcskDYDVZ1cklO1dCerQBLJ3zc6iqyVdoABj0pMlfWvRyYj+8oRa1AgJ\n1K0FMkcT9UJ3jTxidoF3/8/sRZEvpuxIb6wSfNEoJVIxqFsz71khWrUCgYEA5LpH\nuKSHqzE2E2UHd9dXbTWf1ZxHbCMJrWMwMXDo1SenlR9E/W/WD7IXrGvdL6PWky9L\nHUxdbuOxMBIGEhRIFFgKBElZVuG5pBAt/1GPx1Skm0tg6V5DvndqQavfYyFVhZ3T\nR0I5tYFBaA7BwVsI1aQTryofZFZ8gRGyIgGUtD0CgYBufn/ohNlElreyrAzhhdPw\nniTbvDSrPDW6fHkPiefYM5EN2UuNGzfHZMDyk+O+NVAUqhywm+e/qOWyc+KjI7wa\nFMV7lfEuGII/7bvublWAAbVXxvomTm5UbidiHkJwOeyknmYhdrqjThPj7VjiwvSi\nAPhDMxj6WkBqhSE1/jjFMQJ/JmsjoOAB6b9aVeeiWX7SMIXRUw/s7zzzYyxF7AgL\nE8KVY3bdH7SpP/mqAEwd2uKqKA7JjyJEj1uvZ2OfoWnGsaQYCqBHYVCI3gXZtAj/\nHXwaKft/S7OJrXRhZKZ53yy6MLdRxaZaCyKq2c+gu9mOolPs+n8YxsHAJ+3Q/eVG\nFQKBgQChCjj0dZAMQd4q/UBfk8cMIZCbDnd1qm/9rwcW4hObvpB0WG8AZ7uE8W1K\nDS+SHu+4n3aA9gY4CSwOdLRz/mMng9cs3wjWiLUsHPAkneANYMNsuikJMM+IVdiv\nZVih7y8Q6BNZOQfpIqR8BNjft8MinJTN//ephL6REOaPzlHfhw==\n-----END RSA PRIVATE KEY-----", + "expiration": "2023-09-20T10:02:48Z", + "thing_id": "3d49a42f-63fd-491b-9784-adf4b64ef347" +} +token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTI2NzM1NTksImlhdCI6MTY5MjYxOTU1OSwiaWRlbnRpdHkiOiJpbnNwaXJpbmdfZ29sZGJlcmdAZW1haWwuY29tIiwiaXNzIjoiY2xpZW50cy5hdXRoIiwic3ViIjoiYzk2ZWQwNmQtNTM5Zi00YjAxLTk2MWUtNTA0MjJmZjQ0OTBkIiwidHlwZSI6ImFjY2VzcyJ9.6J34t9Ts0VmjfsdxeUd66DQihFuB-mwlJ884KwoCjT1FmNr70yPjtIXpOvRjA58ggs-5kTh_ZZh25KtkTipWEg" +thing_id= "2544670a-a992-4865-8222-24e5deed7bae" +cert_id= "22:16:df:60:c2:99:bc:c4:9b:1d:fd:71:5e:e9:07:d9:1b:3c:85:1d" + +url= "http://localhost" + +def test_issue(requests_mock): + requests_mock.register_uri( "POST", url + "/certs", headers={"location": "/certs/" + thing_id}, json=certs, status_code=201) + r = s.certs.issue(thing_id=thing_id, valid= "10h", token=token) + assert r.error.status == 0 + assert certs == r.value + +def test_issue_bad_token(requests_mock): + requests_mock.register_uri( "POST", url + "/certs", headers={"location": "/certs/" + thing_id}, json=certs, status_code=401) + r = s.certs.issue(thing_id=thing_id, valid= "10h", token=token) + assert r.error.status == 1 + assert r.error.message == "Missing or invalid access token provided." + +def test_view_by_thing(requests_mock): + requests_mock.register_uri( "GET", url + "/serials" + "/" + thing_id, json=certs, status_code=200) + r = s.certs.view_by_thing(thing_id=thing_id, token=token) + assert r.error.status == 0 + assert certs == r.value + +def test_view_by_thing_bad_token(requests_mock): + requests_mock.register_uri( "GET", url + "/serials" + "/" + thing_id, json=certs, status_code=404) + r = s.certs.view_by_thing(thing_id=thing_id, token=token) + assert r.error.status == 1 + assert r.error.message == "Failed to retrieve corresponding certificate." + +def test_view_by_serial(requests_mock): + requests_mock.register_uri( "GET", url + "/certs" + "/" + cert_id, json=certs, status_code=200) + r = s.certs.view_by_serial(cert_id=cert_id, token=token) + assert r.error.status == 0 + assert certs == r.value + +def test_view_by_serial_bad_token(requests_mock): + requests_mock.register_uri( "GET", url + "/certs" + "/" + cert_id, json=certs, status_code=404) + r = s.certs.view_by_serial(cert_id=cert_id, token=token) + assert r.error.status == 1 + assert r.error.message == "Failed to retrieve corresponding certificate." + +def test_revoke(requests_mock): + requests_mock.register_uri( "DELETE", url + "/certs" + "/" + thing_id, status_code=200) + r = s.certs.revoke(thing_id=thing_id, token=token) + assert r.error.status == 0 + +def test_revoke(requests_mock): + requests_mock.register_uri( "DELETE", url + "/certs" + "/" + thing_id, status_code=404) + r = s.certs.revoke(thing_id=thing_id, token=token) + assert r.error.status == 1 + assert r.error.message == "Failed to revoke corresponding certificate." From 8a68f4c37cfc2b830cc1c78de10661069fbdff9c Mon Sep 17 00:00:00 2001 From: Musilah Date: Mon, 21 Aug 2023 17:06:00 +0300 Subject: [PATCH 08/31] Add Certs Docs Signed-off-by: Musilah --- docs/certs.md | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/certs.md b/docs/certs.md index 73a21e1..2f05caa 100644 --- a/docs/certs.md +++ b/docs/certs.md @@ -40,7 +40,7 @@ __init__(url: str) ### method `issue` ```python -issue(thing_id: str, key_bits: int, key_type: str, valid: str, token: str) +issue(thing_id: str, valid: str, token: str) ``` @@ -49,7 +49,7 @@ issue(thing_id: str, key_bits: int, key_type: str, valid: str, token: str) --- - + ### method `revoke` @@ -63,15 +63,27 @@ revoke(thing_id: str, token: str) --- - + -### method `view` +### method `view_by_serial` ```python -view(thing_id: str, token: str) +view_by_serial(cert_id: str, token: str) ``` -Generates an access token when provided with proper credentials. +Retrieves a certificate for a given cert ID. + +--- + + + +### method `view_by_thing` + +```python +view_by_thing(thing_id: str, token: str) +``` + +Retrieves a list of certificates' serial IDs for a given thing ID. From dfbac29351e00f3a32941d11d1fb6093bc058f87 Mon Sep 17 00:00:00 2001 From: Musilah Date: Tue, 22 Aug 2023 20:37:03 +0300 Subject: [PATCH 09/31] Update Bootstrap Signed-off-by: Musilah --- docs/boostrap.md | 14 +++--- docs/errors.md | 2 +- mainflux/boostrap.py | 59 +++++++++++++----------- mainflux/errors.py | 12 +++-- tests/test_bootstrap.py | 99 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 149 insertions(+), 37 deletions(-) create mode 100644 tests/test_bootstrap.py diff --git a/docs/boostrap.md b/docs/boostrap.md index fa3f4a0..7467361 100644 --- a/docs/boostrap.md +++ b/docs/boostrap.md @@ -47,7 +47,7 @@ Adds new config to the list of config owned by user identified using the provide --- - + ### method `bootstrap` @@ -59,7 +59,7 @@ Retrieves a configuration with given external ID and external key. --- - + ### method `remove` @@ -71,7 +71,7 @@ Removes a Config. In case of successful removal the service will ensure that the --- - + ### method `update` @@ -83,7 +83,7 @@ Update is performed by replacing the current resource data with values provided --- - + ### method `update_certs` @@ -101,19 +101,19 @@ Update is performed by replacing the current certificate data with values provid --- - + ### method `view` ```python -view(config_id: str, token: str) +view(thing_id: str, token: str) ``` Retrieves a configuration with given config id --- - + ### method `whitelist` diff --git a/docs/errors.md b/docs/errors.md index 6a1bf99..b981d57 100644 --- a/docs/errors.md +++ b/docs/errors.md @@ -15,7 +15,7 @@ - **channels** - **messages** - **groups** -- **boostrap** +- **bootstrap** - **certs** --- diff --git a/mainflux/boostrap.py b/mainflux/boostrap.py index bd74011..a8f919f 100644 --- a/mainflux/boostrap.py +++ b/mainflux/boostrap.py @@ -6,10 +6,10 @@ class Bootstrap: - configs_endpoint = "configs" - bootstrap_endpoint = "bootstrap" - whitelist_endpoint = "state" - bootstrap_certs_endpoint = "configs/certs" + CONFIGS_ENDPOINT = "configs" + BOOTSTRAP_ENDPOINT = "bootstrap" + WHITELIST_ENDPOINT = "things/state" + BOOTSTRAP_CERTS_ENDPOINT = "configs/certs" def __init__(self, url: str): self.url = url @@ -19,18 +19,17 @@ def add(self, config: dict, token: str): using the provided access token.""" mf_resp = response.Response() http_resp = requests.post( - self.url + "/" + self.configs_endpoint, + self.url + "/things" + "/" + self.CONFIGS_ENDPOINT, json=config, headers=utils.construct_header(token, utils.CTJSON), ) if http_resp.status_code != 201: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( - errors.boostrap["add"], http_resp.status_code + errors.bootstrap["add"], http_resp.status_code ) else: - location = http_resp.headers.get("location") - mf_resp.value = location.split("/")[2] + mf_resp.value = "added" return mf_resp def whitelist(self, config: dict, token: str): @@ -38,32 +37,34 @@ def whitelist(self, config: dict, token: str): i.e.connecting and disconnecting corresponding Mainflux Thing to the list of Channels.""" mf_resp = response.Response() - if config["MFThing"] == "": + if config["thing_id"] == "": mf_resp.error.status = 1 mf_resp.error.message = "parameter not found in the query" http_resp = requests.put( - self.url + "/" + self.whitelist_endpoint + "/" + config["MFThing"], + self.url + "/" + self.WHITELIST_ENDPOINT + "/" + config["thing_id"], json=config, headers=utils.construct_header(token, utils.CTJSON), ) if http_resp.status_code != 201: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( - errors.boostrap["whitelist"], http_resp.status_code + errors.bootstrap["whitelist"], http_resp.status_code ) + else: + mf_resp.value = "OK" return mf_resp - def view(self, config_id: str, token: str): + def view(self, thing_id: str, token: str): """Retrieves a configuration with given config id""" mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.configs_endpoint + "/" + config_id, + self.url + "/things" + "/" + self.CONFIGS_ENDPOINT + "/" + thing_id, headers=utils.construct_header(token, utils.CTJSON), ) if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( - errors.boostrap["view"], http_resp.status_code + errors.bootstrap["view"], http_resp.status_code ) else: mf_resp.value = http_resp.json() @@ -75,19 +76,21 @@ def update(self, config: dict, token: str): external ID, external key, Mainflux Thing ID and key cannot be changed.""" mf_resp = response.Response() - if config["MFThing"] == "": + if config["thing_id"] == "": mf_resp.error.status = 1 mf_resp.error.message = "parameter not found in the query" http_resp = requests.put( - self.url + "/" + self.configs_endpoint + "/" + config["MFThing"], + self.url + "/things/" + self.CONFIGS_ENDPOINT + "/" + config["thing_id"], headers=utils.construct_header(token, utils.CTJSON), - data=config, + json=config, ) if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( - errors.boostrap["update"], http_resp.status_code + errors.bootstrap["update"], http_resp.status_code ) + else: + mf_resp.value = "Config updated." return mf_resp def update_certs( @@ -99,7 +102,7 @@ def update_certs( payload = {"client_cert": client_cert, "client_key": client_key, "ca_cert": ca} http_resp = requests.patch( - self.url + "/" + self.bootstrap_certs_endpoint + "/" + config_id, + self.url + "/" + self.BOOTSTRAP_CERTS_ENDPOINT + "/" + config_id, headers=utils.construct_header(token, utils.CTJSON), json=payload, ) @@ -107,7 +110,7 @@ def update_certs( if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( - errors.boostrap["update"], http_resp.status_code + errors.bootstrap["update"], http_resp.status_code ) return mf_resp @@ -116,15 +119,17 @@ def remove(self, config_id: str, token: str): ensure that the removed config is disconnected from all the Mainflux channels.""" mf_resp = response.Response() - http_resp = requests.post( - self.url + "/" + self.configs_endpoint + "/" + config_id, + http_resp = requests.delete( + self.url + "/things/" + self.CONFIGS_ENDPOINT + "/" + config_id, headers=utils.construct_header(token, utils.CTJSON), ) if http_resp.status_code != 204: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( - errors.boostrap["remove"], http_resp.status_code + errors.bootstrap["remove"], http_resp.status_code ) + else: + mf_resp.value = "Config removed." return mf_resp def bootstrap(self, external_id: str, external_key: str): @@ -132,12 +137,14 @@ def bootstrap(self, external_id: str, external_key: str): key.""" mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.bootstrap_endpoint + "/" + external_id, - headers=utils.construct_header(external_key, utils.CTJSON), + self.url + "/things/bootstrap" + "/" + external_id, + headers=utils.construct_header(utils.ThingPrefix+external_key, utils.CTJSON), ) if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( - errors.boostrap["bootstrap"], http_resp.status_code + errors.bootstrap["bootstrap"], http_resp.status_code ) + else: + mf_resp.value = http_resp.json() return mf_resp diff --git a/mainflux/errors.py b/mainflux/errors.py index 002008a..f5175a6 100644 --- a/mainflux/errors.py +++ b/mainflux/errors.py @@ -144,7 +144,10 @@ def handle_error(error_dict, status_code): }, } -boostrap = { +bootstrap = { + "add": { + 401: "Missing or invalid access token provided.", + }, "view": { 404: "Config does not exist.", }, @@ -155,9 +158,12 @@ def handle_error(error_dict, status_code): "update": { 404: "Config does not exist.", }, - "boostrap": { + "bootstrap": { 404: "Failed to retrieve corresponding config." - } + }, + "remove": { + 400: "Failed due to malformed config ID." + } } certs = { "issue": { diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py new file mode 100644 index 0000000..4cafb85 --- /dev/null +++ b/tests/test_bootstrap.py @@ -0,0 +1,99 @@ +from mainflux import sdk + +import json +import requests_mock + +s= sdk.SDK() + +config = { + "external_id": "234567", + "external_key": "234567", + "thing_id": "828b93e3-52b3-43a4-9ce2-ed8a47127ddd", + "name": "demo5" +} + +token= "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTI3NzI5NDgsImlhdCI6MTY5MjcxODk0OCwiaWRlbnRpdHkiOiJqb2xseV9uYXBpZXJAZW1haWwuY29tIiwiaXNzIjoiY2xpZW50cy5hdXRoIiwic3ViIjoiZjhiMDIwMmEtOGE4ZS00M2NjLWExZjctOWIzOWZkYmFlYjY3IiwidHlwZSI6ImFjY2VzcyJ9.-aEhFrpXxiCUW-zjCqQvUDi2UTtu5y0nkJgzDtUV-YiN1ZyMYUwwc9z8NvJPAfHCscagP4ifidWJ-ovkZULg4g" +thing_id= "828b93e3-52b3-43a4-9ce2-ed8a47127ddd" +external_id= "234567" +external_key= "234567" +config_id="828b93e3-52b3-43a4-9ce2-ed8a47127ddd" + +url = "http://localhost" + +def test_add(requests_mock): + requests_mock.register_uri( "POST", url+ "/things/configs", headers={"location": "/configs/" + thing_id}, json=config, status_code=201) + r = s.bootstrap.add(config=config, token=token) + assert r.error.status == 0 + assert r.value == "added" + +def test_add_bad_token(requests_mock): + requests_mock.register_uri( "POST", url+ "/things/configs", headers={"location": "/configs/" + thing_id}, json=config, status_code=401) + r = s.bootstrap.add(config=config, token=token) + assert r.error.status == 1 + assert r.error.message =="Missing or invalid access token provided." + +def test_whitelist(requests_mock): + requests_mock.register_uri( "PUT", url+ "/things/state/" + config["thing_id"], json=config, status_code=201) + r = s.bootstrap.whitelist(config=config, token=token) + assert r.error.status == 0 + assert r.value == "OK" + +def test_whitelist_bad_config(requests_mock): + requests_mock.register_uri( "PUT", url+ "/things/state/" + config["thing_id"], json=config, status_code=400) + r = s.bootstrap.whitelist(config=config, token=token) + assert r.error.status == 1 + assert r.error.message == "Failed due to malformed config's ID." + +def test_whitelist_config_removed(requests_mock): + requests_mock.register_uri( "PUT", url+ "/things/state/" + config["thing_id"], json=config, status_code=204) + r = s.bootstrap.whitelist(config=config, token=token) + assert r.error.status == 1 + assert r.error.message == "Config removed." + +def test_view(requests_mock): + requests_mock.register_uri( "GET", url+ "/things/configs/" + thing_id, json=config, status_code=200) + r = s.bootstrap.view(thing_id=thing_id, token=token) + assert r.error.status == 0 + assert config == r.value + +def test_view_bad_config(requests_mock): + requests_mock.register_uri( "GET", url+ "/things/configs/" + thing_id, json=config, status_code=404) + r = s.bootstrap.view(thing_id=thing_id, token=token) + assert r.error.status == 1 + assert r.error.message == "Config does not exist." + +def test_update(requests_mock): + requests_mock.register_uri( "PUT", url+ "/things/configs/" + config["thing_id"], json=config, status_code=200) + r = s.bootstrap.update(config=config, token=token) + assert r.error.status == 0 + assert r.value == "Config updated." + +def test_update_bad_config(requests_mock): + requests_mock.register_uri( "PUT", url+ "/things/configs/" + config["thing_id"], json=config, status_code=404) + r = s.bootstrap.update(config=config, token=token) + assert r.error.status == 1 + assert r.error.message == "Config does not exist." + +def test_bootstrap(requests_mock): + requests_mock.register_uri( "GET", url+ "/things/bootstrap/" + external_id, json=config, status_code=200) + r = s.bootstrap.bootstrap(external_id=external_id, external_key=external_key) + assert r.error.status == 0 + assert config == r.value + +def test_bootstrap_bad_config(requests_mock): + requests_mock.register_uri( "GET", url+ "/things/bootstrap/" + external_id, json=config, status_code=404) + r = s.bootstrap.bootstrap(external_id=external_id, external_key=external_key) + assert r.error.status == 1 + assert r.error.message == "Failed to retrieve corresponding config." + +def test_remove(requests_mock): + requests_mock.register_uri( "DELETE", url+ "/things/configs/" + config_id, status_code=204) + r = s.bootstrap.remove(config_id=config_id, token=token) + assert r.error.status == 0 + assert r.value== "Config removed." + +def test_remove_bad_config(requests_mock): + requests_mock.register_uri( "DELETE", url+ "/things/configs/" + config_id, status_code=400) + r = s.bootstrap.remove(config_id=config_id, token=token) + assert r.error.status == 1 + assert r.error.message == "Failed due to malformed config ID." \ No newline at end of file From 77203fea0d825dfd10f98ae0ad830e321f184320 Mon Sep 17 00:00:00 2001 From: Musilah Date: Thu, 24 Aug 2023 01:05:09 +0300 Subject: [PATCH 10/31] Update users and things Signed-off-by: Musilah --- mainflux/channels.py | 2 - mainflux/errors.py | 37 ++++++++++++- mainflux/groups.py | 2 - mainflux/things.py | 97 +++++++++++++++++++++++++++++++-- mainflux/users.py | 124 +++++++++++++++++++++++++++++++++++++++++-- tests/test_things.py | 58 +++++++++++++------- 6 files changed, 287 insertions(+), 33 deletions(-) diff --git a/mainflux/channels.py b/mainflux/channels.py index 972f353..69fdeec 100644 --- a/mainflux/channels.py +++ b/mainflux/channels.py @@ -119,7 +119,6 @@ def disable(self, channel_id: str, token: str): self.url + "/" + self.channels_endpoint + "/" + channel_id + "/disable", headers=utils.construct_header(token, utils.CTJSON), ) - print(http_resp.request.url) mf_resp = response.Response() if http_resp.status_code != 200: mf_resp.error.status = 1 @@ -134,7 +133,6 @@ def identify_thing(self, thing_key: str): self.url + "/" + self.identify_endpoint, headers=utils.construct_header(utils.ThingPrefix + thing_key, utils.CTJSON), ) - print(http_resp.request.url) mf_resp = response.Response() if http_resp.status_code != 200: mf_resp.error.status = 1 diff --git a/mainflux/errors.py b/mainflux/errors.py index f5175a6..d9ad239 100644 --- a/mainflux/errors.py +++ b/mainflux/errors.py @@ -25,6 +25,9 @@ def handle_error(error_dict, status_code): "login": { 409: "Failed due to using an existing email address.", }, + "refresh_token": { + 404: "A non-existent entity request.", + }, "get": { 400: "Failed due to malformed query parameters.", }, @@ -34,12 +37,30 @@ def handle_error(error_dict, status_code): "update": { 404: "Failed due to non existing user.", }, + "update_user_identity": { + 401: "Missing or invalid access token provided.", + }, + "update_user_tags": { + 401: "Missing or invalid access token provided.", + }, + "update_user_owner": { + 401: "Missing or invalid access token provided.", + }, "enable": { 404: "Failed due to non existing user." }, "disable": { 404: "Failed due to non existing user." }, + "reset_password_request": { + 400: "Failed due to malformed JSON." + }, + "reset_password": { + 400: "Failed due to malformed JSON." + }, + "authorise_user":{ + 400: "Failed due to malformed JSON." + } } things = { @@ -47,7 +68,6 @@ def handle_error(error_dict, status_code): 422: "Unprocessable Entity." }, "create_bulk": { - }, "get": { 400: "Failed due to malformed query parameters.", @@ -62,6 +82,15 @@ def handle_error(error_dict, status_code): "update": { 404: "Thing does not exist.", }, + "update_thing_secret": { + 401: "Missing or invalid access token provided.", + }, + "update_thing_tags": { + 401: "Missing or invalid access token provided.", + }, + "update_thing_owner": { + 401: "Missing or invalid access token provided.", + }, "delete": { 400: "Failed due to malformed thing's ID.", }, @@ -72,6 +101,12 @@ def handle_error(error_dict, status_code): 400: "Failed due to malformed query parameters.", 404: "Channel or thing does not exist.", }, + "share_thing": { + 400: "A non-existent entity request." + }, + "authorise_thing":{ + 400: "False" + } } channels = { diff --git a/mainflux/groups.py b/mainflux/groups.py index b8154a9..b2a5a9a 100644 --- a/mainflux/groups.py +++ b/mainflux/groups.py @@ -105,7 +105,6 @@ def update(self, group_id: str, group: dict, token: str): data= json.dumps(group), headers=utils.construct_header(token, utils.CTJSON), ) - print(http_resp) mf_resp = response.Response() if http_resp.status_code != 200: mf_resp.error.status = 1 @@ -140,7 +139,6 @@ def memberships(self, member_id: str, query_params: dict, token: str): headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) - print(http_resp.request.url) mf_resp = response.Response() if http_resp.status_code != 200: mf_resp.error.status = 1 diff --git a/mainflux/things.py b/mainflux/things.py index 13c83cd..2515a79 100644 --- a/mainflux/things.py +++ b/mainflux/things.py @@ -1,5 +1,5 @@ import requests - +import json from mainflux import response from mainflux import errors from mainflux import utils @@ -111,6 +111,59 @@ def update(self, thing_id: str, thing: dict, token: str): mf_resp.error.message = errors.handle_error( errors.things["update"], http_resp.status_code ) + else: + mf_resp.value = http_resp.json() + return mf_resp + + def update_thing_secret(self, thing_id: str, thing: dict, token: str): + """Updates thing secret""" + http_resp = requests.patch( + self.URL + "/" + self.THINGS_ENDPOINT + "/" + thing_id + "/secret", + json=thing, + headers=utils.construct_header(token, utils.CTJSON), + ) + mf_resp = response.Response() + if http_resp.status_code != 200: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.things["update_thing_secret"], http_resp.status_code + ) + else: + mf_resp.value = http_resp.json() + return mf_resp + + def update_thing_tags(self, thing_id: str, thing: dict, token: str): + """Updates thing secret""" + http_resp = requests.patch( + self.URL + "/" + self.THINGS_ENDPOINT + "/" + thing_id + "/tags", + json=thing, + headers=utils.construct_header(token, utils.CTJSON), + ) + mf_resp = response.Response() + if http_resp.status_code != 200: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.things["update_thing_tags"], http_resp.status_code + ) + else: + mf_resp.value = http_resp.json() + return mf_resp + + def update_thing_owner(self, thing_id: str, thing: dict, token: str): + """Updates thing secret""" + http_resp = requests.patch( + self.URL + "/" + self.THINGS_ENDPOINT + "/" + thing_id + "/owner", + json=thing, + headers=utils.construct_header(token, utils.CTJSON), + ) + mf_resp = response.Response() + if http_resp.status_code != 200: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.things["update_thing_owner"], http_resp.status_code + ) + else: + mf_resp.value = http_resp.json() return mf_resp def disable(self, thing_id: str, token: str): @@ -135,7 +188,6 @@ def connects(self, thing_ids: list, channel_ids: list, actions: list, token: str headers=utils.construct_header(token, utils.CTJSON), json=payload, ) - print(http_resp.request.url) mf_resp = response.Response() if http_resp.status_code != 201: mf_resp.error.status = 1 @@ -154,7 +206,6 @@ def disconnects(self, thing_ids: list, channel_ids: list, token: str): headers=utils.construct_header(token, utils.CTJSON), json=payload, ) - print(http_resp.request.url) mf_resp = response.Response() if http_resp.status_code != 204: mf_resp.error.status = 1 @@ -171,7 +222,6 @@ def connect(self, thing_id: str, channel_id: str, action: str, token: str): headers=utils.construct_header(token, utils.CTJSON), json= payload, ) - print(http_resp.request.url) mf_resp = response.Response() if http_resp.status_code != 201: mf_resp.error.status = 1 @@ -190,7 +240,6 @@ def disconnect(self, thing_id: str, channel_id: str, token: str): headers=utils.construct_header(token, utils.CTJSON), json=payload, ) - print(http_resp.request.url) mf_resp = response.Response() if http_resp.status_code != 204: mf_resp.error.status = 1 @@ -198,3 +247,41 @@ def disconnect(self, thing_id: str, channel_id: str, token: str): errors.things["disconnect"], http_resp.status_code ) return mf_resp + + def share_thing(self, user_id: str, group_id: str, actions: dict, token: str): + """Share thing""" + payload = {"object": group_id, "subject": user_id, "Actions": actions, "External": True} + http_resp = requests.post( + self.URL + "/policies", + headers=utils.construct_header(token, utils.CTJSON), + data=json.dumps(payload) + ) + print(http_resp.request.url) + print(http_resp) + mf_resp = response.Response() + if http_resp.status_code != 201: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.things["share_thing"], http_resp.status_code + ) + else: + mf_resp.value = http_resp.json() + return mf_resp + + def authorise_thing(self,access_request: dict, token: str): + """Authorises thing""" + mf_resp = response.Response() + http_resp= requests.post( + self.URL +"/authorize", + headers=utils.construct_header(token, utils.CTJSON), + json= access_request + ) + if http_resp.status_code != 200: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.things["authorise_thing"], http_resp.status_code + ) + else: + mf_resp.value = "True" + return mf_resp + \ No newline at end of file diff --git a/mainflux/users.py b/mainflux/users.py index 70fcae6..f65f1e7 100644 --- a/mainflux/users.py +++ b/mainflux/users.py @@ -42,6 +42,23 @@ def login(self, user: dict): else: mf_resp.value = http_resp.json() return mf_resp + + def refresh_token(self, user: dict, token: str): + """Refreshes Access and Refresh Token used for authenticating into the system.""" + mf_resp = response.Response() + http_resp = requests.post( + self.URL + "/users/tokens/refresh", + headers=utils.construct_header(token, utils.CTJSON), + json=user + ) + if http_resp.status_code != 201: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.users["refresh_token"], http_resp.status_code + ) + else: + mf_resp.value = http_resp.json() + return mf_resp def get(self, user_id: str, token: str): """Gets a user information""" @@ -77,8 +94,7 @@ def get_all(self, query_params: dict, user_token: str): return mf_resp def update(self, user: dict, user_token: str): - """Updates info on currently logged in user. Info is updated using - authorization user_token""" + """Updates info on currently logged in user. Info is updated using authorization user_token""" http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"], headers=utils.construct_header(user_token, utils.CTJSON), @@ -93,7 +109,58 @@ def update(self, user: dict, user_token: str): else: mf_resp.value = http_resp.json() return mf_resp - + + def update_user_identity(self, user: dict, user_token: str): + """Updates Identity of the user""" + http_resp = requests.patch( + self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"] + "/identity", + headers=utils.construct_header(user_token, utils.CTJSON), + data=json.dumps(user), + ) + mf_resp = response.Response() + if http_resp.status_code != 200: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.users["update_user_identity"], http_resp.status_code + ) + else: + mf_resp.value = http_resp.json() + return mf_resp + + def update_user_tags(self, user: dict, user_token: str): + """Updating user tags in the database""" + http_resp = requests.patch( + self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"] + "/tags", + headers=utils.construct_header(user_token, utils.CTJSON), + data=json.dumps(user), + ) + mf_resp = response.Response() + if http_resp.status_code != 200: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.users["update_user_tags"], http_resp.status_code + ) + else: + mf_resp.value = http_resp.json() + return mf_resp + + def update_user_owner(self, user: dict, user_token: str): + """Updating user tags in the database""" + http_resp = requests.patch( + self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"] + "/owner", + headers=utils.construct_header(user_token, utils.CTJSON), + data=json.dumps(user), + ) + mf_resp = response.Response() + if http_resp.status_code != 200: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.users["update_user_owner"], http_resp.status_code + ) + else: + mf_resp.value = http_resp.json() + return mf_resp + def update_password(self, old_secret: str, new_secret: str, user_token: str): """Changes user password""" payload = {"old_secret": old_secret, "new_secret": new_secret} @@ -111,6 +178,40 @@ def update_password(self, old_secret: str, new_secret: str, user_token: str): else: mf_resp.value = "OK" return mf_resp + + def reset_password_request(self, email: str, url: str): + """User Password reset request""" + http_resp = requests.post( + self.URL + "/password/reset-request", + headers= {"Referer": url}, + json= {"email": email} + ) + mf_resp = response.Response() + if http_resp.status_code != 201: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.users["reset_password_request"], http_resp.status_code + ) + else: + mf_resp.value = http_resp.json() + return mf_resp + + def reset_password(self, password: str, confirm_password: str, token: str): + """Changes user password with the reset_request token""" + payload = {"password": password, "confirm_password": confirm_password, "token": token} + http_resp = requests.put( + self.URL + "/password/reset", + json=payload, + ) + mf_resp = response.Response() + if http_resp.status_code != 201: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.users["reset_password"], http_resp.status_code + ) + else: + mf_resp.value = "OK" + return mf_resp def enable(self, user_id: str, user_token: str): """Enables a disabled user account for a given user ID.""" @@ -143,3 +244,20 @@ def disable(self, user_id: str, user_token: str): else: mf_resp.value = http_resp.json() return mf_resp + + def authorise_user(self,access_request: dict, token: str): + """Authorises user""" + mf_resp = response.Response() + http_resp= requests.post( + self.URL +"/authorize", + headers=utils.construct_header(token, utils.CTJSON), + json= access_request + ) + if http_resp.status_code != 200: + mf_resp.error.status = 1 + mf_resp.error.message = errors.handle_error( + errors.users["authorise_user"], http_resp.status_code + ) + else: + mf_resp.value = "True" + return mf_resp \ No newline at end of file diff --git a/tests/test_things.py b/tests/test_things.py index b46b1cc..ccc8a74 100644 --- a/tests/test_things.py +++ b/tests/test_things.py @@ -1,6 +1,5 @@ from mainflux import sdk -import json import requests_mock s = sdk.SDK() @@ -93,96 +92,119 @@ def test_create_thing(requests_mock): assert r.error.status == 0 assert thing == r.value - def test_create_existing_thing(requests_mock): requests_mock.register_uri("POST", url + "/things", headers={"location": "/things/" + thing_id}, status_code=409) r = s.things.create(thing=thing, token=token) assert r.error.status == 1 assert r.error.message == "Entity already exist." - def test_create_bulk_things(requests_mock): requests_mock.register_uri("POST", url + "/things/bulk", json=things, status_code=200) r = s.things.create_bulk(things=things, token=token) assert r.error.status == 0 assert things == r.value - def test_create_bulk_things_missing_token(requests_mock): requests_mock.register_uri("POST", url + "/things/bulk", json=[thing_id, thing_id1], headers={"location": "/things/" + thing_id}, status_code=401) r = s.things.create_bulk(things=things, token=token) assert r.error.status == 1 assert r.error.message == "Missing or invalid access token provided." - def test_get_thing(requests_mock): requests_mock.register_uri("GET", url + "/things/" + thing_id, json=thing, status_code=200) r = s.things.get(thing_id=thing_id, token=token) assert r.error.status == 0 assert thing == r.value - def test_get_thing_malformed_query(requests_mock): requests_mock.register_uri("GET", url + "/things/" + thing_id, json=thing, status_code=400) r = s.things.get(thing_id=thing_id, token=token) assert r.error.status == 1 assert r.error.message == "Failed due to malformed query parameters." - def test_get_all_things(requests_mock): requests_mock.register_uri("GET", url + "/things", json=[thing_id, thing_id1], status_code=200) r = s.things.get_all(token=token, query_params=params) assert r.error.status == 0 assert [thing_id, thing_id1] == r.value - def test_get_all_thing_does_not_exist(requests_mock): requests_mock.register_uri("GET", url + "/things", json=[thing_id, thing_id1], status_code=404) r = s.things.get_all(token=token, query_params=params) assert r.error.status == 1 assert r.error.message == "Thing does not exist." - def test_get_by_channel(requests_mock): requests_mock.register_uri("GET", url + "/channels/" + channel_id + "/things", json=channel_id, headers={"Authorization": "/channels/" + channel_id + "/things"}, status_code=200) r = s.things.get_by_channel(channel_id=channel_id, query_params=params, token=token) assert r.error.status == 0 assert channel_id == r.value - def test_get_by_channel_missing_token(requests_mock): requests_mock.register_uri("GET", url + "/channels/" + channel_id + "/things", json=channel_id, headers={"Authorization": "/channels/" + channel_id + "/things"}, status_code=401) r = s.things.get_by_channel(channel_id=channel_id, query_params=params, token=token) assert r.error.status == 1 assert r.error.message == "Missing or invalid access token provided." - def test_update_thing(requests_mock): requests_mock.register_uri("PATCH", url + "/things/" + thing["id"], json=thing, status_code=200) r = s.things.update(thing_id=thing["id"], token=token, thing=thing) assert r.error.status == 0 - + assert thing== r.value def test_update_thing_bad_json(requests_mock): - requests_mock.register_uri("PATCH", url + "/things/" + thing["id"], json=thing, status_code=400) + requests_mock.register_uri("PATCH", url + "/things/" + thing["id"], json=thing, status_code=404) r = s.things.update(thing_id=thing["id"], token=token, thing=thing) assert r.error.status == 1 - assert r.error.message == "Failed due to malformed JSON." + assert r.error.message == "Thing does not exist." + +def test_update_thing_secret(requests_mock): + requests_mock.register_uri("PATCH", url + "/things/" + thing["id"] + "/secret", json=thing, status_code=200) + r = s.things.update_thing_secret(thing_id=thing["id"], token=token, thing=thing) + assert r.error.status == 0 + assert thing== r.value + +def test_update_thing_secret_bad_token(requests_mock): + requests_mock.register_uri("PATCH", url + "/things/" + thing["id"] + "/secret", json=thing, status_code=401) + r = s.things.update_thing_secret(thing_id=thing["id"], token=token, thing=thing) + assert r.error.status == 1 + assert r.error.message == "Missing or invalid access token provided." + +def test_update_thing_tags(requests_mock): + requests_mock.register_uri("PATCH", url + "/things/" + thing["id"] + "/tags", json=thing, status_code=200) + r = s.things.update_thing_tags(thing_id=thing["id"], token=token, thing=thing) + assert r.error.status == 0 + assert thing== r.value + +def test_update_thing_tags_bad_token(requests_mock): + requests_mock.register_uri("PATCH", url + "/things/" + thing["id"] + "/tags", json=thing, status_code=401) + r = s.things.update_thing_tags(thing_id=thing["id"], token=token, thing=thing) + assert r.error.status == 1 + assert r.error.message == "Missing or invalid access token provided." + +def test_update_thing_owner(requests_mock): + requests_mock.register_uri("PATCH", url + "/things/" + thing["id"] + "/owner", json=thing, status_code=200) + r = s.things.update_thing_owner(thing_id=thing["id"], token=token, thing=thing) + assert r.error.status == 0 + assert thing== r.value +def test_update_thing_owner_bad_token(requests_mock): + requests_mock.register_uri("PATCH", url + "/things/" + thing["id"] + "/owner", json=thing, status_code=401) + r = s.things.update_thing_owner(thing_id=thing["id"], token=token, thing=thing) + assert r.error.status == 1 + assert r.error.message == "Missing or invalid access token provided." def test_disable_thing(requests_mock): requests_mock.register_uri("POST", url + "/things/" + thing["id"] + "/disable", status_code=200) r = s.things.disable(thing_id=thing["id"], token=token) assert r.error.status == 0 - def test_disable_bad_thing_id(requests_mock): requests_mock.register_uri("POST", url + "/things/" + thing["id"] + "/disable", status_code=400) r = s.things.disable(thing_id=thing["id"], token=token) assert r.error.status == 1 assert r.error.message == "Failed due to malformed thing's ID." - def test_connect_thing(requests_mock): requests_mock.register_uri("POST", url + "/policies", status_code=201) r = s.things.connect(channel_id=channel_id, thing_id=thing_id, token=token, action=["m_read"]) @@ -206,26 +228,22 @@ def test_connect_non_existing_entity(requests_mock): assert r.error.status == 1 assert r.error.message == "A non-existent entity request." - def test_disconnect_thing(requests_mock): requests_mock.register_uri("POST", url + "/disconnect", status_code=204) r = s.things.disconnect(channel_id=channel_id, thing_id=thing_id, token=token) assert r.error.status == 0 - def test_disconnect_thing_or_channel_does_not_exist(requests_mock): requests_mock.register_uri("POST", url + "/disconnect", status_code=404) r = s.things.disconnect(channel_id=channel_id, thing_id=thing_id, token=token) assert r.error.status == 1 assert r.error.message == "Channel or thing does not exist." - def test_disconnects(requests_mock): requests_mock.register_uri("POST", url + "/disconnect", status_code=204) r = s.things.disconnects(channel_ids=[channel_id], thing_ids=[thing_id, thing_id1], token=token) assert r.error.status == 0 - def test_disconnects_bad_json(requests_mock): requests_mock.register_uri("POST", url + "/disconnect", status_code=404) r = s.things.disconnects(channel_ids=[channel_id], thing_ids=[thing_id, thing_id1], token=token) From f50470955c2bb92771286219c85de638b1ba4800 Mon Sep 17 00:00:00 2001 From: Musilah Date: Thu, 24 Aug 2023 11:18:18 +0300 Subject: [PATCH 11/31] Fix and Update examples.py Signed-off-by: Musilah --- docs/channels.md | 20 +-- docs/groups.md | 12 +- docs/things.md | 70 +++++++- docs/users.md | 96 +++++++++- examples/examples.py | 409 +++++++++++++++++++++++++++++++++---------- mainflux/channels.py | 23 ++- mainflux/things.py | 4 +- tests/test_users.py | 83 +++++++-- 8 files changed, 573 insertions(+), 144 deletions(-) diff --git a/docs/channels.md b/docs/channels.md index c1be396..20f375a 100644 --- a/docs/channels.md +++ b/docs/channels.md @@ -11,14 +11,14 @@ --- - + ## class `Channels` - + ### method `__init__` @@ -35,7 +35,7 @@ __init__(url: str) --- - + ### method `create` @@ -47,7 +47,7 @@ Creates channel entity in the database --- - + ### method `create_bulk` @@ -59,7 +59,7 @@ Creates multiple channels in a bulk --- - + ### method `disable` @@ -71,7 +71,7 @@ Deletes a channel entity from database --- - + ### method `get` @@ -83,7 +83,7 @@ Gets a channel entity for a logged-in user --- - + ### method `get_all` @@ -95,7 +95,7 @@ Gets all channels from database --- - + ### method `get_by_thing` @@ -107,7 +107,7 @@ Gets all channels to which a specific thing is connected to --- - + ### method `identify_thing` @@ -119,7 +119,7 @@ Validates thing's key and returns it's ID if key is valid --- - + ### method `update` diff --git a/docs/groups.md b/docs/groups.md index fc739fb..571a54c 100644 --- a/docs/groups.md +++ b/docs/groups.md @@ -35,7 +35,7 @@ __init__(url: str) --- - + ### method `assign` @@ -71,7 +71,7 @@ Creates group entity in the database --- - + ### method `disable` @@ -107,7 +107,7 @@ Gets all groups from database --- - + ### method `members` @@ -119,7 +119,7 @@ Get list of members ID's from group --- - + ### method `memberships` @@ -143,7 +143,7 @@ Gets parents for a specific group from database --- - + ### method `share_groups` @@ -155,7 +155,7 @@ Adds access rights on thing groups to the user group --- - + ### method `unassign` diff --git a/docs/things.md b/docs/things.md index 8605b50..32d329d 100644 --- a/docs/things.md +++ b/docs/things.md @@ -35,7 +35,19 @@ __init__(url: str) --- - + + +### method `authorise_thing` + +```python +authorise_thing(access_request: dict, token: str) +``` + +Authorises thing + +--- + + ### method `connect` @@ -47,7 +59,7 @@ Connects thing and channel --- - + ### method `connects` @@ -83,7 +95,7 @@ Creates multiple things in a bulk --- - + ### method `disable` @@ -95,7 +107,7 @@ Deletes a thing entity from database --- - + ### method `disconnect` @@ -107,7 +119,7 @@ Disconnect thing and channel --- - + ### method `disconnects` @@ -155,6 +167,18 @@ Gets all things to which a specific thing is connected to --- + + +### method `share_thing` + +```python +share_thing(user_id: str, channel_id: str, actions: dict, token: str) +``` + +Share thing + +--- + ### method `update` @@ -165,6 +189,42 @@ update(thing_id: str, thing: dict, token: str) Updates thing entity +--- + + + +### method `update_thing_owner` + +```python +update_thing_owner(thing_id: str, thing: dict, token: str) +``` + +Updates thing secret + +--- + + + +### method `update_thing_secret` + +```python +update_thing_secret(thing_id: str, thing: dict, token: str) +``` + +Updates thing secret + +--- + + + +### method `update_thing_tags` + +```python +update_thing_tags(thing_id: str, thing: dict, token: str) +``` + +Updates thing secret + diff --git a/docs/users.md b/docs/users.md index ff5d96f..867b3dc 100644 --- a/docs/users.md +++ b/docs/users.md @@ -33,6 +33,18 @@ __init__(url: str) +--- + + + +### method `authorise_user` + +```python +authorise_user(access_request: dict, token: str) +``` + +Authorises user + --- @@ -47,7 +59,7 @@ Registers new user account given email and password. New account will be uniquel --- - + ### method `disable` @@ -59,7 +71,7 @@ Disables an enabled user account for a given user ID. --- - + ### method `enable` @@ -71,7 +83,7 @@ Enables a disabled user account for a given user ID. --- - + ### method `get` @@ -83,7 +95,7 @@ Gets a user information --- - + ### method `get_all` @@ -107,7 +119,43 @@ Generates an access token when provided with proper credentials. --- - + + +### method `refresh_token` + +```python +refresh_token(user: dict, token: str) +``` + +Refreshes Access and Refresh Token used for authenticating into the system. + +--- + + + +### method `reset_password` + +```python +reset_password(password: str, confirm_password: str, token: str) +``` + +Changes user password with the reset_request token + +--- + + + +### method `reset_password_request` + +```python +reset_password_request(email: str, url: str) +``` + +User Password reset request + +--- + + ### method `update` @@ -119,7 +167,7 @@ Updates info on currently logged in user. Info is updated using authorization us --- - + ### method `update_password` @@ -129,6 +177,42 @@ update_password(old_secret: str, new_secret: str, user_token: str) Changes user password +--- + + + +### method `update_user_identity` + +```python +update_user_identity(user: dict, user_token: str) +``` + +Updates Identity of the user + +--- + + + +### method `update_user_owner` + +```python +update_user_owner(user: dict, user_token: str) +``` + +Updating user tags in the database + +--- + + + +### method `update_user_tags` + +```python +update_user_tags(user: dict, user_token: str) +``` + +Updating user tags in the database + diff --git a/examples/examples.py b/examples/examples.py index 036f3ca..c2becbf 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -7,15 +7,15 @@ things_url=default_url + ":9000", reader_url=default_url + ":9204", http_adapter_url=default_url, - certs_url=default_url + ":8204", - bootstrap_url=default_url + ":8202", + certs_url=default_url + ":9019", + bootstrap_url=default_url + ":9013", auth_url=default_url, ) -''' + """To start working with the Mainflux system, you need to create a user account""" mf_resp = mfsdk.users.create( - user={"credentials": {"identity": "example25@example.com", "secret": "12345678"}}, + user={"credentials": {"identity": "", "secret": ""}}, token="", ) if mf_resp.error.status == 0: @@ -25,81 +25,173 @@ """To log in to the Mainflux system, you need to create a user token""" mf_resp = mfsdk.users.login( - user={ "identity" : "example20@example.com", "secret": "12345678"} + user={ "identity" : "", "secret": ""} ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -''' -''' + +"""Refreshes Access and Refresh Token used for authenticating into the system.""" +user= { + "credentials": { + "identity": "", + "secret": "" + }, + "id": "", + "name": "" +} +mf_resp = mfsdk.users.refresh_token( + user= user, + token="" +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + """You can always check the user entity that is logged in by entering the user ID and token""" -mf_resp = mfsdk.users.get(user_id="0f047968-b170-4dd4-85f5-6e03e1b3798e", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE3NTIxOTcsImlhdCI6MTY5MTc1MTI5NywiaWRlbnRpdHkiOiJleGFtcGxlMTJAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiIwZjA0Nzk2OC1iMTcwLTRkZDQtODVmNS02ZTAzZTFiMzc5OGUiLCJ0eXBlIjoiYWNjZXNzIn0.REa8wv-veZm2fpAeLe3jO9SMYMnyPrcT07YTmx4M_lOE3wYYal26HYp8RHd6z3Igy7ccadSKiqaygyvrpkMLzw") +mf_resp = mfsdk.users.get(user_id="", token="") if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -''' -''' -"""Updating user entities in the database""" + +"""Updates user entities in the database""" user = { - "id": "", - "name": "", + "id": "", + "name": "", "metadata": { "foo": "bar" } } -mf_resp = mfsdk.users.update( - user_token="", user=user -) +mf_resp = mfsdk.users.update(user_token="", user=user) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Updates user identity in the database""" +user = { + "credentials": { + "identity": "", + }, + "id": "" +} +mf_resp = mfsdk.users.update_user_identity(user_token="", user=user) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -''' -''' + +"""Updates user tags in the database""" +user = { + "id": "", + "name": "", + "tags": [ + "yellow", + "orange" + ] +} +mf_resp = mfsdk.users.update_user_tags(user_token="", user=user) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Updates user owner in the database""" +user = { + "credentials": { + "identity": "", + "secret": "" + }, + "id": "", + "owner": "" +} +mf_resp = mfsdk.users.update_user_owner(user_token="", user=user) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""User Password reset request""" +mf_resp = mfsdk.users.reset_password_request(email= "", url= "") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""User Password reset with the reset_request token""" +mf_resp = mfsdk.users.reset_password(password="", confirm_password="", token= "") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + """You can get all users in the database by calling the get_all () function""" mf_resp = mfsdk.users.get_all( query_params={"offset": 0, "limit": 5}, - admin_token="", + user_token="" ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -''' -''' -mf_resp = mfsdk.users.disable(user_id="46c266a8-084d-4863-b013-9d27be7617e5", user_token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE4MTIxMjQsImlhdCI6MTY5MTc1ODEyNCwiaWRlbnRpdHkiOiJleGFtcGxlMTVAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiJhZTE4ZjZiZS01OTJmLTQ1NjAtOGIxNy1jMmUxYmYyNzNhYWUiLCJ0eXBlIjoiYWNjZXNzIn0.SO3Z6-mNbYFEuJDlO1E477nQblg0UR6r0C7aR8jhRcTpDA62isovYjXhdoDdjPrRrDb7K1hHSHrxHhMFPiYz7w") + +"""Disables user""" +mf_resp = mfsdk.users.disable(user_id="", user_token="") if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) - -mf_resp = mfsdk.users.enable(user_id="46c266a8-084d-4863-b013-9d27be7617e5", user_token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTE4MTIxMjQsImlhdCI6MTY5MTc1ODEyNCwiaWRlbnRpdHkiOiJleGFtcGxlMTVAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiJhZTE4ZjZiZS01OTJmLTQ1NjAtOGIxNy1jMmUxYmYyNzNhYWUiLCJ0eXBlIjoiYWNjZXNzIn0.SO3Z6-mNbYFEuJDlO1E477nQblg0UR6r0C7aR8jhRcTpDA62isovYjXhdoDdjPrRrDb7K1hHSHrxHhMFPiYz7w") + +"""Enables user""" +mf_resp = mfsdk.users.enable(user_id="", user_token="") if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -"""Changing the user password can be done by calling -the update password function""" -''' -""" +"""Changing the user password can be done by calling the update password function""" mf_resp = mfsdk.users.update_password( - old_secret="", secret="", - user_token="" + old_secret="", new_secret="", + user_token="" ) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Authorising a User""" +access_request = { + "subject": "", + "object": "", + "Action": "", + "Entity_type": "" +} +mf_resp = mfsdk.users.authorise_user(access_request=access_request, token="") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) +"""Authorising a Thing""" +access_request = { + "subject": "", + "object": "", + "Action": "", + "Entity_type": "" +} +mf_resp = mfsdk.things.authorise_thing(access_request=access_request, token="") if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -""" -''' + """To create a thing, you need the thing name and a user token""" mf_resp = mfsdk.things.create( - thing={"name": "thing1"}, token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ") + thing={"name": ""}, token="") if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -108,8 +200,8 @@ """You can create multiple things at once by entering a series of things structures and a user token""" mf_resp = mfsdk.things.create_bulk( - things=[{"name": "thing_8"}, {"name": "thing_9"}, {"name": "thing_10"}], - token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ", + things=[{"name": ""}, {"name": ""}, {"name": ""}], + token="", ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -117,7 +209,7 @@ print(mf_resp.error.message) """You can get thing information by entering the thing ID and user token""" -mf_resp = mfsdk.things.get(token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ", thing_id="6d591627-8657-43af-bfaa-79047b5f8ec3") +mf_resp = mfsdk.things.get(thing_id= "", token="") if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -125,23 +217,62 @@ """You can get all things in the database by calling the get_all () function""" mf_resp = mfsdk.things.get_all( - query_params={"offset": 0, "limit": 5}, token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ" + query_params={"offset": 0, "limit": 5}, token="" ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -"""Updating a thing entity in a database""" +"""Updates a thing entity in a database""" mf_resp = mfsdk.things.update( - thing_id="6d591627-8657-43af-bfaa-79047b5f8ec3", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ", thing={"name": "thing_1"} + thing_id="", token="", thing={"name": ""} ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -"You can get all thing connected to channel" +"""Updates a thing secret in a database""" +mf_resp = mfsdk.things.update_thing_secret( + thing_id="", token="", thing={"secret": ""} +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Updates a thing's tags in a database""" +thing= { + "id": "", + "name": "", + "tags": [ + "dev","back" + ] + } +mf_resp = mfsdk.things.update_thing_tags( + thing_id="", token="", thing=thing +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Updates a thing's owner""" +thing= { + "id": "", + "name": "", + "owner": "", +} +mf_resp = mfsdk.things.update_thing_owner( + thing_id="", token="", thing=thing +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""You can get all thing connected to channel""" mf_resp = mfsdk.things.get_by_channel( channel_id="", query_params={"offset": 1, "limit": 5}, @@ -153,7 +284,7 @@ print(mf_resp.error.message) """To disable a thing you need a thing ID and a user token""" -mf_resp = mfsdk.things.disable(thing_id="2ad76a79-640b-44c3-ab1c-3894d4013391", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ") +mf_resp = mfsdk.things.disable(thing_id="", token="") if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -161,7 +292,7 @@ """Connect thing to channel""" mf_resp = mfsdk.things.connect( - channel_id="6a4c094d-b192-4e7b-837f-6d2a2bae12d5", thing_id="769c8d58-bc7e-4003-8e5b-84301534ba7f", action="m_write", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMzI1ODUsImlhdCI6MTY5MjI3ODU4NSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.hAJllwSCLDOqJseCKkTtw4qI9EyuBat6qaLGsvdsU-OGVS6-VkkK6boiDQ-_Men9CT6oUpzzTmW3e0dRF72j3g" + channel_id="", thing_id="", action="", token="" ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -170,7 +301,7 @@ """Disconnect thing from channel""" mf_resp = mfsdk.things.disconnect( - channel_id="2b7ff10e-9294-47a9-a66b-e8f7de7c5a8b", thing_id="6d591627-8657-43af-bfaa-79047b5f8ec3", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMzI1ODUsImlhdCI6MTY5MjI3ODU4NSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.hAJllwSCLDOqJseCKkTtw4qI9EyuBat6qaLGsvdsU-OGVS6-VkkK6boiDQ-_Men9CT6oUpzzTmW3e0dRF72j3g" + channel_id="", thing_id="", token="" ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -179,10 +310,10 @@ """Connect things to channels""" mf_resp = mfsdk.things.connects( - thing_ids=["769c8d58-bc7e-4003-8e5b-84301534ba7f", "a937d27a-b0aa-4e4f-a85e-bb95bf0ac1bf"], - channel_ids=["6a4c094d-b192-4e7b-837f-6d2a2bae12d5"], - action="m_read", - token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ", + thing_ids=["", ""], + channel_ids=[""], + action="", + token="", ) if mf_resp.error.status == 0: @@ -201,9 +332,21 @@ else: print(mf_resp.error.message) +"""Share thing""" +mf_resp = mfsdk.things.share_thing( + channel_id= "", + user_id= "", + actions= ["action"], + token= "" +) +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + """To create a channel, you need a channel and a token""" mf_resp = mfsdk.channels.create( - channel={"name": "channel_3"}, token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ") + channel={"name": ""}, token="") if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -211,8 +354,8 @@ """As with things, you can create multiple channels at once""" mf_resp = mfsdk.channels.create_bulk( - channels=[{"name": "channel_6"}, {"name": "channel_7"}], - token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ", + channels=[{"name": ""}, {"name": ""}], + token="", ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -221,18 +364,17 @@ """Update channel entities in the database""" mf_resp = mfsdk.channels.update( - channel_id="2b7ff10e-9294-47a9-a66b-e8f7de7c5a8b", - token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ", - channel={"name": "channel_3"}, + channel_id="", + token="", + channel={"name": ""}, ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -''' -''' + """You can get channel information by entering the channel ID and user token""" -mf_resp = mfsdk.channels.get(token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ", channel_id="2b7ff10e-9294-47a9-a66b-e8f7de7c5a8b") +mf_resp = mfsdk.channels.get(token="", channel_id="") if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -241,7 +383,7 @@ """You can get all channels in the database by calling the get_all () function""" mf_resp = mfsdk.channels.get_all( - query_params={"offset": 0, "limit": 5}, token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ" + query_params={"offset": 0, "limit": 5}, token="" ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -250,78 +392,72 @@ """A list of all the channels to which a given thing is connected""" mf_resp = mfsdk.channels.get_by_thing( - thing_id="2ad76a79-640b-44c3-ab1c-3894d4013391", query_params={"offset": 0, "limit": 5}, - token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ" + thing_id="", query_params={"offset": 0, "limit": 5}, + token="" ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) - """Identifies thing when given thing key""" -mf_resp = mfsdk.channels.identify_thing(thing_key="a0c5471a-b7a6-4337-81af-b6113f41d898", user_token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ") +mf_resp = mfsdk.channels.identify_thing(thing_key="", user_token="") if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) - """Delete channels from the database""" mf_resp = mfsdk.channels.disable( - channel_id="2b7ff10e-9294-47a9-a66b-e8f7de7c5a8b", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIwNTUxNzIsImlhdCI6MTY5MjAwMTE3MiwiaWRlbnRpdHkiOiJleGFtcGxlMTlAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI2OWFkNjk0Ny0xZGQ1LTRmNzItYTQ3NC1kMGZmNDE0MTUyYTEiLCJ0eXBlIjoiYWNjZXNzIn0.mlfRaQG69XmKUei9KW2287Kvk7_EiuAVeGbmq9aojA2FzzoicRxsTWkwEJGuhwWBHxQgBMe99j5rdb6EbJHkWQ") + channel_id="", token="") if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -''' -''' + """To create a group, you need the group name and a user token""" mf_resp = mfsdk.groups.create( - group={"name": "group_D", "parent_id": "d6198103-4724-427e-b052-e6ad544c8864"}, token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIyNjk5MzEsImlhdCI6MTY5MjIxNTkzMSwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.vDHq7AOvppvknsKPdAxnGjsErUZ25_gAbZJ1zom3QqZ1sNAoPPU5AyVor-EgMeq1yvhggh8wzLx-9TSK6pQcCA") + group={"name": "", "parent_id": ""}, token="") if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) """You can get group information by entering the group ID and token""" -mf_resp = mfsdk.groups.get(group_id="1705dbd3-e542-4a38-8bef-aa7c33bdcf2d", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ") +mf_resp = mfsdk.groups.get(group_id="", token="") if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -''' -''' + """Group update""" group={ - "id": "75b2f10c-b903-4205-8af5-9d672be26d63", - "name": "group_15" + "id": "", + "name": "" } mf_resp = mfsdk.groups.update( - token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIyNjk5MzEsImlhdCI6MTY5MjIxNTkzMSwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.vDHq7AOvppvknsKPdAxnGjsErUZ25_gAbZJ1zom3QqZ1sNAoPPU5AyVor-EgMeq1yvhggh8wzLx-9TSK6pQcCA", group= group + token="", group= group, group_id="group_id" ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -''' -''' + """You can get groups in the database by calling the get_all () function""" mf_resp = mfsdk.groups.get_all( - token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ", query_params={"offset": 0, "limit": 5} + token="", query_params={"offset": 0, "limit": 5} ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) - """Assign user, thing or channel to a group""" mf_resp = mfsdk.groups.assign( - group_id="d6198103-4724-427e-b052-e6ad544c8864", - token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMjEyNzgsImlhdCI6MTY5MjI2NzI3OCwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.o5l7GX9OXrTr_st-gc1FNPwf7Kx-7FYrO7JUfXOUIL9GR0lKqBuwOLHpQav_8RCWmO1EFsiRzo1hsWRE1BKoXA", - members_ids="9c398baf-5520-48ed-86de-572be9405d5b", - member_type=["g_update"], + group_id="", + token="", + members_ids="", + member_type=[""], ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -330,9 +466,9 @@ """Unassign""" mf_resp = mfsdk.groups.unassign( - group_id="d6198103-4724-427e-b052-e6ad544c8864", - token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMjEyNzgsImlhdCI6MTY5MjI2NzI3OCwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.o5l7GX9OXrTr_st-gc1FNPwf7Kx-7FYrO7JUfXOUIL9GR0lKqBuwOLHpQav_8RCWmO1EFsiRzo1hsWRE1BKoXA", - members_ids="9c398baf-5520-48ed-86de-572be9405d5b", + group_id="", + token="", + members_ids="", ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -341,7 +477,7 @@ """Get list of children from group""" mf_resp = mfsdk.groups.children( - group_id="75b2f10c-b903-4205-8af5-9d672be26d63", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIyNjk5MzEsImlhdCI6MTY5MjIxNTkzMSwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.vDHq7AOvppvknsKPdAxnGjsErUZ25_gAbZJ1zom3QqZ1sNAoPPU5AyVor-EgMeq1yvhggh8wzLx-9TSK6pQcCA", + group_id="", token="", query_params={"offset": 0, "limit": 5} ) if mf_resp.error.status == 0: @@ -351,7 +487,7 @@ """Get list of parents from group""" mf_resp = mfsdk.groups.parents( - group_id="b7cbb7c3-39af-4577-bae9-f83f3674b364", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIyNjk5MzEsImlhdCI6MTY5MjIxNTkzMSwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.vDHq7AOvppvknsKPdAxnGjsErUZ25_gAbZJ1zom3QqZ1sNAoPPU5AyVor-EgMeq1yvhggh8wzLx-9TSK6pQcCA", + group_id="", token="", query_params={"offset": 0, "limit": 5} ) if mf_resp.error.status == 0: @@ -361,7 +497,7 @@ """Get list of members from group""" mf_resp = mfsdk.groups.members( - group_id="d6198103-4724-427e-b052-e6ad544c8864", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMjEyNzgsImlhdCI6MTY5MjI2NzI3OCwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.o5l7GX9OXrTr_st-gc1FNPwf7Kx-7FYrO7JUfXOUIL9GR0lKqBuwOLHpQav_8RCWmO1EFsiRzo1hsWRE1BKoXA", + group_id="", token="", query_params={"offset": 0, "limit": 5} ) if mf_resp.error.status == 0: @@ -371,8 +507,8 @@ """Get list of memberships from member""" mf_resp = mfsdk.groups.memberships( - member_id="9c398baf-5520-48ed-86de-572be9405d5b", - token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMjEyNzgsImlhdCI6MTY5MjI2NzI3OCwiaWRlbnRpdHkiOiJleGFtcGxlMjRAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI5ZjczNGQ1Yi03NTgwLTQ5NzEtYmM0Mi1hYWYxMTlhZTg5MGEiLCJ0eXBlIjoiYWNjZXNzIn0.o5l7GX9OXrTr_st-gc1FNPwf7Kx-7FYrO7JUfXOUIL9GR0lKqBuwOLHpQav_8RCWmO1EFsiRzo1hsWRE1BKoXA", + member_id="", + token="", query_params={"offset": 0, "limit": 5}, ) if mf_resp.error.status == 0: @@ -381,7 +517,7 @@ print(mf_resp.error.message) """Delete group from the database""" -mf_resp = mfsdk.groups.disable(group_id="29474bea-a8d6-4e5c-9336-5de0c8ca9aaf", user_token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIxNDM0MTEsImlhdCI6MTY5MjA4OTQxMSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.BgXBpOdkOP6s2QMLdzv4jHsl3rX16ZkA_r34BS4wL8UA_xr5gWxeyqaNL8x9tkNNRz4RML40Lo2lGtd2sMvVZQ") +mf_resp = mfsdk.groups.disable(group_id="", user_token="") if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -389,16 +525,105 @@ """Sends message via HTTP protocol""" mf_resp = mfsdk.messages.send( - channel_id="6a4c094d-b192-4e7b-837f-6d2a2bae12d5", msg="Hello", thing_key="a0c5471a-b7a6-4337-81af-b6113f41d898" + channel_id="", msg="<[message]>", thing_key="" ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) -''' + """Reads messages from database for a given channel""" -mf_resp = mfsdk.messages.read(channel_id="6a4c094d-b192-4e7b-837f-6d2a2bae12d5", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTIzMzI1ODUsImlhdCI6MTY5MjI3ODU4NSwiaWRlbnRpdHkiOiJleGFtcGxlMjBAZXhhbXBsZS5jb20iLCJpc3MiOiJjbGllbnRzLmF1dGgiLCJzdWIiOiI4N2MxZTY5MC1kMDFhLTRhN2YtOGYyNy0xZjhhOWE2ZGIwMmUiLCJ0eXBlIjoiYWNjZXNzIn0.hAJllwSCLDOqJseCKkTtw4qI9EyuBat6qaLGsvdsU-OGVS6-VkkK6boiDQ-_Men9CT6oUpzzTmW3e0dRF72j3g") +mf_resp = mfsdk.messages.read(channel_id="", token="") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Issue certs""" +mf_resp = mfsdk.certs.issue(thing_id="",valid="10h", token="") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""View Certs""" +mf_resp = mfsdk.certs.view_by_thing(thing_id="", token="") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""View Certs""" +mf_resp = mfsdk.certs.view_by_serial(cert_id="", token="") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Revoke Certs""" +mf_resp = mfsdk.certs.revoke(thing_id="", token="") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Adds new config to the list of config owned by user identified using the provided access token.""" +config = { + "external_id": "", + "external_key": "", + "thing_id": "", + "name": "" +} +mf_resp = mfsdk.bootstrap.add(config=config, token="") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) +"""Updating state represents enabling/disabling Config, i.e.connecting and disconnecting corresponding Mainflux Thing to the list of Channels.""" +config = { + "external_id": "", + "external_key": "", + "thing_id": "", + "name": "" +} +mf_resp = mfsdk.bootstrap.whitelist(config=config, token="") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Retrieves a configuration with given config id""" +mf_resp = mfsdk.bootstrap.view(thing_id= "", token="") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Update is performed by replacing the current resource data with values provided in a request payload. Note that the owner, ID, external ID, external key, Mainflux Thing ID and key cannot be changed.""" +config = { + "external_id": "", + "external_key": "", + "thing_id": "", + "name": "" +} +mf_resp = mfsdk.bootstrap.update(config=config, token="") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Retrieves a configuration with given external ID and external key.""" +mf_resp = mfsdk.bootstrap.bootstrap(external_id="", external_key= "") +if mf_resp.error.status == 0: + print(mf_resp.value) +else: + print(mf_resp.error.message) + +"""Removes a Config. In case of successful removal the service will ensure that the removed config is disconnected from all the Mainflux channels.""" + +mf_resp = mfsdk.bootstrap.remove(config_id= "", token="") if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) + \ No newline at end of file diff --git a/mainflux/channels.py b/mainflux/channels.py index 69fdeec..0d4109a 100644 --- a/mainflux/channels.py +++ b/mainflux/channels.py @@ -3,13 +3,12 @@ from mainflux import response from mainflux import errors from mainflux import utils -from mainflux import things class Channels: - channels_endpoint = "channels" - things_endpoint = "things" - identify_endpoint = "identify" + CHANNELS_ENDPOINT = "channels" + THINGS_ENDPOINT = "things" + IDENTIFY_ENDPOINT = "identify" def __init__(self, url: str): self.url = url @@ -18,7 +17,7 @@ def create(self, channel: dict, token: str): """Creates channel entity in the database""" mf_resp = response.Response() http_resp = requests.post( - self.url + "/" + self.channels_endpoint, + self.url + "/" + self.CHANNELS_ENDPOINT, json=channel, headers=utils.construct_header(token, utils.CTJSON), ) @@ -35,7 +34,7 @@ def create_bulk(self, channels: list, token: str): """Creates multiple channels in a bulk""" mf_resp = response.Response() http_resp = requests.post( - self.url + "/" + self.channels_endpoint + "/bulk", + self.url + "/" + self.CHANNELS_ENDPOINT + "/bulk", json=channels, headers=utils.construct_header(token, utils.CTJSON), ) @@ -52,7 +51,7 @@ def get(self, channel_id: str, token: str): """Gets a channel entity for a logged-in user""" mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.channels_endpoint + "/" + channel_id, + self.url + "/" + self.CHANNELS_ENDPOINT + "/" + channel_id, headers=utils.construct_header(token, utils.CTJSON), ) if http_resp.status_code != 200: @@ -68,7 +67,7 @@ def get_all(self, query_params: dict, token: str): """Gets all channels from database""" mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.channels_endpoint, + self.url + "/" + self.CHANNELS_ENDPOINT, headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -85,7 +84,7 @@ def get_by_thing(self, thing_id: str, query_params: dict, token: str): """Gets all channels to which a specific thing is connected to""" mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.things_endpoint + "/" + thing_id + "/" + self.channels_endpoint, + self.url + "/" + self.THINGS_ENDPOINT + "/" + thing_id + "/" + self.CHANNELS_ENDPOINT, headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -101,7 +100,7 @@ def get_by_thing(self, thing_id: str, query_params: dict, token: str): def update(self, channel_id: str, channel: dict, token: str): """Updates channel entity""" http_resp = requests.put( - self.url + "/" + self.channels_endpoint + "/" + channel_id, + self.url + "/" + self.CHANNELS_ENDPOINT + "/" + channel_id, json=channel, headers=utils.construct_header(token, utils.CTJSON), ) @@ -116,7 +115,7 @@ def update(self, channel_id: str, channel: dict, token: str): def disable(self, channel_id: str, token: str): """Deletes a channel entity from database""" http_resp = requests.post( - self.url + "/" + self.channels_endpoint + "/" + channel_id + "/disable", + self.url + "/" + self.CHANNELS_ENDPOINT + "/" + channel_id + "/disable", headers=utils.construct_header(token, utils.CTJSON), ) mf_resp = response.Response() @@ -130,7 +129,7 @@ def disable(self, channel_id: str, token: str): def identify_thing(self, thing_key: str): """Validates thing's key and returns it's ID if key is valid""" http_resp = requests.post( - self.url + "/" + self.identify_endpoint, + self.url + "/" + self.IDENTIFY_ENDPOINT, headers=utils.construct_header(utils.ThingPrefix + thing_key, utils.CTJSON), ) mf_resp = response.Response() diff --git a/mainflux/things.py b/mainflux/things.py index 2515a79..a6fb053 100644 --- a/mainflux/things.py +++ b/mainflux/things.py @@ -248,9 +248,9 @@ def disconnect(self, thing_id: str, channel_id: str, token: str): ) return mf_resp - def share_thing(self, user_id: str, group_id: str, actions: dict, token: str): + def share_thing(self, user_id: str, channel_id: str, actions: dict, token: str): """Share thing""" - payload = {"object": group_id, "subject": user_id, "Actions": actions, "External": True} + payload = {"object": channel_id, "subject": user_id, "Actions": actions, "External": True} http_resp = requests.post( self.URL + "/policies", headers=utils.construct_header(token, utils.CTJSON), diff --git a/tests/test_users.py b/tests/test_users.py index 7041cc4..1d94d10 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -1,6 +1,6 @@ from mainflux import sdk -import json, requests_mock +import requests_mock s = sdk.SDK() user = { @@ -66,8 +66,11 @@ "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", "access_type": "access" } +password= "12345678" +confirm_password="12345678" +email={"admin@example.com": "email"} url = "http://localhost" - +url2 = "http://localhost/password/reset-request" def test_create_user(requests_mock): requests_mock.register_uri("POST", url + "/users", headers={"location": "/users/" + user_id}, json=user, status_code=201) @@ -80,21 +83,30 @@ def test_create_user_bad_user(requests_mock): r = s.users.create(user=user) assert r.error.status == 1 assert r.error.message == "Failed due to using an existing identity." - - + def test_login_user(requests_mock): requests_mock.register_uri("POST", url + "/users/tokens/issue", json=token, status_code=201) r = s.users.login(user=user) assert r.error.status == 0 assert token == r.value - def test_login_user_bad_email(requests_mock): requests_mock.register_uri("POST", url + "/users/tokens/issue", status_code=409) r = s.users.login(user=user) assert r.error.status == 1 assert r.error.message == "Failed due to using an existing email address." + +def test_refresh_token(requests_mock): + requests_mock.register_uri("POST", url + "/users/tokens/refresh", json=token, status_code=201) + r = s.users.refresh_token(user=user, token=token["refresh_token"]) + assert r.error.status == 0 + assert token == r.value +def test_refresh_token_bad_token(requests_mock): + requests_mock.register_uri("POST", url + "/users/tokens/refresh",json=token, status_code=404) + r = s.users.refresh_token(user=user, token=token["refresh_token"]) + assert r.error.status == 1 + assert r.error.message == "A non-existent entity request." def test_get_user(requests_mock): requests_mock.register_uri("GET", url + "/users/" + user_id, json=user, status_code=200) @@ -102,53 +114,102 @@ def test_get_user(requests_mock): assert r.error.status == 0 assert user == r.value - def test_get_user_bad_token(requests_mock): requests_mock.register_uri("GET", url + "/users/" + user_id, json=user, status_code=401) r = s.users.get(user_id=user_id, token=token["access_token"]) assert r.error.status == 1 assert r.error.message == "Missing or invalid access token provided." - def test_get_all_users(requests_mock): requests_mock.register_uri("GET", url + "/users", json=[user, user2], status_code=200) r = s.users.get_all(query_params=None, user_token=token["access_token"]) assert r.error.status == 0 assert [user, user2] == r.value - def test_get_all_user_bad_request(requests_mock): requests_mock.register_uri("GET", url + "/users" , json=user, status_code=422) r = s.users.get_all(query_params=None, user_token=token["access_token"]) assert r.error.status == 1 assert r.error.message == "Database can't process request." - def test_update_user(requests_mock): requests_mock.register_uri("PATCH", url + "/users/" + user["id"], json=user, status_code=200) r = s.users.update(user=user, user_token=token["access_token"]) assert r.error.status == 0 - def test_non_existing_user_update(requests_mock): requests_mock.register_uri("PATCH",url + "/users/" + user["id"], json=user, status_code=404) r = s.users.update(user=user, user_token=token["access_token"]) assert r.error.status == 1 assert r.error.message == "Failed due to non existing user." +def test_update_user_identity(requests_mock): + requests_mock.register_uri("PATCH", url + "/users/" + user["id"] + "/identity", json=user, status_code=200) + r = s.users.update_user_identity(user=user, user_token=token["access_token"]) + assert r.error.status == 0 + +def test_non_existing_user_identity_update(requests_mock): + requests_mock.register_uri("PATCH",url + "/users/" + user["id"] + "/identity", json=user, status_code=401) + r = s.users.update_user_identity(user=user, user_token=token["access_token"]) + assert r.error.status == 1 + assert r.error.message == "Missing or invalid access token provided." + +def test_update_user_tags(requests_mock): + requests_mock.register_uri("PATCH", url + "/users/" + user["id"] + "/tags", json=user, status_code=200) + r = s.users.update_user_tags(user=user, user_token=token["access_token"]) + assert r.error.status == 0 + + +def test_non_existing_user_tags_update(requests_mock): + requests_mock.register_uri("PATCH",url + "/users/" + user["id"] + "/tags", json=user, status_code=401) + r = s.users.update_user_tags(user=user, user_token=token["access_token"]) + assert r.error.status == 1 + assert r.error.message == "Missing or invalid access token provided." + +def test_update_user_owner(requests_mock): + requests_mock.register_uri("PATCH", url + "/users/" + user["id"] + "/owner", json=user, status_code=200) + r = s.users.update_user_owner(user=user, user_token=token["access_token"]) + assert r.error.status == 0 + +def test_non_existing_user_owner_update(requests_mock): + requests_mock.register_uri("PATCH",url + "/users/" + user["id"] + "/owner", json=user, status_code=401) + r = s.users.update_user_owner(user=user, user_token=token["access_token"]) + assert r.error.status == 1 + assert r.error.message == "Missing or invalid access token provided." def test_update_user_password(requests_mock): requests_mock.register_uri("PATCH", url + "/users" + "/secret", status_code=200) r = s.users.update_password(old_secret=old_secret, new_secret=new_secret, user_token=token["access_token"]) assert r.error.status == 0 - def test_update_user_password_bad_token(requests_mock): requests_mock.register_uri("PATCH",url + "/users" + "/secret", status_code=415) r = s.users.update_password(old_secret=old_secret, new_secret=new_secret, user_token=token["access_token"]) assert r.error.status == 1 assert r.error.message == "Missing or invalid content type." +def test_reset_password_request(requests_mock): + requests_mock.register_uri("POST", url + "/password/reset-request", json=email, status_code=201) + r = s.users. reset_password_request(email=email, url=url2) + assert r.error.status == 0 + +def test_reset_password_request_bad_email(requests_mock): + requests_mock.register_uri("POST",url + "/password/reset-request", status_code=400) + r = s.users. reset_password_request(email=email, url=url2) + assert r.error.status == 1 + assert r.error.message == "Failed due to malformed JSON." + +def test_reset_password(requests_mock): + requests_mock.register_uri("PUT", url + "/password/reset", status_code=201) + r = s.users. reset_password(password=password, confirm_password=confirm_password, token=token) + assert r.error.status == 0 + +def test_reset_password_bad_token(requests_mock): + requests_mock.register_uri("PUT",url + "/password/reset", status_code=400) + r = s.users. reset_password(password=password, confirm_password=confirm_password, token=token) + assert r.error.status == 1 + assert r.error.message == "Failed due to malformed JSON." + def test_enable_user(requests_mock): requests_mock.register_uri("POST", url + "/users/" + user["id"] + "/enable", json=user, status_code=204) r = s.users.enable(user_id=user["id"], user_token= token["access_token"]) From d96d0f5fd972b631beb7102e49e662d55493ed8a Mon Sep 17 00:00:00 2001 From: Musilah Date: Fri, 25 Aug 2023 11:47:01 +0300 Subject: [PATCH 12/31] Fix users and comment resolution Signed-off-by: Musilah --- examples/examples.py | 58 ++++++++++++++++++----------------------- mainflux/errors.py | 4 +-- mainflux/things.py | 13 ++++----- mainflux/users.py | 19 +++++++------- tests/test_bootstrap.py | 3 ++- tests/test_groups.py | 3 +-- tests/test_things.py | 42 ++++++++++++++++++++++------- tests/test_users.py | 24 ++++++++++++++--- 8 files changed, 98 insertions(+), 68 deletions(-) diff --git a/examples/examples.py b/examples/examples.py index c2becbf..5a6feaa 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -21,11 +21,11 @@ if mf_resp.error.status == 0: print(mf_resp.value) else: - print(mf_resp.error.message) - + print(mf_resp.error.message) + """To log in to the Mainflux system, you need to create a user token""" mf_resp = mfsdk.users.login( - user={ "identity" : "", "secret": ""} + user={ "identity" : "admin@example.com", "secret": "12345678"} ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -33,17 +33,9 @@ print(mf_resp.error.message) """Refreshes Access and Refresh Token used for authenticating into the system.""" -user= { - "credentials": { - "identity": "", - "secret": "" - }, - "id": "", - "name": "" -} + mf_resp = mfsdk.users.refresh_token( - user= user, - token="" + refresh_token="" ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -75,7 +67,7 @@ """Updates user identity in the database""" user = { "credentials": { - "identity": "", + "identity": "", }, "id": "" } @@ -165,10 +157,10 @@ """Authorising a User""" access_request = { - "subject": "", - "object": "", - "Action": "", - "Entity_type": "" + "subject": "", + "object": "", + "action": "", + "entity_type": "" } mf_resp = mfsdk.users.authorise_user(access_request=access_request, token="") if mf_resp.error.status == 0: @@ -178,10 +170,10 @@ """Authorising a Thing""" access_request = { - "subject": "", - "object": "", - "Action": "", - "Entity_type": "" + "subject": "", + "object": "", + "action": "", + "entity_type": "" } mf_resp = mfsdk.things.authorise_thing(access_request=access_request, token="") if mf_resp.error.status == 0: @@ -292,7 +284,7 @@ """Connect thing to channel""" mf_resp = mfsdk.things.connect( - channel_id="", thing_id="", action="", token="" + channel_id="4921c9f2-6b7b-4291-98bf-fefd4a43591d", thing_id="d58ca9f5-e5f1-4a1b-9063-0c31ff9ba298", action="m_read", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTI5MzI0MjMsImlhdCI6MTY5Mjg3ODQyMywiaWRlbnRpdHkiOiJkZXRlcm1pbmVkX3JvZW50Z2VuQGVtYWlsLmNvbSIsImlzcyI6ImNsaWVudHMuYXV0aCIsInN1YiI6IjVhN2M1NGExLTgzMzUtNDBiNy1hOTE3LTc2MmZmYmFmOGFkOSIsInR5cGUiOiJhY2Nlc3MifQ.s74K5y6k9Hjzhi3MNU0cX1U9lKpJiRUwrIBLWgw_fcXUeMUN9HAIidu0sWj-iGxI6c-KUUy993I9yNIBOrUqaw" ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -312,7 +304,7 @@ mf_resp = mfsdk.things.connects( thing_ids=["", ""], channel_ids=[""], - action="", + actions="", token="", ) @@ -334,16 +326,16 @@ """Share thing""" mf_resp = mfsdk.things.share_thing( - channel_id= "", - user_id= "", - actions= ["action"], - token= "" + channel_id= "", + user_id= "", + actions= [""], + token= "" ) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) - + """To create a channel, you need a channel and a token""" mf_resp = mfsdk.channels.create( channel={"name": ""}, token="") @@ -401,7 +393,7 @@ print(mf_resp.error.message) """Identifies thing when given thing key""" -mf_resp = mfsdk.channels.identify_thing(thing_key="", user_token="") +mf_resp = mfsdk.channels.identify_thing(thing_key="") if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -417,7 +409,7 @@ """To create a group, you need the group name and a user token""" mf_resp = mfsdk.groups.create( - group={"name": "", "parent_id": ""}, token="") + group={"name": "group_auth", "parent_id": ""}, token="") if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -579,6 +571,7 @@ print(mf_resp.value) else: print(mf_resp.error.message) + """Updating state represents enabling/disabling Config, i.e.connecting and disconnecting corresponding Mainflux Thing to the list of Channels.""" config = { "external_id": "", @@ -620,10 +613,9 @@ print(mf_resp.error.message) """Removes a Config. In case of successful removal the service will ensure that the removed config is disconnected from all the Mainflux channels.""" - mf_resp = mfsdk.bootstrap.remove(config_id= "", token="") if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) - \ No newline at end of file + \ No newline at end of file diff --git a/mainflux/errors.py b/mainflux/errors.py index d9ad239..d9f8171 100644 --- a/mainflux/errors.py +++ b/mainflux/errors.py @@ -105,8 +105,8 @@ def handle_error(error_dict, status_code): 400: "A non-existent entity request." }, "authorise_thing":{ - 400: "False" - } + 403: "False", + }, } channels = { diff --git a/mainflux/things.py b/mainflux/things.py index a6fb053..d54609a 100644 --- a/mainflux/things.py +++ b/mainflux/things.py @@ -1,5 +1,4 @@ import requests -import json from mainflux import response from mainflux import errors from mainflux import utils @@ -248,16 +247,14 @@ def disconnect(self, thing_id: str, channel_id: str, token: str): ) return mf_resp - def share_thing(self, user_id: str, channel_id: str, actions: dict, token: str): + def share_thing(self, user_id: str, channel_id: str, actions: list, token: str): """Share thing""" - payload = {"object": channel_id, "subject": user_id, "Actions": actions, "External": True} + payload = {"object": channel_id, "subject": user_id, "actions": actions, "external": True} http_resp = requests.post( self.URL + "/policies", headers=utils.construct_header(token, utils.CTJSON), - data=json.dumps(payload) + data=payload ) - print(http_resp.request.url) - print(http_resp) mf_resp = response.Response() if http_resp.status_code != 201: mf_resp.error.status = 1 @@ -265,14 +262,14 @@ def share_thing(self, user_id: str, channel_id: str, actions: dict, token: str): errors.things["share_thing"], http_resp.status_code ) else: - mf_resp.value = http_resp.json() + mf_resp.value = "OK" return mf_resp def authorise_thing(self,access_request: dict, token: str): """Authorises thing""" mf_resp = response.Response() http_resp= requests.post( - self.URL +"/authorize", + self.URL +"/channels/object/access", headers=utils.construct_header(token, utils.CTJSON), json= access_request ) diff --git a/mainflux/users.py b/mainflux/users.py index f65f1e7..ff118b9 100644 --- a/mainflux/users.py +++ b/mainflux/users.py @@ -1,5 +1,4 @@ import requests -import json from mainflux import response from mainflux import errors @@ -43,14 +42,13 @@ def login(self, user: dict): mf_resp.value = http_resp.json() return mf_resp - def refresh_token(self, user: dict, token: str): + def refresh_token(self, refresh_token: str): """Refreshes Access and Refresh Token used for authenticating into the system.""" mf_resp = response.Response() http_resp = requests.post( self.URL + "/users/tokens/refresh", - headers=utils.construct_header(token, utils.CTJSON), - json=user - ) + headers=utils.construct_header(refresh_token, utils.CTJSON), + ) if http_resp.status_code != 201: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( @@ -98,7 +96,7 @@ def update(self, user: dict, user_token: str): http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"], headers=utils.construct_header(user_token, utils.CTJSON), - data=json.dumps(user), + data=user, ) mf_resp = response.Response() if http_resp.status_code != 200: @@ -115,7 +113,7 @@ def update_user_identity(self, user: dict, user_token: str): http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"] + "/identity", headers=utils.construct_header(user_token, utils.CTJSON), - data=json.dumps(user), + data=user, ) mf_resp = response.Response() if http_resp.status_code != 200: @@ -132,7 +130,7 @@ def update_user_tags(self, user: dict, user_token: str): http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"] + "/tags", headers=utils.construct_header(user_token, utils.CTJSON), - data=json.dumps(user), + data=user, ) mf_resp = response.Response() if http_resp.status_code != 200: @@ -149,7 +147,7 @@ def update_user_owner(self, user: dict, user_token: str): http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"] + "/owner", headers=utils.construct_header(user_token, utils.CTJSON), - data=json.dumps(user), + data=user, ) mf_resp = response.Response() if http_resp.status_code != 200: @@ -260,4 +258,5 @@ def authorise_user(self,access_request: dict, token: str): ) else: mf_resp.value = "True" - return mf_resp \ No newline at end of file + return mf_resp + \ No newline at end of file diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index 4cafb85..8c59a2d 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -96,4 +96,5 @@ def test_remove_bad_config(requests_mock): requests_mock.register_uri( "DELETE", url+ "/things/configs/" + config_id, status_code=400) r = s.bootstrap.remove(config_id=config_id, token=token) assert r.error.status == 1 - assert r.error.message == "Failed due to malformed config ID." \ No newline at end of file + assert r.error.message == "Failed due to malformed config ID." + \ No newline at end of file diff --git a/tests/test_groups.py b/tests/test_groups.py index 2c550b5..89bfa23 100644 --- a/tests/test_groups.py +++ b/tests/test_groups.py @@ -136,7 +136,6 @@ def test_delete_group_does_not_exist(requests_mock): assert r.error.message == "Group does not exist." def test_share_groups(requests_mock): - requests_mock.register_uri("POST", url + "/groups/" + group_id + "/share", status_code=200, - headers={"Authorization": token}, json={"thing_group_id": thing_group_id}) + requests_mock.register_uri("POST", url + "/groups/" + group_id + "/share", status_code=200, headers={"Authorization": token}, json={"thing_group_id": thing_group_id}) r = s.groups.share_groups(token=token, user_group_id=group_id, thing_group_id=thing_group_id) assert r.error.status == 0 diff --git a/tests/test_things.py b/tests/test_things.py index ccc8a74..b1fcd83 100644 --- a/tests/test_things.py +++ b/tests/test_things.py @@ -19,9 +19,7 @@ "metadata": { "domain": "example.com" }, - "status": "enabled", - "created_at": "2019-11-26 13:31:52", - "updated_at": "2019-11-26 13:31:52" + "status": "enabled" } things = [{ "id": "4e5532c0-cf92-4ef3-ab7b-65ee30151c99", @@ -38,9 +36,7 @@ "metadata": { "domain": "example.com" }, - "status": "enabled", - "created_at": "2019-11-26 13:31:52", - "updated_at": "2019-11-26 13:31:52" + "status": "enabled" }, { "id": "53ed347d-f277-4e2b-9ee1-442389ad1a9a", "name": "thing2", @@ -56,17 +52,23 @@ "metadata": { "domain": "example.com" }, - "status": "enabled", - "created_at": "2019-11-26 13:31:52", - "updated_at": "2019-11-26 13:31:52" + "status": "enabled" }] thing_id = "123-456-789" thing_id1 = "123-223-333" channel_id = "654-654-654" channel_id1 = "654-654-654" +user_id= "123-679-773" +action= "m_read" token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" url = "http://localhost" params = None +access_request= { + "subject": "123-456-789", + "object": "654-654-654", + "action": "m_read", + "entity_type": "group" +} policies= { "policies": [ { @@ -249,3 +251,25 @@ def test_disconnects_bad_json(requests_mock): r = s.things.disconnects(channel_ids=[channel_id], thing_ids=[thing_id, thing_id1], token=token) assert r.error.status == 1 assert r.error.message == "Channel or thing does not exist." + +def test_share_thing(requests_mock): + requests_mock.register_uri("POST", url + "/policies", status_code=201) + r = s.things.share_thing(channel_id=channel_id, user_id=user_id, actions= action, token=token) + assert r.error.status == 0 + +def test_share_thing_bad_token(requests_mock): + requests_mock.register_uri("POST", url + "/policies", status_code=400) + r = s.things.share_thing(channel_id=channel_id, user_id=user_id, actions= action, token=token) + assert r.error.status == 1 + assert r.error.message == "A non-existent entity request." + +def test_authorise_thing(requests_mock): + requests_mock.register_uri("POST", url + "/channels/object/access", status_code=200) + r = s.things.authorise_thing(access_request=access_request , token=token) + assert r.error.status == 0 + +def test_authorise_thing_bad_token(requests_mock): + requests_mock.register_uri("POST", url + "/channels/object/access", status_code=403) + r = s.things.authorise_thing(access_request=access_request , token=token) + assert r.error.status == 1 + assert r.error.message == "False" diff --git a/tests/test_users.py b/tests/test_users.py index 1d94d10..5ef80b0 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -66,6 +66,12 @@ "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", "access_type": "access" } +access_request ={ + "subject": "e2c769b8-8b8c-4886-8b19-e155c4d363e6", + "object": "f20e0b0e-b05e-401e-ac53-59b99eea3519", + "action": "g_add", + "entity_type": "client" +} password= "12345678" confirm_password="12345678" email={"admin@example.com": "email"} @@ -98,13 +104,13 @@ def test_login_user_bad_email(requests_mock): def test_refresh_token(requests_mock): requests_mock.register_uri("POST", url + "/users/tokens/refresh", json=token, status_code=201) - r = s.users.refresh_token(user=user, token=token["refresh_token"]) + r = s.users.refresh_token(refresh_token=token["refresh_token"]) assert r.error.status == 0 assert token == r.value def test_refresh_token_bad_token(requests_mock): requests_mock.register_uri("POST", url + "/users/tokens/refresh",json=token, status_code=404) - r = s.users.refresh_token(user=user, token=token["refresh_token"]) + r = s.users.refresh_token(refresh_token=token["refresh_token"]) assert r.error.status == 1 assert r.error.message == "A non-existent entity request." @@ -232,4 +238,16 @@ def test_disable_user_bad_user(requests_mock): requests_mock.register_uri("POST", url + "/users/" + user["id"] + "/disable", json=user, status_code=404) r = s.users.disable(user_id=user["id"], user_token= token["access_token"]) assert r.error.status == 1 - assert r.error.message == "Failed due to non existing user." \ No newline at end of file + assert r.error.message == "Failed due to non existing user." + +def test_authorise_user(requests_mock): + requests_mock.register_uri("POST", url + "/authorize", status_code=200) + r = s.users.authorise_user(access_request=access_request , token=token["access_token"]) + assert r.error.status == 0 + +def test_authorise_user_bad_token(requests_mock): + requests_mock.register_uri("POST", url + "/authorize", status_code=400) + r = s.users.authorise_user(access_request=access_request , token=token["access_token"]) + assert r.error.status == 1 + assert r.error.message == "Failed due to malformed JSON." + \ No newline at end of file From 666458b5157fdedb6c577ef3148ca665532d9a6d Mon Sep 17 00:00:00 2001 From: Musilah Date: Fri, 25 Aug 2023 11:51:32 +0300 Subject: [PATCH 13/31] Update docs Signed-off-by: Musilah --- docs/things.md | 38 +++++++++++++++++++------------------- docs/users.md | 36 ++++++++++++++++++------------------ 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/docs/things.md b/docs/things.md index 32d329d..37945ef 100644 --- a/docs/things.md +++ b/docs/things.md @@ -11,14 +11,14 @@ --- - + ## class `Things` - + ### method `__init__` @@ -35,7 +35,7 @@ __init__(url: str) --- - + ### method `authorise_thing` @@ -47,7 +47,7 @@ Authorises thing --- - + ### method `connect` @@ -59,7 +59,7 @@ Connects thing and channel --- - + ### method `connects` @@ -71,7 +71,7 @@ Connects thing and channel --- - + ### method `create` @@ -83,7 +83,7 @@ Creates thing entity in the database --- - + ### method `create_bulk` @@ -95,7 +95,7 @@ Creates multiple things in a bulk --- - + ### method `disable` @@ -107,7 +107,7 @@ Deletes a thing entity from database --- - + ### method `disconnect` @@ -119,7 +119,7 @@ Disconnect thing and channel --- - + ### method `disconnects` @@ -131,7 +131,7 @@ Disconnect thing and channel --- - + ### method `get` @@ -143,7 +143,7 @@ Gets a thing entity for a logged-in user --- - + ### method `get_all` @@ -155,7 +155,7 @@ Gets all things from database --- - + ### method `get_by_channel` @@ -167,19 +167,19 @@ Gets all things to which a specific thing is connected to --- - + ### method `share_thing` ```python -share_thing(user_id: str, channel_id: str, actions: dict, token: str) +share_thing(user_id: str, channel_id: str, actions: list, token: str) ``` Share thing --- - + ### method `update` @@ -191,7 +191,7 @@ Updates thing entity --- - + ### method `update_thing_owner` @@ -203,7 +203,7 @@ Updates thing secret --- - + ### method `update_thing_secret` @@ -215,7 +215,7 @@ Updates thing secret --- - + ### method `update_thing_tags` diff --git a/docs/users.md b/docs/users.md index 867b3dc..1487618 100644 --- a/docs/users.md +++ b/docs/users.md @@ -11,14 +11,14 @@ --- - + ## class `Users` - + ### method `__init__` @@ -35,7 +35,7 @@ __init__(url: str) --- - + ### method `authorise_user` @@ -47,7 +47,7 @@ Authorises user --- - + ### method `create` @@ -59,7 +59,7 @@ Registers new user account given email and password. New account will be uniquel --- - + ### method `disable` @@ -71,7 +71,7 @@ Disables an enabled user account for a given user ID. --- - + ### method `enable` @@ -83,7 +83,7 @@ Enables a disabled user account for a given user ID. --- - + ### method `get` @@ -95,7 +95,7 @@ Gets a user information --- - + ### method `get_all` @@ -107,7 +107,7 @@ Retrieves a list of users --- - + ### method `login` @@ -119,19 +119,19 @@ Generates an access token when provided with proper credentials. --- - + ### method `refresh_token` ```python -refresh_token(user: dict, token: str) +refresh_token(refresh_token: str) ``` Refreshes Access and Refresh Token used for authenticating into the system. --- - + ### method `reset_password` @@ -143,7 +143,7 @@ Changes user password with the reset_request token --- - + ### method `reset_password_request` @@ -155,7 +155,7 @@ User Password reset request --- - + ### method `update` @@ -167,7 +167,7 @@ Updates info on currently logged in user. Info is updated using authorization us --- - + ### method `update_password` @@ -179,7 +179,7 @@ Changes user password --- - + ### method `update_user_identity` @@ -191,7 +191,7 @@ Updates Identity of the user --- - + ### method `update_user_owner` @@ -203,7 +203,7 @@ Updating user tags in the database --- - + ### method `update_user_tags` From 8e2709620e96a95e2056dbd7fea1970be6826fb0 Mon Sep 17 00:00:00 2001 From: Musilah Date: Sat, 26 Aug 2023 08:23:47 +0300 Subject: [PATCH 14/31] Add tests for Groups and Comment Resolution Signed-off-by: Musilah --- docs/certs.md | 2 +- docs/groups.md | 12 --------- examples/examples.py | 1 - mainflux/boostrap.py | 8 +++--- mainflux/certs.py | 3 --- mainflux/channels.py | 2 +- mainflux/errors.py | 22 ++++++++++++---- mainflux/groups.py | 20 ++------------ tests/test_channels.py | 31 +++++++++------------- tests/test_groups.py | 59 ++++++++++++++++++++++++++++-------------- 10 files changed, 76 insertions(+), 84 deletions(-) diff --git a/docs/certs.md b/docs/certs.md index 2f05caa..2e0acd2 100644 --- a/docs/certs.md +++ b/docs/certs.md @@ -49,7 +49,7 @@ issue(thing_id: str, valid: str, token: str) --- - + ### method `revoke` diff --git a/docs/groups.md b/docs/groups.md index 571a54c..04f5c9c 100644 --- a/docs/groups.md +++ b/docs/groups.md @@ -143,18 +143,6 @@ Gets parents for a specific group from database --- - - -### method `share_groups` - -```python -share_groups(token: str, user_group_id: str, thing_group_id: str) -``` - -Adds access rights on thing groups to the user group - ---- - ### method `unassign` diff --git a/examples/examples.py b/examples/examples.py index 5a6feaa..d234ea5 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -618,4 +618,3 @@ print(mf_resp.value) else: print(mf_resp.error.message) - \ No newline at end of file diff --git a/mainflux/boostrap.py b/mainflux/boostrap.py index a8f919f..3ec52fd 100644 --- a/mainflux/boostrap.py +++ b/mainflux/boostrap.py @@ -29,7 +29,7 @@ def add(self, config: dict, token: str): errors.bootstrap["add"], http_resp.status_code ) else: - mf_resp.value = "added" + mf_resp.value = "Configuration added" return mf_resp def whitelist(self, config: dict, token: str): @@ -51,7 +51,7 @@ def whitelist(self, config: dict, token: str): errors.bootstrap["whitelist"], http_resp.status_code ) else: - mf_resp.value = "OK" + mf_resp.value = "Configuration Updated" return mf_resp def view(self, thing_id: str, token: str): @@ -90,7 +90,7 @@ def update(self, config: dict, token: str): errors.bootstrap["update"], http_resp.status_code ) else: - mf_resp.value = "Config updated." + mf_resp.value = "Configuration updated." return mf_resp def update_certs( @@ -129,7 +129,7 @@ def remove(self, config_id: str, token: str): errors.bootstrap["remove"], http_resp.status_code ) else: - mf_resp.value = "Config removed." + mf_resp.value = "Configuration removed." return mf_resp def bootstrap(self, external_id: str, external_key: str): diff --git a/mainflux/certs.py b/mainflux/certs.py index 9063717..32298d7 100644 --- a/mainflux/certs.py +++ b/mainflux/certs.py @@ -55,7 +55,6 @@ def view_by_serial(self, cert_id: str, token: str): self.url + "/" + self.certs_endpoint + "/" + cert_id, headers=utils.construct_header(token, utils.CTJSON), ) - print(http_resp.url) if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( @@ -66,13 +65,11 @@ def view_by_serial(self, cert_id: str, token: str): return mf_resp def revoke(self, thing_id: str, token: str): - mf_resp = response.Response() http_resp = requests.delete( self.url + "/" + self.certs_endpoint + "/" + thing_id, headers=utils.construct_header(token, utils.CTJSON), ) - if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( diff --git a/mainflux/channels.py b/mainflux/channels.py index 0d4109a..8969522 100644 --- a/mainflux/channels.py +++ b/mainflux/channels.py @@ -136,7 +136,7 @@ def identify_thing(self, thing_key: str): if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( - errors.channels["get_by_thing"], http_resp.status_code + errors.channels["identify_thing"], http_resp.status_code ) else: mf_resp.value = http_resp.json() diff --git a/mainflux/errors.py b/mainflux/errors.py index d9f8171..09a435c 100644 --- a/mainflux/errors.py +++ b/mainflux/errors.py @@ -111,13 +111,13 @@ def handle_error(error_dict, status_code): channels = { "create": { - + 409: "Failed due to using an existing identity." }, "create_bulk": { - + 401: "Missing or invalid access token provided." }, "get": { - + 401: "Missing or invalid access token provided." }, "get_all": { 400: "Failed due to malformed channel's ID.", @@ -133,6 +133,9 @@ def handle_error(error_dict, status_code): "delete": { 400: "Failed due to malformed channel's ID." }, + "identify_thing":{ + 401: "Thing and channel are not connected, or thing with specified key doesn't exist." + }, } messages = { @@ -166,9 +169,18 @@ def handle_error(error_dict, status_code): "members": { 409: "Failed due to using an existing email address.", }, - "assign": { - + "memberships":{ + 400: "Failed due to malformed query parameters." + }, + "parents": { + 400: "Failed due to malformed query parameters." + }, + "children": { + 400: "Failed due to malformed query parameters." }, + "assign": { + 400: "Failed due to malformed JSON." + }, "unassign": { 400: "Failed due to malformed query parameters.", 404: "Group does not exist.", diff --git a/mainflux/groups.py b/mainflux/groups.py index b2a5a9a..986d607 100644 --- a/mainflux/groups.py +++ b/mainflux/groups.py @@ -75,7 +75,7 @@ def parents(self, group_id: str, query_params: dict, token: str): if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( - errors.groups["get_all"], http_resp.status_code + errors.groups["parents"], http_resp.status_code ) else: mf_resp.value = http_resp.json() @@ -143,7 +143,7 @@ def memberships(self, member_id: str, query_params: dict, token: str): if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( - errors.groups["members"], http_resp.status_code + errors.groups["memberships"], http_resp.status_code ) else: mf_resp.value = http_resp.json() @@ -194,19 +194,3 @@ def disable(self, group_id: str, user_token: str): errors.groups["disable"], http_resp.status_code ) return mf_resp - - def share_groups(self, token: str, user_group_id: str, thing_group_id: str): - """Adds access rights on thing groups to the user group""" - mf_resp = response.Response() - http_resp = requests.post( - self.url + "/" + self.groups_endpoint + "/" + user_group_id + - "/share", - headers=utils.construct_header(token, utils.CTJSON), - json=thing_group_id, - ) - if http_resp.status_code != 200: - mf_resp.error.status = 1 - mf_resp.error.message = errors.handle_error( - errors.groups["assign"], http_resp.status_code - ) - return mf_resp diff --git a/tests/test_channels.py b/tests/test_channels.py index 40f6e18..cb2f44e 100644 --- a/tests/test_channels.py +++ b/tests/test_channels.py @@ -35,14 +35,11 @@ def test_create_channel(requests_mock): assert r.error.status == 0 assert channel == r.value - def test_create_channel_entity_exist(requests_mock): - requests_mock.register_uri( - "POST", url + "/channels", headers={"location": "/channels/" + channel_id}, status_code=409) + requests_mock.register_uri("POST", url + "/channels", headers={"location": "/channels/" + channel_id}, status_code=409) r = s.channels.create(channel=channel, token=token) assert r.error.status == 1 - assert r.error.message == "Entity already exist." - + assert r.error.message == "Failed due to using an existing identity." def test_create_bulk_channels(requests_mock): requests_mock.register_uri("POST", url + "/channels/bulk", json=[channel_id, channel_id1], headers={"location": "/channels/channel_ids"}, status_code=201) @@ -50,13 +47,11 @@ def test_create_bulk_channels(requests_mock): assert r.error.status == 0 assert [channel_id, channel_id1] == r.value - def test_create_bulk_channels_server_error(requests_mock): - requests_mock.register_uri("POST", url + "/channels/bulk", json=[channel_id, channel_id1], headers={"location": "/channels/channel_ids"}, status_code=500) + requests_mock.register_uri("POST", url + "/channels/bulk", json=[channel_id, channel_id1], headers={"location": "/channels/channel_ids"}, status_code=401) r = s.channels.create_bulk(channel_id, token=token) assert r.error.status == 1 - assert r.error.message == "Unexpected server-side error occurred." - + assert r.error.message == "Missing or invalid access token provided." def test_get_channel(requests_mock): requests_mock.register_uri("GET", url + "/channels/" + channel_id, json=channel, status_code=200) @@ -64,28 +59,24 @@ def test_get_channel(requests_mock): assert r.error.status == 0 assert channel == r.value - def test_get_channel_bad_token(requests_mock): requests_mock.register_uri("GET", url + "/channels/" + channel_id, json=channel, status_code=401) r = s.channels.get(channel_id=channel_id, token=token) assert r.error.status == 1 assert r.error.message == "Missing or invalid access token provided." - def test_get_all_channels(requests_mock): requests_mock.register_uri("GET", url + "/channels", json=[channel_id, channel_id1], status_code=200) r = s.channels.get_all(token=token, query_params=params) assert r.error.status == 0 assert [channel_id, channel_id1] == r.value - def test_get_all_channels_channel_does_not_exist(requests_mock): requests_mock.register_uri("GET", url + "/channels", json=[channel_id, channel_id1], status_code=404) r = s.channels.get_all(token=token, query_params=params) assert r.error.status == 1 assert r.error.message == "Channel does not exist." - def test_get_by_thing(requests_mock): requests_mock.register_uri("GET", url + "/things/" + thing_id + "/channels", json=channel_id, headers={"Authorization": "/channels/" + channel_id + "/things"}, status_code=200) r = s.channels.get_by_thing( @@ -93,7 +84,6 @@ def test_get_by_thing(requests_mock): assert r.error.status == 0 assert channel_id == r.value - def test_get_by_thing_does_not_exist(requests_mock): requests_mock.register_uri("GET", url + "/things/" + thing_id + "/channels", json=channel_id, headers={"Authorization": "/channels/" + channel_id + "/things"}, status_code=404) r = s.channels.get_by_thing( @@ -101,36 +91,39 @@ def test_get_by_thing_does_not_exist(requests_mock): assert r.error.status == 1 assert r.error.message == "Thing does not exist." - def test_update_channel(requests_mock): requests_mock.register_uri("PUT", url + "/channels/" + channel_id, json=json.dumps(channel), status_code=200) r = s.channels.update(channel_id=channel_id, token=token, channel=channel) assert r.error.status == 0 - def test_update_channel_does_not_exist(requests_mock): requests_mock.register_uri("PUT", url + "/channels/" + channel_id, json=json.dumps(channel), status_code=404) r = s.channels.update(channel_id=channel_id, token=token, channel=channel) assert r.error.status == 1 assert r.error.message == "Channel does not exist." - def test_delete_channel(requests_mock): requests_mock.register_uri("POST", url + "/channels/" + channel_id + "/disable", status_code=200) r = s.channels.disable(channel_id=channel_id, token=token) assert r.error.status == 0 - def test_delete_channel_malformed_channel_id(requests_mock): requests_mock.register_uri("POST", url + "/channels/" + channel_id + "/disable", status_code=400) r = s.channels.disable(channel_id=channel_id, token=token) assert r.error.status == 1 assert r.error.message == "Failed due to malformed channel's ID." - def test_identify_thing(requests_mock): requests_mock.register_uri( "POST", url + "/identify", json=thing_key, status_code=200) r = s.channels.identify_thing(thing_key) assert r.error.status == 0 assert thing_key == r.value + +def test_identify_thing_bad_key(requests_mock): + requests_mock.register_uri( + "POST", url + "/identify", json=thing_key, status_code=401) + r = s.channels.identify_thing(thing_key) + assert r.error.status == 1 + assert r.error.message == "Thing and channel are not connected, or thing with specified key doesn't exist." + \ No newline at end of file diff --git a/tests/test_groups.py b/tests/test_groups.py index 89bfa23..c45d41e 100644 --- a/tests/test_groups.py +++ b/tests/test_groups.py @@ -7,6 +7,7 @@ channel_id = "654-559-774" members = {"members": channel_id, "type": "channels"} members_ids ="4e5532c0-cf92-4ef3-ab7b-65ee30151c99" +member_id= "4e5532c0-cf92-4ef3-ab7b-65ee30151c99" group ={ "id": "bb7edb32-2eac-4aad-aebe-ed96fe073879", "name": "groupName", @@ -22,40 +23,63 @@ "updated_at": "2019-11-26 13:31:52", "status": "enabled" } +query_params= { + "offset": 0, + "limit": 5 +} group_id = "888-888-888" group_id1 = "989-787-686" thing_group_id = "868-464-262" token = "9a8b7c6d5e4f3g21" url = "http://localhost" - def test_create_group(requests_mock): requests_mock.register_uri("POST", url + "/groups", headers={"location": "/groups/" + group_id}, json=group, status_code=201) r = s.groups.create(group=group, token=token) assert r.error.status == 0 assert group == r.value - def test_create_group_existing_email_address(requests_mock): requests_mock.register_uri("POST", url + "/groups", headers={"location": "/groups/" + group_id}, status_code=409) r = s.groups.create(group=group, token=token) assert r.error.status == 1 assert r.error.message == "Failed due to using an existing email address." - def test_get_group(requests_mock): requests_mock.register_uri("GET", url + "/groups/" + group_id, json=group, status_code=200) r = s.groups.get(group_id=group_id, token=token) assert r.error.status == 0 assert group == r.value - def test_get_group_does_not_exist(requests_mock): requests_mock.register_uri("GET", url + "/groups/" + group_id, json=group, status_code=404) r = s.groups.get(group_id=group_id, token=token) assert r.error.status == 1 assert r.error.message == "Group does not exist." + +def test_get_parents(requests_mock): + requests_mock.register_uri("GET", url + "/groups/" + group_id + "/parents", json=group, status_code=200) + r = s.groups.parents(group_id=group_id, query_params= query_params, token=token) + assert r.error.status == 0 + assert group == r.value +def test_get_parents_bad_json(requests_mock): + requests_mock.register_uri("GET", url + "/groups/" + group_id + "/parents", status_code=400) + r = s.groups.parents(group_id=group_id, query_params= query_params, token=token) + assert r.error.status == 1 + assert r.error.message == "Failed due to malformed query parameters." + +def test_get_children(requests_mock): + requests_mock.register_uri("GET", url + "/groups/" + group_id + "/children", json=group, status_code=200) + r = s.groups.children(group_id=group_id, query_params= query_params, token=token) + assert r.error.status == 0 + assert group == r.value + +def test_get_children_bad_json(requests_mock): + requests_mock.register_uri("GET", url + "/groups/" + group_id + "/children", status_code=400) + r = s.groups.children(group_id=group_id, query_params= query_params, token=token) + assert r.error.status == 1 + assert r.error.message == "Failed due to malformed query parameters." def test_get_all_groups(requests_mock): requests_mock.register_uri("GET", url + "/groups", json=group_id, status_code=200) @@ -63,79 +87,74 @@ def test_get_all_groups(requests_mock): assert r.error.status == 0 assert group_id == r.value - def test_get_all_groups_malformed_query(requests_mock): requests_mock.register_uri("GET", url + "/groups", json=group_id, status_code=400) r = s.groups.get_all(query_params=None, token=token) assert r.error.status == 1 assert r.error.message == "Failed due to malformed query parameters." - def test_update_group(requests_mock): requests_mock.register_uri("PUT", url + "/groups/" + group_id, json=group, status_code=200) r = s.groups.update(group_id=group_id, group=group, token=token) assert r.error.status == 0 - -def test_update_group_sverver_error(requests_mock): +def test_update_group_server_error(requests_mock): requests_mock.register_uri("PUT", url + "/groups/" + group_id, json=group, status_code=500) r = s.groups.update(group_id=group_id, group=group, token=token) assert r.error.status == 1 assert r.error.message == "Unexpected server-side error occurred." - def test_members(requests_mock): requests_mock.register_uri("GET", url + "/groups/" + group_id + "/members",json=group_id, status_code=200) r = s.groups.members(group_id=group_id, query_params=None, token=token) assert r.error.status == 0 - def test_members_bad_content_type(requests_mock): requests_mock.register_uri("GET", url + "/groups/" + group_id + "/members", status_code=415) r = s.groups.members(group_id=group_id, query_params=None, token=token) assert r.error.status == 1 assert r.error.message == "Missing or invalid content type." +def test_membership(requests_mock): + requests_mock.register_uri("GET", url + "/users/" + member_id + "/memberships", json=members_ids, status_code=200) + r = s.groups.memberships(member_id=member_id, query_params=query_params, token=token) + assert r.error.status == 0 + +def test_membership_bad_content_type(requests_mock): + requests_mock.register_uri("GET", url + "/users/" + member_id + "/memberships", status_code=400) + r = s.groups.memberships(member_id=member_id, query_params=query_params, token=token) + assert r.error.status == 1 + assert r.error.message == "Failed due to malformed query parameters." def test_assign(requests_mock): requests_mock.register_uri("POST", url + "/users/policies" , status_code=200) r = s.groups.assign(group_id=group_id, token=token, members_ids=members, member_type= ["m_read"]) assert r.error.status == 0 - def test_assign_malformed_json(requests_mock): requests_mock.register_uri("POST", url + "/users/policies", status_code=400) r = s.groups.assign(group_id=group_id, token=token, members_ids=members, member_type= ["m_read"]) assert r.error.status == 1 assert r.error.message == "Failed due to malformed JSON." - def test_unassign(requests_mock): requests_mock.register_uri("DELETE", url + "/users/policies" + "/" + members_ids + "/" + group_id, json=group, status_code=204) r = s.groups.unassign(group_id=group_id, members_ids=members_ids, token=token) assert r.error.status == 0 - def test_unassign_bad_token(requests_mock): requests_mock.register_uri("DELETE", url + "/users/policies" + "/" + members_ids + "/" + group_id, status_code=403) r = s.groups.unassign(group_id=group_id, token=token, members_ids=members_ids) assert r.error.status == 1 assert r.error.message == "Missing or invalid access token provided." - def test_delete_group(requests_mock): requests_mock.register_uri("POST", url + "/groups/" + group_id + "/disable", status_code=200) r = s.groups.disable(group_id=group_id, user_token=token) assert r.error.status == 0 - def test_delete_group_does_not_exist(requests_mock): requests_mock.register_uri("POST", url + "/groups/" + group_id + "/disable", status_code=404) r = s.groups.disable(group_id=group_id, user_token=token) assert r.error.status == 1 assert r.error.message == "Group does not exist." - -def test_share_groups(requests_mock): - requests_mock.register_uri("POST", url + "/groups/" + group_id + "/share", status_code=200, headers={"Authorization": token}, json={"thing_group_id": thing_group_id}) - r = s.groups.share_groups(token=token, user_group_id=group_id, thing_group_id=thing_group_id) - assert r.error.status == 0 From 5f388364005ffca95a130342fc9744c040ced0ab Mon Sep 17 00:00:00 2001 From: Musilah Date: Sat, 26 Aug 2023 19:13:06 +0300 Subject: [PATCH 15/31] Fixing failing Tests in Test_groups.py Signed-off-by: Musilah --- tests/test_bootstrap.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index 8c59a2d..2de2649 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -24,7 +24,7 @@ def test_add(requests_mock): requests_mock.register_uri( "POST", url+ "/things/configs", headers={"location": "/configs/" + thing_id}, json=config, status_code=201) r = s.bootstrap.add(config=config, token=token) assert r.error.status == 0 - assert r.value == "added" + assert r.value == "Configuration added" def test_add_bad_token(requests_mock): requests_mock.register_uri( "POST", url+ "/things/configs", headers={"location": "/configs/" + thing_id}, json=config, status_code=401) @@ -36,7 +36,7 @@ def test_whitelist(requests_mock): requests_mock.register_uri( "PUT", url+ "/things/state/" + config["thing_id"], json=config, status_code=201) r = s.bootstrap.whitelist(config=config, token=token) assert r.error.status == 0 - assert r.value == "OK" + assert r.value == "Configuration Updated" def test_whitelist_bad_config(requests_mock): requests_mock.register_uri( "PUT", url+ "/things/state/" + config["thing_id"], json=config, status_code=400) @@ -66,7 +66,7 @@ def test_update(requests_mock): requests_mock.register_uri( "PUT", url+ "/things/configs/" + config["thing_id"], json=config, status_code=200) r = s.bootstrap.update(config=config, token=token) assert r.error.status == 0 - assert r.value == "Config updated." + assert r.value == "Configuration updated." def test_update_bad_config(requests_mock): requests_mock.register_uri( "PUT", url+ "/things/configs/" + config["thing_id"], json=config, status_code=404) @@ -90,7 +90,7 @@ def test_remove(requests_mock): requests_mock.register_uri( "DELETE", url+ "/things/configs/" + config_id, status_code=204) r = s.bootstrap.remove(config_id=config_id, token=token) assert r.error.status == 0 - assert r.value== "Config removed." + assert r.value== "Configuration removed." def test_remove_bad_config(requests_mock): requests_mock.register_uri( "DELETE", url+ "/things/configs/" + config_id, status_code=400) From 5aebbd679e2321e3aa8278f75e47e63e77793182 Mon Sep 17 00:00:00 2001 From: Musilah Date: Mon, 4 Sep 2023 15:38:45 +0300 Subject: [PATCH 16/31] Comment resolution Signed-off-by: Musilah --- docs/groups.md | 28 ++++++++++++++-------------- examples/examples.py | 10 +++++----- mainflux/groups.py | 18 ++++++++---------- mainflux/things.py | 1 - mainflux/users.py | 1 - tests/test_bootstrap.py | 1 - tests/test_channels.py | 5 ++--- tests/test_groups.py | 4 ++-- tests/test_users.py | 3 +-- 9 files changed, 32 insertions(+), 39 deletions(-) diff --git a/docs/groups.md b/docs/groups.md index 04f5c9c..1839775 100644 --- a/docs/groups.md +++ b/docs/groups.md @@ -11,14 +11,14 @@ --- - + ## class `Groups` - + ### method `__init__` @@ -35,19 +35,19 @@ __init__(url: str) --- - + ### method `assign` ```python -assign(group_id: str, members_ids: str, member_type: dict, token: str) +assign(group_id: str, member_id: str, member_type: list, token: str) ``` Assign --- - + ### method `children` @@ -59,7 +59,7 @@ Gets children for a specific group from database --- - + ### method `create` @@ -71,7 +71,7 @@ Creates group entity in the database --- - + ### method `disable` @@ -83,7 +83,7 @@ Disables a group entity from database --- - + ### method `get` @@ -95,7 +95,7 @@ Gets a group entity --- - + ### method `get_all` @@ -107,7 +107,7 @@ Gets all groups from database --- - + ### method `members` @@ -119,7 +119,7 @@ Get list of members ID's from group --- - + ### method `memberships` @@ -131,7 +131,7 @@ Get list of members ID's from group --- - + ### method `parents` @@ -143,7 +143,7 @@ Gets parents for a specific group from database --- - + ### method `unassign` @@ -155,7 +155,7 @@ Unassign --- - + ### method `update` diff --git a/examples/examples.py b/examples/examples.py index d234ea5..5c2942c 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -409,7 +409,7 @@ """To create a group, you need the group name and a user token""" mf_resp = mfsdk.groups.create( - group={"name": "group_auth", "parent_id": ""}, token="") + group={"name": "group_name"}, token="") if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -444,12 +444,12 @@ else: print(mf_resp.error.message) -"""Assign user, thing or channel to a group""" +"""Assign user to a group""" mf_resp = mfsdk.groups.assign( - group_id="", + group_id="", token="", - members_ids="", - member_type=[""], + member_id="", + member_type=[""], ) if mf_resp.error.status == 0: print(mf_resp.value) diff --git a/mainflux/groups.py b/mainflux/groups.py index 986d607..2a333ae 100644 --- a/mainflux/groups.py +++ b/mainflux/groups.py @@ -1,5 +1,4 @@ import requests -import json from mainflux import response from mainflux import errors @@ -67,8 +66,7 @@ def parents(self, group_id: str, query_params: dict, token: str): mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.groups_endpoint + "/" + group_id + - "/parents", + self.url + "/" + self.groups_endpoint + "/" + group_id + "/parents", headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -102,7 +100,7 @@ def update(self, group_id: str, group: dict, token: str): """Updates group entity""" http_resp = requests.put( self.url + "/" + self.groups_endpoint + "/" + group_id, - data= json.dumps(group), + data=group, headers=utils.construct_header(token, utils.CTJSON), ) mf_resp = response.Response() @@ -112,7 +110,7 @@ def update(self, group_id: str, group: dict, token: str): errors.groups["update"], http_resp.status_code ) else: - mf_resp.value = http_resp.json() + mf_resp.value = http_resp.json() return mf_resp def members(self, group_id: str, query_params: dict, token: str): @@ -129,7 +127,7 @@ def members(self, group_id: str, query_params: dict, token: str): errors.groups["members"], http_resp.status_code ) else: - mf_resp.value = http_resp.json() + mf_resp.value = http_resp.json() return mf_resp def memberships(self, member_id: str, query_params: dict, token: str): @@ -146,17 +144,17 @@ def memberships(self, member_id: str, query_params: dict, token: str): errors.groups["memberships"], http_resp.status_code ) else: - mf_resp.value = http_resp.json() + mf_resp.value = http_resp.json() return mf_resp - def assign(self, group_id: str, members_ids: str, member_type: dict, token: str): + def assign(self, group_id: str, member_id: str, member_type: list, token: str): """Assign""" - payload = {"Object": group_id, "Subject": members_ids, "Actions": member_type} + payload = {"object": group_id, "subject": member_id, "actions": member_type} mf_resp = response.Response() http_resp = requests.post( self.url + "/users/policies", headers=utils.construct_header(token, utils.CTJSON), - json= payload, + json=payload, ) if http_resp.status_code != 200: mf_resp.error.status = 1 diff --git a/mainflux/things.py b/mainflux/things.py index d54609a..17b339b 100644 --- a/mainflux/things.py +++ b/mainflux/things.py @@ -281,4 +281,3 @@ def authorise_thing(self,access_request: dict, token: str): else: mf_resp.value = "True" return mf_resp - \ No newline at end of file diff --git a/mainflux/users.py b/mainflux/users.py index ff118b9..e49b3ba 100644 --- a/mainflux/users.py +++ b/mainflux/users.py @@ -259,4 +259,3 @@ def authorise_user(self,access_request: dict, token: str): else: mf_resp.value = "True" return mf_resp - \ No newline at end of file diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index 2de2649..39428e6 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -97,4 +97,3 @@ def test_remove_bad_config(requests_mock): r = s.bootstrap.remove(config_id=config_id, token=token) assert r.error.status == 1 assert r.error.message == "Failed due to malformed config ID." - \ No newline at end of file diff --git a/tests/test_channels.py b/tests/test_channels.py index cb2f44e..8b4992e 100644 --- a/tests/test_channels.py +++ b/tests/test_channels.py @@ -92,12 +92,12 @@ def test_get_by_thing_does_not_exist(requests_mock): assert r.error.message == "Thing does not exist." def test_update_channel(requests_mock): - requests_mock.register_uri("PUT", url + "/channels/" + channel_id, json=json.dumps(channel), status_code=200) + requests_mock.register_uri("PUT", url + "/channels/" + channel_id, json=channel, status_code=200) r = s.channels.update(channel_id=channel_id, token=token, channel=channel) assert r.error.status == 0 def test_update_channel_does_not_exist(requests_mock): - requests_mock.register_uri("PUT", url + "/channels/" + channel_id, json=json.dumps(channel), status_code=404) + requests_mock.register_uri("PUT", url + "/channels/" + channel_id, json=channel, status_code=404) r = s.channels.update(channel_id=channel_id, token=token, channel=channel) assert r.error.status == 1 assert r.error.message == "Channel does not exist." @@ -126,4 +126,3 @@ def test_identify_thing_bad_key(requests_mock): r = s.channels.identify_thing(thing_key) assert r.error.status == 1 assert r.error.message == "Thing and channel are not connected, or thing with specified key doesn't exist." - \ No newline at end of file diff --git a/tests/test_groups.py b/tests/test_groups.py index c45d41e..3dd4275 100644 --- a/tests/test_groups.py +++ b/tests/test_groups.py @@ -128,12 +128,12 @@ def test_membership_bad_content_type(requests_mock): def test_assign(requests_mock): requests_mock.register_uri("POST", url + "/users/policies" , status_code=200) - r = s.groups.assign(group_id=group_id, token=token, members_ids=members, member_type= ["m_read"]) + r = s.groups.assign(group_id=group_id, token=token, member_id=members, member_type= ["m_read"]) assert r.error.status == 0 def test_assign_malformed_json(requests_mock): requests_mock.register_uri("POST", url + "/users/policies", status_code=400) - r = s.groups.assign(group_id=group_id, token=token, members_ids=members, member_type= ["m_read"]) + r = s.groups.assign(group_id=group_id, token=token, member_id=members, member_type= ["m_read"]) assert r.error.status == 1 assert r.error.message == "Failed due to malformed JSON." diff --git a/tests/test_users.py b/tests/test_users.py index 5ef80b0..66caebd 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -249,5 +249,4 @@ def test_authorise_user_bad_token(requests_mock): requests_mock.register_uri("POST", url + "/authorize", status_code=400) r = s.users.authorise_user(access_request=access_request , token=token["access_token"]) assert r.error.status == 1 - assert r.error.message == "Failed due to malformed JSON." - \ No newline at end of file + assert r.error.message == "Failed due to malformed JSON." From 609635ade582d355a94206a201bf4e9a1d2a0214 Mon Sep 17 00:00:00 2001 From: Musilah Date: Tue, 12 Sep 2023 20:49:26 +0300 Subject: [PATCH 17/31] resolve comment Signed-off-by: Musilah --- tests/test_certs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_certs.py b/tests/test_certs.py index 7bc6dd7..6690d67 100644 --- a/tests/test_certs.py +++ b/tests/test_certs.py @@ -59,7 +59,7 @@ def test_revoke(requests_mock): r = s.certs.revoke(thing_id=thing_id, token=token) assert r.error.status == 0 -def test_revoke(requests_mock): +def test_revoke_bad_response(requests_mock): requests_mock.register_uri( "DELETE", url + "/certs" + "/" + thing_id, status_code=404) r = s.certs.revoke(thing_id=thing_id, token=token) assert r.error.status == 1 From 074f8ea5783f0c1ce9cbc77739240e42ae7d76fa Mon Sep 17 00:00:00 2001 From: Musilah Date: Mon, 18 Sep 2023 16:26:00 +0300 Subject: [PATCH 18/31] update docstrings on users.py file Signed-off-by: Musilah --- docs/README.md | 2 +- docs/groups.md | 2 +- docs/sdk.md | 2 +- docs/users.md | 264 ++++++++++++++++++++--- examples/examples.py | 10 +- mainflux/groups.py | 2 +- mainflux/sdk.py | 4 +- mainflux/things.py | 4 +- mainflux/users.py | 493 ++++++++++++++++++++++++++++++++++++++++--- tests/test_things.py | 4 +- 10 files changed, 711 insertions(+), 76 deletions(-) diff --git a/docs/README.md b/docs/README.md index 674d4b5..ce62250 100644 --- a/docs/README.md +++ b/docs/README.md @@ -27,7 +27,7 @@ - [`response.Response`](./response.md#class-response) - [`sdk.SDK`](./sdk.md#class-sdk) - [`things.Things`](./things.md#class-things) -- [`users.Users`](./users.md#class-users) +- [`users.Users`](./users.md#class-users): Users API client. ## Functions diff --git a/docs/groups.md b/docs/groups.md index 1839775..f58663a 100644 --- a/docs/groups.md +++ b/docs/groups.md @@ -115,7 +115,7 @@ Gets all groups from database members(group_id: str, query_params: dict, token: str) ``` -Get list of members ID's from group +Gets members associated with the group specified by id --- diff --git a/docs/sdk.md b/docs/sdk.md index 14ba5eb..6f3182f 100644 --- a/docs/sdk.md +++ b/docs/sdk.md @@ -33,7 +33,7 @@ __init__( http_adapter_url='http://localhost', certs_url='http://localhost', bootstrap_url='http://localhost', - auth_url='http://localhost' + groups_url='http://localhost' ) ``` diff --git a/docs/users.md b/docs/users.md index 1487618..81610aa 100644 --- a/docs/users.md +++ b/docs/users.md @@ -14,11 +14,18 @@ ## class `Users` +Users API client. +Users API is used for creating and managing users. It is used for creating new users, logging in, refreshing tokens, getting user information, updating user information, disabling and enabling users. - +**Attributes:** + + - `URL`: str - URL of the Users API + - `USERS_ENDPOINT`: str - Users API endpoint + + ### method `__init__` @@ -35,7 +42,7 @@ __init__(url: str) --- - + ### method `authorise_user` @@ -45,9 +52,22 @@ authorise_user(access_request: dict, token: str) Authorises user +Creates policies for a user as a subject over a group which is the object. It authorizes the User to perform some actions over the group. + +params: access_request = { "subject": "", "object": "", "action": "", "entity_type": "" } token: strOnly admin can use this endpoint. Therefore, you need an authentication token for the admin. Also, only policies defined on the system are allowed to add. + + + +**returns:** + + - `mf_resp`: "True" + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" >>> mf_resp = mfsdk.users.authorise_user(user) >>> mf_resp + --- - + ### method `create` @@ -55,11 +75,26 @@ Authorises user create(user: dict, token: str = '') ``` -Registers new user account given email and password. New account will be uniquely identified by its email address. +Creates a new user. + +Creates a new user with provided user information. If token is provided, it will be used to create a new user. + +params: user: dict - user information for example: + + { "name": "example", "credentials": { "identity": "example@main.com", "secret": "12345678" } } token: str - token used for creating a new user + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { ... "name": "example", ... "credentials": { ... "identity": "example@mail.com", ... "secret": "12345678" ... } ... } >>> mf_resp = mfsdk.users.create(user) >>> mf_resp --- - + ### method `disable` @@ -67,11 +102,22 @@ Registers new user account given email and password. New account will be uniquel disable(user_id: str, user_token: str) ``` -Disables an enabled user account for a given user ID. +Disables an enabled user account for a given user ID. + +params: user_id: str - the user's given ID. token: str - token used for enabling a user + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" >>> mf_resp = mfsdk.users.disable(user) >>> mf_resp --- - + ### method `enable` @@ -79,11 +125,24 @@ Disables an enabled user account for a given user ID. enable(user_id: str, user_token: str) ``` -Enables a disabled user account for a given user ID. +Enables a disabled user account for a given user ID. + +Takes in the disabled User's ID and a valid token and enables the user. + +params: user_id: str - the user's given ID. token: str - token used for enabling a user + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" >>> mf_resp = mfsdk.users.enable(user) >>> mf_resp --- - + ### method `get` @@ -91,11 +150,24 @@ Enables a disabled user account for a given user ID. get(user_id: str, token: str) ``` -Gets a user information +Gets a user information. + +Gets info on currently logged in user. Info is obtained using authorization token and the user id. + +params: user_id: str - user information eg "886b4266-77d1-4258-abae-2931fb4f16de", token: str - token used for creating a new user + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id = "886b4266-77d1-4258-abae-2931fb4f16de" >>> mf_resp = mfsdk.users.get(user) >>> mf_resp --- - + ### method `get_all` @@ -103,11 +175,26 @@ Gets a user information get_all(query_params: dict, user_token: str) ``` -Retrieves a list of users +Retrieves a list of users. + +Gets a list of users from the database when provided with a user token and some parameters. + +params: user_token: str - token used for creating a new user query_params: dict - has a limit(int) which is the size of the subset to be expected and offset which is the number of items to skip during retrieval. For example: { "offset" : 0, "limit" : 10 } + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> query_params = { ... "offset" : 0, "limit" : 10 ... } >>> mf_resp = mfsdk.users.get(user) >>> mf_resp --- - + ### method `login` @@ -117,9 +204,22 @@ login(user: dict) Generates an access token when provided with proper credentials. +Issues a new access and refresh token for a user for authenticating into the system. + +params: user: a dict with the user information and password. { "identity": "user@mainflux.com", "secret": "12345678" } + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { ... "name": "example", ... "credentials": { ... "identity": "user@mainflux.com", ... "secret": "12345678" ... } ... } >>> mf_resp = mfsdk.users.login(user) >>> mf_resp + --- - + ### method `refresh_token` @@ -127,11 +227,26 @@ Generates an access token when provided with proper credentials. refresh_token(refresh_token: str) ``` -Refreshes Access and Refresh Token used for authenticating into the system. +Refreshes Access and Refresh Token used for authenticating into the system. + +Creates a new access token and refresh token for a user when provided with a valid refresh token. + +params: refresh_token: str - token used to refresh access. + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { ... "name": "example", ... "credentials": { ... "identity": "example@mail.com", ... "secret": "12345678" ... } ... } >>> mf_resp = mfsdk.users.refresh_token(user) >>> mf_resp --- - + ### method `reset_password` @@ -141,9 +256,19 @@ reset_password(password: str, confirm_password: str, token: str) Changes user password with the reset_request token +When user gets reset token, after he submitted email to /password/reset-request, posting a new password along to this endpoint will change password. + +params: passwor: str - the user's new password. confirm_password: str - a recurrence of the password to ensure it is the same. token: str - the reset token recieved from the reset_request email. + + + +**returns:** + + - `mf_resp`: "OK" + --- - + ### method `reset_password_request` @@ -151,11 +276,21 @@ Changes user password with the reset_request token reset_password_request(email: str, url: str) ``` -User Password reset request +User Password reset request. + +Generates a reset token and sends and email with link for resetting password. + +params: referrer email: str - this is the host being sent by the browser. the email is part of the header. url: str. + + + +**returns:** + + - `mf_resp`: response.Response - response object --- - + ### method `update` @@ -163,11 +298,26 @@ User Password reset request update(user: dict, user_token: str) ``` -Updates info on currently logged in user. Info is updated using authorization user_token +Updates information on currently logged in user. + +Information such as name and metadata is updated using authorization user_token + +params: user: dict - user information for example: + + { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" } } token: str - token used for creating a new user + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" } } >>> mf_resp = mfsdk.users.update(user) >>> mf_resp --- - + ### method `update_password` @@ -175,11 +325,24 @@ Updates info on currently logged in user. Info is updated using authorization us update_password(old_secret: str, new_secret: str, user_token: str) ``` -Changes user password +Changes user password. + +Updates secret of currently logged in user. Secret is updated using authorization token and the new received info. + +params: old_secret: str - the logged in user's current secret. new_secret: str - the user's new secret. token: str - token used for creating a new user + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> old_secret = old_secret >>> new_secret = new_secret >>> mf_resp = mfsdk.users.update(user) >>> mf_resp --- - + ### method `update_user_identity` @@ -187,11 +350,26 @@ Changes user password update_user_identity(user: dict, user_token: str) ``` -Updates Identity of the user +Updates identity information on currently logged in user. + +The user Identity is updated using authorization user_token + +params: user: dict - user information for example: + + { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" } } token: str - token used for creating a new user + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" } } >>> mf_resp = mfsdk.users.update_user_idenity(user) >>> mf_resp --- - + ### method `update_user_owner` @@ -199,11 +377,26 @@ Updates Identity of the user update_user_owner(user: dict, user_token: str) ``` -Updating user tags in the database +Updates owner on currently logged in user. + +Updates owner for the user with provided ID. Owner is updated using authorization token and a new owner identifier received in request. + +params: user: dict - user information for example: + + { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "tags": [ "yello", "orange" ] "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" }, "owner": "c52d-3b0d-43b9-8c3e-275c087d875af" } token: str - token used for creating a new user + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de", "owner": "c52d-3b0d-43b9-8c3e-275c087d875af" } >>> mf_resp = mfsdk.users.update(user) >>> mf_resp --- - + ### method `update_user_tags` @@ -211,7 +404,22 @@ Updating user tags in the database update_user_tags(user: dict, user_token: str) ``` -Updating user tags in the database +Updates tags on currently logged in user. + +Updates tags of the user with provided ID. Tags is updated using authorization token and the new tags received in request. + +params: user: dict - user information for example: + + { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "tags": [ "yello", "orange" ] "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" } } token: str - token used for creating a new user + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" } } >>> mf_resp = mfsdk.users.update(user) >>> mf_resp diff --git a/examples/examples.py b/examples/examples.py index 5c2942c..a1c172c 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -22,10 +22,10 @@ print(mf_resp.value) else: print(mf_resp.error.message) - + """To log in to the Mainflux system, you need to create a user token""" mf_resp = mfsdk.users.login( - user={ "identity" : "admin@example.com", "secret": "12345678"} + user={ "identity" : "admin@example.com", "secret": ""} ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -130,7 +130,7 @@ print(mf_resp.value) else: print(mf_resp.error.message) - + """Disables user""" mf_resp = mfsdk.users.disable(user_id="", user_token="") if mf_resp.error.status == 0: @@ -284,7 +284,7 @@ """Connect thing to channel""" mf_resp = mfsdk.things.connect( - channel_id="4921c9f2-6b7b-4291-98bf-fefd4a43591d", thing_id="d58ca9f5-e5f1-4a1b-9063-0c31ff9ba298", action="m_read", token="eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTI5MzI0MjMsImlhdCI6MTY5Mjg3ODQyMywiaWRlbnRpdHkiOiJkZXRlcm1pbmVkX3JvZW50Z2VuQGVtYWlsLmNvbSIsImlzcyI6ImNsaWVudHMuYXV0aCIsInN1YiI6IjVhN2M1NGExLTgzMzUtNDBiNy1hOTE3LTc2MmZmYmFmOGFkOSIsInR5cGUiOiJhY2Nlc3MifQ.s74K5y6k9Hjzhi3MNU0cX1U9lKpJiRUwrIBLWgw_fcXUeMUN9HAIidu0sWj-iGxI6c-KUUy993I9yNIBOrUqaw" + channel_id="", thing_id="", action="m_read", token="" ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -338,7 +338,7 @@ """To create a channel, you need a channel and a token""" mf_resp = mfsdk.channels.create( - channel={"name": ""}, token="") + channel={"name": ""}, token="") if mf_resp.error.status == 0: print(mf_resp.value) else: diff --git a/mainflux/groups.py b/mainflux/groups.py index 2a333ae..6638d1e 100644 --- a/mainflux/groups.py +++ b/mainflux/groups.py @@ -114,7 +114,7 @@ def update(self, group_id: str, group: dict, token: str): return mf_resp def members(self, group_id: str, query_params: dict, token: str): - """Get list of members ID's from group""" + """Gets members associated with the group specified by id""" http_resp = requests.get( self.url + "/" + self.groups_endpoint + "/" + group_id + "/members", headers=utils.construct_header(token, utils.CTJSON), diff --git a/mainflux/sdk.py b/mainflux/sdk.py index 5e9c0f0..464927d 100644 --- a/mainflux/sdk.py +++ b/mainflux/sdk.py @@ -20,7 +20,7 @@ def __init__( http_adapter_url=default_url, certs_url=default_url, bootstrap_url=default_url, - auth_url=default_url, + groups_url=default_url, ): self.users = users.Users(users_url) self.things = things.Things(things_url) @@ -28,7 +28,7 @@ def __init__( adapter_url=http_adapter_url, reader_url=reader_url ) self.channels = channels.Channels(things_url) - self.groups = groups.Groups(auth_url) + self.groups = groups.Groups(groups_url) self.bootstrap = boostrap.Bootstrap(bootstrap_url) self.certs = certs.Certs(certs_url) self.version_url = things_url diff --git a/mainflux/things.py b/mainflux/things.py index 17b339b..ea882e8 100644 --- a/mainflux/things.py +++ b/mainflux/things.py @@ -234,8 +234,8 @@ def connect(self, thing_id: str, channel_id: str, action: str, token: str): def disconnect(self, thing_id: str, channel_id: str, token: str): """Disconnect thing and channel""" payload = {"subject": thing_id, "object": channel_id} - http_resp = requests.post( - self.URL + "/disconnect", + http_resp = requests.delete( + self.URL + "/policies" + "/" + thing_id + "/" + channel_id, headers=utils.construct_header(token, utils.CTJSON), json=payload, ) diff --git a/mainflux/users.py b/mainflux/users.py index e49b3ba..debc2b7 100644 --- a/mainflux/users.py +++ b/mainflux/users.py @@ -6,14 +6,67 @@ class Users: + """Users API client. + + Users API is used for creating and managing users. + It is used for creating new users, logging in, refreshing tokens, + getting user information, updating user information, disabling + and enabling users. + + Attributes: + URL: str - URL of the Users API + USERS_ENDPOINT: str - Users API endpoint + """ USERS_ENDPOINT = "users" def __init__(self, url: str): self.URL = url - + """Initializes Users API client. + + params: + url: str - URL of the Users API + + returns: + Users: Users - Users API client + + raises: + None + """ def create(self, user: dict, token: str = ""): - """Registers new user account given email and password. New account - will be uniquely identified by its email address.""" + """Creates a new user. + + Creates a new user with provided user information. + If token is provided, it will be used to create a new user. + + params: + user: dict - user information for example: + + { + "name": "example", + "credentials": { + "identity": "example@main.com", + "secret": "12345678" + } + } + token: str - token used for creating a new user + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> user = { + ... "name": "example", + ... "credentials": { + ... "identity": "example@mail.com", + ... "secret": "12345678" + ... } + ... } + >>> mf_resp = mfsdk.users.create(user) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.post( self.URL + "/users", @@ -30,7 +83,34 @@ def create(self, user: dict, token: str = ""): return mf_resp def login(self, user: dict): - """Generates an access token when provided with proper credentials.""" + """Generates an access token when provided with proper credentials. + + Issues a new access and refresh token for a user for authenticating + into the system. + + params: + user: a dict with the user information and password. + { + "identity": "user@mainflux.com", + "secret": "12345678" + } + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> user = { + ... "name": "example", + ... "credentials": { + ... "identity": "user@mainflux.com", + ... "secret": "12345678" + ... } + ... } + >>> mf_resp = mfsdk.users.login(user) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.post(self.URL + "/users/tokens/issue", json=user) if http_resp.status_code != 201: @@ -41,14 +121,39 @@ def login(self, user: dict): else: mf_resp.value = http_resp.json() return mf_resp - + def refresh_token(self, refresh_token: str): - """Refreshes Access and Refresh Token used for authenticating into the system.""" + """Refreshes Access and Refresh Token used for authenticating + into the system. + + Creates a new access token and refresh token for a user when + provided with a valid refresh token. + + params: + refresh_token: str - token used to refresh access. + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> user = { + ... "name": "example", + ... "credentials": { + ... "identity": "example@mail.com", + ... "secret": "12345678" + ... } + ... } + >>> mf_resp = mfsdk.users.refresh_token(user) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.post( - self.URL + "/users/tokens/refresh", + self.URL + "/users/tokens/refresh", headers=utils.construct_header(refresh_token, utils.CTJSON), - ) + ) if http_resp.status_code != 201: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( @@ -59,7 +164,26 @@ def refresh_token(self, refresh_token: str): return mf_resp def get(self, user_id: str, token: str): - """Gets a user information""" + """Gets a user information. + + Gets info on currently logged in user. Info is obtained + using authorization token and the user id. + + params: + user_id: str - user information eg "886b4266-77d1-4258-abae-2931fb4f16de", + token: str - token used for creating a new user + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> user_id = "886b4266-77d1-4258-abae-2931fb4f16de" + >>> mf_resp = mfsdk.users.get(user) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( self.URL + "/" + self.USERS_ENDPOINT + "/" + user_id, @@ -75,12 +199,39 @@ def get(self, user_id: str, token: str): return mf_resp def get_all(self, query_params: dict, user_token: str): - """Retrieves a list of users""" + """Retrieves a list of users. + + Gets a list of users from the database when provided with a user token and + some parameters. + + params: + user_token: str - token used for creating a new user + query_params: dict - has a limit(int) which is the size of the subset + to be expected and offset which is the number of items to skip during retrieval. + For example: + { + "offset" : 0, "limit" : 10 + } + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> query_params = { + ... "offset" : 0, "limit" : 10 + ... } + >>> mf_resp = mfsdk.users.get(user) + >>> mf_resp + """ http_resp = requests.get( self.URL + "/" + self.USERS_ENDPOINT, headers=utils.construct_header(user_token, utils.CTJSON), params=query_params, ) + print(http_resp.url) mf_resp = response.Response() if http_resp.status_code != 200: mf_resp.error.status = 1 @@ -92,7 +243,47 @@ def get_all(self, query_params: dict, user_token: str): return mf_resp def update(self, user: dict, user_token: str): - """Updates info on currently logged in user. Info is updated using authorization user_token""" + """Updates information on currently logged in user. + + Information such as name and metadata is updated using authorization user_token + + params: + user: dict - user information for example: + + { + "name": "example", + "id": "886b4266-77d1-4258-abae-2931fb4f16de" + "credentials": { + "identity": "example@main.com", + "secret": "12345678" + }, + "metadata": { + "foo": "bar" + } + } + token: str - token used for creating a new user + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> user = { + "name": "example", + "id": "886b4266-77d1-4258-abae-2931fb4f16de" + "credentials": { + "identity": "example@main.com", + "secret": "12345678" + }, + "metadata": { + "foo": "bar" + } + } + >>> mf_resp = mfsdk.users.update(user) + >>> mf_resp + """ http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"], headers=utils.construct_header(user_token, utils.CTJSON), @@ -107,9 +298,49 @@ def update(self, user: dict, user_token: str): else: mf_resp.value = http_resp.json() return mf_resp - + def update_user_identity(self, user: dict, user_token: str): - """Updates Identity of the user""" + """Updates identity information on currently logged in user. + + The user Identity is updated using authorization user_token + + params: + user: dict - user information for example: + + { + "name": "example", + "id": "886b4266-77d1-4258-abae-2931fb4f16de" + "credentials": { + "identity": "example@main.com", + "secret": "12345678" + }, + "metadata": { + "foo": "bar" + } + } + token: str - token used for creating a new user + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> user = { + "name": "example", + "id": "886b4266-77d1-4258-abae-2931fb4f16de" + "credentials": { + "identity": "example@main.com", + "secret": "12345678" + }, + "metadata": { + "foo": "bar" + } + } + >>> mf_resp = mfsdk.users.update_user_idenity(user) + >>> mf_resp + """ http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"] + "/identity", headers=utils.construct_header(user_token, utils.CTJSON), @@ -124,9 +355,54 @@ def update_user_identity(self, user: dict, user_token: str): else: mf_resp.value = http_resp.json() return mf_resp - + def update_user_tags(self, user: dict, user_token: str): - """Updating user tags in the database""" + """Updates tags on currently logged in user. + + Updates tags of the user with provided ID. Tags is updated using + authorization token and the new tags received in request. + + params: + user: dict - user information for example: + + { + "name": "example", + "id": "886b4266-77d1-4258-abae-2931fb4f16de" + "tags": [ + "yello", + "orange" + ] + "credentials": { + "identity": "example@main.com", + "secret": "12345678" + }, + "metadata": { + "foo": "bar" + } + } + token: str - token used for creating a new user + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> user = { + "name": "example", + "id": "886b4266-77d1-4258-abae-2931fb4f16de" + "credentials": { + "identity": "example@main.com", + "secret": "12345678" + }, + "metadata": { + "foo": "bar" + } + } + >>> mf_resp = mfsdk.users.update(user) + >>> mf_resp + """ http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"] + "/tags", headers=utils.construct_header(user_token, utils.CTJSON), @@ -141,9 +417,49 @@ def update_user_tags(self, user: dict, user_token: str): else: mf_resp.value = http_resp.json() return mf_resp - + def update_user_owner(self, user: dict, user_token: str): - """Updating user tags in the database""" + """Updates owner on currently logged in user. + + Updates owner for the user with provided ID. Owner is updated using + authorization token and a new owner identifier received in request. + + params: + user: dict - user information for example: + + { + "name": "example", + "id": "886b4266-77d1-4258-abae-2931fb4f16de" + "tags": [ + "yello", + "orange" + ] + "credentials": { + "identity": "example@main.com", + "secret": "12345678" + }, + "metadata": { + "foo": "bar" + }, + "owner": "c52d-3b0d-43b9-8c3e-275c087d875af" + } + token: str - token used for creating a new user + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> user = { + "name": "example", + "id": "886b4266-77d1-4258-abae-2931fb4f16de", + "owner": "c52d-3b0d-43b9-8c3e-275c087d875af" + } + >>> mf_resp = mfsdk.users.update(user) + >>> mf_resp + """ http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"] + "/owner", headers=utils.construct_header(user_token, utils.CTJSON), @@ -158,9 +474,30 @@ def update_user_owner(self, user: dict, user_token: str): else: mf_resp.value = http_resp.json() return mf_resp - + def update_password(self, old_secret: str, new_secret: str, user_token: str): - """Changes user password""" + """Changes user password. + + Updates secret of currently logged in user. Secret is updated using + authorization token and the new received info. + + params: + old_secret: str - the logged in user's current secret. + new_secret: str - the user's new secret. + token: str - token used for creating a new user + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> old_secret = old_secret + >>> new_secret = new_secret + >>> mf_resp = mfsdk.users.update(user) + >>> mf_resp + """ payload = {"old_secret": old_secret, "new_secret": new_secret} http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/secret", @@ -176,13 +513,25 @@ def update_password(self, old_secret: str, new_secret: str, user_token: str): else: mf_resp.value = "OK" return mf_resp - + def reset_password_request(self, email: str, url: str): - """User Password reset request""" + """User Password reset request. + + Generates a reset token and sends and email + with link for resetting password. + + params: + referrer email: str - this is the host being sent by the browser. + the email is part of the header. + url: str. + + returns: + mf_resp: response.Response - response object + """ http_resp = requests.post( self.URL + "/password/reset-request", - headers= {"Referer": url}, - json= {"email": email} + headers={"Referer": url}, + json={"email": email}, ) mf_resp = response.Response() if http_resp.status_code != 201: @@ -193,10 +542,28 @@ def reset_password_request(self, email: str, url: str): else: mf_resp.value = http_resp.json() return mf_resp - + def reset_password(self, password: str, confirm_password: str, token: str): - """Changes user password with the reset_request token""" - payload = {"password": password, "confirm_password": confirm_password, "token": token} + """Changes user password with the reset_request token + + When user gets reset token, after he submitted email to + /password/reset-request, posting a new password along to this + endpoint will change password. + + params: + passwor: str - the user's new password. + confirm_password: str - a recurrence of the password to ensure it + is the same. + token: str - the reset token recieved from the reset_request email. + + returns: + mf_resp: "OK" + """ + payload = { + "password": password, + "confirm_password": confirm_password, + "token": token, + } http_resp = requests.put( self.URL + "/password/reset", json=payload, @@ -212,7 +579,25 @@ def reset_password(self, password: str, confirm_password: str, token: str): return mf_resp def enable(self, user_id: str, user_token: str): - """Enables a disabled user account for a given user ID.""" + """Enables a disabled user account for a given user ID. + + Takes in the disabled User's ID and a valid token and enables the user. + + params: + user_id: str - the user's given ID. + token: str - token used for enabling a user + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" + >>> mf_resp = mfsdk.users.enable(user) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.post( self.URL + "/" + self.USERS_ENDPOINT + "/" + user_id + "/enable", @@ -228,7 +613,23 @@ def enable(self, user_id: str, user_token: str): return mf_resp def disable(self, user_id: str, user_token: str): - """Disables an enabled user account for a given user ID.""" + """Disables an enabled user account for a given user ID. + + params: + user_id: str - the user's given ID. + token: str - token used for enabling a user + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" + >>> mf_resp = mfsdk.users.disable(user) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.post( self.URL + "/" + self.USERS_ENDPOINT + "/" + user_id + "/disable", @@ -243,13 +644,39 @@ def disable(self, user_id: str, user_token: str): mf_resp.value = http_resp.json() return mf_resp - def authorise_user(self,access_request: dict, token: str): - """Authorises user""" + def authorise_user(self, access_request: dict, token: str): + """Authorises user + + Creates policies for a user as a subject over a group which is the object. + It authorizes the User to perform some actions over the group. + + params: + access_request = { + "subject": "", + "object": "", + "action": "", + "entity_type": "" + } + token: strOnly admin can use this endpoint. Therefore, you need + an authentication token for the admin. Also, only policies + defined on the system are allowed to add. + + returns: + mf_resp: "True" + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" + >>> mf_resp = mfsdk.users.authorise_user(user) + >>> mf_resp + """ mf_resp = response.Response() - http_resp= requests.post( - self.URL +"/authorize", + http_resp = requests.post( + self.URL + "/authorize", headers=utils.construct_header(token, utils.CTJSON), - json= access_request + json=access_request, ) if http_resp.status_code != 200: mf_resp.error.status = 1 diff --git a/tests/test_things.py b/tests/test_things.py index b1fcd83..795afc6 100644 --- a/tests/test_things.py +++ b/tests/test_things.py @@ -231,12 +231,12 @@ def test_connect_non_existing_entity(requests_mock): assert r.error.message == "A non-existent entity request." def test_disconnect_thing(requests_mock): - requests_mock.register_uri("POST", url + "/disconnect", status_code=204) + requests_mock.register_uri("DELETE", url + "/policies" + "/" + thing_id + "/" + channel_id, status_code=204) r = s.things.disconnect(channel_id=channel_id, thing_id=thing_id, token=token) assert r.error.status == 0 def test_disconnect_thing_or_channel_does_not_exist(requests_mock): - requests_mock.register_uri("POST", url + "/disconnect", status_code=404) + requests_mock.register_uri("DELETE", url + "/policies" + "/" + thing_id + "/" + channel_id, status_code=404) r = s.things.disconnect(channel_id=channel_id, thing_id=thing_id, token=token) assert r.error.status == 1 assert r.error.message == "Channel or thing does not exist." From 1c5ad19e22e006174871d266ddbe78f93d7a244b Mon Sep 17 00:00:00 2001 From: Musilah Date: Wed, 20 Sep 2023 04:37:52 +0300 Subject: [PATCH 19/31] add docstrings to things.py file Signed-off-by: Musilah --- docs/README.md | 2 - docs/users.md | 72 +++---- mainflux/things.py | 461 ++++++++++++++++++++++++++++++++++++++++++--- mainflux/users.py | 155 +++++++-------- 4 files changed, 550 insertions(+), 140 deletions(-) diff --git a/docs/README.md b/docs/README.md index ce62250..fc15856 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,7 +12,6 @@ - [`messages`](./messages.md#module-messages) - [`response`](./response.md#module-response) - [`sdk`](./sdk.md#module-sdk) -- [`things`](./things.md#module-things) - [`users`](./users.md#module-users) - [`utils`](./utils.md#module-utils) @@ -26,7 +25,6 @@ - [`response.Error`](./response.md#class-error) - [`response.Response`](./response.md#class-response) - [`sdk.SDK`](./sdk.md#class-sdk) -- [`things.Things`](./things.md#class-things) - [`users.Users`](./users.md#class-users): Users API client. ## Functions diff --git a/docs/users.md b/docs/users.md index 81610aa..c2924bd 100644 --- a/docs/users.md +++ b/docs/users.md @@ -42,7 +42,7 @@ __init__(url: str) --- - + ### method `authorise_user` @@ -63,7 +63,7 @@ params: access_request = { "subject": "", "object": "", " - `mf_resp`: "True" Usage: -``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" >>> mf_resp = mfsdk.users.authorise_user(user) >>> mf_resp +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> access_request = { ... "subject": "", ... "object": "", ... "action": "", ... "entity_type": "" ... } >>> mf_resp = mfsdk.users.authorise_user(access_request, token) >>> mf_resp --- @@ -79,9 +79,7 @@ Creates a new user. Creates a new user with provided user information. If token is provided, it will be used to create a new user. -params: user: dict - user information for example: - - { "name": "example", "credentials": { "identity": "example@main.com", "secret": "12345678" } } token: str - token used for creating a new user +params: user: dict - user information for example: { "name": "example", "credentials": { "identity": "example@main.com", "secret": "12345678" } } token: str - token used for creating a new user @@ -94,7 +92,7 @@ Usage: --- - + ### method `disable` @@ -113,11 +111,11 @@ params: user_id: str - the user's given ID. token: str - token used for enabli - `mf_resp`: response.Response - response object Usage: -``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" >>> mf_resp = mfsdk.users.disable(user) >>> mf_resp +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" >>> mf_resp = mfsdk.users.disable(user_id, user_token) >>> mf_resp --- - + ### method `enable` @@ -138,11 +136,11 @@ params: user_id: str - the user's given ID. token: str - token used for enabli - `mf_resp`: response.Response - response object Usage: -``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" >>> mf_resp = mfsdk.users.enable(user) >>> mf_resp +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" >>> mf_resp = mfsdk.users.enable(user_id, user_token) >>> mf_resp --- - + ### method `get` @@ -163,11 +161,11 @@ params: user_id: str - user information eg "886b4266-77d1-4258-abae-2931fb4f16d - `mf_resp`: response.Response - response object Usage: -``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id = "886b4266-77d1-4258-abae-2931fb4f16de" >>> mf_resp = mfsdk.users.get(user) >>> mf_resp +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id = "886b4266-77d1-4258-abae-2931fb4f16de" >>> token = "" >>> mf_resp = mfsdk.users.get(user_id, token) >>> mf_resp --- - + ### method `get_all` @@ -190,11 +188,11 @@ params: user_token: str - token used for creating a new user query_params: di Usage: ``` - >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> query_params = { ... "offset" : 0, "limit" : 10 ... } >>> mf_resp = mfsdk.users.get(user) >>> mf_resp + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> query_params = { ... "offset" : 0, "limit" : 10 ... } >>> mf_resp = mfsdk.users.get(query_params, user_token) >>> mf_resp --- - + ### method `login` @@ -206,7 +204,7 @@ Generates an access token when provided with proper credentials. Issues a new access and refresh token for a user for authenticating into the system. -params: user: a dict with the user information and password. { "identity": "user@mainflux.com", "secret": "12345678" } +params: user: a dict with the user information and password for example: {"credentials":{ "identity": "user@mainflux.com", "secret": "12345678" } } **returns:** @@ -215,11 +213,11 @@ params: user: a dict with the user information and password. { "identity": Usage: ``` - >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { ... "name": "example", ... "credentials": { ... "identity": "user@mainflux.com", ... "secret": "12345678" ... } ... } >>> mf_resp = mfsdk.users.login(user) >>> mf_resp + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> credentials= { ... "identity": "user@mainflux.com", ... "secret": "12345678" ... } >>> mf_resp = mfsdk.users.login(credentials) >>> mf_resp --- - + ### method `refresh_token` @@ -242,11 +240,11 @@ params: refresh_token: str - token used to refresh access. Usage: ``` - >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { ... "name": "example", ... "credentials": { ... "identity": "example@mail.com", ... "secret": "12345678" ... } ... } >>> mf_resp = mfsdk.users.refresh_token(user) >>> mf_resp + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> mf_resp = mfsdk.users.refresh_token(refresh_token) >>> mf_resp --- - + ### method `reset_password` @@ -266,9 +264,12 @@ params: passwor: str - the user's new password. confirm_password: str - a rec - `mf_resp`: "OK" +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") ... password = 234567 ... confirm_password = 234567 >>> mf_resp = mfsdk.users.reset_password(password, confirm_password, token) >>> mf_resp + --- - + ### method `reset_password_request` @@ -288,9 +289,12 @@ params: referrer email: str - this is the host being sent by the browser. the - `mf_resp`: response.Response - response object +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") ... email = admin@example.com ... url = stp@gmail.com >>> mf_resp = mfsdk.users.reset_password_request(email, url) >>> mf_resp + --- - + ### method `update` @@ -302,9 +306,7 @@ Updates information on currently logged in user. Information such as name and metadata is updated using authorization user_token -params: user: dict - user information for example: - - { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" } } token: str - token used for creating a new user +params: user: dict - user information for example: { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" } } token: str - token used for creating a new user @@ -313,11 +315,11 @@ params: user: dict - user information for example: - `mf_resp`: response.Response - response object Usage: -``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" } } >>> mf_resp = mfsdk.users.update(user) >>> mf_resp +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { ... "name": "example", ... "id": "886b4266-77d1-4258-abae-2931fb4f16de" ... "metadata": { ... "foo": "bar" ... } ... } >>> mf_resp = mfsdk.users.update(user, token) >>> mf_resp --- - + ### method `update_password` @@ -338,11 +340,11 @@ params: old_secret: str - the logged in user's current secret. new_secret: str - `mf_resp`: response.Response - response object Usage: -``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> old_secret = old_secret >>> new_secret = new_secret >>> mf_resp = mfsdk.users.update(user) >>> mf_resp +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") ... old_secret = 12345678 ... new_secret = 87654321 >>> mf_resp = mfsdk.users.update(old_secret, new_secret, user_token) >>> mf_resp --- - + ### method `update_user_identity` @@ -365,11 +367,11 @@ params: user: dict - user information for example: - `mf_resp`: response.Response - response object Usage: -``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" } } >>> mf_resp = mfsdk.users.update_user_idenity(user) >>> mf_resp +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { ... "name": "example", ... "id": "886b4266-77d1-4258-abae-2931fb4f16de" ... "credentials": { ... "identity": "example@main.com", ... "secret": "12345678" ... }, ... "metadata": { ... "foo": "bar" ... } ... } >>> mf_resp = mfsdk.users.update_user_identity(user, user_token) >>> mf_resp --- - + ### method `update_user_owner` @@ -383,7 +385,7 @@ Updates owner for the user with provided ID. Owner is updated using authorizati params: user: dict - user information for example: - { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "tags": [ "yello", "orange" ] "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" }, "owner": "c52d-3b0d-43b9-8c3e-275c087d875af" } token: str - token used for creating a new user + { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "owner": "c52d-3b0d-43b9-8c3e-275c087d875af" } token: str - token used for creating a new user @@ -392,11 +394,11 @@ params: user: dict - user information for example: - `mf_resp`: response.Response - response object Usage: -``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de", "owner": "c52d-3b0d-43b9-8c3e-275c087d875af" } >>> mf_resp = mfsdk.users.update(user) >>> mf_resp +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { ... "name": "example", ... "id": "886b4266-77d1-4258-abae-2931fb4f16de", ... "owner": "c52d-3b0d-43b9-8c3e-275c087d875af" ... } >>> mf_resp = mfsdk.users.update_user_owner(user, user_token) >>> mf_resp --- - + ### method `update_user_tags` @@ -410,7 +412,7 @@ Updates tags of the user with provided ID. Tags is updated using authorization params: user: dict - user information for example: - { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "tags": [ "yello", "orange" ] "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" } } token: str - token used for creating a new user + { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "tags": [ "back", "end" ] "metadata": { "foo": "bar" } } token: str - token used for creating a new user @@ -419,7 +421,7 @@ params: user: dict - user information for example: - `mf_resp`: response.Response - response object Usage: -``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "credentials": { "identity": "example@main.com", "secret": "12345678" }, "metadata": { "foo": "bar" } } >>> mf_resp = mfsdk.users.update(user) >>> mf_resp +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { ... "name": "example", ... "id": "886b4266-77d1-4258-abae-2931fb4f16de" ... "tags": [ ... "back", ... "end" ... ] ... } >>> mf_resp = mfsdk.users.update_user_tags(user, user_token) >>> mf_resp diff --git a/mainflux/things.py b/mainflux/things.py index ea882e8..2c6eb24 100644 --- a/mainflux/things.py +++ b/mainflux/things.py @@ -5,16 +5,58 @@ class Things: + """Things API client. + + Things API is used for creating and managing things. + It is used for creating new things, creating multiple things + getting thing information, updating thing information, disabling + and enabling things ,and connecting and disconnecting things. + + Attributes: + URL: str - URL of the Things API + THINGS_ENDPOINT: str - Things API endpoint + """ THINGS_ENDPOINT = "things" - CONNECT_ENDPOINT = "connect" - DISCONNECT_ENDPOINT = "disconnect" - IDENTIFY_ENDPOINT= "identify" def __init__(self, url: str): self.URL = url - + """Initializes Things API client. + + params: + url: str - URL of the Things API + + returns: + Thigs: Things - Things API client + + raises: + None + """ def create(self, thing: dict, token: str): - """Creates thing entity in the database""" + """Creates thing entity in the databas + + Creates a new thing with provided thing information. + If token is provided, it will be used to create a new thing + + params: + thing: dict - thing information for example: + { + "name": "thing1" + } + token: str - token used for creating a new thing + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> thing = { + ... "name": "thing1", + ... } + >>> mf_resp = mfsdk.things.create(thing) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.post( self.URL + "/" + self.THINGS_ENDPOINT, @@ -30,8 +72,36 @@ def create(self, thing: dict, token: str): mf_resp.value = http_resp.json() return mf_resp - def create_bulk(self, things: list, token: str): - """Creates multiple things in a bulk""" + def create_bulk(self, things: list, token: str) + """Creates multiple things in bulk. + + Creates multiple new things with provided things information. + If a token is provided, it will be used to create the new things. + + params: + things: list - a list of things with theri information for example: + [ + {"name": "thing2"}, + {"name": "thing3"}, + {"name": "thing4"} + ] + token: str - token used for creating the new things. + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> things = [ + ... {"name": "thing2"}, + ... {"name": "thing3"}, + ... {"name": "thing4"} + ... ] + >>> mf_resp = mfsdk.things.create_bulk(things) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.post( self.URL + "/" + self.THINGS_ENDPOINT + "/bulk", @@ -48,7 +118,27 @@ def create_bulk(self, things: list, token: str): return mf_resp def get(self, thing_id: str, token: str): - """Gets a thing entity for a logged-in user""" + """Gets a thing entity for a logged-in user + + Provides information about a thing with provided thing ID and token. + Information about a thing is provided in a JSON format and includes the name + its owner, secret,tags and status. + + params: + thing_id: str - ID of the thing + token: str - token used for getting thing information + + returns: + mf_resp: response.Response - response object. + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> mf_resp = mfsdk.things.get(thing_id) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( self.URL + "/" + self.THINGS_ENDPOINT + "/" + thing_id, @@ -64,7 +154,34 @@ def get(self, thing_id: str, token: str): return mf_resp def get_all(self, query_params: dict, token: str): - """Gets all things from database""" + """Gets all things from database. + + Provides information about all things in a JSON format. It is controlled + by a set of query parameters and a valid token. + + params: + query_params: dict - query parameters for example: + { + "offset": 0, + "limit": 10 + } + where offset is the number of things to skip and limit is the maximum + token: str - token used for getting all things information + + returns: + mf_resp: response.Response - response object. + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> query_params = { + ... "offset": 0, + ... "limit": 10 + ... } + >>> mf_resp = mfsdk.things.get_all(query_params) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( self.URL + "/" + self.THINGS_ENDPOINT, @@ -81,7 +198,36 @@ def get_all(self, query_params: dict, token: str): return mf_resp def get_by_channel(self, channel_id: str, query_params: dict, token: str): - """Gets all things to which a specific thing is connected to""" + """Gets all things to which a specific thing is connected to. + + Provides a list of all things that are connected to a specific channel when + given a channel ID and valid token. + + params: + channel_id: str - ID of the channel + query_params: dict - query parameters for example: + { + "offset": 0, + "limit": 10 + } + where offset is the number of things to skip and limit is the maximum + token: str - token used for getting all things information + + returns: + mf_resp: response.Response - response object. + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> channel_id = "567f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> query_params = { + ... "offset": 0, + ... "limit": 10 + ... } + >>> mf_resp = mfsdk.things.get_by_channel(channel_id, query_params) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( self.URL + "/channels/" + channel_id + "/" + self.THINGS_ENDPOINT, @@ -98,7 +244,34 @@ def get_by_channel(self, channel_id: str, query_params: dict, token: str): return mf_resp def update(self, thing_id: str, thing: dict, token: str): - """Updates thing entity""" + """Updates thing entity + + Allows a logged in user to make changes and update a thing's + information with provided thing ID and valid token. Information + such as the metadata and name can be updated. + + params: + thing_id: str - ID of the thing + thing: dict - thing information for example: + { + "name": "thing1" + } + token: str - token used for updating thing information + + returns: + mf_resp: response.Response - response object. + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> thing = { + ... "name": "thing2", + ... } + >>> mf_resp = mfsdk.things.update(thing_id, thing) + >>> mf_resp + """ http_resp = requests.patch( self.URL + "/" + self.THINGS_ENDPOINT + "/" + thing_id, json=thing, @@ -115,7 +288,34 @@ def update(self, thing_id: str, thing: dict, token: str): return mf_resp def update_thing_secret(self, thing_id: str, thing: dict, token: str): - """Updates thing secret""" + """Updates thing secret + + Allows a logged in user to make changes and update a thing's + information with provided thing ID and valid token. The thing's + secret can be updated. + + params: + thing_id: str - ID of the thing + thing: dict - thing information for example: + { + "key": "thing1" + } + token: str - token used for updating thing information + + returns: + mf_resp: response.Response - response object. + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> thing = { + ... "key": "thing2", + ... } + >>> mf_resp = mfsdk.things.update_thing_secret(thing_id, thing) + >>> mf_resp + """ http_resp = requests.patch( self.URL + "/" + self.THINGS_ENDPOINT + "/" + thing_id + "/secret", json=thing, @@ -132,7 +332,34 @@ def update_thing_secret(self, thing_id: str, thing: dict, token: str): return mf_resp def update_thing_tags(self, thing_id: str, thing: dict, token: str): - """Updates thing secret""" + """Updates thing tags + + Allows a logged in user to make changes and update a thing's + information with provided thing ID and valid token. The thing's + tags can be updated. + + params: + thing_id: str - ID of the thing + thing: dict - thing information for example: + { + "tags": ["tag1", "tag2"] + } + token: str - token used for updating thing information + + returns: + mf_resp: response.Response - response object. + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> thing = { + ... "tags": ["tag1", "tag2"] + ... } + >>> mf_resp = mfsdk.things.update_thing_tags(thing_id, thing) + >>> mf_resp + """ http_resp = requests.patch( self.URL + "/" + self.THINGS_ENDPOINT + "/" + thing_id + "/tags", json=thing, @@ -149,7 +376,34 @@ def update_thing_tags(self, thing_id: str, thing: dict, token: str): return mf_resp def update_thing_owner(self, thing_id: str, thing: dict, token: str): - """Updates thing secret""" + """Updates thing owner + + Allows a logged in user to make changes and update a thing's + information with provided thing ID and valid token. The thing + owner can be updated. + + params: + thing_id: str - ID of the thing + thing: dict - thing information for example: + { + "owner": "user1" + } + token: str - token used for updating thing information + + returns: + mf_resp: response.Response - response object. + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> thing = { + ... "owner": "user1" + ... } + >>> mf_resp = mfsdk.things.update_thing_owner(thing_id, thing) + >>> mf_resp + """ http_resp = requests.patch( self.URL + "/" + self.THINGS_ENDPOINT + "/" + thing_id + "/owner", json=thing, @@ -166,7 +420,25 @@ def update_thing_owner(self, thing_id: str, thing: dict, token: str): return mf_resp def disable(self, thing_id: str, token: str): - """Deletes a thing entity from database""" + """Deletes a thing entity from database. + + Deletes a thing with provided thing ID and valid token. + + params: + thing_id: str - ID of the thing + token: str - token used for deleting thing + + returns: + mf_resp: response.Response - response object. + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> mf_resp = mfsdk.things.disable(thing_id) + >>> mf_resp + """ http_resp = requests.post( self.URL + "/" + self.THINGS_ENDPOINT + "/" + thing_id + "/disable", headers=utils.construct_header(token, utils.CTJSON), @@ -180,7 +452,32 @@ def disable(self, thing_id: str, token: str): return mf_resp def connects(self, thing_ids: list, channel_ids: list, actions: list, token: str): - """Connects thing and channel""" + """Connects thing and channel. + + Connects multiple things and channels with provided thing IDs + as the subjects, channel IDs as the objects, actions that the + thing can partake in and a valid token. + + params: + thing_ids: list - list of thing IDs + channel_ids: list - list of channel IDs + actions: list - list of actions for example: + ["m_write", "m_read"] + token: str - token used for connecting things and channels + + returns: + mf_resp: response.Response - response object. + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> thing_ids = ["fd4f7da5-b7bf-49b7-bf2f-99995e78afd9"] + >>> channel_ids = ["567f7da5-b7bf-49b7-bf2f-99995e78afd9"] + >>> actions = ["m_write", "m_read"] + >>> mf_resp = mfsdk.things.connects(thing_ids, channel_ids, actions) + >>> mf_resp + """ payload = {"subjects": thing_ids, "objects": channel_ids, "actions": actions} http_resp = requests.post( self.URL + "/connect", @@ -198,7 +495,28 @@ def connects(self, thing_ids: list, channel_ids: list, actions: list, token: str return mf_resp def disconnects(self, thing_ids: list, channel_ids: list, token: str): - """Disconnect thing and channel""" + """Disconnect thing and channel + + Disconnects multiple things and channels with provided thing IDs + as the subjects, channel IDs as the objects and a valid token. + + params: + thing_ids: list - list of thing IDs + channel_ids: list - list of channel IDs + token: str - token used for disconnecting things and channels + + returns: + mf_resp: response.Response - response object. + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> thing_ids = ["fd4f7da5-b7bf-49b7-bf2f-99995e78afd9"] + >>> channel_ids = ["567f7da5-b7bf-49b7-bf2f-99995e78afd9"] + >>> mf_resp = mfsdk.things.disconnects(thing_ids, channel_ids) + >>> mf_resp + """ payload = {"subjects": thing_ids, "objects": channel_ids} http_resp = requests.post( self.URL + "/disconnect", @@ -214,7 +532,31 @@ def disconnects(self, thing_ids: list, channel_ids: list, token: str): return mf_resp def connect(self, thing_id: str, channel_id: str, action: str, token: str): - """Connects thing and channel""" + """Connects thing and channel + + Connects a thing and channel with provided thing ID as the subject, + channel ID as the object, action that the thing can partake in and a + valid token. + + params: + thing_id: str - ID of the thing + channel_id: str - ID of the channel + action: str - action for example: "m_write" + token: str - token used for connecting thing and channel + + returns: + mf_resp: "connected" + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> channel_id = "567f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> action = "m_write" + >>> mf_resp = mfsdk.things.connect(thing_id, channel_id, action) + >>> mf_resp + """ payload= {"subject": thing_id, "object": channel_id, "action": action} http_resp = requests.post( self.URL + "/policies", @@ -232,7 +574,28 @@ def connect(self, thing_id: str, channel_id: str, action: str, token: str): return mf_resp def disconnect(self, thing_id: str, channel_id: str, token: str): - """Disconnect thing and channel""" + """Disconnect thing and channel + + Disconnects a thing and channel with provided thing ID as the subject, + channel ID as the object and a valid token. + + params: + thing_id: str - ID of the thing + channel_id: str - ID of the channel + token: str - token used for disconnecting thing and channel + + returns: + mf_resp: response.Response - response object. + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> channel_id = "567f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> mf_resp = mfsdk.things.disconnect(thing_id, channel_id) + >>> mf_resp + """ payload = {"subject": thing_id, "object": channel_id} http_resp = requests.delete( self.URL + "/policies" + "/" + thing_id + "/" + channel_id, @@ -248,7 +611,32 @@ def disconnect(self, thing_id: str, channel_id: str, token: str): return mf_resp def share_thing(self, user_id: str, channel_id: str, actions: list, token: str): - """Share thing""" + """Share thing + + Allows a logged in user to create new policies for a thing over a channel + provided with a user ID, channel ID, actions that the thing can partake in + and a valid token. + + params: + user_id: str - ID of the user + channel_id: str - ID of the channel + actions: list - list of actions for example: + ["m_write", "m_read"] + token: str - token used for sharing thing + + returns: + mf_resp: "OK" + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> user_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> channel_id = "567f7da5-b7bf-49b7-bf2f-99995e78afd9" + >>> actions = ["m_write", "m_read"] + >>> mf_resp = mfsdk.things.share_thing(user_id, channel_id, actions) + >>> mf_resp + """ payload = {"object": channel_id, "subject": user_id, "actions": actions, "external": True} http_resp = requests.post( self.URL + "/policies", @@ -266,7 +654,38 @@ def share_thing(self, user_id: str, channel_id: str, actions: list, token: str): return mf_resp def authorise_thing(self,access_request: dict, token: str): - """Authorises thing""" + """Authorises thing + + Creates policies for a thing as a subject over a channel which is the object. + It authorizes the thing to perform some actions over the channel. + + params: + + access_request: dict - access request information for example: + { + "subject": "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9", + "object": "567f7da5-b7bf-49b7-bf2f-99995e78afd9", + "actions": "m_write" + "entity_type": "group" + } + token: str - token used for authorising thing + + returns: + mf_resp: "True" + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") + >>> access_request = { + ... "subject": "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9", + ... "object": "567f7da5-b7bf-49b7-bf2f-99995e78afd9", + ... "actions": "m_write" + ... "entity_type": "group" + ... } + >>> mf_resp = mfsdk.things.authorise_thing(access_request) + >>> mf_resp + """ mf_resp = response.Response() http_resp= requests.post( self.URL +"/channels/object/access", diff --git a/mainflux/users.py b/mainflux/users.py index debc2b7..5e33868 100644 --- a/mainflux/users.py +++ b/mainflux/users.py @@ -40,7 +40,6 @@ def create(self, user: dict, token: str = ""): params: user: dict - user information for example: - { "name": "example", "credentials": { @@ -89,10 +88,11 @@ def login(self, user: dict): into the system. params: - user: a dict with the user information and password. - { + user: a dict with the user information and password for example: + {"credentials":{ "identity": "user@mainflux.com", "secret": "12345678" + } } returns: mf_resp: response.Response - response object @@ -101,14 +101,11 @@ def login(self, user: dict): >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") - >>> user = { - ... "name": "example", - ... "credentials": { + >>> credentials= { ... "identity": "user@mainflux.com", ... "secret": "12345678" - ... } ... } - >>> mf_resp = mfsdk.users.login(user) + >>> mf_resp = mfsdk.users.login(credentials) >>> mf_resp """ mf_resp = response.Response() @@ -139,14 +136,7 @@ def refresh_token(self, refresh_token: str): >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") - >>> user = { - ... "name": "example", - ... "credentials": { - ... "identity": "example@mail.com", - ... "secret": "12345678" - ... } - ... } - >>> mf_resp = mfsdk.users.refresh_token(user) + >>> mf_resp = mfsdk.users.refresh_token(refresh_token) >>> mf_resp """ mf_resp = response.Response() @@ -181,7 +171,8 @@ def get(self, user_id: str, token: str): >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id = "886b4266-77d1-4258-abae-2931fb4f16de" - >>> mf_resp = mfsdk.users.get(user) + >>> token = "" + >>> mf_resp = mfsdk.users.get(user_id, token) >>> mf_resp """ mf_resp = response.Response() @@ -218,12 +209,12 @@ def get_all(self, query_params: dict, user_token: str): Usage:: - >>> from mainflux import sdk + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> query_params = { ... "offset" : 0, "limit" : 10 ... } - >>> mf_resp = mfsdk.users.get(user) + >>> mf_resp = mfsdk.users.get(query_params, user_token) >>> mf_resp """ http_resp = requests.get( @@ -249,7 +240,6 @@ def update(self, user: dict, user_token: str): params: user: dict - user information for example: - { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" @@ -271,17 +261,13 @@ def update(self, user: dict, user_token: str): >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { - "name": "example", - "id": "886b4266-77d1-4258-abae-2931fb4f16de" - "credentials": { - "identity": "example@main.com", - "secret": "12345678" - }, - "metadata": { - "foo": "bar" - } - } - >>> mf_resp = mfsdk.users.update(user) + ... "name": "example", + ... "id": "886b4266-77d1-4258-abae-2931fb4f16de" + ... "metadata": { + ... "foo": "bar" + ... } + ... } + >>> mf_resp = mfsdk.users.update(user, token) >>> mf_resp """ http_resp = requests.patch( @@ -328,17 +314,17 @@ def update_user_identity(self, user: dict, user_token: str): >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { - "name": "example", - "id": "886b4266-77d1-4258-abae-2931fb4f16de" - "credentials": { - "identity": "example@main.com", - "secret": "12345678" - }, - "metadata": { - "foo": "bar" - } - } - >>> mf_resp = mfsdk.users.update_user_idenity(user) + ... "name": "example", + ... "id": "886b4266-77d1-4258-abae-2931fb4f16de" + ... "credentials": { + ... "identity": "example@main.com", + ... "secret": "12345678" + ... }, + ... "metadata": { + ... "foo": "bar" + ... } + ... } + >>> mf_resp = mfsdk.users.update_user_identity(user, user_token) >>> mf_resp """ http_resp = requests.patch( @@ -369,13 +355,9 @@ def update_user_tags(self, user: dict, user_token: str): "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" "tags": [ - "yello", - "orange" + "back", + "end" ] - "credentials": { - "identity": "example@main.com", - "secret": "12345678" - }, "metadata": { "foo": "bar" } @@ -390,17 +372,14 @@ def update_user_tags(self, user: dict, user_token: str): >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { - "name": "example", - "id": "886b4266-77d1-4258-abae-2931fb4f16de" - "credentials": { - "identity": "example@main.com", - "secret": "12345678" - }, - "metadata": { - "foo": "bar" - } - } - >>> mf_resp = mfsdk.users.update(user) + ... "name": "example", + ... "id": "886b4266-77d1-4258-abae-2931fb4f16de" + ... "tags": [ + ... "back", + ... "end" + ... ] + ... } + >>> mf_resp = mfsdk.users.update_user_tags(user, user_token) >>> mf_resp """ http_resp = requests.patch( @@ -430,17 +409,6 @@ def update_user_owner(self, user: dict, user_token: str): { "name": "example", "id": "886b4266-77d1-4258-abae-2931fb4f16de" - "tags": [ - "yello", - "orange" - ] - "credentials": { - "identity": "example@main.com", - "secret": "12345678" - }, - "metadata": { - "foo": "bar" - }, "owner": "c52d-3b0d-43b9-8c3e-275c087d875af" } token: str - token used for creating a new user @@ -453,11 +421,11 @@ def update_user_owner(self, user: dict, user_token: str): >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user = { - "name": "example", - "id": "886b4266-77d1-4258-abae-2931fb4f16de", - "owner": "c52d-3b0d-43b9-8c3e-275c087d875af" - } - >>> mf_resp = mfsdk.users.update(user) + ... "name": "example", + ... "id": "886b4266-77d1-4258-abae-2931fb4f16de", + ... "owner": "c52d-3b0d-43b9-8c3e-275c087d875af" + ... } + >>> mf_resp = mfsdk.users.update_user_owner(user, user_token) >>> mf_resp """ http_resp = requests.patch( @@ -493,9 +461,9 @@ def update_password(self, old_secret: str, new_secret: str, user_token: str): >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") - >>> old_secret = old_secret - >>> new_secret = new_secret - >>> mf_resp = mfsdk.users.update(user) + ... old_secret = 12345678 + ... new_secret = 87654321 + >>> mf_resp = mfsdk.users.update(old_secret, new_secret, user_token) >>> mf_resp """ payload = {"old_secret": old_secret, "new_secret": new_secret} @@ -527,6 +495,15 @@ def reset_password_request(self, email: str, url: str): returns: mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + ... email = admin@example.com + ... url = stp@gmail.com + >>> mf_resp = mfsdk.users.reset_password_request(email, url) + >>> mf_resp """ http_resp = requests.post( self.URL + "/password/reset-request", @@ -558,6 +535,15 @@ def reset_password(self, password: str, confirm_password: str, token: str): returns: mf_resp: "OK" + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + ... password = 234567 + ... confirm_password = 234567 + >>> mf_resp = mfsdk.users.reset_password(password, confirm_password, token) + >>> mf_resp """ payload = { "password": password, @@ -595,7 +581,7 @@ def enable(self, user_id: str, user_token: str): >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" - >>> mf_resp = mfsdk.users.enable(user) + >>> mf_resp = mfsdk.users.enable(user_id, user_token) >>> mf_resp """ mf_resp = response.Response() @@ -627,7 +613,7 @@ def disable(self, user_id: str, user_token: str): >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" - >>> mf_resp = mfsdk.users.disable(user) + >>> mf_resp = mfsdk.users.disable(user_id, user_token) >>> mf_resp """ mf_resp = response.Response() @@ -668,8 +654,13 @@ def authorise_user(self, access_request: dict, token: str): >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") - >>> user_id= "886b4266-77d1-4258-abae-2931fb4f16de" - >>> mf_resp = mfsdk.users.authorise_user(user) + >>> access_request = { + ... "subject": "", + ... "object": "", + ... "action": "", + ... "entity_type": "" + ... } + >>> mf_resp = mfsdk.users.authorise_user(access_request, token) >>> mf_resp """ mf_resp = response.Response() From fed7257a1a12ef2537d3abdf5a71a74c11df6f22 Mon Sep 17 00:00:00 2001 From: Musilah Date: Wed, 20 Sep 2023 04:50:54 +0300 Subject: [PATCH 20/31] fix things.py file Signed-off-by: Musilah --- docs/README.md | 2 + docs/things.md | 297 ++++++++++++++++++++++++++++++++++++++++----- mainflux/things.py | 28 ++--- 3 files changed, 280 insertions(+), 47 deletions(-) diff --git a/docs/README.md b/docs/README.md index fc15856..0ab5ddc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,6 +12,7 @@ - [`messages`](./messages.md#module-messages) - [`response`](./response.md#module-response) - [`sdk`](./sdk.md#module-sdk) +- [`things`](./things.md#module-things) - [`users`](./users.md#module-users) - [`utils`](./utils.md#module-utils) @@ -25,6 +26,7 @@ - [`response.Error`](./response.md#class-error) - [`response.Response`](./response.md#class-response) - [`sdk.SDK`](./sdk.md#class-sdk) +- [`things.Things`](./things.md#class-things): Things API client. - [`users.Users`](./users.md#class-users): Users API client. ## Functions diff --git a/docs/things.md b/docs/things.md index 37945ef..d0e74f0 100644 --- a/docs/things.md +++ b/docs/things.md @@ -14,11 +14,18 @@ ## class `Things` +Things API client. +Things API is used for creating and managing things. It is used for creating new things, creating multiple things getting thing information, updating thing information, disabling and enabling things ,and connecting and disconnecting things. - +**Attributes:** + + - `URL`: str - URL of the Things API + - `THINGS_ENDPOINT`: str - Things API endpoint + + ### method `__init__` @@ -35,7 +42,7 @@ __init__(url: str) --- - + ### method `authorise_thing` @@ -43,11 +50,28 @@ __init__(url: str) authorise_thing(access_request: dict, token: str) ``` -Authorises thing +Authorises thing. + +Creates policies for a thing as a subject over a channel which is the object. It authorizes the thing to perform some actions over the channel. + +params: + + access_request: dict - access request information for example: { "subject": "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9", "object": "567f7da5-b7bf-49b7-bf2f-99995e78afd9", "actions": "m_write" "entity_type": "group" } token: str - token used for authorising thing + + + +**returns:** + + - `mf_resp`: "True" + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> access_request = { ... "subject": "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9", ... "object": "567f7da5-b7bf-49b7-bf2f-99995e78afd9", ... "actions": "m_write" ... "entity_type": "group" ... } >>> mf_resp = mfsdk.things.authorise_thing(access_request) >>> mf_resp --- - + ### method `connect` @@ -55,11 +79,26 @@ Authorises thing connect(thing_id: str, channel_id: str, action: str, token: str) ``` -Connects thing and channel +Connects thing and channel. + +Connects a thing and channel with provided thing ID as the subject, channel ID as the object, action that the thing can partake in and a valid token. + +params: thing_id: str - ID of the thing channel_id: str - ID of the channel action: str - action for example: "m_write" token: str - token used for connecting thing and channel + + + +**returns:** + + - `mf_resp`: "connected" + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> channel_id = "567f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> action = "m_write" >>> mf_resp = mfsdk.things.connect(thing_id, channel_id, action) >>> mf_resp --- - + ### method `connects` @@ -67,11 +106,26 @@ Connects thing and channel connects(thing_ids: list, channel_ids: list, actions: list, token: str) ``` -Connects thing and channel +Connects things and channels. + +Connects multiple things and channels with provided thing IDs as the subjects, channel IDs as the objects, actions that the thing can partake in and a valid token. + +params: thing_ids: list - list of thing IDs channel_ids: list - list of channel IDs actions: list - list of actions for example: ["m_write", "m_read"] token: str - token used for connecting things and channels + + + +**returns:** + + - `mf_resp`: response.Response - response object. + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> thing_ids = ["fd4f7da5-b7bf-49b7-bf2f-99995e78afd9"] >>> channel_ids = ["567f7da5-b7bf-49b7-bf2f-99995e78afd9"] >>> actions = ["m_write", "m_read"] >>> mf_resp = mfsdk.things.connects(thing_ids, channel_ids, actions) >>> mf_resp --- - + ### method `create` @@ -79,11 +133,24 @@ Connects thing and channel create(thing: dict, token: str) ``` -Creates thing entity in the database +Creates thing entity in the database. + +Creates a new thing with provided thing information. If token is provided, it will be used to create a new thing + +params: thing: dict - thing information for example: { "name": "thing1" } token: str - token used for creating a new thing + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> thing = { ... "name": "thing1", ... } >>> mf_resp = mfsdk.things.create(thing) >>> mf_resp --- - + ### method `create_bulk` @@ -91,11 +158,24 @@ Creates thing entity in the database create_bulk(things: list, token: str) ``` -Creates multiple things in a bulk +Creates multiple things in bulk. + +Creates multiple new things with provided things information. If a token is provided, it will be used to create the new things. + +params: things: list - a list of things with theri information for example: [ {"name": "thing2"}, {"name": "thing3"}, {"name": "thing4"} ] token: str - token used for creating the new things. + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> things = [ ... {"name": "thing2"}, ... {"name": "thing3"}, ... {"name": "thing4"} ... ] >>> mf_resp = mfsdk.things.create_bulk(things) >>> mf_resp --- - + ### method `disable` @@ -103,11 +183,24 @@ Creates multiple things in a bulk disable(thing_id: str, token: str) ``` -Deletes a thing entity from database +Deletes a thing entity from the database. + +Deletes a thing with provided thing ID and valid token. + +params: thing_id: str - ID of the thing token: str - token used for deleting thing + + + +**returns:** + + - `mf_resp`: response.Response - response object. + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> mf_resp = mfsdk.things.disable(thing_id) >>> mf_resp --- - + ### method `disconnect` @@ -115,11 +208,26 @@ Deletes a thing entity from database disconnect(thing_id: str, channel_id: str, token: str) ``` -Disconnect thing and channel +Disconnects thing and channel. + +Disconnects a thing and channel with provided thing ID as the subject, channel ID as the object and a valid token. + +params: thing_id: str - ID of the thing channel_id: str - ID of the channel token: str - token used for disconnecting thing and channel + + + +**returns:** + + - `mf_resp`: response.Response - response object. + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> channel_id = "567f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> mf_resp = mfsdk.things.disconnect(thing_id, channel_id) >>> mf_resp --- - + ### method `disconnects` @@ -127,11 +235,26 @@ Disconnect thing and channel disconnects(thing_ids: list, channel_ids: list, token: str) ``` -Disconnect thing and channel +Disconnect things and channels. + +Disconnects multiple things and channels with provided thing IDs as the subjects, channel IDs as the objects and a valid token. + +params: thing_ids: list - list of thing IDs channel_ids: list - list of channel IDs token: str - token used for disconnecting things and channels + + + +**returns:** + + - `mf_resp`: response.Response - response object. + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> thing_ids = ["fd4f7da5-b7bf-49b7-bf2f-99995e78afd9"] >>> channel_ids = ["567f7da5-b7bf-49b7-bf2f-99995e78afd9"] >>> mf_resp = mfsdk.things.disconnects(thing_ids, channel_ids) >>> mf_resp --- - + ### method `get` @@ -139,11 +262,24 @@ Disconnect thing and channel get(thing_id: str, token: str) ``` -Gets a thing entity for a logged-in user +Gets a thing entity. + +Provides information about a thing with provided thing ID and token. Information about a thing is provided in a JSON format and includes the name its owner, secret,tags and status. + +params: thing_id: str - ID of the thing token: str - token used for getting thing information + + + +**returns:** + + - `mf_resp`: response.Response - response object. + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> mf_resp = mfsdk.things.get(thing_id) >>> mf_resp --- - + ### method `get_all` @@ -151,11 +287,24 @@ Gets a thing entity for a logged-in user get_all(query_params: dict, token: str) ``` -Gets all things from database +Gets all things from database. + +Provides information about all things in a JSON format. It is controlled by a set of query parameters and a valid token. + +params: query_params: dict - query parameters for example: { "offset": 0, "limit": 10 } where offset is the number of things to skip and limit is the maximum token: str - token used for getting all things information + + + +**returns:** + + - `mf_resp`: response.Response - response object. + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> query_params = { ... "offset": 0, ... "limit": 10 ... } >>> mf_resp = mfsdk.things.get_all(query_params) >>> mf_resp --- - + ### method `get_by_channel` @@ -163,11 +312,20 @@ Gets all things from database get_by_channel(channel_id: str, query_params: dict, token: str) ``` -Gets all things to which a specific thing is connected to +Gets all things to which a specific thing is connected to. + +Provides a list of all things that are connected to a specific channel when given a channel ID and valid token. + +params: channel_id: str - ID of the channel query_params: dict - query parameters for example: { "offset": 0, "limit": 10 } where offset is the number of things to skip and limit is the maximum token: str - token used for getting all things information + +returns: mf_resp: response.Response - response object. + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> channel_id = "567f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> query_params = { ... "offset": 0, ... "limit": 10 ... } >>> mf_resp = mfsdk.things.get_by_channel(channel_id, query_params) >>> mf_resp --- - + ### method `share_thing` @@ -175,11 +333,26 @@ Gets all things to which a specific thing is connected to share_thing(user_id: str, channel_id: str, actions: list, token: str) ``` -Share thing +Shares thing. + +Allows a logged in user to create new policies for a thing over a channel provided with a user ID, channel ID, actions that the thing can partake in and a valid token. + +params: user_id: str - ID of the user channel_id: str - ID of the channel actions: list - list of actions for example: ["m_write", "m_read"] token: str - token used for sharing thing + + + +**returns:** + + - `mf_resp`: "OK" + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> user_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> channel_id = "567f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> actions = ["m_write", "m_read"] >>> mf_resp = mfsdk.things.share_thing(user_id, channel_id, actions) >>> mf_resp --- - + ### method `update` @@ -187,11 +360,24 @@ Share thing update(thing_id: str, thing: dict, token: str) ``` -Updates thing entity +Updates thing entity. + +Allows a logged in user to make changes and update a thing's information with provided thing ID and valid token. Information such as the metadata and name can be updated. + +params: thing_id: str - ID of the thing thing: dict - thing information for example: { "name": "thing1" } token: str - token used for updating thing information + + + +**returns:** + + - `mf_resp`: response.Response - response object. + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> thing = { ... "name": "thing2", ... } >>> mf_resp = mfsdk.things.update(thing_id, thing) >>> mf_resp --- - + ### method `update_thing_owner` @@ -199,11 +385,26 @@ Updates thing entity update_thing_owner(thing_id: str, thing: dict, token: str) ``` -Updates thing secret +Updates thing owner. + +Allows a logged in user to make changes and update a thing's information with provided thing ID and valid token. The thing owner can be updated. + +params: thing_id: str - ID of the thing thing: dict - thing information for example: { "owner": "user1" } token: str - token used for updating thing information + + + +**returns:** + + - `mf_resp`: response.Response - response object. + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> thing = { ... "owner": "user1" ... } >>> mf_resp = mfsdk.things.update_thing_owner(thing_id, thing) >>> mf_resp --- - + ### method `update_thing_secret` @@ -211,11 +412,26 @@ Updates thing secret update_thing_secret(thing_id: str, thing: dict, token: str) ``` -Updates thing secret +Updates thing secret. + +Allows a logged in user to make changes and update a thing's information with provided thing ID and valid token. The thing's secret can be updated. + +params: thing_id: str - ID of the thing thing: dict - thing information for example: { "key": "thing1" } token: str - token used for updating thing information + + + +**returns:** + + - `mf_resp`: response.Response - response object. + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> thing = { ... "key": "thing2", ... } >>> mf_resp = mfsdk.things.update_thing_secret(thing_id, thing) >>> mf_resp --- - + ### method `update_thing_tags` @@ -223,7 +439,22 @@ Updates thing secret update_thing_tags(thing_id: str, thing: dict, token: str) ``` -Updates thing secret +Updates thing tags. + +Allows a logged in user to make changes and update a thing's information with provided thing ID and valid token. The thing's tags can be updated. + +params: thing_id: str - ID of the thing thing: dict - thing information for example: { "tags": ["tag1", "tag2"] } token: str - token used for updating thing information + + + +**returns:** + + - `mf_resp`: response.Response - response object. + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(things_url="http://localhost:9000") >>> thing_id = "fd4f7da5-b7bf-49b7-bf2f-99995e78afd9" >>> thing = { ... "tags": ["tag1", "tag2"] ... } >>> mf_resp = mfsdk.things.update_thing_tags(thing_id, thing) >>> mf_resp diff --git a/mainflux/things.py b/mainflux/things.py index 2c6eb24..024dd59 100644 --- a/mainflux/things.py +++ b/mainflux/things.py @@ -32,7 +32,7 @@ def __init__(self, url: str): None """ def create(self, thing: dict, token: str): - """Creates thing entity in the databas + """Creates thing entity in the database. Creates a new thing with provided thing information. If token is provided, it will be used to create a new thing @@ -72,7 +72,7 @@ def create(self, thing: dict, token: str): mf_resp.value = http_resp.json() return mf_resp - def create_bulk(self, things: list, token: str) + def create_bulk(self, things: list, token: str): """Creates multiple things in bulk. Creates multiple new things with provided things information. @@ -118,7 +118,7 @@ def create_bulk(self, things: list, token: str) return mf_resp def get(self, thing_id: str, token: str): - """Gets a thing entity for a logged-in user + """Gets a thing entity. Provides information about a thing with provided thing ID and token. Information about a thing is provided in a JSON format and includes the name @@ -244,7 +244,7 @@ def get_by_channel(self, channel_id: str, query_params: dict, token: str): return mf_resp def update(self, thing_id: str, thing: dict, token: str): - """Updates thing entity + """Updates thing entity. Allows a logged in user to make changes and update a thing's information with provided thing ID and valid token. Information @@ -288,7 +288,7 @@ def update(self, thing_id: str, thing: dict, token: str): return mf_resp def update_thing_secret(self, thing_id: str, thing: dict, token: str): - """Updates thing secret + """Updates thing secret. Allows a logged in user to make changes and update a thing's information with provided thing ID and valid token. The thing's @@ -332,7 +332,7 @@ def update_thing_secret(self, thing_id: str, thing: dict, token: str): return mf_resp def update_thing_tags(self, thing_id: str, thing: dict, token: str): - """Updates thing tags + """Updates thing tags. Allows a logged in user to make changes and update a thing's information with provided thing ID and valid token. The thing's @@ -376,7 +376,7 @@ def update_thing_tags(self, thing_id: str, thing: dict, token: str): return mf_resp def update_thing_owner(self, thing_id: str, thing: dict, token: str): - """Updates thing owner + """Updates thing owner. Allows a logged in user to make changes and update a thing's information with provided thing ID and valid token. The thing @@ -420,7 +420,7 @@ def update_thing_owner(self, thing_id: str, thing: dict, token: str): return mf_resp def disable(self, thing_id: str, token: str): - """Deletes a thing entity from database. + """Deletes a thing entity from the database. Deletes a thing with provided thing ID and valid token. @@ -452,7 +452,7 @@ def disable(self, thing_id: str, token: str): return mf_resp def connects(self, thing_ids: list, channel_ids: list, actions: list, token: str): - """Connects thing and channel. + """Connects things and channels. Connects multiple things and channels with provided thing IDs as the subjects, channel IDs as the objects, actions that the @@ -495,7 +495,7 @@ def connects(self, thing_ids: list, channel_ids: list, actions: list, token: str return mf_resp def disconnects(self, thing_ids: list, channel_ids: list, token: str): - """Disconnect thing and channel + """Disconnect things and channels. Disconnects multiple things and channels with provided thing IDs as the subjects, channel IDs as the objects and a valid token. @@ -532,7 +532,7 @@ def disconnects(self, thing_ids: list, channel_ids: list, token: str): return mf_resp def connect(self, thing_id: str, channel_id: str, action: str, token: str): - """Connects thing and channel + """Connects thing and channel. Connects a thing and channel with provided thing ID as the subject, channel ID as the object, action that the thing can partake in and a @@ -574,7 +574,7 @@ def connect(self, thing_id: str, channel_id: str, action: str, token: str): return mf_resp def disconnect(self, thing_id: str, channel_id: str, token: str): - """Disconnect thing and channel + """Disconnects thing and channel. Disconnects a thing and channel with provided thing ID as the subject, channel ID as the object and a valid token. @@ -611,7 +611,7 @@ def disconnect(self, thing_id: str, channel_id: str, token: str): return mf_resp def share_thing(self, user_id: str, channel_id: str, actions: list, token: str): - """Share thing + """Shares thing. Allows a logged in user to create new policies for a thing over a channel provided with a user ID, channel ID, actions that the thing can partake in @@ -654,7 +654,7 @@ def share_thing(self, user_id: str, channel_id: str, actions: list, token: str): return mf_resp def authorise_thing(self,access_request: dict, token: str): - """Authorises thing + """Authorises thing. Creates policies for a thing as a subject over a channel which is the object. It authorizes the thing to perform some actions over the channel. From 974e3b49aca2dd82ddd515612e5efa69facda37e Mon Sep 17 00:00:00 2001 From: Musilah Date: Fri, 22 Sep 2023 12:22:04 +0300 Subject: [PATCH 21/31] remove auth_url Signed-off-by: Musilah --- examples/examples.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/examples.py b/examples/examples.py index a1c172c..d1dddb2 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -8,8 +8,7 @@ reader_url=default_url + ":9204", http_adapter_url=default_url, certs_url=default_url + ":9019", - bootstrap_url=default_url + ":9013", - auth_url=default_url, + bootstrap_url=default_url + ":9013" ) """To start working with the Mainflux system, From ee0014d03a57aae479470fa0b0f0836908117981 Mon Sep 17 00:00:00 2001 From: Musilah Date: Fri, 22 Sep 2023 14:06:54 +0300 Subject: [PATCH 22/31] fix users.py file and add groups.py docstrings Signed-off-by: Musilah --- docs/README.md | 2 +- docs/groups.md | 194 +++++++++++++++++++++-- docs/users.md | 14 +- examples/examples.py | 2 +- mainflux/groups.py | 355 ++++++++++++++++++++++++++++++++++++++++--- mainflux/users.py | 10 +- 6 files changed, 524 insertions(+), 53 deletions(-) diff --git a/docs/README.md b/docs/README.md index 0ab5ddc..832574f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,7 +21,7 @@ - [`boostrap.Bootstrap`](./boostrap.md#class-bootstrap) - [`certs.Certs`](./certs.md#class-certs) - [`channels.Channels`](./channels.md#class-channels) -- [`groups.Groups`](./groups.md#class-groups) +- [`groups.Groups`](./groups.md#class-groups): Groups class provides the abstraction of the Mainflux groups service API. - [`messages.Messages`](./messages.md#class-messages) - [`response.Error`](./response.md#class-error) - [`response.Response`](./response.md#class-response) diff --git a/docs/groups.md b/docs/groups.md index f58663a..0ac8354 100644 --- a/docs/groups.md +++ b/docs/groups.md @@ -14,11 +14,18 @@ ## class `Groups` +Groups class provides the abstraction of the Mainflux groups service API. +Groups class provides the following functionality: create, get, get_all, parents, children, update, members, memberships, assign, unassign, disable. - +**Attributes:** + + - `URL`: Mainflux groups service URL. + - `GROUPS_ENDPOINT`: Mainflux groups service API endpoint. + + ### method `__init__` @@ -35,7 +42,7 @@ __init__(url: str) --- - + ### method `assign` @@ -45,9 +52,24 @@ assign(group_id: str, member_id: str, member_type: list, token: str) Assign +Assigns a member to a group when provided with group_id, member_id, member_type which is their action and a token. + +params: group_id: str - group id member_id: str - member id member_type: list - actions the member can perform for example: [ "m_read", "m_write", "m_admin" ] token: str - token used to assign a member to a group. + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> group_id = "group_id" >>> member_id = "member_id" >>> member_type = [ ... "m_read", "m_write", "m_admin" ... ] >>> mf_resp = mfsdk.groups.assign(group_id, member_id, member_type) >>> mf_resp + --- - + ### method `children` @@ -57,9 +79,24 @@ children(group_id: str, query_params: dict, token: str) Gets children for a specific group from database +Provides information about children for a specific group from database when provided with group_id, query_params and token. + +params: group_id: str - group id of the parent group in question. query_params: dict - query parameters for example: { "offset": 0, "limit": 10, } where offset is the number of items to skip before starting to collect the result set and limit is the numbers of items to return. token: str - token used to get children for a specific group. + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> group_id = "group_id" >>> query_params = { ... "offset": 0, ... "limit": 10, ... } >>> mf_resp = mfsdk.groups.children(group_id, query_params) >>> mf_resp + --- - + ### method `create` @@ -67,11 +104,26 @@ Gets children for a specific group from database create(group: dict, token: str) ``` -Creates group entity in the database +Creates a group entity in the database. + +Creates a group entity in the database using the provided group object and token. + +params: group: dict - group information for example: { "name": "groupName", } token: str - token used to create a new group. + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> group = { ... "name": "groupName", ... } >>> mf_resp = mfsdk.groups.create(group) >>> mf_resp --- - + ### method `disable` @@ -81,9 +133,22 @@ disable(group_id: str, user_token: str) Disables a group entity from database +Deletes a group from the database when provided with group_id and user_token. + +params: group_id: str - group id user_token: str - token used to delete a group. + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> group_id = "group_id" >>> mf_resp = mfsdk.groups.disable(group_id) >>> mf_resp + --- - + ### method `get` @@ -93,9 +158,24 @@ get(group_id: str, token: str) Gets a group entity +Provides information about a group entity using the provided group_id and a token. + +params: group_id: str - group id token: str - token used to get a group. + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> group_id = "group_id" >>> mf_resp = mfsdk.groups.get(group_id) >>> mf_resp + --- - + ### method `get_all` @@ -105,9 +185,24 @@ get_all(query_params: dict, token: str) Gets all groups from database +Gets all groups from database using the provided query_params and token. + +params: query_params: dict - query parameters for example: { "offset": 0, "limit": 10, } where offset is the number of items to skip before starting to collect the result set and limit is the numbers of items to return. token: str - token used to get all groups. + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> query_params = { ... "offset": 0, ... "limit": 10, ... } >>> mf_resp = mfsdk.groups.get_all(query_params) >>> mf_resp + --- - + ### method `members` @@ -117,9 +212,24 @@ members(group_id: str, query_params: dict, token: str) Gets members associated with the group specified by id +Provides information about members associated with the group specified by id when provided with group_id, query_params and token. + +params: group_id: str - group id query_params: dict - query parameters for example: { "offset": 0, "limit": 10, } where offset is the number of items to skip before starting to collect the result set and limit is the numbers of items to return. token: str - token used to get members associated with the group specified by id. + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> group_id = "group_id" >>> query_params = { ... "offset": 0, ... "limit": 10, ... } >>> mf_resp = mfsdk.groups.members(group_id, query_params) >>> mf_resp + --- - + ### method `memberships` @@ -127,11 +237,24 @@ Gets members associated with the group specified by id memberships(member_id: str, query_params: dict, token: str) ``` -Get list of members ID's from group +Retrieves a list of groups the user is connected to + +Retrieves a list of groups the user is connected to when provided with the users id, query_params and token. + +params: member_id: str - user id query_params: dict - query parameters for example: { "offset": 0, "limit": 10, } where offset is the number of items to skip before starting to collect the result set and limit is the numbers of items to return. token: str - token used to retrieve a list of groups the user is connected to. + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> member_id = "member_id" >>> query_params = { ... "offset": 0, ... "limit": 10, ... } >>> mf_resp = mfsdk.groups.memberships(member_id, query_params) >>> mf_resp --- - + ### method `parents` @@ -141,9 +264,24 @@ parents(group_id: str, query_params: dict, token: str) Gets parents for a specific group from database +Provides information about parents for a specific group from database when provided with group_id, query_params and token. + +params: group_id: str - group id of the child group in question. query_params: dict - query parameters for example: { "offset": 0, "limit": 10, } where offset is the number of items to skip before starting to collect the result set and limit is the numbers of items to return. token: str - token used to get parents for a specific group. + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` + + >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> group_id = "group_id" >>> query_params = { ... "offset": 0, ... "limit": 10, ... } >>> mf_resp = mfsdk.groups.parents(group_id, query_params) >>> mf_resp + --- - + ### method `unassign` @@ -153,9 +291,22 @@ unassign(group_id: str, token: str, members_ids) Unassign +Deletes a user's policy from over a group when provided with group_id, token and members_ids. + +params: group_id: str - group id token: str - token used to delete a user's policy from over a group. members_ids: str - member id + + + +**returns:** + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> group_id = "group_id" >>> members_ids = "members_ids" >>> mf_resp = mfsdk.groups.unassign(group_id, members_ids) >>> mf_resp + --- - + ### method `update` @@ -165,6 +316,21 @@ update(group_id: str, group: dict, token: str) Updates group entity +Updates a group entity in the database using the provided group_id, group object and token. It updates the group name and metadata. + +params: group_id: str - group id group: dict - group information for example: { "name": "groupName", } token: str - token used to update a group. + + + +**returns:** + + + + - `mf_resp`: response.Response - response object + +Usage: +``` >>> from mainflux import sdk >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") >>> group_id = "group_id" >>> group = { ... "name": "groupName", ... } >>> mf_resp = mfsdk.groups.update(group_id, group) >>> mf_resp + diff --git a/docs/users.md b/docs/users.md index c2924bd..0aea505 100644 --- a/docs/users.md +++ b/docs/users.md @@ -11,7 +11,7 @@ --- - + ## class `Users` Users API client. @@ -25,7 +25,7 @@ Users API is used for creating and managing users. It is used for creating new u - `URL`: str - URL of the Users API - `USERS_ENDPOINT`: str - Users API endpoint - + ### method `__init__` @@ -67,7 +67,7 @@ Usage: --- - + ### method `create` @@ -140,7 +140,7 @@ Usage: --- - + ### method `get` @@ -165,7 +165,7 @@ Usage: --- - + ### method `get_all` @@ -192,7 +192,7 @@ Usage: --- - + ### method `login` @@ -217,7 +217,7 @@ Usage: --- - + ### method `refresh_token` diff --git a/examples/examples.py b/examples/examples.py index d1dddb2..619159c 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -129,7 +129,7 @@ print(mf_resp.value) else: print(mf_resp.error.message) - + """Disables user""" mf_resp = mfsdk.users.disable(user_id="", user_token="") if mf_resp.error.status == 0: diff --git a/mainflux/groups.py b/mainflux/groups.py index 6638d1e..af34012 100644 --- a/mainflux/groups.py +++ b/mainflux/groups.py @@ -6,16 +6,60 @@ class Groups: - groups_endpoint = "groups" + """Groups class provides the abstraction of the Mainflux groups service API. + + Groups class provides the following functionality: create, get, get_all, parents, + children, update, members, memberships, assign, unassign, disable. + + Attributes: + URL: Mainflux groups service URL. + GROUPS_ENDPOINT: Mainflux groups service API endpoint. + + """ + GROUPS_ENDPOINT = "groups" def __init__(self, url: str): - self.url = url - + self.URL = url + """Initializes Groups API client with the provided URL. + + params: + url: Mainflux groups service URL. + + returns: + Groups object. + + raises: + None. + """ def create(self, group: dict, token: str): - """Creates group entity in the database""" + """Creates a group entity in the database. + + Creates a group entity in the database using the provided group + object and token. + + params: + group: dict - group information for example: + { + "name": "groupName", + } + token: str - token used to create a new group. + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> group = { + ... "name": "groupName", + ... } + >>> mf_resp = mfsdk.groups.create(group) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.post( - self.url + "/" + self.groups_endpoint, + self.URL + "/" + self.GROUPS_ENDPOINT, json=group, headers=utils.construct_header(token, utils.CTJSON), ) @@ -29,10 +73,29 @@ def create(self, group: dict, token: str): return mf_resp def get(self, group_id: str, token: str): - """Gets a group entity""" + """Gets a group entity + + Provides information about a group entity using the provided group_id + and a token. + + params: + group_id: str - group id + token: str - token used to get a group. + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> group_id = "group_id" + >>> mf_resp = mfsdk.groups.get(group_id) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.groups_endpoint + "/" + group_id, + self.URL + "/" + self.GROUPS_ENDPOINT + "/" + group_id, headers=utils.construct_header(token, utils.CTJSON), ) if http_resp.status_code != 200: @@ -45,10 +108,37 @@ def get(self, group_id: str, token: str): return mf_resp def get_all(self, query_params: dict, token: str): - """Gets all groups from database""" + """Gets all groups from database + + Gets all groups from database using the provided query_params and token. + + params: + query_params: dict - query parameters for example: + { + "offset": 0, + "limit": 10, + } + where offset is the number of items to skip before starting to collect + the result set and limit is the numbers of items to return. + token: str - token used to get all groups. + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> query_params = { + ... "offset": 0, + ... "limit": 10, + ... } + >>> mf_resp = mfsdk.groups.get_all(query_params) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.groups_endpoint, + self.URL + "/" + self.GROUPS_ENDPOINT, headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -62,11 +152,41 @@ def get_all(self, query_params: dict, token: str): return mf_resp def parents(self, group_id: str, query_params: dict, token: str): - """Gets parents for a specific group from database""" + """Gets parents for a specific group from database + + Provides information about parents for a specific group from database + when provided with group_id, query_params and token. + + params: + group_id: str - group id of the child group in question. + query_params: dict - query parameters for example: + { + "offset": 0, + "limit": 10, + } + where offset is the number of items to skip before starting to collect + the result set and limit is the numbers of items to return. + token: str - token used to get parents for a specific group. + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> group_id = "group_id" + >>> query_params = { + ... "offset": 0, + ... "limit": 10, + ... } + >>> mf_resp = mfsdk.groups.parents(group_id, query_params) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.groups_endpoint + "/" + group_id + "/parents", + self.URL + "/" + self.GROUPS_ENDPOINT + "/" + group_id + "/parents", headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -80,10 +200,40 @@ def parents(self, group_id: str, query_params: dict, token: str): return mf_resp def children(self, group_id: str, query_params: dict, token: str): - """Gets children for a specific group from database""" + """Gets children for a specific group from database + + Provides information about children for a specific group from database + when provided with group_id, query_params and token. + + params: + group_id: str - group id of the parent group in question. + query_params: dict - query parameters for example: + { + "offset": 0, + "limit": 10, + } + where offset is the number of items to skip before starting to collect + the result set and limit is the numbers of items to return. + token: str - token used to get children for a specific group. + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> group_id = "group_id" + >>> query_params = { + ... "offset": 0, + ... "limit": 10, + ... } + >>> mf_resp = mfsdk.groups.children(group_id, query_params) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.groups_endpoint + "/" + group_id + "/children", + self.URL + "/" + self.GROUPS_ENDPOINT + "/" + group_id + "/children", headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -97,9 +247,36 @@ def children(self, group_id: str, query_params: dict, token: str): return mf_resp def update(self, group_id: str, group: dict, token: str): - """Updates group entity""" + """Updates group entity + + Updates a group entity in the database using the provided group_id, + group object and token. It updates the group name and metadata. + + params: + group_id: str - group id + group: dict - group information for example: + { + "name": "groupName", + } + token: str - token used to update a group. + + returns: + + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> group_id = "group_id" + >>> group = { + ... "name": "groupName", + ... } + >>> mf_resp = mfsdk.groups.update(group_id, group) + >>> mf_resp + """ http_resp = requests.put( - self.url + "/" + self.groups_endpoint + "/" + group_id, + self.URL + "/" + self.GROUPS_ENDPOINT + "/" + group_id, data=group, headers=utils.construct_header(token, utils.CTJSON), ) @@ -114,9 +291,39 @@ def update(self, group_id: str, group: dict, token: str): return mf_resp def members(self, group_id: str, query_params: dict, token: str): - """Gets members associated with the group specified by id""" + """Gets members associated with the group specified by id + + Provides information about members associated with the group specified by id + when provided with group_id, query_params and token. + + params: + group_id: str - group id + query_params: dict - query parameters for example: + { + "offset": 0, + "limit": 10, + } + where offset is the number of items to skip before starting to collect + the result set and limit is the numbers of items to return. + token: str - token used to get members associated with the group specified by id. + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> group_id = "group_id" + >>> query_params = { + ... "offset": 0, + ... "limit": 10, + ... } + >>> mf_resp = mfsdk.groups.members(group_id, query_params) + >>> mf_resp + """ http_resp = requests.get( - self.url + "/" + self.groups_endpoint + "/" + group_id + "/members", + self.URL + "/" + self.GROUPS_ENDPOINT + "/" + group_id + "/members", headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -131,9 +338,39 @@ def members(self, group_id: str, query_params: dict, token: str): return mf_resp def memberships(self, member_id: str, query_params: dict, token: str): - """Get list of members ID's from group""" + """Retrieves a list of groups the user is connected to + + Retrieves a list of groups the user is connected to when provided with + the users id, query_params and token. + + params: + member_id: str - user id + query_params: dict - query parameters for example: + { + "offset": 0, + "limit": 10, + } + where offset is the number of items to skip before starting to collect + the result set and limit is the numbers of items to return. + token: str - token used to retrieve a list of groups the user is connected to. + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> member_id = "member_id" + >>> query_params = { + ... "offset": 0, + ... "limit": 10, + ... } + >>> mf_resp = mfsdk.groups.memberships(member_id, query_params) + >>> mf_resp + """ http_resp = requests.get( - self.url + "/users" + "/" + member_id + "/memberships", + self.URL + "/users" + "/" + member_id + "/memberships", headers=utils.construct_header(token, utils.CTJSON), params=query_params, ) @@ -148,11 +385,39 @@ def memberships(self, member_id: str, query_params: dict, token: str): return mf_resp def assign(self, group_id: str, member_id: str, member_type: list, token: str): - """Assign""" + """Assign + + Assigns a member to a group when provided with group_id, member_id, + member_type which is their action and a token. + + params: + group_id: str - group id + member_id: str - member id + member_type: list - actions the member can perform for example: + [ + "m_read", "m_write", "m_admin" + ] + token: str - token used to assign a member to a group. + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> group_id = "group_id" + >>> member_id = "member_id" + >>> member_type = [ + ... "m_read", "m_write", "m_admin" + ... ] + >>> mf_resp = mfsdk.groups.assign(group_id, member_id, member_type) + >>> mf_resp + """ payload = {"object": group_id, "subject": member_id, "actions": member_type} mf_resp = response.Response() http_resp = requests.post( - self.url + "/users/policies", + self.URL + "/users/policies", headers=utils.construct_header(token, utils.CTJSON), json=payload, ) @@ -164,11 +429,32 @@ def assign(self, group_id: str, member_id: str, member_type: list, token: str): return mf_resp def unassign(self, group_id: str, token: str, members_ids): - """Unassign""" + """Unassign + + Deletes a user's policy from over a group when provided with group_id, + token and members_ids. + + params: + group_id: str - group id + token: str - token used to delete a user's policy from over a group. + members_ids: str - member id + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> group_id = "group_id" + >>> members_ids = "members_ids" + >>> mf_resp = mfsdk.groups.unassign(group_id, members_ids) + >>> mf_resp + """ payload = {"Object": group_id, "Subject": members_ids} mf_resp = response.Response() http_resp = requests.delete( - self.url + "/users/policies" + "/" + members_ids + "/" + group_id, + self.URL + "/users/policies" + "/" + members_ids + "/" + group_id, headers=utils.construct_header(token, utils.CTJSON), json=payload, ) @@ -180,9 +466,28 @@ def unassign(self, group_id: str, token: str, members_ids): return mf_resp def disable(self, group_id: str, user_token: str): - """Disables a group entity from database""" + """Disables a group entity from database + + Deletes a group from the database when provided with group_id and + user_token. + + params: + group_id: str - group id + user_token: str - token used to delete a group. + + returns: + mf_resp: response.Response - response object + + Usage:: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(users_url="http://localhost:9002") + >>> group_id = "group_id" + >>> mf_resp = mfsdk.groups.disable(group_id) + >>> mf_resp + """ http_resp = requests.post( - self.url + "/" + self.groups_endpoint + "/" + group_id + "/disable", + self.URL + "/" + self.GROUPS_ENDPOINT + "/" + group_id + "/disable", headers=utils.construct_header(user_token, utils.CTJSON), ) mf_resp = response.Response() diff --git a/mainflux/users.py b/mainflux/users.py index 5e33868..a652bcf 100644 --- a/mainflux/users.py +++ b/mainflux/users.py @@ -1,4 +1,5 @@ import requests +import json from mainflux import response from mainflux import errors @@ -222,7 +223,6 @@ def get_all(self, query_params: dict, user_token: str): headers=utils.construct_header(user_token, utils.CTJSON), params=query_params, ) - print(http_resp.url) mf_resp = response.Response() if http_resp.status_code != 200: mf_resp.error.status = 1 @@ -273,7 +273,7 @@ def update(self, user: dict, user_token: str): http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"], headers=utils.construct_header(user_token, utils.CTJSON), - data=user, + data=json.dumps(user), ) mf_resp = response.Response() if http_resp.status_code != 200: @@ -330,7 +330,7 @@ def update_user_identity(self, user: dict, user_token: str): http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"] + "/identity", headers=utils.construct_header(user_token, utils.CTJSON), - data=user, + data= json.dumps(user), ) mf_resp = response.Response() if http_resp.status_code != 200: @@ -385,7 +385,7 @@ def update_user_tags(self, user: dict, user_token: str): http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"] + "/tags", headers=utils.construct_header(user_token, utils.CTJSON), - data=user, + data=json.dumps(user), ) mf_resp = response.Response() if http_resp.status_code != 200: @@ -431,7 +431,7 @@ def update_user_owner(self, user: dict, user_token: str): http_resp = requests.patch( self.URL + "/" + self.USERS_ENDPOINT + "/" + user["id"] + "/owner", headers=utils.construct_header(user_token, utils.CTJSON), - data=user, + data=json.dumps(user), ) mf_resp = response.Response() if http_resp.status_code != 200: From 053c4c4cf70a994a5ba880619474a172d277b56c Mon Sep 17 00:00:00 2001 From: Musilah Date: Mon, 25 Sep 2023 12:04:37 +0300 Subject: [PATCH 23/31] update docstrings Signed-off-by: Musilah --- docs/README.md | 6 +- docs/boostrap.md | 202 ++++++++++++++++++++++++++++++++-- docs/certs.md | 108 ++++++++++++++++++- docs/channels.md | 250 +++++++++++++++++++++++++++++++++++++++--- docs/users.md | 12 +-- examples/examples.py | 4 +- mainflux/boostrap.py | 199 ++++++++++++++++++++++++++++++++-- mainflux/certs.py | 105 ++++++++++++++++-- mainflux/channels.py | 251 +++++++++++++++++++++++++++++++++++++++++-- mainflux/users.py | 8 +- 10 files changed, 1082 insertions(+), 63 deletions(-) diff --git a/docs/README.md b/docs/README.md index 832574f..4f553ee 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,9 +18,9 @@ ## Classes -- [`boostrap.Bootstrap`](./boostrap.md#class-bootstrap) -- [`certs.Certs`](./certs.md#class-certs) -- [`channels.Channels`](./channels.md#class-channels) +- [`boostrap.Bootstrap`](./boostrap.md#class-bootstrap): Bootstrap service API client. +- [`certs.Certs`](./certs.md#class-certs): Mainflux Certificates API +- [`channels.Channels`](./channels.md#class-channels): Channels class provides the abstraction of the Mainflux Channels API. - [`groups.Groups`](./groups.md#class-groups): Groups class provides the abstraction of the Mainflux groups service API. - [`messages.Messages`](./messages.md#class-messages) - [`response.Error`](./response.md#class-error) diff --git a/docs/boostrap.md b/docs/boostrap.md index 7467361..8cf4128 100644 --- a/docs/boostrap.md +++ b/docs/boostrap.md @@ -14,11 +14,23 @@ ## class `Bootstrap` +Bootstrap service API client. +Bootstrap service is used to manage configurations for Mainflux Things. It provides services such as updating, viewing, removing and adding new configurations. - +**Attributes:** + + - `url` (str): Mainflux Bootstrap API URL. + - `CONFIGS_ENDPOINT` (str): Configurations API endpoint. + - `BOOTSTRAP_ENDPOINT` (str): Bootstrap API endpoint. + - `WHITELIST_ENDPOINT` (str): Whitelist API endpoint. + - `BOOTSTRAP_CERTS_ENDPOINT` (str): Bootstrap certificates API endpoint. + + + + ### method `__init__` @@ -26,16 +38,27 @@ __init__(url: str) ``` +Initializes Bootstrap with the provided URL. + +params: url (str): Mainflux Bootstrap API URL. + +**returns:** + + - `Bootstrap`: Bootstrap object. +**raises:** + None + + --- - + ### method `add` @@ -45,9 +68,38 @@ add(config: dict, token: str) Adds new config to the list of config owned by user identified using the provided access token. +Some of the key data needed include the external_key and external_id which must be specific to the thing provided with the thing_id. + +params: config (dict): Configuration data for example: { "external_id": "123", "external_key": "456", "thing_id": "fdb1057c-2905-4f71-9a80-e0ce9191e667", "name": "thing_name" } token (str): Authorization token. + + + +**returns:** + + - `mf_response `: response.Response. + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + >>> config = { + + - ` ... "external_id"`: "123", + + - ` ... "external_key"`: "456", + + - ` ... "thing_id"`: "fdb1057c-2905-4f71-9a80-e0ce9191e667", + + - ` ... "name"`: "thing_name" + ... } + >>> mf_resp = mfsdk.bootstrap.add(config, token) + >>> mf_resp + + --- - + ### method `bootstrap` @@ -57,9 +109,28 @@ bootstrap(external_id: str, external_key: str) Retrieves a configuration with given external ID and external key. +params: external_id (str): External ID. external_key (str): External key. + + + +**returns:** + + - `mf_resp `: response.Response - response object. + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + >>> external_id = "external_id" + >>> external_key = "external_key" + >>> mf_resp = mfsdk.bootstrap.bootstrap(external_id, external_key) + >>> mf_resp + + --- - + ### method `remove` @@ -69,9 +140,27 @@ remove(config_id: str, token: str) Removes a Config. In case of successful removal the service will ensure that the removed config is disconnected from all the Mainflux channels. +params: config_id (str): Configuration ID. token (str): Authorization token. + + + +**returns:** + + - `mf_response `: response.Response. + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + >>> config_id = "config_id" + >>> mf_resp = mfsdk.bootstrap.remove(config_id, token) + >>> mf_resp + + --- - + ### method `update` @@ -81,9 +170,38 @@ update(config: dict, token: str) Update is performed by replacing the current resource data with values provided in a request payload. Note that the owner, ID, external ID, external key, Mainflux Thing ID and key cannot be changed. +params: config (dict): Configuration data for example: { "external_id": "123", "external_key": "456", "thing_id": "fdb1057c-2905-4f71-9a80-e0ce9191e667", "name": "thing_name" } token (str): Authorization token. + + + +**returns:** + + + + - `mf_response `: response.Response. + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + >>> config = { + + - ` ... "external_id"`: "123", + + - ` ... "external_key"`: "456", + + - ` ... "thing_id"`: "fdb1057c-2905-4f71-9a80-e0ce9191e667", + + - ` ... "name"`: "thing_name" + ... } + >>> mf_resp = mfsdk.bootstrap.update(config, token) + >>> mf_resp + + --- - + ### method `update_certs` @@ -99,9 +217,30 @@ update_certs( Update is performed by replacing the current certificate data with values provided in a request payload. +params: config_id (str): Configuration ID. client_cert (str): Client certificate. client_key (str): Client key. ca (str): CA certificate. token (str): Authorization token. + + + +**returns:** + + - `mf_response `: response.Response. + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + >>> config_id = "config_id" + >>> client_cert = "client_cert" + >>> client_key = "client_key" + >>> ca = "ca" + >>> mf_resp = mfsdk.bootstrap.update_certs(config_id, client_cert, client_key, ca, token) + >>> mf_resp + + --- - + ### method `view` @@ -111,9 +250,29 @@ view(thing_id: str, token: str) Retrieves a configuration with given config id +Provides a configuration with given config id. + +params: thing_id (str): Thing ID. token (str): Authorization token. + + + +**returns:** + + - `mf_resp `: response.Response - response object. + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + >>> thing_id = "thing_id" + >>> mf_resp = mfsdk.bootstrap.view(thing_id, token) + >>> mf_resp + + --- - + ### method `whitelist` @@ -123,6 +282,33 @@ whitelist(config: dict, token: str) Updating state represents enabling/disabling Config, i.e.connecting and disconnecting corresponding Mainflux Thing to the list of Channels. +params: config (dict): Configuration data for example: { "external_id": "123", "external_key": "456", "thing_id": "fdb1057c-2905-4f71-9a80-e0ce9191e667", "name": "thing_name" } token (str): Authorization token. + + + +**returns:** + + - `mf_response `: response.Response. + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + >>> config = { + + - ` ... "external_id"`: "123", + + - ` ... "external_key"`: "456", + + - ` ... "thing_id"`: "fdb1057c-2905-4f71-9a80-e0ce9191e667", + + - ` ... "name"`: "thing_name" + ... } + >>> mf_resp = mfsdk.bootstrap.whitelist(config, token) + >>> mf_resp + + diff --git a/docs/certs.md b/docs/certs.md index 2e0acd2..c096cd4 100644 --- a/docs/certs.md +++ b/docs/certs.md @@ -14,11 +14,18 @@ ## class `Certs` +Mainflux Certificates API +Certs is used to issue, view, and revoke certificates. It is used to issue certificates for things. - +**Args:** + + - `url` (str): Mainflux Certificates API URL. + - `CERTS_ENDPOINT` (str): Certificates API endpoint. + + ### method `__init__` @@ -26,16 +33,26 @@ __init__(url: str) ``` +Initializes Certs with the provided URL. + + +**Args:** + + - `url` (str): Mainflux Certificates API URL. +**Returns:** + + - `Certs`: Certs object. + --- - + ### method `issue` @@ -43,13 +60,34 @@ __init__(url: str) issue(thing_id: str, valid: str, token: str) ``` +Issues a certificate for a given thing ID. + + + +**Args:** + + - `thing_id` (str): Thing ID. + - `valid` (str): Certificate validity period. + - `token` (str): Authorization token. + + +**Returns:** + + - `Response`: Mainflux response. +Usage: ``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(certs_url="http`: //localhost:9019") + >>> thing_id = "thing_id" + >>> valid = "1h" + >>> mf_resp = mfsdk.certs.issue(thing_id, valid) + >>> mf_resp --- - + ### method `revoke` @@ -57,13 +95,31 @@ issue(thing_id: str, valid: str, token: str) revoke(thing_id: str, token: str) ``` +Revokes a certificate for a given thing ID. + +Deletes a certificate for a given thing ID and valid token. + +params: thing_id (str): thing id token (str): valid authorization token used to delete the certificate + + +**Returns:** + + - `mf_resp `: response.Response - response object. +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(certs_url="http`: //localhost:9019") + >>> thing_id = "thing_id" + >>> mf_resp = mfsdk.certs.revoke(thing_id) + >>> mf_resp --- - + ### method `view_by_serial` @@ -73,9 +129,31 @@ view_by_serial(cert_id: str, token: str) Retrieves a certificate for a given cert ID. +Provides a certificate for a given cert ID. + +Params: + + cert_id (str): Certificate ID. token (str): Authorization token. + + + +**Returns:** + + - `mf_resp `: response.Response - response object. + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(certs_url="http`: //localhost:9019") + >>> cert_id = "cert_id" + >>> mf_resp = mfsdk.certs.view_by_serial(cert_id) + >>> mf_resp + + --- - + ### method `view_by_thing` @@ -85,6 +163,26 @@ view_by_thing(thing_id: str, token: str) Retrieves a list of certificates' serial IDs for a given thing ID. +Provides a list of certificates' serial IDs for a given thing ID. + +Params: thing_id (str): Thing ID. token (str): Authorization token. + + + +**Returns:** + + - `mf_resp `: response.Response - response object. + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(certs_url="http`: //localhost:9019") + >>> thing_id = "thing_id" + >>> mf_resp = mfsdk.certs.view_by_thing(thing_id) + >>> mf_resp + + diff --git a/docs/channels.md b/docs/channels.md index 20f375a..4ecf2d8 100644 --- a/docs/channels.md +++ b/docs/channels.md @@ -14,11 +14,29 @@ ## class `Channels` +Channels class provides the abstraction of the Mainflux Channels API. +Channels are used to connect things and users. They are used to send messages to things and receive messages from things. Channels API provides the following functionalities: + - create channel + - create multiple channels in a bulk + - get channel + - get all channels + - get all channels to which a specific thing is connected to + - update channel + - delete channel + - identify thing - +**Attributes:** + + - `CHANNELS_ENDPOINT` (str): Channels API endpoint + - `THINGS_ENDPOINT` (str): Things API endpoint + - `IDENTIFY_ENDPOINT` (str): Identify API endpoint + + + + ### method `__init__` @@ -26,16 +44,31 @@ __init__(url: str) ``` +Initializes Channels class with the provided url + + + +**Args:** + + - `url` (str): Mainflux Channels API URL +**returns:** + + - `Channels`: Channels object initialized with the provided url. + + + +**raises:** + None --- - + ### method `create` @@ -45,9 +78,32 @@ create(channel: dict, token: str) Creates channel entity in the database +Creates a new channel in the database when provided with a valid token. + +params: channel (dict): Channel entity to be created for example: { "name": "channel_name", "metadata": { "description": "channel_description" } } token (str): User's token + + + +**returns:** + + - `Response`: Response object containing the response from the server + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(channels_url="http`: //localhost:9000") + >>> channel = { + + - ` ... "name"`: "channel_name" + ... } + >>> mf_resp = mfsdk.channels.create(channel, token) + >>> mf_resp + + --- - + ### method `create_bulk` @@ -55,11 +111,42 @@ Creates channel entity in the database create_bulk(channels: list, token: str) ``` -Creates multiple channels in a bulk +Creates multiple channels in bulk + +Creates multiple new channels when provided with channels information and a valid token. + +params: channels: list- Channel entities to be created for example: [ { "name": "channel_name", "metadata": { "description": "channel_description" } }, { "name": "channel_name", "metadata": { "description": "channel_description" } } ] + + token (str): User's token + + + +**returns:** + + - `Response`: Response object containing the response from the server + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(channels_url="http`: //localhost:9000") + >>> channels = [ + ... { + + - ` ... "name"`: "channel_name" + ... }, + ... { + + - ` ... "name"`: "channel_name" + ... } + ... ] + >>> mf_resp = mfsdk.channels.create_bulk(channels, token) + >>> mf_resp + --- - + ### method `disable` @@ -67,11 +154,35 @@ Creates multiple channels in a bulk disable(channel_id: str, token: str) ``` -Deletes a channel entity from database +Deletes a channel entity from database. + +Deletes a channel entity from database when provided with a valid channel ID and token. The channel is not deleted from the database but is marked as disabled. + +params: + + channel_id (str): Channel ID token (str): User's token + + + +**returns:** + + + + - `mf_resp`: response.Response -response object + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(channels_url="http`: //localhost:9000") + >>> channel_id = "channel_id" + >>> mf_resp = mfsdk.channels.disable(channel_id, token) + >>> mf_resp + --- - + ### method `get` @@ -81,9 +192,29 @@ get(channel_id: str, token: str) Gets a channel entity for a logged-in user +Provides a channel entity when provided with a valid channel ID and token. + +params: channel_id (str): Channel ID token (str): User's token + + + +**returns:** + + - `Response`: Response object + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(channels_url="http`: //localhost:9000") + >>> channel_id = "channel_id" + >>> mf_resp = mfsdk.channels.get(channel_id, token) + >>> mf_resp + + --- - + ### method `get_all` @@ -93,9 +224,34 @@ get_all(query_params: dict, token: str) Gets all channels from database +Gets all channels from database when provided with a valid token.. + +params: query_params (dict): Query parameters for example: { "offset": 0, "limit": 10 } token (str): User's token + + + +**returns:** + + - `mf_resp`: response.Response -response object + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(channels_url="http`: //localhost:9000") + >>> query_params = { + + - ` ... "offset"`: 0, + + - ` ... "limit"`: 10 + ... } + >>> mf_resp = mfsdk.channels.get_all(query_params, token) + >>> mf_resp + + --- - + ### method `get_by_thing` @@ -103,11 +259,37 @@ Gets all channels from database get_by_thing(thing_id: str, query_params: dict, token: str) ``` -Gets all channels to which a specific thing is connected to +Gets all channels to which a specific thing is connected to. + +Provides a list of all the channels a thing is connected to when provided with a valid token and thing ID. + +params: thing_id (str): Thing ID query_params (dict): Query parameters for example: { "offset": 0, "limit": 10 } token (str): User's token + + + +**returns:** + + - `mf_resp`: response.Response -response object + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(channels_url="http`: //localhost:9000") + >>> thing_id = "thing_id" + >>> query_params = { + + - ` ... "offset"`: 0, + + - ` ... "limit"`: 10 + ... } + >>> mf_resp = mfsdk.channels.get_by_thing(thing_id, query_params, token) + >>> mf_resp + --- - + ### method `identify_thing` @@ -117,9 +299,29 @@ identify_thing(thing_key: str) Validates thing's key and returns it's ID if key is valid +Uses a thing_key or secret to validate a thing and provide its information. + +params: thing_key (str): Thing's key + + + +**returns:** + + - `mf_resp`: response.Response -response object + +Usage: + +``` from mainflux import sdk ``` + + - ` >>> mfsdk = sdk.SDK(channels_url="http`: //localhost:9000") + >>> thing_key = "thing_key" + >>> mf_resp = mfsdk.channels.identify_thing(thing_key) + >>> mf_resp + + --- - + ### method `update` @@ -129,6 +331,30 @@ update(channel_id: str, channel: dict, token: str) Updates channel entity +Updates a channel entity when provided with a valid channel ID, channel entity and token. The information that can be updated are channel's name and metadata. + +params: channel_id (str): Channel ID channel (dict): Channel entity to be updated for example: { "name": "channel_name", "metadata": { "description": "channel_description" } } token (str): User's token + + + +**returns:** + + - `mf_resp`: response.Response -response object + +Usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.SDK(channels_url="http`: //localhost:9000") + >>> channel_id = "channel_id" + >>> channel = { + + - ` ... "name"`: "channel_name" + ... } + >>> mf_resp = mfsdk.channels.update(channel_id, channel, token) + >>> mf_resp + + diff --git a/docs/users.md b/docs/users.md index 0aea505..837aacd 100644 --- a/docs/users.md +++ b/docs/users.md @@ -42,7 +42,7 @@ __init__(url: str) --- - + ### method `authorise_user` @@ -92,7 +92,7 @@ Usage: --- - + ### method `disable` @@ -115,7 +115,7 @@ Usage: --- - + ### method `enable` @@ -244,7 +244,7 @@ Usage: --- - + ### method `reset_password` @@ -279,9 +279,9 @@ reset_password_request(email: str, url: str) User Password reset request. -Generates a reset token and sends and email with link for resetting password. +Generates a reset token and sends an email to the user with link for resetting password. -params: referrer email: str - this is the host being sent by the browser. the email is part of the header. url: str. +params: referrer email: str - this is the host being sent by the browser. The email must be valid preferably gmail and ensure that the email is already linked to a user as their identity in the database. The email is part of the header. url: str - http://localhost/reset-request diff --git a/examples/examples.py b/examples/examples.py index 619159c..85ba49b 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -105,9 +105,9 @@ print(mf_resp.value) else: print(mf_resp.error.message) - + """User Password reset request""" -mf_resp = mfsdk.users.reset_password_request(email= "", url= "") +mf_resp = mfsdk.users.reset_password_request(email= "", url= "http://localhost/reset-request") if mf_resp.error.status == 0: print(mf_resp.value) else: diff --git a/mainflux/boostrap.py b/mainflux/boostrap.py index 3ec52fd..d1add16 100644 --- a/mainflux/boostrap.py +++ b/mainflux/boostrap.py @@ -6,17 +6,71 @@ class Bootstrap: + """Bootstrap service API client. + + Bootstrap service is used to manage configurations for Mainflux Things. It provides + services such as updating, viewing, removing and adding new configurations. + + Attributes: + url (str): Mainflux Bootstrap API URL. + CONFIGS_ENDPOINT (str): Configurations API endpoint. + BOOTSTRAP_ENDPOINT (str): Bootstrap API endpoint. + WHITELIST_ENDPOINT (str): Whitelist API endpoint. + BOOTSTRAP_CERTS_ENDPOINT (str): Bootstrap certificates API endpoint. + + """ CONFIGS_ENDPOINT = "configs" BOOTSTRAP_ENDPOINT = "bootstrap" WHITELIST_ENDPOINT = "things/state" BOOTSTRAP_CERTS_ENDPOINT = "configs/certs" def __init__(self, url: str): + """Initializes Bootstrap with the provided URL. + + params: + url (str): Mainflux Bootstrap API URL. + + returns: + Bootstrap: Bootstrap object. + + raises: + None + """ self.url = url def add(self, config: dict, token: str): """Adds new config to the list of config owned by user identified - using the provided access token.""" + using the provided access token. + + Some of the key data needed include the external_key and external_id which must be + specific to the thing provided with the thing_id. + + params: + config (dict): Configuration data for example: + { + "external_id": "123", + "external_key": "456", + "thing_id": "fdb1057c-2905-4f71-9a80-e0ce9191e667", + "name": "thing_name" + } + token (str): Authorization token. + + returns: + mf_response : response.Response. + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(bootstrap_url="http://localhost:9013") + >>> config = { + ... "external_id": "123", + ... "external_key": "456", + ... "thing_id": "fdb1057c-2905-4f71-9a80-e0ce9191e667", + ... "name": "thing_name" + ... } + >>> mf_resp = mfsdk.bootstrap.add(config, token) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.post( self.url + "/things" + "/" + self.CONFIGS_ENDPOINT, @@ -35,7 +89,34 @@ def add(self, config: dict, token: str): def whitelist(self, config: dict, token: str): """Updating state represents enabling/disabling Config, i.e.connecting and disconnecting corresponding Mainflux Thing to the - list of Channels.""" + list of Channels. + + params: + config (dict): Configuration data for example: + { + "external_id": "123", + "external_key": "456", + "thing_id": "fdb1057c-2905-4f71-9a80-e0ce9191e667", + "name": "thing_name" + } + token (str): Authorization token. + + returns: + mf_response : response.Response. + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(bootstrap_url="http://localhost:9013") + >>> config = { + ... "external_id": "123", + ... "external_key": "456", + ... "thing_id": "fdb1057c-2905-4f71-9a80-e0ce9191e667", + ... "name": "thing_name" + ... } + >>> mf_resp = mfsdk.bootstrap.whitelist(config, token) + >>> mf_resp + """ mf_resp = response.Response() if config["thing_id"] == "": mf_resp.error.status = 1 @@ -55,7 +136,25 @@ def whitelist(self, config: dict, token: str): return mf_resp def view(self, thing_id: str, token: str): - """Retrieves a configuration with given config id""" + """Retrieves a configuration with given config id + + Provides a configuration with given config id. + + params: + thing_id (str): Thing ID. + token (str): Authorization token. + + returns: + mf_resp : response.Response - response object. + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(bootstrap_url="http://localhost:9013") + >>> thing_id = "thing_id" + >>> mf_resp = mfsdk.bootstrap.view(thing_id, token) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( self.url + "/things" + "/" + self.CONFIGS_ENDPOINT + "/" + thing_id, @@ -74,7 +173,35 @@ def update(self, config: dict, token: str): """Update is performed by replacing the current resource data with values provided in a request payload. Note that the owner, ID, external ID, external key, Mainflux Thing ID and key cannot be - changed.""" + changed. + + params: + config (dict): Configuration data for example: + { + "external_id": "123", + "external_key": "456", + "thing_id": "fdb1057c-2905-4f71-9a80-e0ce9191e667", + "name": "thing_name" + } + token (str): Authorization token. + + returns: + + mf_response : response.Response. + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(bootstrap_url="http://localhost:9013") + >>> config = { + ... "external_id": "123", + ... "external_key": "456", + ... "thing_id": "fdb1057c-2905-4f71-9a80-e0ce9191e667", + ... "name": "thing_name" + ... } + >>> mf_resp = mfsdk.bootstrap.update(config, token) + >>> mf_resp + """ mf_resp = response.Response() if config["thing_id"] == "": mf_resp.error.status = 1 @@ -95,10 +222,31 @@ def update(self, config: dict, token: str): def update_certs( self, config_id: str, client_cert: str, client_key: str, ca: str, - token: str - ): + token: str): """Update is performed by replacing the current certificate data - with values provided in a request payload.""" + with values provided in a request payload. + + params: + config_id (str): Configuration ID. + client_cert (str): Client certificate. + client_key (str): Client key. + ca (str): CA certificate. + token (str): Authorization token. + + returns: + mf_response : response.Response. + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(bootstrap_url="http://localhost:9013") + >>> config_id = "config_id" + >>> client_cert = "client_cert" + >>> client_key = "client_key" + >>> ca = "ca" + >>> mf_resp = mfsdk.bootstrap.update_certs(config_id, client_cert, client_key, ca, token) + >>> mf_resp + """ payload = {"client_cert": client_cert, "client_key": client_key, "ca_cert": ca} http_resp = requests.patch( @@ -117,7 +265,23 @@ def update_certs( def remove(self, config_id: str, token: str): """Removes a Config. In case of successful removal the service will ensure that the removed config is disconnected from all the - Mainflux channels.""" + Mainflux channels. + + params: + config_id (str): Configuration ID. + token (str): Authorization token. + + returns: + mf_response : response.Response. + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(bootstrap_url="http://localhost:9013") + >>> config_id = "config_id" + >>> mf_resp = mfsdk.bootstrap.remove(config_id, token) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.delete( self.url + "/things/" + self.CONFIGS_ENDPOINT + "/" + config_id, @@ -134,7 +298,24 @@ def remove(self, config_id: str, token: str): def bootstrap(self, external_id: str, external_key: str): """Retrieves a configuration with given external ID and external - key.""" + key. + + params: + external_id (str): External ID. + external_key (str): External key. + + returns: + mf_resp : response.Response - response object. + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(bootstrap_url="http://localhost:9013") + >>> external_id = "external_id" + >>> external_key = "external_key" + >>> mf_resp = mfsdk.bootstrap.bootstrap(external_id, external_key) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( self.url + "/things/bootstrap" + "/" + external_id, diff --git a/mainflux/certs.py b/mainflux/certs.py index 32298d7..2837ba8 100644 --- a/mainflux/certs.py +++ b/mainflux/certs.py @@ -6,20 +6,55 @@ class Certs: - certs_endpoint = "certs" + """Mainflux Certificates API + + Certs is used to issue, view, and revoke certificates. + It is used to issue certificates for things. + + Args: + url (str): Mainflux Certificates API URL. + CERTS_ENDPOINT (str): Certificates API endpoint. + """ + CERTS_ENDPOINT = "certs" def __init__(self, url: str): + """Initializes Certs with the provided URL. + + Args: + url (str): Mainflux Certificates API URL. + + Returns: + Certs: Certs object. + """ self.url = url def issue(self, thing_id: str, valid: str, token: str): - + """ + Issues a certificate for a given thing ID. + + Args: + thing_id (str): Thing ID. + valid (str): Certificate validity period. + token (str): Authorization token. + + Returns: + Response: Mainflux response. + + Usage: + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(certs_url="http://localhost:9019") + >>> thing_id = "thing_id" + >>> valid = "1h" + >>> mf_resp = mfsdk.certs.issue(thing_id, valid) + >>> mf_resp + """ payload = { "thing_id": thing_id, "ttl": valid, } mf_resp = response.Response() http_resp = requests.post( - self.url + "/" + self.certs_endpoint, + self.url + "/" + self.CERTS_ENDPOINT, json=payload, headers=utils.construct_header(token, utils.CTJSON), ) @@ -33,7 +68,25 @@ def issue(self, thing_id: str, valid: str, token: str): return mf_resp def view_by_thing(self, thing_id: str, token: str): - """Retrieves a list of certificates' serial IDs for a given thing ID.""" + """Retrieves a list of certificates' serial IDs for a given thing ID. + + Provides a list of certificates' serial IDs for a given thing ID. + + Params: + thing_id (str): Thing ID. + token (str): Authorization token. + + Returns: + mf_resp : response.Response - response object. + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(certs_url="http://localhost:9019") + >>> thing_id = "thing_id" + >>> mf_resp = mfsdk.certs.view_by_thing(thing_id) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( self.url + "/serials" + "/" + thing_id, @@ -49,10 +102,29 @@ def view_by_thing(self, thing_id: str, token: str): return mf_resp def view_by_serial(self, cert_id: str, token: str): - """Retrieves a certificate for a given cert ID.""" + """Retrieves a certificate for a given cert ID. + + Provides a certificate for a given cert ID. + + Params: + + cert_id (str): Certificate ID. + token (str): Authorization token. + + Returns: + mf_resp : response.Response - response object. + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(certs_url="http://localhost:9019") + >>> cert_id = "cert_id" + >>> mf_resp = mfsdk.certs.view_by_serial(cert_id) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( - self.url + "/" + self.certs_endpoint + "/" + cert_id, + self.url + "/" + self.CERTS_ENDPOINT + "/" + cert_id, headers=utils.construct_header(token, utils.CTJSON), ) if http_resp.status_code != 200: @@ -65,9 +137,28 @@ def view_by_serial(self, cert_id: str, token: str): return mf_resp def revoke(self, thing_id: str, token: str): + """Revokes a certificate for a given thing ID. + + Deletes a certificate for a given thing ID and valid token. + + params: + thing_id (str): thing id + token (str): valid authorization token used to delete the certificate + + Returns: + mf_resp : response.Response - response object. + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(certs_url="http://localhost:9019") + >>> thing_id = "thing_id" + >>> mf_resp = mfsdk.certs.revoke(thing_id) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.delete( - self.url + "/" + self.certs_endpoint + "/" + thing_id, + self.url + "/" + self.CERTS_ENDPOINT + "/" + thing_id, headers=utils.construct_header(token, utils.CTJSON), ) if http_resp.status_code != 200: diff --git a/mainflux/channels.py b/mainflux/channels.py index 8969522..a16c8e2 100644 --- a/mainflux/channels.py +++ b/mainflux/channels.py @@ -6,15 +6,71 @@ class Channels: + """Channels class provides the abstraction of the Mainflux Channels API. + + Channels are used to connect things and users. They are used to send messages to things and + receive messages from things. Channels API provides the following functionalities: + - create channel + - create multiple channels in a bulk + - get channel + - get all channels + - get all channels to which a specific thing is connected to + - update channel + - delete channel + - identify thing + + Attributes: + CHANNELS_ENDPOINT (str): Channels API endpoint + THINGS_ENDPOINT (str): Things API endpoint + IDENTIFY_ENDPOINT (str): Identify API endpoint + + """ CHANNELS_ENDPOINT = "channels" THINGS_ENDPOINT = "things" IDENTIFY_ENDPOINT = "identify" def __init__(self, url: str): + """Initializes Channels class with the provided url + + Args: + url (str): Mainflux Channels API URL + + returns: + Channels: Channels object initialized with the provided url. + + raises: + None + """ self.url = url def create(self, channel: dict, token: str): - """Creates channel entity in the database""" + """Creates channel entity in the database + + Creates a new channel in the database when provided with a valid token. + + params: + channel (dict): Channel entity to be created for example: + { + "name": "channel_name", + "metadata": { + "description": "channel_description" + } + } + token (str): User's token + + returns: + Response: Response object containing the response from the server + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(channels_url="http://localhost:9000") + >>> channel = { + ... "name": "channel_name" + ... } + >>> mf_resp = mfsdk.channels.create(channel, token) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.post( self.url + "/" + self.CHANNELS_ENDPOINT, @@ -31,7 +87,48 @@ def create(self, channel: dict, token: str): return mf_resp def create_bulk(self, channels: list, token: str): - """Creates multiple channels in a bulk""" + """Creates multiple channels in bulk + + Creates multiple new channels when provided with channels information + and a valid token. + + params: + channels: list- Channel entities to be created for example: + [ + { + "name": "channel_name", + "metadata": { + "description": "channel_description" + } + }, + { + "name": "channel_name", + "metadata": { + "description": "channel_description" + } + } + ] + + token (str): User's token + + returns: + Response: Response object containing the response from the server + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(channels_url="http://localhost:9000") + >>> channels = [ + ... { + ... "name": "channel_name" + ... }, + ... { + ... "name": "channel_name" + ... } + ... ] + >>> mf_resp = mfsdk.channels.create_bulk(channels, token) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.post( self.url + "/" + self.CHANNELS_ENDPOINT + "/bulk", @@ -48,7 +145,25 @@ def create_bulk(self, channels: list, token: str): return mf_resp def get(self, channel_id: str, token: str): - """Gets a channel entity for a logged-in user""" + """Gets a channel entity for a logged-in user + + Provides a channel entity when provided with a valid channel ID and token. + + params: + channel_id (str): Channel ID + token (str): User's token + + returns: + Response: Response object + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(channels_url="http://localhost:9000") + >>> channel_id = "channel_id" + >>> mf_resp = mfsdk.channels.get(channel_id, token) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( self.url + "/" + self.CHANNELS_ENDPOINT + "/" + channel_id, @@ -64,7 +179,32 @@ def get(self, channel_id: str, token: str): return mf_resp def get_all(self, query_params: dict, token: str): - """Gets all channels from database""" + """Gets all channels from database + + Gets all channels from database when provided with a valid token.. + + params: + query_params (dict): Query parameters for example: + { + "offset": 0, + "limit": 10 + } + token (str): User's token + + returns: + mf_resp: response.Response -response object + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(channels_url="http://localhost:9000") + >>> query_params = { + ... "offset": 0, + ... "limit": 10 + ... } + >>> mf_resp = mfsdk.channels.get_all(query_params, token) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( self.url + "/" + self.CHANNELS_ENDPOINT, @@ -81,7 +221,35 @@ def get_all(self, query_params: dict, token: str): return mf_resp def get_by_thing(self, thing_id: str, query_params: dict, token: str): - """Gets all channels to which a specific thing is connected to""" + """Gets all channels to which a specific thing is connected to. + + Provides a list of all the channels a thing is connected to when provided with a valid + token and thing ID. + + params: + thing_id (str): Thing ID + query_params (dict): Query parameters for example: + { + "offset": 0, + "limit": 10 + } + token (str): User's token + + returns: + mf_resp: response.Response -response object + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(channels_url="http://localhost:9000") + >>> thing_id = "thing_id" + >>> query_params = { + ... "offset": 0, + ... "limit": 10 + ... } + >>> mf_resp = mfsdk.channels.get_by_thing(thing_id, query_params, token) + >>> mf_resp + """ mf_resp = response.Response() http_resp = requests.get( self.url + "/" + self.THINGS_ENDPOINT + "/" + thing_id + "/" + self.CHANNELS_ENDPOINT, @@ -98,7 +266,36 @@ def get_by_thing(self, thing_id: str, query_params: dict, token: str): return mf_resp def update(self, channel_id: str, channel: dict, token: str): - """Updates channel entity""" + """Updates channel entity + + Updates a channel entity when provided with a valid channel ID, channel entity and token. + The information that can be updated are channel's name and metadata. + + params: + channel_id (str): Channel ID + channel (dict): Channel entity to be updated for example: + { + "name": "channel_name", + "metadata": { + "description": "channel_description" + } + } + token (str): User's token + + returns: + mf_resp: response.Response -response object + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(channels_url="http://localhost:9000") + >>> channel_id = "channel_id" + >>> channel = { + ... "name": "channel_name" + ... } + >>> mf_resp = mfsdk.channels.update(channel_id, channel, token) + >>> mf_resp + """ http_resp = requests.put( self.url + "/" + self.CHANNELS_ENDPOINT + "/" + channel_id, json=channel, @@ -113,7 +310,28 @@ def update(self, channel_id: str, channel: dict, token: str): return mf_resp def disable(self, channel_id: str, token: str): - """Deletes a channel entity from database""" + """Deletes a channel entity from database. + + Deletes a channel entity from database when provided with a valid channel ID and token. + The channel is not deleted from the database but is marked as disabled. + + params: + + channel_id (str): Channel ID + token (str): User's token + + returns: + + mf_resp: response.Response -response object + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(channels_url="http://localhost:9000") + >>> channel_id = "channel_id" + >>> mf_resp = mfsdk.channels.disable(channel_id, token) + >>> mf_resp + """ http_resp = requests.post( self.url + "/" + self.CHANNELS_ENDPOINT + "/" + channel_id + "/disable", headers=utils.construct_header(token, utils.CTJSON), @@ -127,7 +345,24 @@ def disable(self, channel_id: str, token: str): return mf_resp def identify_thing(self, thing_key: str): - """Validates thing's key and returns it's ID if key is valid""" + """Validates thing's key and returns it's ID if key is valid + + Uses a thing_key or secret to validate a thing and provide its information. + + params: + thing_key (str): Thing's key + + returns: + mf_resp: response.Response -response object + + Usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.SDK(channels_url="http://localhost:9000") + >>> thing_key = "thing_key" + >>> mf_resp = mfsdk.channels.identify_thing(thing_key) + >>> mf_resp + """ http_resp = requests.post( self.url + "/" + self.IDENTIFY_ENDPOINT, headers=utils.construct_header(utils.ThingPrefix + thing_key, utils.CTJSON), diff --git a/mainflux/users.py b/mainflux/users.py index a652bcf..d3c32a7 100644 --- a/mainflux/users.py +++ b/mainflux/users.py @@ -485,13 +485,15 @@ def update_password(self, old_secret: str, new_secret: str, user_token: str): def reset_password_request(self, email: str, url: str): """User Password reset request. - Generates a reset token and sends and email + Generates a reset token and sends an email to the user with link for resetting password. params: referrer email: str - this is the host being sent by the browser. - the email is part of the header. - url: str. + The email must be valid preferably gmail and ensure that the email is + already linked to a user as their identity in the database. + The email is part of the header. + url: str - http://localhost/reset-request returns: mf_resp: response.Response - response object From a10f60a4d3fca8ae7a931147b4b6c4a41d9a2b3e Mon Sep 17 00:00:00 2001 From: Musilah Date: Fri, 29 Sep 2023 11:40:02 +0300 Subject: [PATCH 24/31] fix messages.py file Signed-off-by: Musilah --- docs/README.md | 2 +- docs/boostrap.md | 14 ++++---- docs/messages.md | 58 +++++++++++++++++++++++++++++--- examples/examples.py | 7 ++-- mainflux/boostrap.py | 3 +- mainflux/messages.py | 75 ++++++++++++++++++++++++++++++++++++++---- tests/test_messages.py | 12 +++++++ 7 files changed, 149 insertions(+), 22 deletions(-) diff --git a/docs/README.md b/docs/README.md index 4f553ee..99543d5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,7 +22,7 @@ - [`certs.Certs`](./certs.md#class-certs): Mainflux Certificates API - [`channels.Channels`](./channels.md#class-channels): Channels class provides the abstraction of the Mainflux Channels API. - [`groups.Groups`](./groups.md#class-groups): Groups class provides the abstraction of the Mainflux groups service API. -- [`messages.Messages`](./messages.md#class-messages) +- [`messages.Messages`](./messages.md#class-messages): Messages API client - [`response.Error`](./response.md#class-error) - [`response.Response`](./response.md#class-response) - [`sdk.SDK`](./sdk.md#class-sdk) diff --git a/docs/boostrap.md b/docs/boostrap.md index 8cf4128..fc2fdcf 100644 --- a/docs/boostrap.md +++ b/docs/boostrap.md @@ -68,7 +68,7 @@ add(config: dict, token: str) Adds new config to the list of config owned by user identified using the provided access token. -Some of the key data needed include the external_key and external_id which must be specific to the thing provided with the thing_id. +Some of the key data needed include the external_key and external_id which must be specific to the thing provided with the thing_id. Mind that every configuration must have a specific thing_id. params: config (dict): Configuration data for example: { "external_id": "123", "external_key": "456", "thing_id": "fdb1057c-2905-4f71-9a80-e0ce9191e667", "name": "thing_name" } token (str): Authorization token. @@ -99,7 +99,7 @@ Usage: --- - + ### method `bootstrap` @@ -130,7 +130,7 @@ Usage: --- - + ### method `remove` @@ -160,7 +160,7 @@ Usage: --- - + ### method `update` @@ -201,7 +201,7 @@ Usage: --- - + ### method `update_certs` @@ -240,7 +240,7 @@ Usage: --- - + ### method `view` @@ -272,7 +272,7 @@ Usage: --- - + ### method `whitelist` diff --git a/docs/messages.md b/docs/messages.md index 308b16c..284fde0 100644 --- a/docs/messages.md +++ b/docs/messages.md @@ -14,11 +14,18 @@ ## class `Messages` +Messages API client +Messages API client enables interaction with Mainflux Messages API. It provides methods for sending and reading messages. - +**Attributes:** + + - `adapter_url`: URL of the Mainflux Messages adapter + - `reader_url`: URL of the Mainflux Messages reader + + ### method `__init__` @@ -35,7 +42,7 @@ __init__(adapter_url: str, reader_url: str) --- - + ### method `read` @@ -45,18 +52,61 @@ read(channel_id: str, token: str) Reads messages from database for a given channel +Reads message from a given channel via HTTP protocol. Message is read through a reader add-on such as timescale. + +params: channel_id: ID of the channel to read message from token: token of the user reading the message + + + +**returns:** + + - `mf_resp`: response object + +usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.Sdk("http`: //localhost:9011") + >>> channel_id = "2b86beba-83dd-4b39-8165-4dda4e6eb4ad" + >>> mf_resp = mfsdk.messages.read(channel_id, token) + >>> mf_resp + + --- - + ### method `send` ```python -send(channel_id: str, msg: dict, thing_key: str) +send(channel_id: str, msg: str, thing_key: str) ``` Sends message via HTTP protocol +Sends message to a given channel via HTTP protocol. Message is sent through a writer add-on such as timescale. Message is sent to a http port specific to the writer add-on. The thing and channel must be created before sending the message and connected. + +params: channel_id: ID of the channel to send message to msg: message to send to the channel that should be in bytes thing_key: secret of the thing sending the message + + + +**returns:** + + - `mf_resp`: response object + +usage: + +``` from mainflux import sdk``` + + - ` >>> mfsdk = sdk.Sdk("http`: //localhost:9011") + >>> channel_id = "2b86beba-83dd-4b39-8165-4dda4e6eb4ad" + + - ` >>> msg = '[{"bn"`: "demo", "bu":"V", "n":"voltage", "u":"V", "v":5}]' + >>> thing_key = "fc68b31b-d7fd-4879-b3a7-0baf4580c5b1" + >>> mf_resp = mfsdk.messages.send(channel_id, msg, thing_key) + >>> mf_resp + + diff --git a/examples/examples.py b/examples/examples.py index 85ba49b..f1630e6 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -1,11 +1,12 @@ from mainflux import sdk +import json default_url = "http://localhost" mfsdk = sdk.SDK( users_url=default_url, things_url=default_url + ":9000", - reader_url=default_url + ":9204", + reader_url=default_url + ":9011", http_adapter_url=default_url, certs_url=default_url + ":9019", bootstrap_url=default_url + ":9013" @@ -516,7 +517,7 @@ """Sends message via HTTP protocol""" mf_resp = mfsdk.messages.send( - channel_id="", msg="<[message]>", thing_key="" + channel_id="", msg='<[message]>', thing_key="" ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -531,7 +532,7 @@ print(mf_resp.error.message) """Issue certs""" -mf_resp = mfsdk.certs.issue(thing_id="",valid="10h", token="") +mf_resp = mfsdk.certs.issue(thing_id="",valid="", token="") if mf_resp.error.status == 0: print(mf_resp.value) else: diff --git a/mainflux/boostrap.py b/mainflux/boostrap.py index d1add16..9f23047 100644 --- a/mainflux/boostrap.py +++ b/mainflux/boostrap.py @@ -43,7 +43,8 @@ def add(self, config: dict, token: str): using the provided access token. Some of the key data needed include the external_key and external_id which must be - specific to the thing provided with the thing_id. + specific to the thing provided with the thing_id. Mind that every configuration + must have a specific thing_id. params: config (dict): Configuration data for example: diff --git a/mainflux/messages.py b/mainflux/messages.py index ce403c0..3d1f773 100644 --- a/mainflux/messages.py +++ b/mainflux/messages.py @@ -6,22 +6,66 @@ class Messages: + """Messages API client + + Messages API client enables interaction with Mainflux Messages API. + It provides methods for sending and reading messages. + + Attributes: + adapter_url: URL of the Mainflux Messages adapter + reader_url: URL of the Mainflux Messages reader + """ def __init__(self, adapter_url: str, reader_url: str): self.adapter_url = adapter_url self.reader_url = reader_url + """Initializes Messages API client with adapter and reader URLs + + params: + adapter_url: URL of the Mainflux Messages adapter + reader_url: URL of the Mainflux Messages reader + + returns: + Messages API client object + + raises: + None + """ + def send(self, channel_id: str, msg: str, thing_key: str): + """Sends message via HTTP protocol + + Sends message to a given channel via HTTP protocol. Message is sent + through a writer add-on such as timescale. Message is sent to a + http port specific to the writer add-on. The thing and channel must be + created before sending the message and connected. + + params: + channel_id: ID of the channel to send message to + msg: message to send to the channel that should be in bytes + thing_key: secret of the thing sending the message + + returns: + mf_resp: response object + + usage: - def send(self, channel_id: str, msg: dict, thing_key: str): - """Sends message via HTTP protocol""" + >>> from mainflux import sdk + >>> mfsdk = sdk.Sdk("http://localhost:9011") + >>> channel_id = "2b86beba-83dd-4b39-8165-4dda4e6eb4ad" + >>> msg = '[{"bn":"demo", "bu":"V", "n":"voltage", "u":"V", "v":5}]' + >>> thing_key = "fc68b31b-d7fd-4879-b3a7-0baf4580c5b1" + >>> mf_resp = mfsdk.messages.send(channel_id, msg, thing_key) + >>> mf_resp + """ chan_name_parts = channel_id.split(".", 2) chan_id = chan_name_parts[0] subtopic = "" if len(chan_name_parts) == 2: - subtopic = chan_name_parts[0].replace(".", "/", -1) + subtopic = chan_name_parts[1].replace(".", "/", -1) mf_resp = response.Response() http_resp = requests.post( self.adapter_url + "/http/channels/" + chan_id + "/messages/" + subtopic, - json=msg, + data=bytes(msg, 'utf-8'), headers=utils.construct_header( utils.ThingPrefix + thing_key, utils.CTJSON), ) @@ -34,12 +78,31 @@ def send(self, channel_id: str, msg: dict, thing_key: str): return mf_resp def read(self, channel_id: str, token: str): - """Reads messages from database for a given channel""" + """Reads messages from database for a given channel + + Reads message from a given channel via HTTP protocol. Message is read + through a reader add-on such as timescale. + + params: + channel_id: ID of the channel to read message from + token: token of the user reading the message + + returns: + mf_resp: response object + + usage: + + >>> from mainflux import sdk + >>> mfsdk = sdk.Sdk("http://localhost:9011") + >>> channel_id = "2b86beba-83dd-4b39-8165-4dda4e6eb4ad" + >>> mf_resp = mfsdk.messages.read(channel_id, token) + >>> mf_resp + """ chan_name_parts = channel_id.split(".", 2) chan_id = chan_name_parts[0] subtopic = "" if len(chan_name_parts) == 2: - subtopic = chan_name_parts[0].replace(".", "/", -1) + subtopic = chan_name_parts[1].replace(".", "/", -1) mf_resp = response.Response() http_resp = requests.get( self.reader_url + "/channels/" + chan_id + "/messages", diff --git a/tests/test_messages.py b/tests/test_messages.py index a3c4b0a..d284216 100644 --- a/tests/test_messages.py +++ b/tests/test_messages.py @@ -19,3 +19,15 @@ def test_read(requests_mock): r = s.messages.read(channel_id=channel_id, token=token) assert r.error.status == 0 assert msg == r.value + +def test_send_malformed_channel_id(requests_mock): + requests_mock.register_uri("POST", url + "/http/channels/" + channel_id + "/messages/", status_code=400) + r = s.messages.send(channel_id=channel_id, msg=msg, thing_key=token) + assert r.error.status == 1 + assert r.error.message == "Message discarded due to its malformed content." + +def test_read_malformed_query_params(requests_mock): + requests_mock.register_uri("GET", url + "/channels/" + channel_id + "/messages", json=msg, status_code=400) + r = s.messages.read(channel_id=channel_id, token=token) + assert r.error.status == 1 + assert r.error.message == "Failed due to malformed query parameters." From 081e148169fdb6cb545cdf4cdec918caaba952e3 Mon Sep 17 00:00:00 2001 From: Musilah Date: Thu, 5 Oct 2023 18:21:58 +0300 Subject: [PATCH 25/31] comment resolution Signed-off-by: Musilah --- docs/channels.md | 4 ++-- docs/groups.md | 26 +++++++++++++------------- docs/messages.md | 4 ++-- docs/things.md | 4 ++-- examples/examples.py | 11 +++++++---- mainflux/channels.py | 4 +++- mainflux/groups.py | 9 ++++++--- mainflux/messages.py | 4 +++- mainflux/things.py | 2 ++ mainflux/users.py | 2 +- tests/test_channels.py | 2 +- tests/test_groups.py | 3 ++- tests/test_users.py | 2 +- 13 files changed, 45 insertions(+), 32 deletions(-) diff --git a/docs/channels.md b/docs/channels.md index 4ecf2d8..85e66cf 100644 --- a/docs/channels.md +++ b/docs/channels.md @@ -146,7 +146,7 @@ Usage: --- - + ### method `disable` @@ -289,7 +289,7 @@ Usage: --- - + ### method `identify_thing` diff --git a/docs/groups.md b/docs/groups.md index 0ac8354..132c1af 100644 --- a/docs/groups.md +++ b/docs/groups.md @@ -11,7 +11,7 @@ --- - + ## class `Groups` Groups class provides the abstraction of the Mainflux groups service API. @@ -25,7 +25,7 @@ Groups class provides the following functionality: create, get, get_all, parents - `URL`: Mainflux groups service URL. - `GROUPS_ENDPOINT`: Mainflux groups service API endpoint. - + ### method `__init__` @@ -42,7 +42,7 @@ __init__(url: str) --- - + ### method `assign` @@ -69,7 +69,7 @@ Usage: --- - + ### method `children` @@ -96,7 +96,7 @@ Usage: --- - + ### method `create` @@ -123,7 +123,7 @@ Usage: --- - + ### method `disable` @@ -148,7 +148,7 @@ Usage: --- - + ### method `get` @@ -175,7 +175,7 @@ Usage: --- - + ### method `get_all` @@ -202,7 +202,7 @@ Usage: --- - + ### method `members` @@ -229,7 +229,7 @@ Usage: --- - + ### method `memberships` @@ -254,7 +254,7 @@ Usage: --- - + ### method `parents` @@ -281,7 +281,7 @@ Usage: --- - + ### method `unassign` @@ -306,7 +306,7 @@ Usage: --- - + ### method `update` diff --git a/docs/messages.md b/docs/messages.md index 284fde0..b6403e8 100644 --- a/docs/messages.md +++ b/docs/messages.md @@ -42,7 +42,7 @@ __init__(adapter_url: str, reader_url: str) --- - + ### method `read` @@ -86,7 +86,7 @@ Sends message via HTTP protocol Sends message to a given channel via HTTP protocol. Message is sent through a writer add-on such as timescale. Message is sent to a http port specific to the writer add-on. The thing and channel must be created before sending the message and connected. -params: channel_id: ID of the channel to send message to msg: message to send to the channel that should be in bytes thing_key: secret of the thing sending the message +params: channel_id: ID of the channel to send message to msg: message to send to the channel that should be in encoded into bytes format for example: [{"bn":"demo", "bu":"V", "n":"voltage", "u":"V", "v":5}] thing_key: secret of the thing sending the message diff --git a/docs/things.md b/docs/things.md index d0e74f0..0af7178 100644 --- a/docs/things.md +++ b/docs/things.md @@ -42,7 +42,7 @@ __init__(url: str) --- - + ### method `authorise_thing` @@ -325,7 +325,7 @@ Usage: --- - + ### method `share_thing` diff --git a/examples/examples.py b/examples/examples.py index f1630e6..0190321 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -284,7 +284,7 @@ """Connect thing to channel""" mf_resp = mfsdk.things.connect( - channel_id="", thing_id="", action="m_read", token="" + channel_id="", thing_id="", action="", token="" ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -338,7 +338,7 @@ """To create a channel, you need a channel and a token""" mf_resp = mfsdk.channels.create( - channel={"name": ""}, token="") + channel={"name": ""}, token="") if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -425,8 +425,11 @@ """Group update""" group={ "id": "", - "name": "" -} + "name": "", + "metdata": { + "foo": "bar" + } + } mf_resp = mfsdk.groups.update( token="", group= group, group_id="group_id" ) diff --git a/mainflux/channels.py b/mainflux/channels.py index a16c8e2..041ca2e 100644 --- a/mainflux/channels.py +++ b/mainflux/channels.py @@ -135,7 +135,7 @@ def create_bulk(self, channels: list, token: str): json=channels, headers=utils.construct_header(token, utils.CTJSON), ) - if http_resp.status_code != 201: + if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.channels["create_bulk"], http_resp.status_code @@ -307,6 +307,8 @@ def update(self, channel_id: str, channel: dict, token: str): mf_resp.error.message = errors.handle_error( errors.channels["update"], http_resp.status_code ) + else: + mf_resp.value = http_resp.json() return mf_resp def disable(self, channel_id: str, token: str): diff --git a/mainflux/groups.py b/mainflux/groups.py index af34012..13e59b2 100644 --- a/mainflux/groups.py +++ b/mainflux/groups.py @@ -1,4 +1,5 @@ import requests +import json from mainflux import response from mainflux import errors @@ -277,7 +278,7 @@ def update(self, group_id: str, group: dict, token: str): """ http_resp = requests.put( self.URL + "/" + self.GROUPS_ENDPOINT + "/" + group_id, - data=group, + data=json.dumps(group), headers=utils.construct_header(token, utils.CTJSON), ) mf_resp = response.Response() @@ -400,7 +401,7 @@ def assign(self, group_id: str, member_id: str, member_type: list, token: str): token: str - token used to assign a member to a group. returns: - mf_resp: response.Response - response object + mf_resp: "Policy created" Usage:: @@ -421,11 +422,13 @@ def assign(self, group_id: str, member_id: str, member_type: list, token: str): headers=utils.construct_header(token, utils.CTJSON), json=payload, ) - if http_resp.status_code != 200: + if http_resp.status_code != 201: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.groups["assign"], http_resp.status_code ) + else: + mf_resp.value = "Policy created" return mf_resp def unassign(self, group_id: str, token: str, members_ids): diff --git a/mainflux/messages.py b/mainflux/messages.py index 3d1f773..2e8e815 100644 --- a/mainflux/messages.py +++ b/mainflux/messages.py @@ -40,7 +40,9 @@ def send(self, channel_id: str, msg: str, thing_key: str): params: channel_id: ID of the channel to send message to - msg: message to send to the channel that should be in bytes + msg: message to send to the channel that should be in encoded into + bytes format for example: + [{"bn":"demo", "bu":"V", "n":"voltage", "u":"V", "v":5}] thing_key: secret of the thing sending the message returns: diff --git a/mainflux/things.py b/mainflux/things.py index 024dd59..b222e75 100644 --- a/mainflux/things.py +++ b/mainflux/things.py @@ -608,6 +608,8 @@ def disconnect(self, thing_id: str, channel_id: str, token: str): mf_resp.error.message = errors.handle_error( errors.things["disconnect"], http_resp.status_code ) + else: + mf_resp.value = "Disconnected" return mf_resp def share_thing(self, user_id: str, channel_id: str, actions: list, token: str): diff --git a/mainflux/users.py b/mainflux/users.py index d3c32a7..595b318 100644 --- a/mainflux/users.py +++ b/mainflux/users.py @@ -591,7 +591,7 @@ def enable(self, user_id: str, user_token: str): self.URL + "/" + self.USERS_ENDPOINT + "/" + user_id + "/enable", headers=utils.construct_header(user_token, utils.CTJSON), ) - if http_resp.status_code != 204: + if http_resp.status_code != 200: mf_resp.error.status = 1 mf_resp.error.message = errors.handle_error( errors.users["enable"], http_resp.status_code diff --git a/tests/test_channels.py b/tests/test_channels.py index 8b4992e..a7da7fb 100644 --- a/tests/test_channels.py +++ b/tests/test_channels.py @@ -42,7 +42,7 @@ def test_create_channel_entity_exist(requests_mock): assert r.error.message == "Failed due to using an existing identity." def test_create_bulk_channels(requests_mock): - requests_mock.register_uri("POST", url + "/channels/bulk", json=[channel_id, channel_id1], headers={"location": "/channels/channel_ids"}, status_code=201) + requests_mock.register_uri("POST", url + "/channels/bulk", json=[channel_id, channel_id1], headers={"location": "/channels/channel_ids"}, status_code=200) r = s.channels.create_bulk(channel_id, token=token) assert r.error.status == 0 assert [channel_id, channel_id1] == r.value diff --git a/tests/test_groups.py b/tests/test_groups.py index 3dd4275..341e1d4 100644 --- a/tests/test_groups.py +++ b/tests/test_groups.py @@ -127,9 +127,10 @@ def test_membership_bad_content_type(requests_mock): assert r.error.message == "Failed due to malformed query parameters." def test_assign(requests_mock): - requests_mock.register_uri("POST", url + "/users/policies" , status_code=200) + requests_mock.register_uri("POST", url + "/users/policies" , status_code=201) r = s.groups.assign(group_id=group_id, token=token, member_id=members, member_type= ["m_read"]) assert r.error.status == 0 + assert r.value == "Policy created" def test_assign_malformed_json(requests_mock): requests_mock.register_uri("POST", url + "/users/policies", status_code=400) diff --git a/tests/test_users.py b/tests/test_users.py index 66caebd..3d56a14 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -217,7 +217,7 @@ def test_reset_password_bad_token(requests_mock): assert r.error.message == "Failed due to malformed JSON." def test_enable_user(requests_mock): - requests_mock.register_uri("POST", url + "/users/" + user["id"] + "/enable", json=user, status_code=204) + requests_mock.register_uri("POST", url + "/users/" + user["id"] + "/enable", json=user, status_code=200) r = s.users.enable(user_id=user["id"], user_token= token["access_token"]) assert r.error.status == 0 assert user == r.value From 208b7fd2414e6254a564bf385bae2d781ca9c84f Mon Sep 17 00:00:00 2001 From: Musilah Date: Thu, 5 Oct 2023 18:26:36 +0300 Subject: [PATCH 26/31] fix groups.md docs Signed-off-by: Musilah --- docs/groups.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/groups.md b/docs/groups.md index 132c1af..f80db33 100644 --- a/docs/groups.md +++ b/docs/groups.md @@ -60,7 +60,7 @@ params: group_id: str - group id member_id: str - member id member_type: list **returns:** - - `mf_resp`: response.Response - response object + - `mf_resp`: "Policy created" Usage: ``` From 6450c0010229cfffeebddc2981d690d7c51f7700 Mon Sep 17 00:00:00 2001 From: Musilah Date: Mon, 23 Oct 2023 14:31:57 +0300 Subject: [PATCH 27/31] simplify examples Signed-off-by: Musilah --- examples/examples.py | 165 +++++++++++++++++++++++-------------------- 1 file changed, 87 insertions(+), 78 deletions(-) diff --git a/examples/examples.py b/examples/examples.py index 0190321..7d43ad6 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -12,11 +12,20 @@ bootstrap_url=default_url + ":9013" ) +"""Repetitive values that can be easily fed into the example code""" + +user_id = "", +token = "", +thing_id = "", +channel_id = "", +group_id = "", +thing_id2 = "", + """To start working with the Mainflux system, you need to create a user account""" mf_resp = mfsdk.users.create( user={"credentials": {"identity": "", "secret": ""}}, - token="", + token= token, ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -25,7 +34,7 @@ """To log in to the Mainflux system, you need to create a user token""" mf_resp = mfsdk.users.login( - user={ "identity" : "admin@example.com", "secret": ""} + user={ "identity" : "", "secret": ""} ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -44,7 +53,7 @@ """You can always check the user entity that is logged in by entering the user ID and token""" -mf_resp = mfsdk.users.get(user_id="", token="") +mf_resp = mfsdk.users.get(user_id= user_id, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -52,13 +61,13 @@ """Updates user entities in the database""" user = { - "id": "", + "id": user_id, "name": "", "metadata": { "foo": "bar" } } -mf_resp = mfsdk.users.update(user_token="", user=user) +mf_resp = mfsdk.users.update(user_token= token, user=user) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -69,9 +78,9 @@ "credentials": { "identity": "", }, - "id": "" + "id": user_id } -mf_resp = mfsdk.users.update_user_identity(user_token="", user=user) +mf_resp = mfsdk.users.update_user_identity(user_token= token, user=user) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -79,14 +88,14 @@ """Updates user tags in the database""" user = { - "id": "", + "id": user_id, "name": "", "tags": [ "yellow", "orange" ] } -mf_resp = mfsdk.users.update_user_tags(user_token="", user=user) +mf_resp = mfsdk.users.update_user_tags(user_token= token, user=user) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -98,10 +107,10 @@ "identity": "", "secret": "" }, - "id": "", + "id": user_id, "owner": "" } -mf_resp = mfsdk.users.update_user_owner(user_token="", user=user) +mf_resp = mfsdk.users.update_user_owner(user_token= token, user=user) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -115,7 +124,7 @@ print(mf_resp.error.message) """User Password reset with the reset_request token""" -mf_resp = mfsdk.users.reset_password(password="", confirm_password="", token= "") +mf_resp = mfsdk.users.reset_password(password="", confirm_password="", token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -124,7 +133,7 @@ """You can get all users in the database by calling the get_all () function""" mf_resp = mfsdk.users.get_all( query_params={"offset": 0, "limit": 5}, - user_token="" + user_token= token ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -132,14 +141,14 @@ print(mf_resp.error.message) """Disables user""" -mf_resp = mfsdk.users.disable(user_id="", user_token="") +mf_resp = mfsdk.users.disable(user_id= user_id, user_token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) """Enables user""" -mf_resp = mfsdk.users.enable(user_id="", user_token="") +mf_resp = mfsdk.users.enable(user_id= user_id, user_token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -148,7 +157,7 @@ """Changing the user password can be done by calling the update password function""" mf_resp = mfsdk.users.update_password( old_secret="", new_secret="", - user_token="" + user_token= token ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -157,12 +166,12 @@ """Authorising a User""" access_request = { - "subject": "", - "object": "", + "subject": user_id, + "object": group_id, "action": "", "entity_type": "" } -mf_resp = mfsdk.users.authorise_user(access_request=access_request, token="") +mf_resp = mfsdk.users.authorise_user(access_request=access_request, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -170,12 +179,12 @@ """Authorising a Thing""" access_request = { - "subject": "", - "object": "", + "subject": thing_id, + "object": channel_id, "action": "", "entity_type": "" } -mf_resp = mfsdk.things.authorise_thing(access_request=access_request, token="") +mf_resp = mfsdk.things.authorise_thing(access_request=access_request, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -183,7 +192,7 @@ """To create a thing, you need the thing name and a user token""" mf_resp = mfsdk.things.create( - thing={"name": ""}, token="") + thing={"name": ""}, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -193,7 +202,7 @@ by entering a series of things structures and a user token""" mf_resp = mfsdk.things.create_bulk( things=[{"name": ""}, {"name": ""}, {"name": ""}], - token="", + token= token, ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -201,7 +210,7 @@ print(mf_resp.error.message) """You can get thing information by entering the thing ID and user token""" -mf_resp = mfsdk.things.get(thing_id= "", token="") +mf_resp = mfsdk.things.get(thing_id= thing_id, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -209,7 +218,7 @@ """You can get all things in the database by calling the get_all () function""" mf_resp = mfsdk.things.get_all( - query_params={"offset": 0, "limit": 5}, token="" + query_params={"offset": 0, "limit": 5}, token= token ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -218,7 +227,7 @@ """Updates a thing entity in a database""" mf_resp = mfsdk.things.update( - thing_id="", token="", thing={"name": ""} + thing_id=thing_id, token= token, thing={"name": ""} ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -227,7 +236,7 @@ """Updates a thing secret in a database""" mf_resp = mfsdk.things.update_thing_secret( - thing_id="", token="", thing={"secret": ""} + thing_id=thing_id, token= token, thing={"secret": ""} ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -236,14 +245,14 @@ """Updates a thing's tags in a database""" thing= { - "id": "", + "id": thing_id, "name": "", "tags": [ "dev","back" ] } mf_resp = mfsdk.things.update_thing_tags( - thing_id="", token="", thing=thing + thing_id=thing_id, token= token, thing=thing ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -252,12 +261,12 @@ """Updates a thing's owner""" thing= { - "id": "", + "id": thing_id, "name": "", "owner": "", } mf_resp = mfsdk.things.update_thing_owner( - thing_id="", token="", thing=thing + thing_id=thing_id, token= token, thing=thing ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -266,7 +275,7 @@ """You can get all thing connected to channel""" mf_resp = mfsdk.things.get_by_channel( - channel_id="", + channel_id=channel_id, query_params={"offset": 1, "limit": 5}, token="", ) @@ -276,7 +285,7 @@ print(mf_resp.error.message) """To disable a thing you need a thing ID and a user token""" -mf_resp = mfsdk.things.disable(thing_id="", token="") +mf_resp = mfsdk.things.disable(thing_id=thing_id, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -284,7 +293,7 @@ """Connect thing to channel""" mf_resp = mfsdk.things.connect( - channel_id="", thing_id="", action="", token="" + channel_id=channel_id, thing_id=thing_id, action="", token= token ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -293,7 +302,7 @@ """Disconnect thing from channel""" mf_resp = mfsdk.things.disconnect( - channel_id="", thing_id="", token="" + channel_id=channel_id, thing_id=thing_id, token= token ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -302,10 +311,10 @@ """Connect things to channels""" mf_resp = mfsdk.things.connects( - thing_ids=["", ""], + thing_ids=[thing_id, thing_id2], channel_ids=[""], actions="", - token="", + token= token, ) if mf_resp.error.status == 0: @@ -315,7 +324,7 @@ """Disconnect things from channels""" mf_resp = mfsdk.things.disconnects( - thing_ids=["", ""], + thing_ids=[thing_id, thing_id2], channel_ids=["", ""], token="", ) @@ -326,8 +335,8 @@ """Share thing""" mf_resp = mfsdk.things.share_thing( - channel_id= "", - user_id= "", + channel_id= channel_id, + user_id= user_id, actions= [""], token= "" ) @@ -338,7 +347,7 @@ """To create a channel, you need a channel and a token""" mf_resp = mfsdk.channels.create( - channel={"name": ""}, token="") + channel={"name": ""}, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -347,7 +356,7 @@ """As with things, you can create multiple channels at once""" mf_resp = mfsdk.channels.create_bulk( channels=[{"name": ""}, {"name": ""}], - token="", + token= token, ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -356,8 +365,8 @@ """Update channel entities in the database""" mf_resp = mfsdk.channels.update( - channel_id="", - token="", + channel_id=channel_id, + token= token, channel={"name": ""}, ) if mf_resp.error.status == 0: @@ -366,7 +375,7 @@ print(mf_resp.error.message) """You can get channel information by entering the channel ID and user token""" -mf_resp = mfsdk.channels.get(token="", channel_id="") +mf_resp = mfsdk.channels.get(token= token, channel_id=channel_id) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -375,7 +384,7 @@ """You can get all channels in the database by calling the get_all () function""" mf_resp = mfsdk.channels.get_all( - query_params={"offset": 0, "limit": 5}, token="" + query_params={"offset": 0, "limit": 5}, token= token ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -384,8 +393,8 @@ """A list of all the channels to which a given thing is connected""" mf_resp = mfsdk.channels.get_by_thing( - thing_id="", query_params={"offset": 0, "limit": 5}, - token="" + thing_id=thing_id, query_params={"offset": 0, "limit": 5}, + token= token ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -401,7 +410,7 @@ """Delete channels from the database""" mf_resp = mfsdk.channels.disable( - channel_id="", token="") + channel_id=channel_id, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -409,14 +418,14 @@ """To create a group, you need the group name and a user token""" mf_resp = mfsdk.groups.create( - group={"name": "group_name"}, token="") + group={"name": "group_name"}, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) """You can get group information by entering the group ID and token""" -mf_resp = mfsdk.groups.get(group_id="", token="") +mf_resp = mfsdk.groups.get(group_id= group_id, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -424,14 +433,14 @@ """Group update""" group={ - "id": "", + "id": group_id, "name": "", "metdata": { "foo": "bar" } } mf_resp = mfsdk.groups.update( - token="", group= group, group_id="group_id" + token= token, group= group, group_id="group_id" ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -440,7 +449,7 @@ """You can get groups in the database by calling the get_all () function""" mf_resp = mfsdk.groups.get_all( - token="", query_params={"offset": 0, "limit": 5} + token= token, query_params={"offset": 0, "limit": 5} ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -449,8 +458,8 @@ """Assign user to a group""" mf_resp = mfsdk.groups.assign( - group_id="", - token="", + group_id=group_id, + token= token, member_id="", member_type=[""], ) @@ -462,7 +471,7 @@ """Unassign""" mf_resp = mfsdk.groups.unassign( group_id="", - token="", + token= token, members_ids="", ) if mf_resp.error.status == 0: @@ -472,7 +481,7 @@ """Get list of children from group""" mf_resp = mfsdk.groups.children( - group_id="", token="", + group_id=group_id, token= token, query_params={"offset": 0, "limit": 5} ) if mf_resp.error.status == 0: @@ -482,7 +491,7 @@ """Get list of parents from group""" mf_resp = mfsdk.groups.parents( - group_id="", token="", + group_id=group_id, token= token, query_params={"offset": 0, "limit": 5} ) if mf_resp.error.status == 0: @@ -492,7 +501,7 @@ """Get list of members from group""" mf_resp = mfsdk.groups.members( - group_id="", token="", + group_id=group_id, token= token, query_params={"offset": 0, "limit": 5} ) if mf_resp.error.status == 0: @@ -503,7 +512,7 @@ """Get list of memberships from member""" mf_resp = mfsdk.groups.memberships( member_id="", - token="", + token= token, query_params={"offset": 0, "limit": 5}, ) if mf_resp.error.status == 0: @@ -512,7 +521,7 @@ print(mf_resp.error.message) """Delete group from the database""" -mf_resp = mfsdk.groups.disable(group_id="", user_token="") +mf_resp = mfsdk.groups.disable(group_id=group_id, user_token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -520,7 +529,7 @@ """Sends message via HTTP protocol""" mf_resp = mfsdk.messages.send( - channel_id="", msg='<[message]>', thing_key="" + channel_id=channel_id, msg='[]', thing_key="" ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -528,35 +537,35 @@ print(mf_resp.error.message) """Reads messages from database for a given channel""" -mf_resp = mfsdk.messages.read(channel_id="", token="") +mf_resp = mfsdk.messages.read(channel_id=channel_id, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) """Issue certs""" -mf_resp = mfsdk.certs.issue(thing_id="",valid="", token="") +mf_resp = mfsdk.certs.issue(thing_id=thing_id,valid="", token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) """View Certs""" -mf_resp = mfsdk.certs.view_by_thing(thing_id="", token="") +mf_resp = mfsdk.certs.view_by_thing(thing_id=thing_id, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) """View Certs""" -mf_resp = mfsdk.certs.view_by_serial(cert_id="", token="") +mf_resp = mfsdk.certs.view_by_serial(cert_id="", token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) """Revoke Certs""" -mf_resp = mfsdk.certs.revoke(thing_id="", token="") +mf_resp = mfsdk.certs.revoke(thing_id=thing_id, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -566,30 +575,30 @@ config = { "external_id": "", "external_key": "", - "thing_id": "", + "thing_id": thing_id, "name": "" } -mf_resp = mfsdk.bootstrap.add(config=config, token="") +mf_resp = mfsdk.bootstrap.add(config=config, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) - + """Updating state represents enabling/disabling Config, i.e.connecting and disconnecting corresponding Mainflux Thing to the list of Channels.""" config = { "external_id": "", "external_key": "", - "thing_id": "", + "thing_id": thing_id, "name": "" } -mf_resp = mfsdk.bootstrap.whitelist(config=config, token="") +mf_resp = mfsdk.bootstrap.whitelist(config=config, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: print(mf_resp.error.message) """Retrieves a configuration with given config id""" -mf_resp = mfsdk.bootstrap.view(thing_id= "", token="") +mf_resp = mfsdk.bootstrap.view(thing_id= thing_id, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -599,10 +608,10 @@ config = { "external_id": "", "external_key": "", - "thing_id": "", + "thing_id": thing_id, "name": "" } -mf_resp = mfsdk.bootstrap.update(config=config, token="") +mf_resp = mfsdk.bootstrap.update(config=config, token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -616,7 +625,7 @@ print(mf_resp.error.message) """Removes a Config. In case of successful removal the service will ensure that the removed config is disconnected from all the Mainflux channels.""" -mf_resp = mfsdk.bootstrap.remove(config_id= "", token="") +mf_resp = mfsdk.bootstrap.remove(config_id= "", token= token) if mf_resp.error.status == 0: print(mf_resp.value) else: From 95b74ce0f21c9cd2a8bf96106040837727ef6758 Mon Sep 17 00:00:00 2001 From: Musilah Date: Mon, 23 Oct 2023 16:01:16 +0300 Subject: [PATCH 28/31] add a few more variables Signed-off-by: Musilah --- examples/examples.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/examples/examples.py b/examples/examples.py index 7d43ad6..e77cb57 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -15,16 +15,20 @@ """Repetitive values that can be easily fed into the example code""" user_id = "", -token = "", +token = "", thing_id = "", channel_id = "", group_id = "", thing_id2 = "", +email = "", +password = "", +refresh_token = "", +channel_id2 = "", """To start working with the Mainflux system, you need to create a user account""" mf_resp = mfsdk.users.create( - user={"credentials": {"identity": "", "secret": ""}}, + user={"credentials": {"identity": "", "secret": password}}, token= token, ) if mf_resp.error.status == 0: @@ -34,7 +38,7 @@ """To log in to the Mainflux system, you need to create a user token""" mf_resp = mfsdk.users.login( - user={ "identity" : "", "secret": ""} + user={ "identity" : "", "secret": password} ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -44,7 +48,7 @@ """Refreshes Access and Refresh Token used for authenticating into the system.""" mf_resp = mfsdk.users.refresh_token( - refresh_token="" + refresh_token= refresh_token ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -105,7 +109,7 @@ user = { "credentials": { "identity": "", - "secret": "" + "secret": password, }, "id": user_id, "owner": "" @@ -117,7 +121,7 @@ print(mf_resp.error.message) """User Password reset request""" -mf_resp = mfsdk.users.reset_password_request(email= "", url= "http://localhost/reset-request") +mf_resp = mfsdk.users.reset_password_request(email= email, url= "http://localhost/reset-request") if mf_resp.error.status == 0: print(mf_resp.value) else: @@ -236,7 +240,7 @@ """Updates a thing secret in a database""" mf_resp = mfsdk.things.update_thing_secret( - thing_id=thing_id, token= token, thing={"secret": ""} + thing_id=thing_id, token= token, thing={"secret": password} ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -277,7 +281,7 @@ mf_resp = mfsdk.things.get_by_channel( channel_id=channel_id, query_params={"offset": 1, "limit": 5}, - token="", + token=token, ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -312,7 +316,7 @@ """Connect things to channels""" mf_resp = mfsdk.things.connects( thing_ids=[thing_id, thing_id2], - channel_ids=[""], + channel_ids=[channel_id, channel_id2], actions="", token= token, ) @@ -325,8 +329,8 @@ """Disconnect things from channels""" mf_resp = mfsdk.things.disconnects( thing_ids=[thing_id, thing_id2], - channel_ids=["", ""], - token="", + channel_ids=[channel_id, channel_id2], + token=token, ) if mf_resp.error.status == 0: print(mf_resp.value) @@ -338,7 +342,7 @@ channel_id= channel_id, user_id= user_id, actions= [""], - token= "" + token= token, ) if mf_resp.error.status == 0: print(mf_resp.value) From 2c3badbd70d98c2eaf5c31a902cb55f1b8c01022 Mon Sep 17 00:00:00 2001 From: Musilah Date: Wed, 25 Oct 2023 17:18:55 +0300 Subject: [PATCH 29/31] fix examples.py Signed-off-by: Musilah --- examples/examples.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/examples.py b/examples/examples.py index e77cb57..f01e0d0 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -14,16 +14,16 @@ """Repetitive values that can be easily fed into the example code""" +email = "", +password = "", user_id = "", token = "", +refresh_token = "", thing_id = "", -channel_id = "", -group_id = "", thing_id2 = "", -email = "", -password = "", -refresh_token = "", +channel_id = "", channel_id2 = "", +group_id = "", """To start working with the Mainflux system, you need to create a user account""" From c0faa18660cb2b6c45b68d831ee1d5970f90cbf5 Mon Sep 17 00:00:00 2001 From: Musilah Date: Fri, 27 Oct 2023 14:05:06 +0300 Subject: [PATCH 30/31] attempt to fix Markdown Signed-off-by: Musilah --- docs/boostrap.md | 64 ++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/docs/boostrap.md b/docs/boostrap.md index fc2fdcf..c50b59e 100644 --- a/docs/boostrap.md +++ b/docs/boostrap.md @@ -22,11 +22,11 @@ Bootstrap service is used to manage configurations for Mainflux Things. It provi **Attributes:** - - `url` (str): Mainflux Bootstrap API URL. - - `CONFIGS_ENDPOINT` (str): Configurations API endpoint. - - `BOOTSTRAP_ENDPOINT` (str): Bootstrap API endpoint. - - `WHITELIST_ENDPOINT` (str): Whitelist API endpoint. - - `BOOTSTRAP_CERTS_ENDPOINT` (str): Bootstrap certificates API endpoint. + - **`url`** (str): Mainflux Bootstrap API URL. + - **`CONFIGS_ENDPOINT`** (str): Configurations API endpoint. + - **`BOOTSTRAP_ENDPOINT`** (str): Bootstrap API endpoint. + - **`WHITELIST_ENDPOINT`** (str): Whitelist API endpoint. + - **`BOOTSTRAP_CERTS_ENDPOINT`** (str): Bootstrap certificates API endpoint. @@ -46,7 +46,7 @@ params: url (str): Mainflux Bootstrap API URL. **returns:** - - `Bootstrap`: Bootstrap object. + - **`Bootstrap`**: Bootstrap object. @@ -76,22 +76,22 @@ params: config (dict): Configuration data for example: { "external_id": "1 **returns:** - - `mf_response `: response.Response. + - **`mf_response `**: response.Response. Usage: ``` from mainflux import sdk``` - - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") >>> config = { - - ` ... "external_id"`: "123", + - **` ... "external_id"`**: "123", - - ` ... "external_key"`: "456", + - **` ... "external_key"`**: "456", - - ` ... "thing_id"`: "fdb1057c-2905-4f71-9a80-e0ce9191e667", + - **` ... "thing_id"`**: "fdb1057c-2905-4f71-9a80-e0ce9191e667", - - ` ... "name"`: "thing_name" + - **` ... "name"`**: "thing_name" ... } >>> mf_resp = mfsdk.bootstrap.add(config, token) >>> mf_resp @@ -115,13 +115,13 @@ params: external_id (str): External ID. external_key (str): External key. **returns:** - - `mf_resp `: response.Response - response object. + - **`mf_resp `**: response.Response - response object. Usage: ``` from mainflux import sdk``` - - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") >>> external_id = "external_id" >>> external_key = "external_key" >>> mf_resp = mfsdk.bootstrap.bootstrap(external_id, external_key) @@ -146,13 +146,13 @@ params: config_id (str): Configuration ID. token (str): Authorization token. **returns:** - - `mf_response `: response.Response. + - **`mf_response `**: response.Response. Usage: ``` from mainflux import sdk``` - - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") >>> config_id = "config_id" >>> mf_resp = mfsdk.bootstrap.remove(config_id, token) >>> mf_resp @@ -178,22 +178,22 @@ params: config (dict): Configuration data for example: { "external_id": "1 - - `mf_response `: response.Response. + - **`mf_response `**: response.Response. Usage: ``` from mainflux import sdk``` - - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") >>> config = { - - ` ... "external_id"`: "123", + - **` ... "external_id"`**: "123", - - ` ... "external_key"`: "456", + - **` ... "external_key"`**: "456", - - ` ... "thing_id"`: "fdb1057c-2905-4f71-9a80-e0ce9191e667", + - **` ... "thing_id"`**: "fdb1057c-2905-4f71-9a80-e0ce9191e667", - - ` ... "name"`: "thing_name" + - **` ... "name"`**: "thing_name" ... } >>> mf_resp = mfsdk.bootstrap.update(config, token) >>> mf_resp @@ -223,13 +223,13 @@ params: config_id (str): Configuration ID. client_cert (str): Client certific **returns:** - - `mf_response `: response.Response. + - **`mf_response `**: response.Response. Usage: ``` from mainflux import sdk``` - - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") >>> config_id = "config_id" >>> client_cert = "client_cert" >>> client_key = "client_key" @@ -258,13 +258,13 @@ params: thing_id (str): Thing ID. token (str): Authorization token. **returns:** - - `mf_resp `: response.Response - response object. + - **`mf_resp `**: response.Response - response object. Usage: ``` from mainflux import sdk``` - - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") >>> thing_id = "thing_id" >>> mf_resp = mfsdk.bootstrap.view(thing_id, token) >>> mf_resp @@ -288,22 +288,22 @@ params: config (dict): Configuration data for example: { "external_id": "1 **returns:** - - `mf_response `: response.Response. + - **`mf_response `**: response.Response. Usage: ``` from mainflux import sdk``` - - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") + - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") >>> config = { - - ` ... "external_id"`: "123", + - **` ... "external_id"`**: "123", - - ` ... "external_key"`: "456", + - **` ... "external_key"`**: "456", - - ` ... "thing_id"`: "fdb1057c-2905-4f71-9a80-e0ce9191e667", + - **` ... "thing_id"`**: "fdb1057c-2905-4f71-9a80-e0ce9191e667", - - ` ... "name"`: "thing_name" + - **` ... "name"`**: "thing_name" ... } >>> mf_resp = mfsdk.bootstrap.whitelist(config, token) >>> mf_resp From 7286ef5aeaab52b39b8e67bf1e54c747b296b66d Mon Sep 17 00:00:00 2001 From: Musilah Date: Fri, 27 Oct 2023 15:13:48 +0300 Subject: [PATCH 31/31] regenerate docs Signed-off-by: Musilah --- docs/boostrap.md | 64 ++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/docs/boostrap.md b/docs/boostrap.md index c50b59e..fc2fdcf 100644 --- a/docs/boostrap.md +++ b/docs/boostrap.md @@ -22,11 +22,11 @@ Bootstrap service is used to manage configurations for Mainflux Things. It provi **Attributes:** - - **`url`** (str): Mainflux Bootstrap API URL. - - **`CONFIGS_ENDPOINT`** (str): Configurations API endpoint. - - **`BOOTSTRAP_ENDPOINT`** (str): Bootstrap API endpoint. - - **`WHITELIST_ENDPOINT`** (str): Whitelist API endpoint. - - **`BOOTSTRAP_CERTS_ENDPOINT`** (str): Bootstrap certificates API endpoint. + - `url` (str): Mainflux Bootstrap API URL. + - `CONFIGS_ENDPOINT` (str): Configurations API endpoint. + - `BOOTSTRAP_ENDPOINT` (str): Bootstrap API endpoint. + - `WHITELIST_ENDPOINT` (str): Whitelist API endpoint. + - `BOOTSTRAP_CERTS_ENDPOINT` (str): Bootstrap certificates API endpoint. @@ -46,7 +46,7 @@ params: url (str): Mainflux Bootstrap API URL. **returns:** - - **`Bootstrap`**: Bootstrap object. + - `Bootstrap`: Bootstrap object. @@ -76,22 +76,22 @@ params: config (dict): Configuration data for example: { "external_id": "1 **returns:** - - **`mf_response `**: response.Response. + - `mf_response `: response.Response. Usage: ``` from mainflux import sdk``` - - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") >>> config = { - - **` ... "external_id"`**: "123", + - ` ... "external_id"`: "123", - - **` ... "external_key"`**: "456", + - ` ... "external_key"`: "456", - - **` ... "thing_id"`**: "fdb1057c-2905-4f71-9a80-e0ce9191e667", + - ` ... "thing_id"`: "fdb1057c-2905-4f71-9a80-e0ce9191e667", - - **` ... "name"`**: "thing_name" + - ` ... "name"`: "thing_name" ... } >>> mf_resp = mfsdk.bootstrap.add(config, token) >>> mf_resp @@ -115,13 +115,13 @@ params: external_id (str): External ID. external_key (str): External key. **returns:** - - **`mf_resp `**: response.Response - response object. + - `mf_resp `: response.Response - response object. Usage: ``` from mainflux import sdk``` - - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") >>> external_id = "external_id" >>> external_key = "external_key" >>> mf_resp = mfsdk.bootstrap.bootstrap(external_id, external_key) @@ -146,13 +146,13 @@ params: config_id (str): Configuration ID. token (str): Authorization token. **returns:** - - **`mf_response `**: response.Response. + - `mf_response `: response.Response. Usage: ``` from mainflux import sdk``` - - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") >>> config_id = "config_id" >>> mf_resp = mfsdk.bootstrap.remove(config_id, token) >>> mf_resp @@ -178,22 +178,22 @@ params: config (dict): Configuration data for example: { "external_id": "1 - - **`mf_response `**: response.Response. + - `mf_response `: response.Response. Usage: ``` from mainflux import sdk``` - - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") >>> config = { - - **` ... "external_id"`**: "123", + - ` ... "external_id"`: "123", - - **` ... "external_key"`**: "456", + - ` ... "external_key"`: "456", - - **` ... "thing_id"`**: "fdb1057c-2905-4f71-9a80-e0ce9191e667", + - ` ... "thing_id"`: "fdb1057c-2905-4f71-9a80-e0ce9191e667", - - **` ... "name"`**: "thing_name" + - ` ... "name"`: "thing_name" ... } >>> mf_resp = mfsdk.bootstrap.update(config, token) >>> mf_resp @@ -223,13 +223,13 @@ params: config_id (str): Configuration ID. client_cert (str): Client certific **returns:** - - **`mf_response `**: response.Response. + - `mf_response `: response.Response. Usage: ``` from mainflux import sdk``` - - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") >>> config_id = "config_id" >>> client_cert = "client_cert" >>> client_key = "client_key" @@ -258,13 +258,13 @@ params: thing_id (str): Thing ID. token (str): Authorization token. **returns:** - - **`mf_resp `**: response.Response - response object. + - `mf_resp `: response.Response - response object. Usage: ``` from mainflux import sdk``` - - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") >>> thing_id = "thing_id" >>> mf_resp = mfsdk.bootstrap.view(thing_id, token) >>> mf_resp @@ -288,22 +288,22 @@ params: config (dict): Configuration data for example: { "external_id": "1 **returns:** - - **`mf_response `**: response.Response. + - `mf_response `: response.Response. Usage: ``` from mainflux import sdk``` - - **` >>> mfsdk = sdk.SDK(bootstrap_url="http`**: //localhost:9013") + - ` >>> mfsdk = sdk.SDK(bootstrap_url="http`: //localhost:9013") >>> config = { - - **` ... "external_id"`**: "123", + - ` ... "external_id"`: "123", - - **` ... "external_key"`**: "456", + - ` ... "external_key"`: "456", - - **` ... "thing_id"`**: "fdb1057c-2905-4f71-9a80-e0ce9191e667", + - ` ... "thing_id"`: "fdb1057c-2905-4f71-9a80-e0ce9191e667", - - **` ... "name"`**: "thing_name" + - ` ... "name"`: "thing_name" ... } >>> mf_resp = mfsdk.bootstrap.whitelist(config, token) >>> mf_resp