diff --git a/src/bcr_api/bwproject.py b/src/bcr_api/bwproject.py old mode 100644 new mode 100755 index 6344999..332f145 --- a/src/bcr_api/bwproject.py +++ b/src/bcr_api/bwproject.py @@ -38,6 +38,7 @@ def __init__( grant_type="api-password", client_id="brandwatch-api-client", apiurl="https://api.brandwatch.com/", + secondary_user=None ): """ Creates a BWUser object. @@ -51,22 +52,39 @@ def __init__( self.apiurl = apiurl self.oauthpath = "oauth/token" self.credentials_store = CredentialsStore(credentials_path=token_path) - if token: - self.username, self.token = self._test_auth(username, token) - self.credentials_store[self.username] = self.token - elif username is not None and password is not None: - self.username, self.token = self._get_auth( - username, password, token_path, grant_type, client_id - ) - if token_path is not None: - self.credentials_store[self.username] = self.token - elif username is not None: - self.username = username - self.token = self.credentials_store[username] + + if secondary_user: + grant_type="application-become" + client_id="brandwatch-application-client" + self.username, self.token = self._get_auth(username, password, token_path, "password", client_id) + url = ("https://api.brandwatch.com/oauth/token?access_token={0}"\ + "&username={1}"\ + "&grant_type={2}"\ + "&client_id={3}" + ).format(self.token, secondary_user, grant_type, client_id) + r = requests.post(url) + + if "access_token" in r.json(): + self.token = r.json()["access_token"] + self._test_auth(secondary_user, self.token) + else: + raise KeyError("Failed to become %s" % secondary_user) else: - raise KeyError( - "Must provide valid token, username and password, or username and path to token file" - ) + if token: + self.username, self.token = self._test_auth(username, token) + self.credentials_store[self.username] = self.token + elif username is not None and password is not None: + self.username, self.token = self._get_auth( + username, password, token_path, grant_type, client_id) + if token_path is not None: + self.credentials_store[self.username] = self.token + elif username is not None: + self.username = username + self.token = self.credentials_store[username] + else: + raise KeyError( + "Must provide valid token, username and password, or username and path to token file" + ) def _test_auth(self, username, token): @@ -120,19 +138,19 @@ def validate_query_search(self, **kwargs): Checks a query search to see if it contains errors. Same query debugging as used in the front end. Keyword Args: - query: Search terms included in the query. + booleanQuery: Search terms included in the query. language: List of the languages in which you'd like to test the query - Optional. Raises: KeyError: If you don't pass a search or if the search has errors in it. """ - if "query" not in kwargs: + if "booleanQuery" not in kwargs: raise KeyError("Must pass: query = 'search terms'") if "language" not in kwargs: kwargs["language"] = ["en"] valid_search = self.request( - verb=requests.get, address="query-validation", params=kwargs + verb=requests.post, address="query-validation", params=kwargs ) return valid_search @@ -141,14 +159,14 @@ def validate_rule_search(self, **kwargs): Checks a rule search to see if it contains errors. Same rule debugging as used in the front end. Keyword Args: - query: Search terms included in the rule. + booleanQuery: Search terms included in the rule. language: List of the languages in which you'd like to test the query - Optional. Raises: KeyError: If you don't pass a search or if the search has errors in it. """ - if "query" not in kwargs: - raise KeyError("Must pass: query = 'search terms'") + if "booleanQuery" not in kwargs: + raise KeyError("Must pass: booleanQuery = 'search terms'") if "language" not in kwargs: kwargs["language"] = ["en"] @@ -258,6 +276,7 @@ def __init__( grant_type="api-password", client_id="brandwatch-api-client", apiurl="https://api.brandwatch.com/", + secondary_user = None ): """ Creates a BWProject object - inheriting directly from the BWUser class. @@ -269,6 +288,10 @@ def __init__( token: Access token - Optional. token_path: File path to the file where access tokens will be read from and written to - Optional. """ + if secondary_user: + grant_type="application-become" + client_id="brandwatch-application-client" + super().__init__( token=token, token_path=token_path, @@ -277,6 +300,7 @@ def __init__( grant_type=grant_type, client_id=client_id, apiurl=apiurl, + secondary_user = secondary_user ) self.project_name = "" self.project_id = -1 diff --git a/src/bcr_api/bwresources.py b/src/bcr_api/bwresources.py old mode 100644 new mode 100755 index 0a35fd2..1bc234b --- a/src/bcr_api/bwresources.py +++ b/src/bcr_api/bwresources.py @@ -273,9 +273,8 @@ def upload(self, create_only=False, modify_only=False, **kwargs): startDate: Date for query data to be collected from (equivalent to backfill_date in Analytics SDK) contentSources: Optional, defaults to same sources in UI description: Optional, defaults to empty string (e.g. "a query to find mentions about cats and dogs") - languages: Optional, defaults to en - languageAgnostic: Optional, set to True instead of passing in a language for the query to match against all mentions regardless of language (generally not recommended) - monitor_sample_percentage: Optional, defaults to 100 (percent) + languages: Optional, defaults to en. Pass in no arguments to make the query language agnostic + samplePercentage: Optional, defaults to 100 (percent) query_type: Optional, defaults to 'monitor' Raises: @@ -296,9 +295,8 @@ def upload_all(self, data_list, create_only=False, modify_only=False): startDate: Date for query data to be collected from (equivalent to backfill_date in Analytics SDK) contentSources: Optional, defaults to same sources in UI description: Optional, defaults to empty string (e.g. "a query to find mentions about cats and dogs") - languages: Optional, defaults to en - languageAgnostic: Optional, set to True instead of passing in a language for the query to match against all mentions regardless of language (generally not recommended) - monitor_sample_percentage: Optional, defaults to 100 (percent) + languages: Optional, defaults to en. Pass in no arguments to make the query language agnostic + samplePercentage: Optional, defaults to 100 (percent) query_type: Optional, defaults to 'monitor' Raises: @@ -329,10 +327,10 @@ def rename(self, name, new_name): raise KeyError( "Cannot rename a " + self.resource_type + " which does not exist", name ) - else: + else: #does exist info = self.get(name=name) info.pop("name") - if info["type"] == "search string": + if info["type"] == "monitor": self.upload(name=name, new_name=new_name, **info) else: raise KeyError( @@ -465,11 +463,6 @@ def _fill_data(self, data): if ("name" not in data) or ("booleanQuery" not in data): raise KeyError("Need name and booleanQuery to post query", data) - if ("language" in data) and ("languageAgnostic" in data): - raise ValueError( - "Please choose either to specify languages or a language agnostic query" - ) - filled["booleanQuery"] = data["booleanQuery"] # if resource exists, create value for filled['id'] @@ -482,12 +475,13 @@ def _fill_data(self, data): # params with default values filled["type"] = data.get("query_type", "monitor") - filled["languageAgnostic"] = data.get("languageAgnostic", False) filled["contentSources"] = data.get("contentSources", default_content_sources) - filled["monitorSamplePercentage"] = data.get("monitorSamplePercentage", 100) + filled["samplePercentage"] = data.get("samplePercentage", 100) filled["description"] = data.get("description", "") - # currently languages field defaults to 'en', similar to UI, but it could alternatively default to False, to create a language agnostic query - filled["languages"] = data.get("languages", "en") + # currently languages field defaults to 'en', similar to UI, but it could alternatively default to an empty list, to create a language agnostic query + filled["languages"] = data.get( + "languages", "en" + ) # BUG: Might need to turn single item into list # If user passes in string to languages parameter, turn into a list containing only that string if isinstance(filled["languages"], str): filled["languages"] = [filled["languages"]] @@ -495,6 +489,9 @@ def _fill_data(self, data): # optional params, with no defaults if "startDate" in data: filled["startDate"] = data["startDate"] + # languageAgnostic is a deprecated variable. If a user does not pass in any language arguments, the languages attribute will create an empty list. + if "language" not in data: + filled["languages"] = [] # validating the query search - comment this out to skip validation self.project.validate_query_search( @@ -1842,4 +1839,4 @@ def _name_to_id(self, attribute, setting): else: return {"excludeTagIds": ids} else: - return {} + return {} \ No newline at end of file diff --git a/src/bcr_api/filters.py b/src/bcr_api/filters.py old mode 100644 new mode 100755 index 9754130..4b70334 --- a/src/bcr_api/filters.py +++ b/src/bcr_api/filters.py @@ -143,25 +143,37 @@ "blog", "forum", "news", - "general", - "video", "twitter", "review", - "image", "instagram", "facebook", + "qq", + "reddit", + "tumblr", + "vk", + "youtube", + "lexis_nexis_licensed_news", + "dark_web", + "sina_weibo", + "four_chan", ], "xpageType": [ "blog", "forum", "news", - "general", - "video", "twitter", "review", - "image", "instagram", "facebook", + "qq", + "reddit", + "tumblr", + "vk", + "youtube", + "lexis_nexis_licensed_news", + "dark_web", + "sina_weibo", + "four_chan", ], "accountType": ["individual", "organizational"], "xaccountType": ["individual", "organizational"], @@ -266,4 +278,4 @@ "removeStatus": ["open", "pending", "closed"], "priority": ["high", "medium", "low"], "removePriority": ["high", "medium", "low"], -} +} \ No newline at end of file