You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by GitBox <gi...@apache.org> on 2020/03/17 14:07:50 UTC

[GitHub] [airflow] michalslowikowski00 opened a new pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

michalslowikowski00 opened a new pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748
 
 
   The operator lists webProperty-Google Ads links for a given web property
   ---
   Issue link: WILL BE INSERTED BY [boring-cyborg](https://github.com/kaxil/boring-cyborg)
   
   Make sure to mark the boxes below before creating PR: [x]
   
   - [x] Description above provides context of the change
   - [x] Commit message/PR title starts with `[AIRFLOW-NNNN]`. AIRFLOW-NNNN = JIRA ID<sup>*</sup>
   - [x] Unit tests coverage for changes (not needed for documentation changes)
   - [x] Commits follow "[How to write a good git commit message](http://chris.beams.io/posts/git-commit/)"
   - [x] Relevant documentation is updated including usage instructions.
   - [x] I will engage committers as explained in [Contribution Workflow Example](https://github.com/apache/airflow/blob/master/CONTRIBUTING.rst#contribution-workflow-example).
   
   <sup>*</sup> For document-only changes commit message can start with `[AIRFLOW-XXXX]`.
   
   ---
   In case of fundamental code change, Airflow Improvement Proposal ([AIP](https://cwiki.apache.org/confluence/display/AIRFLOW/Airflow+Improvements+Proposals)) is needed.
   In case of a new dependency, check compliance with the [ASF 3rd Party License Policy](https://www.apache.org/legal/resolved.html#category-x).
   In case of backwards incompatible changes please leave a note in [UPDATING.md](https://github.com/apache/airflow/blob/master/UPDATING.md).
   Read the [Pull Request Guidelines](https://github.com/apache/airflow/blob/master/CONTRIBUTING.rst#pull-request-guidelines) for more information.
   

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] nuclearpinguin commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
nuclearpinguin commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r394179317
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/hooks/analytics.py
 ##########
 @@ -66,10 +66,43 @@ def list_accounts(self) -> List[Dict[str, Any]]:
             # start index has value 1
             request = accounts.list(start_index=len(result) + 1)
             response = request.execute(num_retries=self.num_retries)
-            result.extend(response.get('items', []))
+            result.extend(response.get("items", []))
             # result is the number of fetched accounts from Analytics
             # when all accounts will be add to the result
             # the loop will be break
             if response["totalResults"] <= len(result):
                 break
         return result
+
+    def list_ad_words_links(
+        self, account_id: str, web_property_id: str
+    ) -> List[Dict[str, Any]]:
+        """
+        Lists webProperty-Google Ads links for a given web property.
+
+        # :param account_id: ID of the account which the given web property belongs to.
+        # :type account_id: str
+        # :param web_property_id: Web property ID to retrieve the Google Ads links for.
+        # :type web_property_id: str
 
 Review comment:
   Let's also fix this in `__init__`:
   `gcp_connection_id: str = "google cloud default"` -> `gcp_connection_id: str = "google_cloud_default"`

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r393891481
 
 

 ##########
 File path: docs/howto/operator/gcp/analytics.rst
 ##########
 @@ -48,3 +48,18 @@ To list accounts from Analytics you can use the
 
 You can use :ref:`Jinja templating <jinja-templating>` with
 :template-fields:`airflow.providers.google.marketing_platform.operators.analytics.GoogleAnalyticsListAccountsOperator`
+
+List Google Ads Links
+^^^^^^^^^^^^^^^^^^^^^
+
+To list Google Ads links you can use the
 
 Review comment:
   I think it would also be great to describe that "list" means store as xcom.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r394939034
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/hooks/analytics.py
 ##########
 @@ -66,10 +66,43 @@ def list_accounts(self) -> List[Dict[str, Any]]:
             # start index has value 1
             request = accounts.list(start_index=len(result) + 1)
             response = request.execute(num_retries=self.num_retries)
-            result.extend(response.get('items', []))
+            result.extend(response.get("items", []))
             # result is the number of fetched accounts from Analytics
             # when all accounts will be add to the result
             # the loop will be break
             if response["totalResults"] <= len(result):
                 break
         return result
+
+    def list_ad_words_links(
+        self, account_id: str, web_property_id: str
+    ) -> List[Dict[str, Any]]:
+        """
+        Lists webProperty-Google Ads links for a given web property.
+
+        # :param account_id: ID of the account which the given web property belongs to.
+        # :type account_id: str
+        # :param web_property_id: Web property ID to retrieve the Google Ads links for.
+        # :type web_property_id: str
+
+        """
+
+        self.log.info("Retrieving ad words list...")
+        result = []  # type: List[Dict]
+        conn = self.get_conn()
+        ads_links = conn.management().webPropertyAdWordsLinks()  # pylint: disable=no-member
+        while True:
+            # start index has value 1
+            request = ads_links.list(
+                accountId=account_id,
+                webPropertyId=web_property_id,
+                start_index=len(result) + 1,
+            )
+            response = request.execute(num_retries=self.num_retries)
+            result.extend(response.get("items", []))
+            # result is the number of fetched links from Analytics
+            # when all links will be add to the result
+            # the loop will be break
 
 Review comment:
   Done

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] potiuk merged pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
potiuk merged pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748
 
 
   

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r395267335
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/example_dags/example_analytics.py
 ##########
 @@ -20,12 +20,15 @@
 
 from airflow import models
 from airflow.providers.google.marketing_platform.operators.analytics import (
-    GoogleAnalyticsListAccountsOperator,
+    GoogleAnalyticsListAccountsOperator, GoogleAnalyticsRetrieveAdsLinksListOperator,
 )
 from airflow.utils import dates
 
 default_args = {"start_date": dates.days_ago(1)}
 
+account_id = "12345"
+web_property_id = "web_property_id"
 
 Review comment:
   Done.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] nuclearpinguin commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
nuclearpinguin commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r394180772
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/hooks/analytics.py
 ##########
 @@ -66,10 +66,43 @@ def list_accounts(self) -> List[Dict[str, Any]]:
             # start index has value 1
             request = accounts.list(start_index=len(result) + 1)
             response = request.execute(num_retries=self.num_retries)
-            result.extend(response.get('items', []))
+            result.extend(response.get("items", []))
             # result is the number of fetched accounts from Analytics
             # when all accounts will be add to the result
             # the loop will be break
             if response["totalResults"] <= len(result):
                 break
         return result
+
+    def list_ad_words_links(
+        self, account_id: str, web_property_id: str
+    ) -> List[Dict[str, Any]]:
+        """
+        Lists webProperty-Google Ads links for a given web property.
+
+        # :param account_id: ID of the account which the given web property belongs to.
+        # :type account_id: str
+        # :param web_property_id: Web property ID to retrieve the Google Ads links for.
 
 Review comment:
   ```suggestion
           # :param web_property_id: Web property UA-string to retrieve the Google Ads links for.
   ```

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r394941128
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/hooks/analytics.py
 ##########
 @@ -66,10 +66,43 @@ def list_accounts(self) -> List[Dict[str, Any]]:
             # start index has value 1
             request = accounts.list(start_index=len(result) + 1)
             response = request.execute(num_retries=self.num_retries)
-            result.extend(response.get('items', []))
+            result.extend(response.get("items", []))
             # result is the number of fetched accounts from Analytics
             # when all accounts will be add to the result
             # the loop will be break
             if response["totalResults"] <= len(result):
                 break
         return result
+
+    def list_ad_words_links(
+        self, account_id: str, web_property_id: str
+    ) -> List[Dict[str, Any]]:
+        """
+        Lists webProperty-Google Ads links for a given web property.
+
+        # :param account_id: ID of the account which the given web property belongs to.
+        # :type account_id: str
+        # :param web_property_id: Web property ID to retrieve the Google Ads links for.
 
 Review comment:
   Same here, the description is taken from API docs. 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] nuclearpinguin commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
nuclearpinguin commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r394957902
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/operators/analytics.py
 ##########
 @@ -44,21 +44,79 @@ class GoogleAnalyticsListAccountsOperator(BaseOperator):
     :type gcp_conn_id: str
     """
 
-    template_fields = ("api_version", "gcp_connection_id",)
+    template_fields = (
+        "api_version",
+        "gcp_connection_id",
+    )
 
     @apply_defaults
-    def __init__(self,
-                 api_version: str = "v3",
-                 gcp_connection_id: str = "google_cloud_default",
-                 *args,
-                 **kwargs):
+    def __init__(
+        self,
+        api_version: str = "v3",
+        gcp_connection_id: str = "google_cloud_default",
+        *args,
+        **kwargs
+    ):
         super().__init__(*args, **kwargs)
 
         self.api_version = api_version
         self.gcp_connection_id = gcp_connection_id
 
     def execute(self, context):
-        hook = GoogleAnalyticsHook(api_version=self.api_version,
-                                   gcp_connection_id=self.gcp_connection_id)
+        hook = GoogleAnalyticsHook(
+            api_version=self.api_version, gcp_connection_id=self.gcp_connection_id
+        )
         result = hook.list_accounts()
         return result
+
+
+class GoogleAnalyticsRetrieveAdsLinksListOperator(BaseOperator):
+    """
+    Lists webProperty-Google Ads links for a given web property
+
+    .. seealso::
+        Check official API docs:
+        https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/webPropertyAdWordsLinks/list#http-request
+
+    .. seealso::
+        For more information on how to use this operator, take a look at the guide:
+        :ref:`howto/operator:GoogleAnalyticsListAccountsOperator`
+
+    :param account_id: ID of the account which the given web property belongs to.
+    :type account_id: str
+    :param web_property_id: Web property ID to retrieve the Google Ads links for.
 
 Review comment:
   I have no strong opinion, but for those not familiar with GA the "UA" is easier to spot :)

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r394941147
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/operators/analytics.py
 ##########
 @@ -44,21 +44,79 @@ class GoogleAnalyticsListAccountsOperator(BaseOperator):
     :type gcp_conn_id: str
     """
 
-    template_fields = ("api_version", "gcp_connection_id",)
+    template_fields = (
+        "api_version",
+        "gcp_connection_id",
+    )
 
     @apply_defaults
-    def __init__(self,
-                 api_version: str = "v3",
-                 gcp_connection_id: str = "google_cloud_default",
-                 *args,
-                 **kwargs):
+    def __init__(
+        self,
+        api_version: str = "v3",
+        gcp_connection_id: str = "google_cloud_default",
+        *args,
+        **kwargs
+    ):
         super().__init__(*args, **kwargs)
 
         self.api_version = api_version
         self.gcp_connection_id = gcp_connection_id
 
     def execute(self, context):
-        hook = GoogleAnalyticsHook(api_version=self.api_version,
-                                   gcp_connection_id=self.gcp_connection_id)
+        hook = GoogleAnalyticsHook(
+            api_version=self.api_version, gcp_connection_id=self.gcp_connection_id
+        )
         result = hook.list_accounts()
         return result
+
+
+class GoogleAnalyticsRetrieveAdsLinksListOperator(BaseOperator):
+    """
+    Lists webProperty-Google Ads links for a given web property
+
+    .. seealso::
+        Check official API docs:
+        https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/webPropertyAdWordsLinks/list#http-request
+
+    .. seealso::
+        For more information on how to use this operator, take a look at the guide:
+        :ref:`howto/operator:GoogleAnalyticsListAccountsOperator`
+
+    :param account_id: ID of the account which the given web property belongs to.
+    :type account_id: str
+    :param web_property_id: Web property ID to retrieve the Google Ads links for.
 
 Review comment:
   Hm, I took this description from API docs. 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r393892047
 
 

 ##########
 File path: tests/providers/google/marketing_platform/operators/test_analytics.py
 ##########
 @@ -41,3 +41,30 @@ def test_execute(self, hook_mock):
         op.execute(context=None)
         hook_mock.assert_called_once()
         hook_mock.return_value.list_accounts.assert_called_once()
+
+
+class TestGoogleAnalyticsRetrieveAdsLinksListOperator(unittest.TestCase):
+    @mock.patch(
+        "airflow.providers.google.marketing_platform.operators."
+        "analytics.GoogleAnalyticsHook"
+    )
+    def test_execute(self, hook_mock):
+        account_id = "the_knight_who_says_ni!"
+        web_property_id = "42"
 
 Review comment:
   :heart: 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] mik-laj commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
mik-laj commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r393910333
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/hooks/analytics.py
 ##########
 @@ -66,10 +66,43 @@ def list_accounts(self) -> List[Dict[str, Any]]:
             # start index has value 1
             request = accounts.list(start_index=len(result) + 1)
             response = request.execute(num_retries=self.num_retries)
-            result.extend(response.get('items', []))
+            result.extend(response.get("items", []))
             # result is the number of fetched accounts from Analytics
             # when all accounts will be add to the result
             # the loop will be break
             if response["totalResults"] <= len(result):
                 break
         return result
+
+    def list_ad_words_links(
+        self, account_id: str, web_property_id: str
+    ) -> List[Dict[str, Any]]:
+        """
+        Lists webProperty-Google Ads links for a given web property.
+
+        # :param account_id: ID of the account which the given web property belongs to.
+        # :type account_id: str
+        # :param web_property_id: Web property ID to retrieve the Google Ads links for.
+        # :type web_property_id: str
 
 Review comment:
   ```suggestion
           :type web_property_id: str
   ```

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r395275705
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/operators/analytics.py
 ##########
 @@ -44,21 +44,79 @@ class GoogleAnalyticsListAccountsOperator(BaseOperator):
     :type gcp_conn_id: str
     """
 
-    template_fields = ("api_version", "gcp_connection_id",)
+    template_fields = (
+        "api_version",
+        "gcp_connection_id",
+    )
 
     @apply_defaults
-    def __init__(self,
-                 api_version: str = "v3",
-                 gcp_connection_id: str = "google_cloud_default",
-                 *args,
-                 **kwargs):
+    def __init__(
+        self,
+        api_version: str = "v3",
+        gcp_connection_id: str = "google_cloud_default",
+        *args,
+        **kwargs
+    ):
         super().__init__(*args, **kwargs)
 
         self.api_version = api_version
         self.gcp_connection_id = gcp_connection_id
 
     def execute(self, context):
-        hook = GoogleAnalyticsHook(api_version=self.api_version,
-                                   gcp_connection_id=self.gcp_connection_id)
+        hook = GoogleAnalyticsHook(
+            api_version=self.api_version, gcp_connection_id=self.gcp_connection_id
+        )
         result = hook.list_accounts()
         return result
+
+
+class GoogleAnalyticsRetrieveAdsLinksListOperator(BaseOperator):
+    """
+    Lists webProperty-Google Ads links for a given web property
+
+    .. seealso::
+        Check official API docs:
+        https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/webPropertyAdWordsLinks/list#http-request
+
+    .. seealso::
+        For more information on how to use this operator, take a look at the guide:
+        :ref:`howto/operator:GoogleAnalyticsListAccountsOperator`
+
+    :param account_id: ID of the account which the given web property belongs to.
+    :type account_id: str
+    :param web_property_id: Web property ID to retrieve the Google Ads links for.
 
 Review comment:
   Done.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r393889350
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/hooks/analytics.py
 ##########
 @@ -66,10 +66,43 @@ def list_accounts(self) -> List[Dict[str, Any]]:
             # start index has value 1
             request = accounts.list(start_index=len(result) + 1)
             response = request.execute(num_retries=self.num_retries)
-            result.extend(response.get('items', []))
+            result.extend(response.get("items", []))
             # result is the number of fetched accounts from Analytics
             # when all accounts will be add to the result
             # the loop will be break
             if response["totalResults"] <= len(result):
                 break
         return result
+
+    def list_ad_words_links(
+        self, account_id: str, web_property_id: str
+    ) -> List[Dict[str, Any]]:
+        """
+        Lists webProperty-Google Ads links for a given web property.
+
+        # :param account_id: ID of the account which the given web property belongs to.
+        # :type account_id: str
+        # :param web_property_id: Web property ID to retrieve the Google Ads links for.
+        # :type web_property_id: str
+
+        """
+
+        self.log.info("Retrieving ad words list...")
+        result = []  # type: List[Dict]
+        conn = self.get_conn()
+        ads_links = conn.management().webPropertyAdWordsLinks()  # pylint: disable=no-member
+        while True:
+            # start index has value 1
+            request = ads_links.list(
+                accountId=account_id,
+                webPropertyId=web_property_id,
+                start_index=len(result) + 1,
+            )
+            response = request.execute(num_retries=self.num_retries)
+            result.extend(response.get("items", []))
+            # result is the number of fetched links from Analytics
+            # when all links will be add to the result
 
 Review comment:
   ```suggestion
               # when all links will be added to the result
   ```

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r394934839
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/hooks/analytics.py
 ##########
 @@ -66,10 +66,43 @@ def list_accounts(self) -> List[Dict[str, Any]]:
             # start index has value 1
             request = accounts.list(start_index=len(result) + 1)
             response = request.execute(num_retries=self.num_retries)
-            result.extend(response.get('items', []))
+            result.extend(response.get("items", []))
             # result is the number of fetched accounts from Analytics
             # when all accounts will be add to the result
             # the loop will be break
             if response["totalResults"] <= len(result):
                 break
         return result
+
+    def list_ad_words_links(
+        self, account_id: str, web_property_id: str
+    ) -> List[Dict[str, Any]]:
+        """
+        Lists webProperty-Google Ads links for a given web property.
+
+        # :param account_id: ID of the account which the given web property belongs to.
+        # :type account_id: str
+        # :param web_property_id: Web property ID to retrieve the Google Ads links for.
+        # :type web_property_id: str
+
+        """
+
+        self.log.info("Retrieving ad words list...")
+        result = []  # type: List[Dict]
+        conn = self.get_conn()
+        ads_links = conn.management().webPropertyAdWordsLinks()  # pylint: disable=no-member
+        while True:
 
 Review comment:
   The Python Jedi Master is good. :) 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r393889777
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/hooks/analytics.py
 ##########
 @@ -66,10 +66,43 @@ def list_accounts(self) -> List[Dict[str, Any]]:
             # start index has value 1
             request = accounts.list(start_index=len(result) + 1)
             response = request.execute(num_retries=self.num_retries)
-            result.extend(response.get('items', []))
+            result.extend(response.get("items", []))
             # result is the number of fetched accounts from Analytics
             # when all accounts will be add to the result
             # the loop will be break
             if response["totalResults"] <= len(result):
                 break
         return result
+
+    def list_ad_words_links(
+        self, account_id: str, web_property_id: str
+    ) -> List[Dict[str, Any]]:
+        """
+        Lists webProperty-Google Ads links for a given web property.
+
+        # :param account_id: ID of the account which the given web property belongs to.
+        # :type account_id: str
+        # :param web_property_id: Web property ID to retrieve the Google Ads links for.
+        # :type web_property_id: str
+
+        """
+
+        self.log.info("Retrieving ad words list...")
+        result = []  # type: List[Dict]
+        conn = self.get_conn()
+        ads_links = conn.management().webPropertyAdWordsLinks()  # pylint: disable=no-member
+        while True:
 
 Review comment:
   Good that you thought about paging!

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r393889462
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/hooks/analytics.py
 ##########
 @@ -66,10 +66,43 @@ def list_accounts(self) -> List[Dict[str, Any]]:
             # start index has value 1
             request = accounts.list(start_index=len(result) + 1)
             response = request.execute(num_retries=self.num_retries)
-            result.extend(response.get('items', []))
+            result.extend(response.get("items", []))
             # result is the number of fetched accounts from Analytics
             # when all accounts will be add to the result
             # the loop will be break
             if response["totalResults"] <= len(result):
                 break
         return result
+
+    def list_ad_words_links(
+        self, account_id: str, web_property_id: str
+    ) -> List[Dict[str, Any]]:
+        """
+        Lists webProperty-Google Ads links for a given web property.
+
+        # :param account_id: ID of the account which the given web property belongs to.
+        # :type account_id: str
+        # :param web_property_id: Web property ID to retrieve the Google Ads links for.
+        # :type web_property_id: str
+
+        """
+
+        self.log.info("Retrieving ad words list...")
+        result = []  # type: List[Dict]
+        conn = self.get_conn()
+        ads_links = conn.management().webPropertyAdWordsLinks()  # pylint: disable=no-member
+        while True:
+            # start index has value 1
+            request = ads_links.list(
+                accountId=account_id,
+                webPropertyId=web_property_id,
+                start_index=len(result) + 1,
+            )
+            response = request.execute(num_retries=self.num_retries)
+            result.extend(response.get("items", []))
+            # result is the number of fetched links from Analytics
+            # when all links will be add to the result
+            # the loop will be break
 
 Review comment:
   ```suggestion
               # the loop will break
   ```

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r394937070
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/hooks/analytics.py
 ##########
 @@ -66,10 +66,43 @@ def list_accounts(self) -> List[Dict[str, Any]]:
             # start index has value 1
             request = accounts.list(start_index=len(result) + 1)
             response = request.execute(num_retries=self.num_retries)
-            result.extend(response.get('items', []))
+            result.extend(response.get("items", []))
             # result is the number of fetched accounts from Analytics
             # when all accounts will be add to the result
             # the loop will be break
             if response["totalResults"] <= len(result):
                 break
         return result
+
+    def list_ad_words_links(
+        self, account_id: str, web_property_id: str
+    ) -> List[Dict[str, Any]]:
+        """
+        Lists webProperty-Google Ads links for a given web property.
+
+        # :param account_id: ID of the account which the given web property belongs to.
+        # :type account_id: str
+        # :param web_property_id: Web property ID to retrieve the Google Ads links for.
+        # :type web_property_id: str
 
 Review comment:
   Yes, definitely.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r395055764
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/operators/analytics.py
 ##########
 @@ -44,21 +44,79 @@ class GoogleAnalyticsListAccountsOperator(BaseOperator):
     :type gcp_conn_id: str
     """
 
-    template_fields = ("api_version", "gcp_connection_id",)
+    template_fields = (
+        "api_version",
+        "gcp_connection_id",
+    )
 
     @apply_defaults
-    def __init__(self,
-                 api_version: str = "v3",
-                 gcp_connection_id: str = "google_cloud_default",
-                 *args,
-                 **kwargs):
+    def __init__(
+        self,
+        api_version: str = "v3",
+        gcp_connection_id: str = "google_cloud_default",
+        *args,
+        **kwargs
+    ):
         super().__init__(*args, **kwargs)
 
         self.api_version = api_version
         self.gcp_connection_id = gcp_connection_id
 
     def execute(self, context):
-        hook = GoogleAnalyticsHook(api_version=self.api_version,
-                                   gcp_connection_id=self.gcp_connection_id)
+        hook = GoogleAnalyticsHook(
+            api_version=self.api_version, gcp_connection_id=self.gcp_connection_id
+        )
         result = hook.list_accounts()
         return result
+
+
+class GoogleAnalyticsRetrieveAdsLinksListOperator(BaseOperator):
+    """
+    Lists webProperty-Google Ads links for a given web property
+
+    .. seealso::
+        Check official API docs:
+        https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/webPropertyAdWordsLinks/list#http-request
+
+    .. seealso::
+        For more information on how to use this operator, take a look at the guide:
+        :ref:`howto/operator:GoogleAnalyticsListAccountsOperator`
+
+    :param account_id: ID of the account which the given web property belongs to.
+    :type account_id: str
+    :param web_property_id: Web property ID to retrieve the Google Ads links for.
 
 Review comment:
   I agree.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] nuclearpinguin commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
nuclearpinguin commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r394178767
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/example_dags/example_analytics.py
 ##########
 @@ -20,12 +20,15 @@
 
 from airflow import models
 from airflow.providers.google.marketing_platform.operators.analytics import (
-    GoogleAnalyticsListAccountsOperator,
+    GoogleAnalyticsListAccountsOperator, GoogleAnalyticsRetrieveAdsLinksListOperator,
 )
 from airflow.utils import dates
 
 default_args = {"start_date": dates.days_ago(1)}
 
+account_id = "12345"
+web_property_id = "web_property_id"
 
 Review comment:
   ```
   ACCOUNT_ID = os.environ.get("GA_ACCOUNT_ID", "123456789")
   WEB_PROPERTY = os.environ.get("GA_WEB_PROPERTY", "UA-12345678-1")
   ```
   This will work with env variables from config file :)

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r394938976
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/hooks/analytics.py
 ##########
 @@ -66,10 +66,43 @@ def list_accounts(self) -> List[Dict[str, Any]]:
             # start index has value 1
             request = accounts.list(start_index=len(result) + 1)
             response = request.execute(num_retries=self.num_retries)
-            result.extend(response.get('items', []))
+            result.extend(response.get("items", []))
             # result is the number of fetched accounts from Analytics
             # when all accounts will be add to the result
             # the loop will be break
             if response["totalResults"] <= len(result):
                 break
         return result
+
+    def list_ad_words_links(
+        self, account_id: str, web_property_id: str
+    ) -> List[Dict[str, Any]]:
+        """
+        Lists webProperty-Google Ads links for a given web property.
+
+        # :param account_id: ID of the account which the given web property belongs to.
+        # :type account_id: str
+        # :param web_property_id: Web property ID to retrieve the Google Ads links for.
+        # :type web_property_id: str
+
+        """
+
+        self.log.info("Retrieving ad words list...")
+        result = []  # type: List[Dict]
+        conn = self.get_conn()
+        ads_links = conn.management().webPropertyAdWordsLinks()  # pylint: disable=no-member
+        while True:
+            # start index has value 1
+            request = ads_links.list(
+                accountId=account_id,
+                webPropertyId=web_property_id,
+                start_index=len(result) + 1,
+            )
+            response = request.execute(num_retries=self.num_retries)
+            result.extend(response.get("items", []))
+            # result is the number of fetched links from Analytics
+            # when all links will be add to the result
 
 Review comment:
   Done

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] nuclearpinguin commented on issue #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
nuclearpinguin commented on issue #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#issuecomment-600494242
 
 
   Would you mind adding a system tests:
   ```python
   import pytest
   
   from tests.providers.google.cloud.utils.gcp_authenticator import GMP_KEY
   from tests.test_utils.gcp_system_helpers import MARKETING_DAG_FOLDER, GoogleSystemTest, provide_gcp_context
   
   # Required scopes
   SCOPES = [
       'https://www.googleapis.com/auth/analytics',
       'https://www.googleapis.com/auth/analytics.edit',
       'https://www.googleapis.com/auth/cloud-platform',
   ]
   
   @pytest.mark.system("google.marketing_platform")
   @pytest.mark.credential_file(GMP_KEY)
   class TestSystemGoogleAds(GoogleSystemTest):
       @provide_gcp_context(GMP_KEY, scopes=SCOPES)
       def test_run_example_dag(self):
           self.run_dag('example_google_analytics', MARKETING_DAG_FOLDER)
   ```

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r393890680
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/hooks/analytics.py
 ##########
 @@ -66,10 +66,43 @@ def list_accounts(self) -> List[Dict[str, Any]]:
             # start index has value 1
             request = accounts.list(start_index=len(result) + 1)
             response = request.execute(num_retries=self.num_retries)
-            result.extend(response.get('items', []))
+            result.extend(response.get("items", []))
             # result is the number of fetched accounts from Analytics
             # when all accounts will be add to the result
             # the loop will be break
             if response["totalResults"] <= len(result):
                 break
         return result
+
+    def list_ad_words_links(
+        self, account_id: str, web_property_id: str
+    ) -> List[Dict[str, Any]]:
+        """
+        Lists webProperty-Google Ads links for a given web property.
+
+        # :param account_id: ID of the account which the given web property belongs to.
+        # :type account_id: str
+        # :param web_property_id: Web property ID to retrieve the Google Ads links for.
+        # :type web_property_id: str
+
 
 Review comment:
   It would be great to describe what are the results. What do they contain? Link to the doc in Google docs is enough but an example would be great.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
potiuk commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r393891891
 
 

 ##########
 File path: tests/providers/google/marketing_platform/operators/test_analytics.py
 ##########
 @@ -41,3 +41,30 @@ def test_execute(self, hook_mock):
         op.execute(context=None)
         hook_mock.assert_called_once()
         hook_mock.return_value.list_accounts.assert_called_once()
+
+
+class TestGoogleAnalyticsRetrieveAdsLinksListOperator(unittest.TestCase):
+    @mock.patch(
+        "airflow.providers.google.marketing_platform.operators."
+        "analytics.GoogleAnalyticsHook"
+    )
+    def test_execute(self, hook_mock):
+        account_id = "the_knight_who_says_ni!"
 
 Review comment:
   :heart: 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
michalslowikowski00 commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r395267507
 
 

 ##########
 File path: docs/howto/operator/gcp/analytics.rst
 ##########
 @@ -48,3 +48,18 @@ To list accounts from Analytics you can use the
 
 You can use :ref:`Jinja templating <jinja-templating>` with
 :template-fields:`airflow.providers.google.marketing_platform.operators.analytics.GoogleAnalyticsListAccountsOperator`
+
+List Google Ads Links
+^^^^^^^^^^^^^^^^^^^^^
+
+To list Google Ads links you can use the
 
 Review comment:
   I agree.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [airflow] nuclearpinguin commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator

Posted by GitBox <gi...@apache.org>.
nuclearpinguin commented on a change in pull request #7748: [AIRFLOW-6752] Add GoogleAnalyticsRetrieveAdsLinksListOperator
URL: https://github.com/apache/airflow/pull/7748#discussion_r394180366
 
 

 ##########
 File path: airflow/providers/google/marketing_platform/operators/analytics.py
 ##########
 @@ -44,21 +44,79 @@ class GoogleAnalyticsListAccountsOperator(BaseOperator):
     :type gcp_conn_id: str
     """
 
-    template_fields = ("api_version", "gcp_connection_id",)
+    template_fields = (
+        "api_version",
+        "gcp_connection_id",
+    )
 
     @apply_defaults
-    def __init__(self,
-                 api_version: str = "v3",
-                 gcp_connection_id: str = "google_cloud_default",
-                 *args,
-                 **kwargs):
+    def __init__(
+        self,
+        api_version: str = "v3",
+        gcp_connection_id: str = "google_cloud_default",
+        *args,
+        **kwargs
+    ):
         super().__init__(*args, **kwargs)
 
         self.api_version = api_version
         self.gcp_connection_id = gcp_connection_id
 
     def execute(self, context):
-        hook = GoogleAnalyticsHook(api_version=self.api_version,
-                                   gcp_connection_id=self.gcp_connection_id)
+        hook = GoogleAnalyticsHook(
+            api_version=self.api_version, gcp_connection_id=self.gcp_connection_id
+        )
         result = hook.list_accounts()
         return result
+
+
+class GoogleAnalyticsRetrieveAdsLinksListOperator(BaseOperator):
+    """
+    Lists webProperty-Google Ads links for a given web property
+
+    .. seealso::
+        Check official API docs:
+        https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/webPropertyAdWordsLinks/list#http-request
+
+    .. seealso::
+        For more information on how to use this operator, take a look at the guide:
+        :ref:`howto/operator:GoogleAnalyticsListAccountsOperator`
+
+    :param account_id: ID of the account which the given web property belongs to.
+    :type account_id: str
+    :param web_property_id: Web property ID to retrieve the Google Ads links for.
 
 Review comment:
   ```suggestion
       :param web_property_id: Web property UA-string to retrieve the Google Ads links for.
   ```

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services