From b8e147538c07775c9f3576f4c6bdbf5fc5f73137 Mon Sep 17 00:00:00 2001 From: "Sherif A. Nada" Date: Wed, 4 May 2022 23:37:10 -0700 Subject: [PATCH] Update various connector input configs & docs copy (#12500) --- .../resources/seed/source_definitions.yaml | 18 +- .../src/main/resources/seed/source_specs.yaml | 443 ++++++++++-------- .../connectors/source-airtable/Dockerfile | 2 +- .../connectors/source-amplitude/Dockerfile | 2 +- .../source_amplitude/spec.json | 6 +- .../unit_tests/test_source.py | 23 +- .../connectors/source-bing-ads/Dockerfile | 2 +- .../source-bing-ads/source_bing_ads/spec.json | 77 +-- .../source-google-analytics-v4/Dockerfile | 2 +- .../source_google_analytics_v4/spec.json | 55 +-- .../connectors/source-s3/Dockerfile | 2 +- .../source-s3/integration_tests/spec.json | 128 +++-- .../connectors/source-s3/setup.py | 2 +- .../connectors/source-s3/source_s3/source.py | 36 +- .../source_files_abstract/formats/csv_spec.py | 45 +- .../formats/parquet_spec.py | 27 +- .../source_s3/source_files_abstract/spec.py | 25 +- .../connectors/source-shopify/Dockerfile | 2 +- .../source-shopify/source_shopify/spec.json | 9 +- .../connectors/source-smartsheets/Dockerfile | 2 +- .../source_smartsheets/spec.json | 9 +- .../connectors/source-stripe/Dockerfile | 2 +- .../source-stripe/source_stripe/spec.yaml | 12 +- .../source-tiktok-marketing/Dockerfile | 2 +- .../integration_tests/spec.json | 31 +- .../source_tiktok_marketing/spec.py | 36 +- docs/.gitbook/assets/airtable_api_key1.png | Bin 0 -> 97689 bytes docs/.gitbook/assets/airtable_api_key2.png | Bin 0 -> 22154 bytes docs/.gitbook/assets/airtable_base_id.png | Bin 0 -> 8908 bytes .../assets/airtable_bases_ui_list1.png | Bin 0 -> 14773 bytes docs/integrations/sources/airtable.md | 24 +- docs/integrations/sources/amplitude.md | 3 +- docs/integrations/sources/bing-ads.md | 92 ++-- .../sources/google-analytics-v4.md | 22 +- docs/integrations/sources/s3.md | 23 +- docs/integrations/sources/shopify.md | 71 +-- docs/integrations/sources/smartsheets.md | 1 + docs/integrations/sources/stripe.md | 1 + docs/integrations/sources/tiktok-marketing.md | 50 +- 39 files changed, 721 insertions(+), 566 deletions(-) create mode 100644 docs/.gitbook/assets/airtable_api_key1.png create mode 100644 docs/.gitbook/assets/airtable_api_key2.png create mode 100644 docs/.gitbook/assets/airtable_base_id.png create mode 100644 docs/.gitbook/assets/airtable_bases_ui_list1.png diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index f3bef77d4606..e6323b13df96 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -1,7 +1,7 @@ - name: Airtable sourceDefinitionId: 14c6e7ea-97ed-4f5e-a7b5-25e9a80b8212 dockerRepository: airbyte/source-airtable - dockerImageTag: 0.1.1 + dockerImageTag: 0.1.2 documentationUrl: https://docs.airbyte.io/integrations/sources/airtable icon: airtable.svg sourceType: api @@ -35,7 +35,7 @@ - name: Amplitude sourceDefinitionId: fa9f58c6-2d03-4237-aaa4-07d75e0c1396 dockerRepository: airbyte/source-amplitude - dockerImageTag: 0.1.5 + dockerImageTag: 0.1.6 documentationUrl: https://docs.airbyte.io/integrations/sources/amplitude icon: amplitude.svg sourceType: api @@ -91,7 +91,7 @@ - name: Bing Ads sourceDefinitionId: 47f25999-dd5e-4636-8c39-e7cea2453331 dockerRepository: airbyte/source-bing-ads - dockerImageTag: 0.1.5 + dockerImageTag: 0.1.6 documentationUrl: https://docs.airbyte.io/integrations/sources/bing-ads icon: bingads.svg sourceType: api @@ -279,7 +279,7 @@ - name: Google Analytics sourceDefinitionId: eff3616a-f9c3-11eb-9a03-0242ac130003 dockerRepository: airbyte/source-google-analytics-v4 - dockerImageTag: 0.1.20 + dockerImageTag: 0.1.21 documentationUrl: https://docs.airbyte.io/integrations/sources/google-analytics-v4 icon: google-analytics.svg sourceType: api @@ -681,7 +681,7 @@ - name: S3 sourceDefinitionId: 69589781-7828-43c5-9f63-8925b1c1ccc2 dockerRepository: airbyte/source-s3 - dockerImageTag: 0.1.10 + dockerImageTag: 0.1.11 documentationUrl: https://docs.airbyte.io/integrations/sources/s3 icon: s3.svg sourceType: file @@ -716,7 +716,7 @@ - name: Shopify sourceDefinitionId: 9da77001-af33-4bcd-be46-6252bf9342b9 dockerRepository: airbyte/source-shopify - dockerImageTag: 0.1.36 + dockerImageTag: 0.1.37 documentationUrl: https://docs.airbyte.io/integrations/sources/shopify icon: shopify.svg sourceType: api @@ -737,7 +737,7 @@ - name: Smartsheets sourceDefinitionId: 374ebc65-6636-4ea0-925c-7d35999a8ffc dockerRepository: airbyte/source-smartsheets - dockerImageTag: 0.1.11 + dockerImageTag: 0.1.12 documentationUrl: https://docs.airbyte.io/integrations/sources/smartsheets icon: smartsheet.svg sourceType: api @@ -771,7 +771,7 @@ - name: Stripe sourceDefinitionId: e094cb9a-26de-4645-8761-65c0c425d1de dockerRepository: airbyte/source-stripe - dockerImageTag: 0.1.31 + dockerImageTag: 0.1.32 documentationUrl: https://docs.airbyte.io/integrations/sources/stripe icon: stripe.svg sourceType: api @@ -799,7 +799,7 @@ - name: TikTok Marketing sourceDefinitionId: 4bfac00d-ce15-44ff-95b9-9e3c3e8fbd35 dockerRepository: airbyte/source-tiktok-marketing - dockerImageTag: 0.1.8 + dockerImageTag: 0.1.9 documentationUrl: https://docs.airbyte.io/integrations/sources/tiktok-marketing icon: tiktok.svg sourceType: api diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index 3c58a225bb62..69305c17d4a7 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -1,7 +1,7 @@ # This file is generated by io.airbyte.config.specs.SeedConnectorSpecGenerator. # Do NOT edit this file directly. See generator class for more details. --- -- dockerImage: "airbyte/source-airtable:0.1.1" +- dockerImage: "airbyte/source-airtable:0.1.2" spec: documentationUrl: "https://docs.airbyte.io/integrations/sources/airtable" connectionSpecification: @@ -480,7 +480,7 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] -- dockerImage: "airbyte/source-amplitude:0.1.5" +- dockerImage: "airbyte/source-amplitude:0.1.6" spec: documentationUrl: "https://docs.airbyte.io/integrations/sources/amplitude" connectionSpecification: @@ -496,18 +496,18 @@ api_key: type: "string" title: "API Key" - description: "Amplitude API Key. See the docs for more information on how to obtain this key." + description: "Amplitude API Key. See the setup guide for more information on how to obtain this key." airbyte_secret: true secret_key: type: "string" title: "Secret Key" - description: "Amplitude Secret Key. See the docs for more information on how to obtain this key." + description: "Amplitude Secret Key. See the setup guide for more information on how to obtain this key." airbyte_secret: true start_date: type: "string" - title: "Start Date" + title: "Replication Start Date" pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$" description: "UTC date and time in the format 2021-01-25T00:00:00Z. Any\ \ data before this date will not be replicated." @@ -801,7 +801,7 @@ - "overwrite" - "append" - "append_dedup" -- dockerImage: "airbyte/source-bing-ads:0.1.5" +- dockerImage: "airbyte/source-bing-ads:0.1.6" spec: documentationUrl: "https://docs.airbyte.io/integrations/sources/bing-ads" connectionSpecification: @@ -824,22 +824,20 @@ additionalProperties: false properties: accounts: - title: "Accounts" + title: "Accounts to replicate data from" type: "object" - description: "Account selection." + description: "" oneOf: - - title: "All accounts assigned to your user" + - title: "All Accounts" additionalProperties: false - description: "Fetch data for all available accounts." + description: "Replicate data from all accounts to which you have access." required: - "selection_strategy" properties: selection_strategy: type: "string" - enum: - - "all" const: "all" - - title: "Subset of your accounts" + - title: "Specific Accounts" additionalProperties: false description: "Fetch data for subset of account IDs." required: @@ -848,13 +846,11 @@ properties: selection_strategy: type: "string" - enum: - - "subset" const: "subset" ids: type: "array" - title: "IDs" - description: "List of accounts from which data will be fetched." + title: "Account IDs" + description: "List of the account IDs from which data will be replicated." items: type: "string" minItems: 1 @@ -864,72 +860,96 @@ title: "Client ID" description: "The Client ID of your Microsoft Advertising developer application." airbyte_secret: true + order: 0 client_secret: type: "string" title: "Client Secret" description: "The Client Secret of your Microsoft Advertising developer\ \ application." airbyte_secret: true - customer_id: + order: 1 + refresh_token: type: "string" - title: "Customer ID" - description: "User's Customer ID. Go to your Accounts and Billing page.\ - \ Your Customer ID will be listed on the Accounts tab under the heading\ - \ Customer." + title: "Refresh Token" + description: "Refresh Token to renew the expired Access Token." + airbyte_secret: true + order: 2 developer_token: type: "string" title: "Developer Token" description: "Developer token associated with user." airbyte_secret: true + order: 3 tenant_id: type: "string" title: "Tenant ID" - description: "The Tenant ID of your Microsoft Advertising developer application." + description: "The Tenant ID of your Microsoft Advertising developer application.\ + \ Set this to \"common\" unless you know you need a different value." airbyte_secret: true default: "common" + order: 4 redirect_uri: type: "string" - title: "Redirect URI" - description: "The Redirect URI of your Microsoft Advertising developer application." + title: "Redirect URI (Optional)" + description: "The Redirect URI of your Microsoft Advertising developer application.\ + \ Leave this empty unless you know that you need it." airbyte_secret: true default: "" - refresh_token: + order: 5 + customer_id: type: "string" - title: "Refresh Token" - description: "Refresh Token to renew the expired Access Token." - airbyte_secret: true + title: "Customer ID" + description: "Your Bing Customer ID. See the \"Getting Started\" section\ + \ in the docs for information on how to obtain this ID" + order: 6 user_id: type: "string" title: "Account ID" - description: "Bing Ads Account ID. You can find Account ID by going to your\ - \ profile and selecting Accounts and Billing." + description: "Bing Ads Account ID. See the \"Getting Started\" section in\ + \ the\ + \ docs for information on how to obtain this ID" + order: 7 reports_start_date: type: "string" - title: "Reports Start Date" + title: "Reports replication start date" format: "date" default: "2020-01-01" - description: "UTC date in YYYY-MM-DD format. Any reports before this date\ - \ will not be replicated." + description: "The start date from which to begin replicating report data.\ + \ Any data generated before this date will not be replicated in reports.\ + \ This is a UTC date in YYYY-MM-DD format." + order: 8 hourly_reports: - title: "Hourly reports" + title: "Enable hourly-aggregate reports" type: "boolean" - description: "The report data will be aggregated by each hour of the day." + description: "Toggle this to enable replicating reports aggregated using\ + \ an hourly time window. More information about report aggregation can\ + \ be found in the docs." default: false daily_reports: - title: "Daily reports" + title: "Enable daily-aggregate reports" type: "boolean" - description: "The report data will be aggregated by each day." + description: "Toggle this to enable replicating reports aggregated using\ + \ a daily time window. More information about report aggregation can be\ + \ found in the docs." default: false weekly_reports: - title: "Weekly reports" + title: "Enable weekly-aggregate reports" type: "boolean" - description: "The report data will be aggregated by each week running from\ - \ Sunday through Saturday." + description: "Toggle this to enable replicating reports aggregated using\ + \ a weekly time window running from Sunday to Saturday. More information\ + \ about report aggregation can be found in the docs." default: false monthly_reports: - title: "Monthly reports" + title: "Enable monthly-aggregate reports" type: "boolean" - description: "The report data will be aggregated by each month." + description: "Toggle this to enable replicating reports aggregated using\ + \ a monthly time window. More information about report aggregation can\ + \ be found in the docs." default: false supportsNormalization: false supportsDBT: false @@ -2810,7 +2830,7 @@ oauthFlowOutputParameters: - - "access_token" - - "refresh_token" -- dockerImage: "airbyte/source-google-analytics-v4:0.1.20" +- dockerImage: "airbyte/source-google-analytics-v4:0.1.21" spec: documentationUrl: "https://docs.airbyte.io/integrations/sources/google-analytics-v4" connectionSpecification: @@ -2822,42 +2842,6 @@ - "start_date" additionalProperties: true properties: - view_id: - order: 2 - type: "string" - title: "View ID" - description: "The ID for the Google Analytics View you want to fetch data\ - \ from. This can be found from the Google Analytics Account Explorer." - start_date: - order: 1 - type: "string" - title: "Start Date" - description: "The date in the format YYYY-MM-DD. Any data before this date\ - \ will not be replicated." - examples: - - "2020-06-01" - window_in_days: - type: "integer" - title: "Data request window (Optional)" - description: "The amount of data batched by the number of days. The bigger\ - \ the value, the bigger the batch size and the lower the API requests\ - \ made. (Min=1, as for a Day; Max=364, as for a Year)." - examples: - - 30 - - 60 - - 90 - - 120 - - 200 - - 364 - default: 1 - custom_reports: - order: 3 - type: "string" - title: "Custom Reports (Optional)" - description: "A JSON array describing the custom reports you want to sync\ - \ from GA. Check out the docs to get more information about this field." credentials: order: 0 type: "object" @@ -2910,13 +2894,57 @@ const: "Service" order: 0 credentials_json: - title: "JSON credentials" + title: "Service Account JSON Key" type: "string" description: "The JSON key of the service account to use for authorization" examples: - "{ \"type\": \"service_account\", \"project_id\": YOUR_PROJECT_ID,\ \ \"private_key_id\": YOUR_PRIVATE_KEY, ... }" airbyte_secret: true + start_date: + order: 1 + type: "string" + title: "Replication Start Date" + description: "The date in the format YYYY-MM-DD. Any data before this date\ + \ will not be replicated." + examples: + - "2020-06-01" + view_id: + order: 2 + type: "string" + title: "View ID" + description: "The ID for the Google Analytics View you want to fetch data\ + \ from. This can be found from the Google Analytics Account Explorer." + custom_reports: + order: 3 + type: "string" + title: "Custom Reports (Optional)" + description: "A JSON array describing the custom reports you want to sync\ + \ from Google Analytics. See the docs for more information about the exact format you can use\ + \ to fill out this field." + window_in_days: + type: "integer" + title: "Data request time increment in days (Optional)" + description: "The time increment used by the connector when requesting data\ + \ from the Google Analytics API. More information is available in the\ + \ the docs. The bigger this value is, the faster the sync will be,\ + \ but the more likely that sampling will be applied to your data, potentially\ + \ causing inaccuracies in the returned results. We recommend setting this\ + \ to 1 unless you have a hard requirement to make the sync faster at the\ + \ expense of accuracy. The minimum allowed value for this field is 1,\ + \ and the maximum is 364. " + examples: + - 30 + - 60 + - 90 + - 120 + - 200 + - 364 + default: 1 + order: 4 supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] @@ -7112,7 +7140,7 @@ path_in_connector_config: - "credentials" - "client_secret" -- dockerImage: "airbyte/source-s3:0.1.10" +- dockerImage: "airbyte/source-s3:0.1.11" spec: documentationUrl: "https://docs.airbyte.io/integrations/sources/s3" changelogUrl: "https://docs.airbyte.io/integrations/sources/s3" @@ -7121,42 +7149,33 @@ type: "object" properties: dataset: - title: "Dataset" - description: "This source creates one table per connection, this field is\ - \ the name of that table. This should include only letters, numbers, dash\ - \ and underscores. Note that this may be altered according to destination." + title: "Output Stream Name" + description: "The name of the stream you would like this source to output.\ + \ Can contain letters, numbers, or underscores." pattern: "^([A-Za-z0-9-_]+)$" + order: 0 type: "string" path_pattern: - title: "Path Pattern" - description: "Add at least 1 pattern here to match filepaths against. Use\ - \ | to separate multiple patterns. Airbyte uses these patterns to determine\ - \ which files to pick up from the provider storage. See wcmatch.glob to understand pattern syntax (GLOBSTAR\ + title: "Pattern of files to replicate" + description: "A regular expression which tells the connector which files\ + \ to replicate. All files which match this pattern will be replicated.\ + \ Use | to separate multiple patterns. See this page to understand pattern syntax (GLOBSTAR\ \ and SPLIT flags are enabled). Use pattern ** to pick\ \ up all files." examples: - "**" - "myFolder/myTableFiles/*.csv|myFolder/myOtherTableFiles/*.csv" - type: "string" - schema: - title: "Schema" - description: "Optionally provide a schema to enforce, as a valid JSON string.\ - \ Ensure this is a mapping of { \"column\" : \"type\" },\ - \ where types are valid JSON Schema datatypes. Leave as {} to auto-infer\ - \ the schema." - default: "{}" - examples: - - "{\"column_1\": \"number\", \"column_2\": \"string\", \"column_3\": \"\ - array\", \"column_4\": \"object\", \"column_5\": \"boolean\"}" + order: 10 type: "string" format: - title: "Format" + title: "File Format" + description: "The format of the files you'd like to replicate" default: "csv" + order: 20 type: "object" oneOf: - - title: "csv" + - title: "CSV" description: "This connector utilises PyArrow (Apache Arrow) for CSV parsing." type: "object" @@ -7172,46 +7191,54 @@ \ data enter '\\t'." default: "," minLength: 1 + order: 0 type: "string" + infer_datatypes: + title: "Infer Datatypes" + description: "Configures whether a schema for the source should be\ + \ inferred from the current data or not. If set to false and a custom\ + \ schema is set, then the manually enforced schema is used. If a\ + \ schema is not manually set, and this is set to false, then all\ + \ fields will be read as strings" + default: true + order: 1 + type: "boolean" quote_char: - title: "Quote Char" - description: "The character used optionally for quoting CSV values.\ - \ To disallow quoting, make this field blank." + title: "Quote Character" + description: "The character used for quoting CSV values. To disallow\ + \ quoting, make this field blank." default: "\"" + order: 2 type: "string" escape_char: - title: "Escape Char" - description: "The character used optionally for escaping special characters.\ + title: "Escape Character" + description: "The character used for escaping special characters.\ \ To disallow escaping, leave this field blank." + order: 3 type: "string" encoding: title: "Encoding" description: "The character encoding of the CSV data. Leave blank\ - \ to default to UTF-8. See UTF8. See list of python encodings for allowable options." default: "utf8" + order: 4 type: "string" double_quote: title: "Double Quote" description: "Whether two quotes in a quoted CSV value denote a single\ \ quote in the data." default: true + order: 5 type: "boolean" newlines_in_values: - title: "Newlines In Values" + title: "Allow newlines in values" description: "Whether newline characters are allowed in CSV values.\ \ Turning this on may affect performance. Leave blank to default\ \ to False." default: false + order: 6 type: "boolean" - block_size: - title: "Block Size" - description: "The chunk size in bytes to process at a time in memory\ - \ from each file. If your data is particularly wide and failing\ - \ during schema detection, increasing this should solve it. Beware\ - \ of raising this too high as you could hit OOM errors." - default: 10000 - type: "integer" additional_reader_options: title: "Additional Reader Options" description: "Optionally add a valid JSON string here to provide additional\ @@ -7224,6 +7251,7 @@ - "{\"timestamp_parsers\": [\"%m/%d/%Y %H:%M\", \"%Y/%m/%d %H:%M\"\ ], \"strings_can_be_null\": true, \"null_values\": [\"NA\", \"NULL\"\ ]}" + order: 7 type: "string" advanced_options: title: "Advanced Options" @@ -7236,17 +7264,18 @@ default: "{}" examples: - "{\"column_names\": [\"column1\", \"column2\"]}" + order: 8 type: "string" - infer_datatypes: - title: "Infer Datatypes" - description: "Configures whether a scheme for the source should be\ - \ inferred from the current data or not.If set to false and a custom\ - \ schema is set, then the custom_schema is usedIf a custom schema\ - \ is not set, and this is set to false, then all fields will be\ - \ read as strings" - default: true - type: "boolean" - - title: "parquet" + block_size: + title: "Block Size" + description: "The chunk size in bytes to process at a time in memory\ + \ from each file. If your data is particularly wide and failing\ + \ during schema detection, increasing this should solve it. Beware\ + \ of raising this too high as you could hit OOM errors." + default: 10000 + order: 9 + type: "integer" + - title: "Parquet" description: "This connector utilises PyArrow (Apache Arrow) for Parquet parsing." type: "object" @@ -7255,31 +7284,45 @@ title: "Filetype" const: "parquet" type: "string" - buffer_size: - title: "Buffer Size" - description: "Perform read buffering when deserializing individual\ - \ column chunks. By default every group column will be loaded fully\ - \ to memory. This option can help to optimize a work with memory\ - \ if your data is particularly wide or failing during detection\ - \ of OOM errors." - default: 0 - type: "integer" columns: - title: "Columns" + title: "Selected Columns" description: "If you only want to sync a subset of the columns from\ - \ the file(s), add the columns you want here. Leave it empty to\ - \ sync all columns." + \ the file(s), add the columns you want here as a comma-delimited\ + \ list. Leave it empty to sync all columns." + order: 0 type: "array" items: type: "string" batch_size: - title: "Batch Size" - description: "Maximum number of records per batch. Batches may be\ - \ smaller if there aren’t enough rows in the file. This option can\ - \ help to optimize a work with memory if your data is particularly\ - \ wide or failing during detection of OOM errors." + title: "Record batch size" + description: "Maximum number of records per batch read from the input\ + \ files. Batches may be smaller if there aren’t enough rows in the\ + \ file. This option can help avoid out-of-memory errors if your\ + \ data is particularly wide." default: 65536 + order: 1 + type: "integer" + buffer_size: + title: "Buffer Size" + description: "Perform read buffering when deserializing individual\ + \ column chunks. By default every group column will be loaded fully\ + \ to memory. This option can help avoid out-of-memory errors if\ + \ your data is particularly wide." + default: 2 type: "integer" + schema: + title: "Manually enforced data schema (Optional)" + description: "Optionally provide a schema to enforce, as a valid JSON string.\ + \ Ensure this is a mapping of { \"column\" : \"type\" },\ + \ where types are valid JSON Schema datatypes. Leave as {} to auto-infer\ + \ the schema." + default: "{}" + examples: + - "{\"column_1\": \"number\", \"column_2\": \"string\", \"column_3\": \"\ + array\", \"column_4\": \"object\", \"column_5\": \"boolean\"}" + order: 30 + type: "string" provider: title: "S3: Amazon Web Services" type: "object" @@ -7287,45 +7330,56 @@ bucket: title: "Bucket" description: "Name of the S3 bucket where the file(s) exist." + order: 0 type: "string" aws_access_key_id: - title: "Aws Access Key Id" + title: "AWS Access Key ID" description: "In order to access private Buckets stored on AWS S3, this\ \ connector requires credentials with the proper permissions. If accessing\ \ publicly available data, this field is not necessary." airbyte_secret: true + order: 1 type: "string" aws_secret_access_key: - title: "Aws Secret Access Key" + title: "AWS Secret Access Key" description: "In order to access private Buckets stored on AWS S3, this\ \ connector requires credentials with the proper permissions. If accessing\ \ publicly available data, this field is not necessary." airbyte_secret: true + order: 2 type: "string" path_prefix: title: "Path Prefix" description: "By providing a path-like prefix (e.g. myFolder/thisTable/)\ - \ under which all the relevant files sit, we can optimise finding\ + \ under which all the relevant files sit, we can optimize finding\ \ these in S3. This is optional but recommended if your bucket contains\ - \ many folders/files." + \ many folders/files which you don't need to replicate." default: "" + order: 3 type: "string" endpoint: title: "Endpoint" description: "Endpoint to an S3 compatible service. Leave empty to use\ \ AWS." default: "" + order: 4 type: "string" use_ssl: - title: "Use Ssl" - description: "Is remote server using secure SSL/TLS connection" + title: "Use TLS" + description: "Whether the remote server is using a secure SSL/TLS connection.\ + \ Only relevant if using an S3-compatible, non-AWS server" + order: 5 type: "boolean" verify_ssl_cert: - title: "Verify Ssl Cert" - description: "Allow self signed certificates" + title: "Verify TLS Certificates" + description: "Set this to false to allow self signed certificates. Only\ + \ relevant if using an S3-compatible, non-AWS server" + order: 6 type: "boolean" required: - "bucket" + order: 11 + description: "Use this to load files from S3 or S3-compatible services" required: - "dataset" - "path_pattern" @@ -7606,7 +7660,7 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] -- dockerImage: "airbyte/source-shopify:0.1.36" +- dockerImage: "airbyte/source-shopify:0.1.37" spec: documentationUrl: "https://docs.airbyte.io/integrations/sources/shopify" connectionSpecification: @@ -7626,20 +7680,19 @@ order: 1 credentials: title: "Shopify Authorization Method" + description: "The authorization method to use to retrieve data from Shopify" type: "object" order: 2 oneOf: - type: "object" title: "OAuth2.0" + description: "OAuth2.0" required: - "auth_method" properties: auth_method: type: "string" const: "oauth2.0" - enum: - - "oauth2.0" - default: "oauth2.0" order: 0 client_id: type: "string" @@ -7657,6 +7710,7 @@ description: "The Access Token for making authenticated requests." airbyte_secret: true - title: "API Password" + description: "API Password Auth" type: "object" required: - "auth_method" @@ -7665,9 +7719,6 @@ auth_method: type: "string" const: "api_password" - enum: - - "api_password" - default: "api_password" order: 0 api_password: type: "string" @@ -7677,7 +7728,7 @@ airbyte_secret: true start_date: type: "string" - title: "Start Date" + title: "Replication Start Date" description: "The date you would like to replicate data from. Format: YYYY-MM-DD.\ \ Any data before this date will not be replicated." examples: @@ -7891,7 +7942,7 @@ oauthFlowOutputParameters: - - "access_token" - - "refresh_token" -- dockerImage: "airbyte/source-smartsheets:0.1.11" +- dockerImage: "airbyte/source-smartsheets:0.1.12" spec: documentationUrl: "https://docs.airbyte.io/integrations/sources/smartsheets" connectionSpecification: @@ -7905,14 +7956,19 @@ properties: access_token: title: "Access Token" - description: "The Access Token for making authenticated requests. Find in\ - \ the main menu: Account > Apps & Integrations > API Access" + description: "The access token to use for accessing your data from Smartsheets.\ + \ This access token must be generated by a user with at least read access\ + \ to the data you'd like to replicate. Generate an access token in the\ + \ Smartsheets main menu by clicking Account > Apps & Integrations > API\ + \ Access. See the setup guide for information on how to obtain this token." type: "string" order: 0 airbyte_secret: true spreadsheet_id: title: "Sheet ID" - description: "The spreadsheet ID. Find in the spreadsheet menu: File > Properties" + description: "The spreadsheet ID. Find it by opening the spreadsheet then\ + \ navigating to File > Properties" type: "string" order: 1 start_datetime: @@ -7921,10 +7977,12 @@ examples: - "2000-01-01T13:00:00" - "2000-01-01T13:00:00-07:00" - description: "ISO 8601, for instance: `YYYY-MM-DDTHH:MM:SS`, `YYYY-MM-DDTHH:MM:SS+HH:MM`" + description: "Only rows modified after this date/time will be replicated.\ + \ This should be an ISO 8601 string, for instance: `2000-01-01T13:00:00`" format: "date-time" default: "2020-01-01T00:00:00+00:00" order: 2 + airbyte_hidden: true supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] @@ -8419,7 +8477,7 @@ type: "string" path_in_connector_config: - "client_secret" -- dockerImage: "airbyte/source-stripe:0.1.31" +- dockerImage: "airbyte/source-stripe:0.1.32" spec: documentationUrl: "https://docs.airbyte.io/integrations/sources/stripe" connectionSpecification: @@ -8447,21 +8505,21 @@ order: 1 start_date: type: "string" - title: "Start Date" + title: "Replication start date" pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$" - description: "UTC date and time in the format 2017-01-25T00:00:00Z. Any\ - \ data before this date will not be replicated." + description: "UTC date and time in the format 2017-01-25T00:00:00Z. Only\ + \ data generated after this date will be replicated." examples: - "2017-01-25T00:00:00Z" order: 2 lookback_window_days: type: "integer" - title: "Lookback Window (in days)" + title: "Lookback Window in days (Optional)" default: 0 minimum: 0 - description: "When set, the connector will always reload data from the past\ - \ N days, where N is the value set here. This is useful if your data is\ - \ updated after creation. More info here" order: 3 supportsNormalization: false @@ -8692,7 +8750,7 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] -- dockerImage: "airbyte/source-tiktok-marketing:0.1.8" +- dockerImage: "airbyte/source-tiktok-marketing:0.1.9" spec: documentationUrl: "https://docs.airbyte.io/integrations/sources/tiktok-marketing" changelogUrl: "https://docs.airbyte.io/integrations/sources/tiktok-marketing" @@ -8701,7 +8759,8 @@ type: "object" properties: credentials: - title: "Authentication *" + title: "Authentication Method" + description: "Authentication method" default: {} order: 0 type: "object" @@ -8716,17 +8775,17 @@ type: "string" app_id: title: "App ID" - description: "The App ID applied by the developer." + description: "The Developer Application App ID." airbyte_secret: true type: "string" secret: title: "Secret" - description: "The private key of the developer's application." + description: "The Developer Application Secret." airbyte_secret: true type: "string" access_token: title: "Access Token" - description: "The long-term authorized access token." + description: "Long-term Authorized Access Token." airbyte_secret: true type: "string" required: @@ -8743,11 +8802,12 @@ type: "string" app_id: title: "App ID" - description: "The App ID applied by the developer." + description: "The Developer Application App ID." + airbyte_secret: true type: "string" secret: title: "Secret" - description: "The private key of the developer application." + description: "The Developer Application Secret." airbyte_secret: true type: "string" access_token: @@ -8781,18 +8841,19 @@ - "advertiser_id" - "access_token" start_date: - title: "Start Date *" + title: "Replication Start Date *" description: "The Start Date in format: YYYY-MM-DD. Any data before this\ - \ date will not be replicated.If this parameter is not set, all data will\ - \ be replicated." + \ date will not be replicated. If this parameter is not set, all data\ + \ will be replicated." default: "2016-09-01" pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" order: 1 type: "string" report_granularity: - title: "Report Granularity *" - description: "Grouping of your reports based on time. Lifetime will have\ - \ no grouping. This option is used for reports' streams only." + title: "Report Aggregation Granularity *" + description: "The granularity used for aggregating performance data in reports.\ + \ See the docs." default: "DAY" enum: - "LIFETIME" diff --git a/airbyte-integrations/connectors/source-airtable/Dockerfile b/airbyte-integrations/connectors/source-airtable/Dockerfile index 0d73131353a7..fc67fe16c272 100644 --- a/airbyte-integrations/connectors/source-airtable/Dockerfile +++ b/airbyte-integrations/connectors/source-airtable/Dockerfile @@ -34,5 +34,5 @@ COPY source_airtable ./source_airtable ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.1 +LABEL io.airbyte.version=0.1.2 LABEL io.airbyte.name=airbyte/source-airtable diff --git a/airbyte-integrations/connectors/source-amplitude/Dockerfile b/airbyte-integrations/connectors/source-amplitude/Dockerfile index f2cad066bbc6..cef81e7daf79 100644 --- a/airbyte-integrations/connectors/source-amplitude/Dockerfile +++ b/airbyte-integrations/connectors/source-amplitude/Dockerfile @@ -12,5 +12,5 @@ RUN pip install . ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.5 +LABEL io.airbyte.version=0.1.6 LABEL io.airbyte.name=airbyte/source-amplitude diff --git a/airbyte-integrations/connectors/source-amplitude/source_amplitude/spec.json b/airbyte-integrations/connectors/source-amplitude/source_amplitude/spec.json index 38e7941d9305..d5b9e0b5d020 100644 --- a/airbyte-integrations/connectors/source-amplitude/source_amplitude/spec.json +++ b/airbyte-integrations/connectors/source-amplitude/source_amplitude/spec.json @@ -10,18 +10,18 @@ "api_key": { "type": "string", "title": "API Key", - "description": "Amplitude API Key. See the docs for more information on how to obtain this key.", + "description": "Amplitude API Key. See the setup guide for more information on how to obtain this key.", "airbyte_secret": true }, "secret_key": { "type": "string", "title": "Secret Key", - "description": "Amplitude Secret Key. See the docs for more information on how to obtain this key.", + "description": "Amplitude Secret Key. See the setup guide for more information on how to obtain this key.", "airbyte_secret": true }, "start_date": { "type": "string", - "title": "Start Date", + "title": "Replication Start Date", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$", "description": "UTC date and time in the format 2021-01-25T00:00:00Z. Any data before this date will not be replicated.", "examples": ["2021-01-25T00:00:00Z"] diff --git a/airbyte-integrations/connectors/source-amplitude/unit_tests/test_source.py b/airbyte-integrations/connectors/source-amplitude/unit_tests/test_source.py index 8c27b4971ec9..d22bbc71846a 100644 --- a/airbyte-integrations/connectors/source-amplitude/unit_tests/test_source.py +++ b/airbyte-integrations/connectors/source-amplitude/unit_tests/test_source.py @@ -3,25 +3,23 @@ # +from unittest.mock import patch + import pytest import requests -from unittest.mock import patch from airbyte_cdk import AirbyteLogger from source_amplitude import SourceAmplitude from source_amplitude.api import ActiveUsers, Annotations, AverageSessionLength, Cohorts, Events - -TEST_CONFIG: dict = { - "api_key": "test_api_key", - "secret_key": "test_secret_key", - "start_date": "2022-05-01T00:00:00Z" -} +TEST_CONFIG: dict = {"api_key": "test_api_key", "secret_key": "test_secret_key", "start_date": "2022-05-01T00:00:00Z"} TEST_INSTANCE: SourceAmplitude = SourceAmplitude() + class MockRequest: def __init__(self, status_code): self.status_code = status_code + def test_convert_auth_to_token(): expected = "dXNlcm5hbWU6cGFzc3dvcmQ=" actual = TEST_INSTANCE._convert_auth_to_token("username", "password") @@ -31,17 +29,18 @@ def test_convert_auth_to_token(): @pytest.mark.parametrize( "response, check_passed", [ - ({"id": 123}, True), - (requests.HTTPError(), False), + ({"id": 123}, True), + (requests.HTTPError(), False), ], ids=["Success", "Fail"], -) +) def test_check(response, check_passed): - with patch.object(Cohorts, 'read_records', return_value=response) as mock_method: + with patch.object(Cohorts, "read_records", return_value=response) as mock_method: result = TEST_INSTANCE.check_connection(logger=AirbyteLogger, config=TEST_CONFIG) mock_method.assert_called() assert check_passed == result[0] - + + @pytest.mark.parametrize( "expected_stream_cls", [ diff --git a/airbyte-integrations/connectors/source-bing-ads/Dockerfile b/airbyte-integrations/connectors/source-bing-ads/Dockerfile index 4bc175d391c4..8349748f3000 100644 --- a/airbyte-integrations/connectors/source-bing-ads/Dockerfile +++ b/airbyte-integrations/connectors/source-bing-ads/Dockerfile @@ -12,5 +12,5 @@ RUN pip install . ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.5 +LABEL io.airbyte.version=0.1.6 LABEL io.airbyte.name=airbyte/source-bing-ads diff --git a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/spec.json b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/spec.json index 188b89b6d4e3..d8dba81babfb 100644 --- a/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/spec.json +++ b/airbyte-integrations/connectors/source-bing-ads/source_bing_ads/spec.json @@ -21,38 +21,36 @@ "additionalProperties": false, "properties": { "accounts": { - "title": "Accounts", + "title": "Accounts to replicate data from", "type": "object", - "description": "Account selection.", + "description": "", "oneOf": [ { - "title": "All accounts assigned to your user", + "title": "All Accounts", "additionalProperties": false, - "description": "Fetch data for all available accounts.", + "description": "Replicate data from all accounts to which you have access.", "required": ["selection_strategy"], "properties": { "selection_strategy": { "type": "string", - "enum": ["all"], "const": "all" } } }, { - "title": "Subset of your accounts", + "title": "Specific Accounts", "additionalProperties": false, "description": "Fetch data for subset of account IDs.", "required": ["ids", "selection_strategy"], "properties": { "selection_strategy": { "type": "string", - "enum": ["subset"], "const": "subset" }, "ids": { "type": "array", - "title": "IDs", - "description": "List of accounts from which data will be fetched.", + "title": "Account IDs", + "description": "List of the account IDs from which data will be replicated.", "items": { "type": "string" }, @@ -67,79 +65,88 @@ "type": "string", "title": "Client ID", "description": "The Client ID of your Microsoft Advertising developer application.", - "airbyte_secret": true + "airbyte_secret": true, + "order": 0 }, "client_secret": { "type": "string", "title": "Client Secret", "description": "The Client Secret of your Microsoft Advertising developer application.", - "airbyte_secret": true + "airbyte_secret": true, + "order": 1 }, - "customer_id": { + "refresh_token": { "type": "string", - "title": "Customer ID", - "description": "User's Customer ID. Go to your Accounts and Billing page. Your Customer ID will be listed on the Accounts tab under the heading Customer." + "title": "Refresh Token", + "description": "Refresh Token to renew the expired Access Token.", + "airbyte_secret": true, + "order": 2 }, "developer_token": { "type": "string", "title": "Developer Token", "description": "Developer token associated with user.", - "airbyte_secret": true + "airbyte_secret": true, + "order": 3 }, "tenant_id": { "type": "string", "title": "Tenant ID", - "description": "The Tenant ID of your Microsoft Advertising developer application.", + "description": "The Tenant ID of your Microsoft Advertising developer application. Set this to \"common\" unless you know you need a different value.", "airbyte_secret": true, - "default": "common" + "default": "common", + "order": 4 }, "redirect_uri": { "type": "string", - "title": "Redirect URI", - "description": "The Redirect URI of your Microsoft Advertising developer application.", + "title": "Redirect URI (Optional)", + "description": "The Redirect URI of your Microsoft Advertising developer application. Leave this empty unless you know that you need it.", "airbyte_secret": true, - "default": "" + "default": "", + "order": 5 }, - "refresh_token": { + "customer_id": { "type": "string", - "title": "Refresh Token", - "description": "Refresh Token to renew the expired Access Token.", - "airbyte_secret": true + "title": "Customer ID", + "description": "Your Bing Customer ID. See the \"Getting Started\" section in the docs for information on how to obtain this ID", + "order": 6 }, "user_id": { "type": "string", "title": "Account ID", - "description": "Bing Ads Account ID. You can find Account ID by going to your profile and selecting Accounts and Billing." + "description": "Bing Ads Account ID. See the \"Getting Started\" section in the docs for information on how to obtain this ID", + "order": 7 }, "reports_start_date": { "type": "string", - "title": "Reports Start Date", + "title": "Reports replication start date", "format": "date", "default": "2020-01-01", - "description": "UTC date in YYYY-MM-DD format. Any reports before this date will not be replicated." + "description": "The start date from which to begin replicating report data. Any data generated before this date will not be replicated in reports. This is a UTC date in YYYY-MM-DD format.", + "order": 8 }, "hourly_reports": { - "title": "Hourly reports", + "title": "Enable hourly-aggregate reports", "type": "boolean", - "description": "The report data will be aggregated by each hour of the day.", + "description": "Toggle this to enable replicating reports aggregated using an hourly time window. More information about report aggregation can be found in the docs.", "default": false }, "daily_reports": { - "title": "Daily reports", + "title": "Enable daily-aggregate reports", "type": "boolean", - "description": "The report data will be aggregated by each day.", + "description": "Toggle this to enable replicating reports aggregated using a daily time window. More information about report aggregation can be found in the docs.", "default": false }, "weekly_reports": { - "title": "Weekly reports", + "title": "Enable weekly-aggregate reports", "type": "boolean", - "description": "The report data will be aggregated by each week running from Sunday through Saturday.", + "description": "Toggle this to enable replicating reports aggregated using a weekly time window running from Sunday to Saturday. More information about report aggregation can be found in the docs.", "default": false }, "monthly_reports": { - "title": "Monthly reports", + "title": "Enable monthly-aggregate reports", "type": "boolean", - "description": "The report data will be aggregated by each month.", + "description": "Toggle this to enable replicating reports aggregated using a monthly time window. More information about report aggregation can be found in the docs.", "default": false } } diff --git a/airbyte-integrations/connectors/source-google-analytics-v4/Dockerfile b/airbyte-integrations/connectors/source-google-analytics-v4/Dockerfile index 56f7b74e9cd3..59d41aa185e4 100644 --- a/airbyte-integrations/connectors/source-google-analytics-v4/Dockerfile +++ b/airbyte-integrations/connectors/source-google-analytics-v4/Dockerfile @@ -12,5 +12,5 @@ COPY main.py ./ ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.20 +LABEL io.airbyte.version=0.1.21 LABEL io.airbyte.name=airbyte/source-google-analytics-v4 diff --git a/airbyte-integrations/connectors/source-google-analytics-v4/source_google_analytics_v4/spec.json b/airbyte-integrations/connectors/source-google-analytics-v4/source_google_analytics_v4/spec.json index 07482cb89535..d2e39b6cf959 100644 --- a/airbyte-integrations/connectors/source-google-analytics-v4/source_google_analytics_v4/spec.json +++ b/airbyte-integrations/connectors/source-google-analytics-v4/source_google_analytics_v4/spec.json @@ -7,32 +7,6 @@ "required": ["view_id", "start_date"], "additionalProperties": true, "properties": { - "view_id": { - "order": 2, - "type": "string", - "title": "View ID", - "description": "The ID for the Google Analytics View you want to fetch data from. This can be found from the Google Analytics Account Explorer." - }, - "start_date": { - "order": 1, - "type": "string", - "title": "Start Date", - "description": "The date in the format YYYY-MM-DD. Any data before this date will not be replicated.", - "examples": ["2020-06-01"] - }, - "window_in_days": { - "type": "integer", - "title": "Data request window (Optional)", - "description": "The amount of data batched by the number of days. The bigger the value, the bigger the batch size and the lower the API requests made. (Min=1, as for a Day; Max=364, as for a Year).", - "examples": [30, 60, 90, 120, 200, 364], - "default": 1 - }, - "custom_reports": { - "order": 3, - "type": "string", - "title": "Custom Reports (Optional)", - "description": "A JSON array describing the custom reports you want to sync from GA. Check out the docs to get more information about this field." - }, "credentials": { "order": 0, "type": "object", @@ -90,7 +64,7 @@ "order": 0 }, "credentials_json": { - "title": "JSON credentials", + "title": "Service Account JSON Key", "type": "string", "description": "The JSON key of the service account to use for authorization", "examples": [ @@ -101,6 +75,33 @@ } } ] + }, + "start_date": { + "order": 1, + "type": "string", + "title": "Replication Start Date", + "description": "The date in the format YYYY-MM-DD. Any data before this date will not be replicated.", + "examples": ["2020-06-01"] + }, + "view_id": { + "order": 2, + "type": "string", + "title": "View ID", + "description": "The ID for the Google Analytics View you want to fetch data from. This can be found from the Google Analytics Account Explorer." + }, + "custom_reports": { + "order": 3, + "type": "string", + "title": "Custom Reports (Optional)", + "description": "A JSON array describing the custom reports you want to sync from Google Analytics. See the docs for more information about the exact format you can use to fill out this field." + }, + "window_in_days": { + "type": "integer", + "title": "Data request time increment in days (Optional)", + "description": "The time increment used by the connector when requesting data from the Google Analytics API. More information is available in the the docs. The bigger this value is, the faster the sync will be, but the more likely that sampling will be applied to your data, potentially causing inaccuracies in the returned results. We recommend setting this to 1 unless you have a hard requirement to make the sync faster at the expense of accuracy. The minimum allowed value for this field is 1, and the maximum is 364. ", + "examples": [30, 60, 90, 120, 200, 364], + "default": 1, + "order": 4 } } }, diff --git a/airbyte-integrations/connectors/source-s3/Dockerfile b/airbyte-integrations/connectors/source-s3/Dockerfile index 7229259512eb..6c2cf7ccbe48 100644 --- a/airbyte-integrations/connectors/source-s3/Dockerfile +++ b/airbyte-integrations/connectors/source-s3/Dockerfile @@ -17,5 +17,5 @@ COPY source_s3 ./source_s3 ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.10 +LABEL io.airbyte.version=0.1.11 LABEL io.airbyte.name=airbyte/source-s3 diff --git a/airbyte-integrations/connectors/source-s3/integration_tests/spec.json b/airbyte-integrations/connectors/source-s3/integration_tests/spec.json index ef7ce5a33e07..602628f04e58 100644 --- a/airbyte-integrations/connectors/source-s3/integration_tests/spec.json +++ b/airbyte-integrations/connectors/source-s3/integration_tests/spec.json @@ -6,36 +6,31 @@ "type": "object", "properties": { "dataset": { - "title": "Dataset", - "description": "This source creates one table per connection, this field is the name of that table. This should include only letters, numbers, dash and underscores. Note that this may be altered according to destination.", + "title": "Output Stream Name", + "description": "The name of the stream you would like this source to output. Can contain letters, numbers, or underscores.", "pattern": "^([A-Za-z0-9-_]+)$", + "order": 0, "type": "string" }, "path_pattern": { - "title": "Path Pattern", - "description": "Add at least 1 pattern here to match filepaths against. Use | to separate multiple patterns. Airbyte uses these patterns to determine which files to pick up from the provider storage. See wcmatch.glob to understand pattern syntax (GLOBSTAR and SPLIT flags are enabled). Use pattern ** to pick up all files.", + "title": "Pattern of files to replicate", + "description": "A regular expression which tells the connector which files to replicate. All files which match this pattern will be replicated. Use | to separate multiple patterns. See this page to understand pattern syntax (GLOBSTAR and SPLIT flags are enabled). Use pattern ** to pick up all files.", "examples": [ "**", "myFolder/myTableFiles/*.csv|myFolder/myOtherTableFiles/*.csv" ], - "type": "string" - }, - "schema": { - "title": "Schema", - "description": "Optionally provide a schema to enforce, as a valid JSON string. Ensure this is a mapping of { \"column\" : \"type\" }, where types are valid JSON Schema datatypes. Leave as {} to auto-infer the schema.", - "default": "{}", - "examples": [ - "{\"column_1\": \"number\", \"column_2\": \"string\", \"column_3\": \"array\", \"column_4\": \"object\", \"column_5\": \"boolean\"}" - ], + "order": 10, "type": "string" }, "format": { - "title": "Format", + "title": "File Format", + "description": "The format of the files you'd like to replicate", "default": "csv", + "order": 20, "type": "object", "oneOf": [ { - "title": "csv", + "title": "CSV", "description": "This connector utilises PyArrow (Apache Arrow) for CSV parsing.", "type": "object", "properties": { @@ -49,43 +44,50 @@ "description": "The character delimiting individual cells in the CSV data. This may only be a 1-character string. For tab-delimited data enter '\\t'.", "default": ",", "minLength": 1, + "order": 0, "type": "string" }, + "infer_datatypes": { + "title": "Infer Datatypes", + "description": "Configures whether a schema for the source should be inferred from the current data or not. If set to false and a custom schema is set, then the manually enforced schema is used. If a schema is not manually set, and this is set to false, then all fields will be read as strings", + "default": true, + "order": 1, + "type": "boolean" + }, "quote_char": { - "title": "Quote Char", - "description": "The character used optionally for quoting CSV values. To disallow quoting, make this field blank.", + "title": "Quote Character", + "description": "The character used for quoting CSV values. To disallow quoting, make this field blank.", "default": "\"", + "order": 2, "type": "string" }, "escape_char": { - "title": "Escape Char", - "description": "The character used optionally for escaping special characters. To disallow escaping, leave this field blank.", + "title": "Escape Character", + "description": "The character used for escaping special characters. To disallow escaping, leave this field blank.", + "order": 3, "type": "string" }, "encoding": { "title": "Encoding", - "description": "The character encoding of the CSV data. Leave blank to default to UTF-8. See list of python encodings for allowable options.", + "description": "The character encoding of the CSV data. Leave blank to default to UTF8. See list of python encodings for allowable options.", "default": "utf8", + "order": 4, "type": "string" }, "double_quote": { "title": "Double Quote", "description": "Whether two quotes in a quoted CSV value denote a single quote in the data.", "default": true, + "order": 5, "type": "boolean" }, "newlines_in_values": { - "title": "Newlines In Values", + "title": "Allow newlines in values", "description": "Whether newline characters are allowed in CSV values. Turning this on may affect performance. Leave blank to default to False.", "default": false, + "order": 6, "type": "boolean" }, - "block_size": { - "title": "Block Size", - "description": "The chunk size in bytes to process at a time in memory from each file. If your data is particularly wide and failing during schema detection, increasing this should solve it. Beware of raising this too high as you could hit OOM errors.", - "default": 10000, - "type": "integer" - }, "additional_reader_options": { "title": "Additional Reader Options", "description": "Optionally add a valid JSON string here to provide additional options to the csv reader. Mappings must correspond to options detailed here. 'column_types' is used internally to handle schema so overriding that would likely cause problems.", @@ -93,6 +95,7 @@ "examples": [ "{\"timestamp_parsers\": [\"%m/%d/%Y %H:%M\", \"%Y/%m/%d %H:%M\"], \"strings_can_be_null\": true, \"null_values\": [\"NA\", \"NULL\"]}" ], + "order": 7, "type": "string" }, "advanced_options": { @@ -100,18 +103,20 @@ "description": "Optionally add a valid JSON string here to provide additional Pyarrow ReadOptions. Specify 'column_names' here if your CSV doesn't have header, or if you want to use custom column names. 'block_size' and 'encoding' are already used above, specify them again here will override the values above.", "default": "{}", "examples": ["{\"column_names\": [\"column1\", \"column2\"]}"], + "order": 8, "type": "string" }, - "infer_datatypes": { - "title": "Infer Datatypes", - "description": "Configures whether a scheme for the source should be inferred from the current data or not.If set to false and a custom schema is set, then the custom_schema is usedIf a custom schema is not set, and this is set to false, then all fields will be read as strings", - "default": true, - "type": "boolean" + "block_size": { + "title": "Block Size", + "description": "The chunk size in bytes to process at a time in memory from each file. If your data is particularly wide and failing during schema detection, increasing this should solve it. Beware of raising this too high as you could hit OOM errors.", + "default": 10000, + "order": 9, + "type": "integer" } } }, { - "title": "parquet", + "title": "Parquet", "description": "This connector utilises PyArrow (Apache Arrow) for Parquet parsing.", "type": "object", "properties": { @@ -120,30 +125,42 @@ "const": "parquet", "type": "string" }, - "buffer_size": { - "title": "Buffer Size", - "description": "Perform read buffering when deserializing individual column chunks. By default every group column will be loaded fully to memory. This option can help to optimize a work with memory if your data is particularly wide or failing during detection of OOM errors.", - "default": 0, - "type": "integer" - }, "columns": { - "title": "Columns", - "description": "If you only want to sync a subset of the columns from the file(s), add the columns you want here. Leave it empty to sync all columns.", + "title": "Selected Columns", + "description": "If you only want to sync a subset of the columns from the file(s), add the columns you want here as a comma-delimited list. Leave it empty to sync all columns.", + "order": 0, "type": "array", "items": { "type": "string" } }, "batch_size": { - "title": "Batch Size", - "description": "Maximum number of records per batch. Batches may be smaller if there aren’t enough rows in the file. This option can help to optimize a work with memory if your data is particularly wide or failing during detection of OOM errors.", + "title": "Record batch size", + "description": "Maximum number of records per batch read from the input files. Batches may be smaller if there aren’t enough rows in the file. This option can help avoid out-of-memory errors if your data is particularly wide.", "default": 65536, + "order": 1, + "type": "integer" + }, + "buffer_size": { + "title": "Buffer Size", + "description": "Perform read buffering when deserializing individual column chunks. By default every group column will be loaded fully to memory. This option can help avoid out-of-memory errors if your data is particularly wide.", + "default": 2, "type": "integer" } } } ] }, + "schema": { + "title": "Manually enforced data schema (Optional)", + "description": "Optionally provide a schema to enforce, as a valid JSON string. Ensure this is a mapping of { \"column\" : \"type\" }, where types are valid JSON Schema datatypes. Leave as {} to auto-infer the schema.", + "default": "{}", + "examples": [ + "{\"column_1\": \"number\", \"column_2\": \"string\", \"column_3\": \"array\", \"column_4\": \"object\", \"column_5\": \"boolean\"}" + ], + "order": 30, + "type": "string" + }, "provider": { "title": "S3: Amazon Web Services", "type": "object", @@ -151,44 +168,53 @@ "bucket": { "title": "Bucket", "description": "Name of the S3 bucket where the file(s) exist.", + "order": 0, "type": "string" }, "aws_access_key_id": { - "title": "Aws Access Key Id", + "title": "AWS Access Key ID", "description": "In order to access private Buckets stored on AWS S3, this connector requires credentials with the proper permissions. If accessing publicly available data, this field is not necessary.", "airbyte_secret": true, + "order": 1, "type": "string" }, "aws_secret_access_key": { - "title": "Aws Secret Access Key", + "title": "AWS Secret Access Key", "description": "In order to access private Buckets stored on AWS S3, this connector requires credentials with the proper permissions. If accessing publicly available data, this field is not necessary.", "airbyte_secret": true, + "order": 2, "type": "string" }, "path_prefix": { "title": "Path Prefix", - "description": "By providing a path-like prefix (e.g. myFolder/thisTable/) under which all the relevant files sit, we can optimise finding these in S3. This is optional but recommended if your bucket contains many folders/files.", + "description": "By providing a path-like prefix (e.g. myFolder/thisTable/) under which all the relevant files sit, we can optimize finding these in S3. This is optional but recommended if your bucket contains many folders/files which you don't need to replicate.", "default": "", + "order": 3, "type": "string" }, "endpoint": { "title": "Endpoint", "description": "Endpoint to an S3 compatible service. Leave empty to use AWS.", "default": "", + "order": 4, "type": "string" }, "use_ssl": { - "title": "Use Ssl", - "description": "Is remote server using secure SSL/TLS connection", + "title": "Use TLS", + "description": "Whether the remote server is using a secure SSL/TLS connection. Only relevant if using an S3-compatible, non-AWS server", + "order": 5, "type": "boolean" }, "verify_ssl_cert": { - "title": "Verify Ssl Cert", - "description": "Allow self signed certificates", + "title": "Verify TLS Certificates", + "description": "Set this to false to allow self signed certificates. Only relevant if using an S3-compatible, non-AWS server", + "order": 6, "type": "boolean" } }, - "required": ["bucket"] + "required": ["bucket"], + "order": 11, + "description": "Use this to load files from S3 or S3-compatible services" } }, "required": ["dataset", "path_pattern", "provider"] diff --git a/airbyte-integrations/connectors/source-s3/setup.py b/airbyte-integrations/connectors/source-s3/setup.py index a5966de78ca4..678b026d3748 100644 --- a/airbyte-integrations/connectors/source-s3/setup.py +++ b/airbyte-integrations/connectors/source-s3/setup.py @@ -6,7 +6,7 @@ from setuptools import find_packages, setup MAIN_REQUIREMENTS = [ - "airbyte-cdk~=0.1.28", + "airbyte-cdk", "pyarrow==4.0.1", "smart-open[s3]==5.1.0", "wcmatch==8.2", diff --git a/airbyte-integrations/connectors/source-s3/source_s3/source.py b/airbyte-integrations/connectors/source-s3/source_s3/source.py index 48add42b020d..5c36b8d6f5cf 100644 --- a/airbyte-integrations/connectors/source-s3/source_s3/source.py +++ b/airbyte-integrations/connectors/source-s3/source_s3/source.py @@ -19,26 +19,48 @@ class Config: class S3Provider(BaseModel): class Config: title = "S3: Amazon Web Services" + # SourceFilesAbstractSpec field are ordered 10 apart to allow subclasses to insert their own spec's fields interspersed + schema_extra = {"order": 11, "description": "Use this to load files from S3 or S3-compatible services"} - bucket: str = Field(description="Name of the S3 bucket where the file(s) exist.") + bucket: str = Field(description="Name of the S3 bucket where the file(s) exist.", order=0) aws_access_key_id: Optional[str] = Field( + title="AWS Access Key ID", default=None, - description="In order to access private Buckets stored on AWS S3, this connector requires credentials with the proper permissions. If accessing publicly available data, this field is not necessary.", + description="In order to access private Buckets stored on AWS S3, this connector requires credentials with the proper " + "permissions. If accessing publicly available data, this field is not necessary.", airbyte_secret=True, + order=1, ) aws_secret_access_key: Optional[str] = Field( + title="AWS Secret Access Key", default=None, - description="In order to access private Buckets stored on AWS S3, this connector requires credentials with the proper permissions. If accessing publicly available data, this field is not necessary.", + description="In order to access private Buckets stored on AWS S3, this connector requires credentials with the proper " + "permissions. If accessing publicly available data, this field is not necessary.", airbyte_secret=True, + order=2, ) path_prefix: str = Field( default="", - description="By providing a path-like prefix (e.g. myFolder/thisTable/) under which all the relevant files sit, we can optimise finding these in S3. This is optional but recommended if your bucket contains many folders/files.", + description="By providing a path-like prefix (e.g. myFolder/thisTable/) under which all the relevant files sit, " + "we can optimize finding these in S3. This is optional but recommended if your bucket contains many " + "folders/files which you don't need to replicate.", + order=3, ) - endpoint: str = Field("", description="Endpoint to an S3 compatible service. Leave empty to use AWS.") - use_ssl: bool = Field(default=None, description="Is remote server using secure SSL/TLS connection") - verify_ssl_cert: bool = Field(default=None, description="Allow self signed certificates") + endpoint: str = Field("", description="Endpoint to an S3 compatible service. Leave empty to use AWS.", order=4) + use_ssl: bool = Field( + default=None, + title="Use TLS", + description="Whether the remote server is using a secure SSL/TLS connection. Only relevant if using an S3-compatible, " + "non-AWS server", + order=5, + ) + verify_ssl_cert: bool = Field( + default=None, + title="Verify TLS Certificates", + description="Set this to false to allow self signed certificates. Only relevant if using an S3-compatible, non-AWS server", + order=6, + ) provider: S3Provider diff --git a/airbyte-integrations/connectors/source-s3/source_s3/source_files_abstract/formats/csv_spec.py b/airbyte-integrations/connectors/source-s3/source_s3/source_files_abstract/formats/csv_spec.py index 0fe3faa3e06a..51c6d86047bf 100644 --- a/airbyte-integrations/connectors/source-s3/source_s3/source_files_abstract/formats/csv_spec.py +++ b/airbyte-integrations/connectors/source-s3/source_s3/source_files_abstract/formats/csv_spec.py @@ -11,10 +11,10 @@ class CsvFormat(BaseModel): 'This connector utilises PyArrow (Apache Arrow) for CSV parsing.' class Config: - title = "csv" + title = "CSV" filetype: str = Field( - Config.title, + "csv", const=True, ) @@ -22,26 +22,40 @@ class Config: default=",", min_length=1, description="The character delimiting individual cells in the CSV data. This may only be a 1-character string. For tab-delimited data enter '\\t'.", + order=0, + ) + infer_datatypes: Optional[bool] = Field( + default=True, + description="Configures whether a schema for the source should be inferred from the current data or not. " + "If set to false and a custom schema is set, then the manually enforced schema is used. " + "If a schema is not manually set, and this is set to false, then all fields will be read as strings", + order=1, ) quote_char: str = Field( - default='"', description="The character used optionally for quoting CSV values. To disallow quoting, make this field blank." + title="Quote Character", + default='"', + description="The character used for quoting CSV values. To disallow quoting, make this field blank.", + order=2, ) escape_char: Optional[str] = Field( + title="Escape Character", default=None, - description="The character used optionally for escaping special characters. To disallow escaping, leave this field blank.", + description="The character used for escaping special characters. To disallow escaping, leave this field blank.", + order=3, ) encoding: Optional[str] = Field( default="utf8", - description='The character encoding of the CSV data. Leave blank to default to UTF-8. See list of python encodings for allowable options.', + description='The character encoding of the CSV data. Leave blank to default to UTF8. See list of python encodings for allowable options.', + order=4, + ) + double_quote: bool = Field( + default=True, description="Whether two quotes in a quoted CSV value denote a single quote in the data.", order=5 ) - double_quote: bool = Field(default=True, description="Whether two quotes in a quoted CSV value denote a single quote in the data.") newlines_in_values: bool = Field( + title="Allow newlines in values", default=False, description="Whether newline characters are allowed in CSV values. Turning this on may affect performance. Leave blank to default to False.", - ) - block_size: int = Field( - default=10000, - description="The chunk size in bytes to process at a time in memory from each file. If your data is particularly wide and failing during schema detection, increasing this should solve it. Beware of raising this too high as you could hit OOM errors.", + order=6, ) additional_reader_options: str = Field( default="{}", @@ -49,15 +63,16 @@ class Config: examples=[ '{"timestamp_parsers": ["%m/%d/%Y %H:%M", "%Y/%m/%d %H:%M"], "strings_can_be_null": true, "null_values": ["NA", "NULL"]}' ], + order=7, ) advanced_options: str = Field( default="{}", description="Optionally add a valid JSON string here to provide additional Pyarrow ReadOptions. Specify 'column_names' here if your CSV doesn't have header, or if you want to use custom column names. 'block_size' and 'encoding' are already used above, specify them again here will override the values above.", examples=['{"column_names": ["column1", "column2"]}'], + order=8, ) - infer_datatypes: Optional[bool] = Field( - default=True, - description="Configures whether a scheme for the source should be inferred from the current data or not." - "If set to false and a custom schema is set, then the custom_schema is used" - "If a custom schema is not set, and this is set to false, then all fields will be read as strings", + block_size: int = Field( + default=10000, + description="The chunk size in bytes to process at a time in memory from each file. If your data is particularly wide and failing during schema detection, increasing this should solve it. Beware of raising this too high as you could hit OOM errors.", + order=9, ) diff --git a/airbyte-integrations/connectors/source-s3/source_s3/source_files_abstract/formats/parquet_spec.py b/airbyte-integrations/connectors/source-s3/source_s3/source_files_abstract/formats/parquet_spec.py index c1ecd9ebb53b..78f3144a8cc5 100644 --- a/airbyte-integrations/connectors/source-s3/source_s3/source_files_abstract/formats/parquet_spec.py +++ b/airbyte-integrations/connectors/source-s3/source_s3/source_files_abstract/formats/parquet_spec.py @@ -11,21 +11,28 @@ class ParquetFormat(BaseModel): 'This connector utilises PyArrow (Apache Arrow) for Parquet parsing.' class Config: - title = "parquet" + title = "Parquet" - filetype: str = Field(Config.title, const=True) - - buffer_size: int = Field( - default=0, - description="Perform read buffering when deserializing individual column chunks. By default every group column will be loaded fully to memory. This option can help to optimize a work with memory if your data is particularly wide or failing during detection of OOM errors.", - ) + filetype: str = Field("parquet", const=True) columns: Optional[List[str]] = Field( default=None, - description="If you only want to sync a subset of the columns from the file(s), add the columns you want here. Leave it empty to sync all columns.", + description="If you only want to sync a subset of the columns from the file(s), add the columns you want here as a comma-delimited" + " list. Leave it empty to sync all columns.", + title="Selected Columns", + order=0, ) - batch_size: int = Field( + title="Record batch size", + order=1, default=64 * 1024, # 64K records - description="Maximum number of records per batch. Batches may be smaller if there aren’t enough rows in the file. This option can help to optimize a work with memory if your data is particularly wide or failing during detection of OOM errors.", + description="Maximum number of records per batch read from the input files. " + "Batches may be smaller if there aren’t enough rows in the file. " + "This option can help avoid out-of-memory errors if your data is particularly wide.", + ) + buffer_size: int = Field( + default=2, + description="Perform read buffering when deserializing individual column chunks. " + "By default every group column will be loaded fully to memory. " + "This option can help avoid out-of-memory errors if your data is particularly wide.", ) diff --git a/airbyte-integrations/connectors/source-s3/source_s3/source_files_abstract/spec.py b/airbyte-integrations/connectors/source-s3/source_s3/source_files_abstract/spec.py index f32703a8e765..5886f484f0a1 100644 --- a/airbyte-integrations/connectors/source-s3/source_s3/source_files_abstract/spec.py +++ b/airbyte-integrations/connectors/source-s3/source_s3/source_files_abstract/spec.py @@ -42,26 +42,39 @@ class SourceFilesAbstractSpec(BaseModel): - dataset: str = Field( pattern=r"^([A-Za-z0-9-_]+)$", - description="This source creates one table per connection, this field is the name of that table. This should include only letters, numbers, dash and underscores. Note that this may be altered according to destination.", + description="The name of the stream you would like this source to output. Can contain letters, numbers, or underscores.", + order=0, + title="Output Stream Name", ) path_pattern: str = Field( - description='Add at least 1 pattern here to match filepaths against. Use | to separate multiple patterns. Airbyte uses these patterns to determine which files to pick up from the provider storage. See wcmatch.glob to understand pattern syntax (GLOBSTAR and SPLIT flags are enabled). Use pattern ** to pick up all files.', + title="Pattern of files to replicate", + description="A regular expression which tells the connector which files to replicate. All files which match this pattern will be " + 'replicated. Use | to separate multiple patterns. See this page to understand pattern syntax (GLOBSTAR and SPLIT flags are enabled). ' + "Use pattern ** to pick up all files.", examples=["**", "myFolder/myTableFiles/*.csv|myFolder/myOtherTableFiles/*.csv"], + order=10, + ) + + format: Union[CsvFormat, ParquetFormat] = Field( + default="csv", title="File Format", description="The format of the files you'd like to replicate", order=20 ) user_schema: str = Field( + title="Manually enforced data schema (Optional)", alias="schema", default="{}", - description='Optionally provide a schema to enforce, as a valid JSON string. Ensure this is a mapping of { "column" : "type" }, where types are valid JSON Schema datatypes. Leave as {} to auto-infer the schema.', + description="Optionally provide a schema to enforce, as a valid JSON string. Ensure this is a mapping of " + '{ "column" : "type" }, where types are valid ' + 'JSON Schema ' + "datatypes. Leave as {} to auto-infer the schema.", examples=['{"column_1": "number", "column_2": "string", "column_3": "array", "column_4": "object", "column_5": "boolean"}'], + order=30, ) - format: Union[CsvFormat, ParquetFormat] = Field(default=CsvFormat.Config.title) - @staticmethod def change_format_to_oneOf(schema: dict) -> dict: props_to_change = ["format"] diff --git a/airbyte-integrations/connectors/source-shopify/Dockerfile b/airbyte-integrations/connectors/source-shopify/Dockerfile index e8d842c23592..edb7ac03c3b0 100644 --- a/airbyte-integrations/connectors/source-shopify/Dockerfile +++ b/airbyte-integrations/connectors/source-shopify/Dockerfile @@ -28,5 +28,5 @@ COPY source_shopify ./source_shopify ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.36 +LABEL io.airbyte.version=0.1.37 LABEL io.airbyte.name=airbyte/source-shopify diff --git a/airbyte-integrations/connectors/source-shopify/source_shopify/spec.json b/airbyte-integrations/connectors/source-shopify/source_shopify/spec.json index b98f465dcce7..9ef00e3ed7fa 100644 --- a/airbyte-integrations/connectors/source-shopify/source_shopify/spec.json +++ b/airbyte-integrations/connectors/source-shopify/source_shopify/spec.json @@ -15,19 +15,19 @@ }, "credentials": { "title": "Shopify Authorization Method", + "description": "The authorization method to use to retrieve data from Shopify", "type": "object", "order": 2, "oneOf": [ { "type": "object", "title": "OAuth2.0", + "description": "OAuth2.0", "required": ["auth_method"], "properties": { "auth_method": { "type": "string", "const": "oauth2.0", - "enum": ["oauth2.0"], - "default": "oauth2.0", "order": 0 }, "client_id": { @@ -52,14 +52,13 @@ }, { "title": "API Password", + "description": "API Password Auth", "type": "object", "required": ["auth_method", "api_password"], "properties": { "auth_method": { "type": "string", "const": "api_password", - "enum": ["api_password"], - "default": "api_password", "order": 0 }, "api_password": { @@ -74,7 +73,7 @@ }, "start_date": { "type": "string", - "title": "Start Date", + "title": "Replication Start Date", "description": "The date you would like to replicate data from. Format: YYYY-MM-DD. Any data before this date will not be replicated.", "examples": ["2021-01-01"], "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$", diff --git a/airbyte-integrations/connectors/source-smartsheets/Dockerfile b/airbyte-integrations/connectors/source-smartsheets/Dockerfile index 8a86cdfb6699..861a0288b281 100644 --- a/airbyte-integrations/connectors/source-smartsheets/Dockerfile +++ b/airbyte-integrations/connectors/source-smartsheets/Dockerfile @@ -14,5 +14,5 @@ COPY $CODE_PATH ./$CODE_PATH ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.11 +LABEL io.airbyte.version=0.1.12 LABEL io.airbyte.name=airbyte/source-smartsheets diff --git a/airbyte-integrations/connectors/source-smartsheets/source_smartsheets/spec.json b/airbyte-integrations/connectors/source-smartsheets/source_smartsheets/spec.json index 5e027cac477e..c756aff00de0 100644 --- a/airbyte-integrations/connectors/source-smartsheets/source_smartsheets/spec.json +++ b/airbyte-integrations/connectors/source-smartsheets/source_smartsheets/spec.json @@ -9,14 +9,14 @@ "properties": { "access_token": { "title": "Access Token", - "description": "The Access Token for making authenticated requests. Find in the main menu: Account > Apps & Integrations > API Access", + "description": "The access token to use for accessing your data from Smartsheets. This access token must be generated by a user with at least read access to the data you'd like to replicate. Generate an access token in the Smartsheets main menu by clicking Account > Apps & Integrations > API Access. See the setup guide for information on how to obtain this token.", "type": "string", "order": 0, "airbyte_secret": true }, "spreadsheet_id": { "title": "Sheet ID", - "description": "The spreadsheet ID. Find in the spreadsheet menu: File > Properties", + "description": "The spreadsheet ID. Find it by opening the spreadsheet then navigating to File > Properties", "type": "string", "order": 1 }, @@ -24,10 +24,11 @@ "title": "Start Datetime (Optional)", "type": "string", "examples": ["2000-01-01T13:00:00", "2000-01-01T13:00:00-07:00"], - "description": "ISO 8601, for instance: `YYYY-MM-DDTHH:MM:SS`, `YYYY-MM-DDTHH:MM:SS+HH:MM`", + "description": "Only rows modified after this date/time will be replicated. This should be an ISO 8601 string, for instance: `2000-01-01T13:00:00`", "format": "date-time", "default": "2020-01-01T00:00:00+00:00", - "order": 2 + "order": 2, + "airbyte_hidden": true } } }, diff --git a/airbyte-integrations/connectors/source-stripe/Dockerfile b/airbyte-integrations/connectors/source-stripe/Dockerfile index 01fa8f2f7b81..6fd1cfeb7711 100644 --- a/airbyte-integrations/connectors/source-stripe/Dockerfile +++ b/airbyte-integrations/connectors/source-stripe/Dockerfile @@ -12,5 +12,5 @@ RUN pip install . ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.31 +LABEL io.airbyte.version=0.1.32 LABEL io.airbyte.name=airbyte/source-stripe diff --git a/airbyte-integrations/connectors/source-stripe/source_stripe/spec.yaml b/airbyte-integrations/connectors/source-stripe/source_stripe/spec.yaml index 67ec8e820b39..65bde0e770d2 100644 --- a/airbyte-integrations/connectors/source-stripe/source_stripe/spec.yaml +++ b/airbyte-integrations/connectors/source-stripe/source_stripe/spec.yaml @@ -26,22 +26,22 @@ connectionSpecification: order: 1 start_date: type: string - title: Start Date + title: Replication start date pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ description: >- - UTC date and time in the format 2017-01-25T00:00:00Z. Any data before - this date will not be replicated. + UTC date and time in the format 2017-01-25T00:00:00Z. Only data generated + after this date will be replicated. examples: - "2017-01-25T00:00:00Z" order: 2 lookback_window_days: type: integer - title: Lookback Window (in days) + title: Lookback Window in days (Optional) default: 0 minimum: 0 description: >- - When set, the connector will always reload data from the past N days, - where N is the value set here. This is useful if your data is updated + When set, the connector will always re-export data from the past N days, + where N is the value set here. This is useful if your data is frequently updated after creation. More info here order: 3 diff --git a/airbyte-integrations/connectors/source-tiktok-marketing/Dockerfile b/airbyte-integrations/connectors/source-tiktok-marketing/Dockerfile index d9fcada3aa5d..ece3093ee312 100644 --- a/airbyte-integrations/connectors/source-tiktok-marketing/Dockerfile +++ b/airbyte-integrations/connectors/source-tiktok-marketing/Dockerfile @@ -32,5 +32,5 @@ COPY source_tiktok_marketing ./source_tiktok_marketing ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.8 +LABEL io.airbyte.version=0.1.9 LABEL io.airbyte.name=airbyte/source-tiktok-marketing diff --git a/airbyte-integrations/connectors/source-tiktok-marketing/integration_tests/spec.json b/airbyte-integrations/connectors/source-tiktok-marketing/integration_tests/spec.json index e008d0a54887..5ad06d70ccbc 100644 --- a/airbyte-integrations/connectors/source-tiktok-marketing/integration_tests/spec.json +++ b/airbyte-integrations/connectors/source-tiktok-marketing/integration_tests/spec.json @@ -6,11 +6,13 @@ "type": "object", "properties": { "credentials": { - "title": "Authentication *", + "title": "Authentication Method", + "description": "Authentication method", "default": {}, "order": 0, "type": "object", - "oneOf": [{ + "oneOf": [ + { "title": "OAuth2.0", "type": "object", "properties": { @@ -22,25 +24,26 @@ }, "app_id": { "title": "App ID", - "description": "The App ID applied by the developer.", + "description": "The Developer Application App ID.", "airbyte_secret": true, "type": "string" }, "secret": { "title": "Secret", - "description": "The private key of the developer's application.", + "description": "The Developer Application Secret.", "airbyte_secret": true, "type": "string" }, "access_token": { "title": "Access Token", - "description": "The long-term authorized access token.", + "description": "Long-term Authorized Access Token.", "airbyte_secret": true, "type": "string" } }, "required": ["app_id", "secret", "access_token"] - }, { + }, + { "title": "Production Access Token", "type": "object", "properties": { @@ -52,12 +55,13 @@ }, "app_id": { "title": "App ID", - "description": "The App ID applied by the developer.", + "description": "The Developer Application App ID.", + "airbyte_secret": true, "type": "string" }, "secret": { "title": "Secret", - "description": "The private key of the developer application.", + "description": "The Developer Application Secret.", "airbyte_secret": true, "type": "string" }, @@ -69,7 +73,8 @@ } }, "required": ["app_id", "secret", "access_token"] - }, { + }, + { "title": "Sandbox Access Token", "type": "object", "properties": { @@ -96,16 +101,16 @@ ] }, "start_date": { - "title": "Start Date *", - "description": "The Start Date in format: YYYY-MM-DD. Any data before this date will not be replicated.If this parameter is not set, all data will be replicated.", + "title": "Replication Start Date *", + "description": "The Start Date in format: YYYY-MM-DD. Any data before this date will not be replicated. If this parameter is not set, all data will be replicated.", "default": "2016-09-01", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$", "order": 1, "type": "string" }, "report_granularity": { - "title": "Report Granularity *", - "description": "Grouping of your reports based on time. Lifetime will have no grouping. This option is used for reports' streams only.", + "title": "Report Aggregation Granularity *", + "description": "The granularity used for aggregating performance data in reports. See the docs.", "default": "DAY", "enum": ["LIFETIME", "DAY", "HOUR"], "order": 2, diff --git a/airbyte-integrations/connectors/source-tiktok-marketing/source_tiktok_marketing/spec.py b/airbyte-integrations/connectors/source-tiktok-marketing/source_tiktok_marketing/spec.py index 6ce93d4b24e2..184152ac0ddf 100644 --- a/airbyte-integrations/connectors/source-tiktok-marketing/source_tiktok_marketing/spec.py +++ b/airbyte-integrations/connectors/source-tiktok-marketing/source_tiktok_marketing/spec.py @@ -18,11 +18,18 @@ class Config: title = "OAuth2.0" auth_type: str = Field(default="oauth2.0", const=True, order=0) + app_id: str = Field(title="App ID", description="The Developer Application App ID.", airbyte_secret=True) + secret: str = Field(title="Secret", description="The Developer Application Secret.", airbyte_secret=True) + access_token: str = Field(title="Access Token", description="Long-term Authorized Access Token.", airbyte_secret=True) - app_id: str = Field(title="App ID", description="The App ID applied by the developer.", airbyte_secret=True) - secret: str = Field(title="Secret", description="The private key of the developer's application.", airbyte_secret=True) +class ProductionEnvSpec(BaseModel): + class Config: + title = "Production Access Token" + auth_type: str = Field(default="prod_access_token", const=True, order=0) + app_id: str = Field(title="App ID", description="The Developer Application App ID.", airbyte_secret=True) + secret: str = Field(title="Secret", description="The Developer Application Secret.", airbyte_secret=True) access_token: str = Field(title="Access Token", description="The long-term authorized access token.", airbyte_secret=True) @@ -31,7 +38,6 @@ class Config: title = "Sandbox Access Token" auth_type: str = Field(default="sandbox_access_token", const=True, order=0) - # it is string because UI has the bug https://github.com/airbytehq/airbyte/issues/6875 advertiser_id: str = Field( title="Advertiser ID", description="The Advertiser ID which generated for the developer's Sandbox application." @@ -40,39 +46,27 @@ class Config: access_token: str = Field(title="Access Token", description="The long-term authorized access token.", airbyte_secret=True) -class ProductionEnvSpec(BaseModel): - class Config: - title = "Production Access Token" - - auth_type: str = Field(default="prod_access_token", const=True, order=0) - - # it is float because UI has the bug https://github.com/airbytehq/airbyte/issues/6875 - app_id: str = Field(description="The App ID applied by the developer.", title="App ID") - secret: str = Field(title="Secret", description="The private key of the developer application.", airbyte_secret=True) - - access_token: str = Field(title="Access Token", description="The long-term authorized access token.", airbyte_secret=True) - - class SourceTiktokMarketingSpec(BaseModel): class Config: title = "TikTok Marketing Source Spec" credentials: Union[OauthCredSpec, ProductionEnvSpec, SandboxEnvSpec] = Field( - title="Authentication *", order=0, default={}, type="object" + title="Authentication Method", description="Authentication method", order=0, default={}, type="object" ) start_date: str = Field( - title="Start Date *", + title="Replication Start Date *", default=DEFAULT_START_DATE, pattern="^[0-9]{4}-[0-9]{2}-[0-9]{2}$", - description="The Start Date in format: YYYY-MM-DD. Any data before this date will not be replicated." + description="The Start Date in format: YYYY-MM-DD. Any data before this date will not be replicated. " "If this parameter is not set, all data will be replicated.", order=1, ) report_granularity: str = Field( - title="Report Granularity *", - description="Grouping of your reports based on time. Lifetime will have no grouping. This option is used for reports' streams only.", + title="Report Aggregation Granularity *", + description="The granularity used for aggregating performance data in reports. See the docs.', default=ReportGranularity.default().value, enum=[g.value for g in ReportGranularity], order=2, diff --git a/docs/.gitbook/assets/airtable_api_key1.png b/docs/.gitbook/assets/airtable_api_key1.png new file mode 100644 index 0000000000000000000000000000000000000000..38a5ab4edd2576de8804d83cd47244ad2748e6d7 GIT binary patch literal 97689 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⁣i^}lvhiF!X;AqA*A?x2C6kFiesC1 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

1ww&&gY%_UbC*gyB}n!{WH ztWE0>r--+KmBO!uLz;|+qjg#$pU?hC?IZC5b4~G_hdUnFI`!Ejw=3|H5vOVmvDrEQ zrG)%IovvKQM+54TBR4S5c{SzaiCRha?78qC$Rkqh<_>a99C-VE8~u%6b(f5mUQZ9b z?4oOZq-IR}?h~I4dgSqK@**yN#~WQIpI#Fyrn|3)qr$ryZy4x95I{g%??~^xOmCsR znEx({#c~5v^YK?lvz2qf8>rnj^0!h?-++4*i}pc_`&H%iqdj|ho+w1T*$$3=WNHAU z%oKbc7=E%NdwG`m&+4VA&)9Fdrtwg{)vy!)h}bX=f3|i_9b!~_yy%)i%d0QI9?tdj zvfc?x<}CG$-SoIkATB!kds*K-&Uw%|KZVR)p@4Aw&Q1)dJ-sXPo7@}3eFOxnw4xEZ zvKB)ADzhVAq7{5YDN+ym>D!QNye~)-{{janF*U-b#&5fvERj{BClAP|Dz++rmB7|o z9#g~C8vYd>ZPcv`k7Pyb9@YYkP=Oor!)NDvkp;6_tM~#tPGCg6md2QtY?VkIz9zgt zP8NO+cRKMih8IYQtaF$`y#qT8gxmh04kbNnp$mjbieP;)Pd0G0e<=;aZvSGcCkgM) z2H0QY5L(N@^4q=3IM+VvzH4tmzjlc~mver%RXEwZQ-c0o=N96n8(qbrXMI6z=UMIa zo{W&%wga6Y)&?<|?z|C&jLtj_Y#1LF6p7~%uxAJ4cX5yOr7r5n1uJjH+@9N4w39&i zkl3Sm?fW|YO-F{3c#nlXCbx9gkMUKka|L% zn$vEJpmzm~*G z*oX}qxjhcRf!^_R;0iCZ{qTSMDW@qXpmUQpp_o|KuXzyuRgDr~7M88HsWvRRg1A|( z1v$)l`?K*{G(&`2AN${1kaWX4@}T9Z0XBI4x>=AK%CH-=-F|)gvMTnt zQK1bXB^6MmsSyE<3Y6-XfC^Uk z(6^U0C7_Zm(uVh$?z}c9_UoOw+4IPkqJ$pF%BOVxz&}hFDX)hU;9U}pd|hgv9whupNoeY)$*!KpNNT@w$1Vt*m~&Ke zUf&A2j?Kq*kV#$Q(F9*6GXW$beLhkKb^u_6V3RI$0GY}9!cz^@jOM%c$ARVL=9SkR z020#jF#YW=Yk{(|UyNZup4-LQ29r489=mYb=5tP8^jQf5SGN7N!}oXL4h+Y-|L(K% zV*N5FP`}CQsJePgBVRMx<5xjcSKNR|Ox&kN)ve>);jOXrEvgvTBFRDF(OaX%`6;$s zDN5m5s>|_}=-bCe@m3mH+RHoVU*WPL+9+ENLYk)WRhQca7Ho~eI~lOU9E8+VE}^3P zF`79m4@;$G<0Rmaw1AZXXStUHR=q)(bbJ|_JkDH&XPGpkn?1_SYMrQU7HQlO?J@aj~L5g*o z?|6|-Z!^Z=3hc#))k|$hUtXRu#24$uoFBtvU1@adVUYWB*bzPfnQYgViwV${B<~|z zBT)sw;k*~EuY9mecKmr*y31cC1s(AZzlU%DHZO$#t;GePm>u<5U+^j>xLLrcoreK} zFoN3*dGyI&f+BZ(J4_vrNQ1-Nbm;@;hcanG;f`y7d5c696_{dv@o1`l=(; zG8AE{gM8X;l5O;5Lr`EFefJmvZQF3XV)OLQ`TW&!`Mzfn5zA8#@7#2~b{LR?MdJ=W z%+-q&W$8SYyYm2v7dHh8n*U?7bj5(>-sazyP^4yUT$bOG(IJ2#s-cfYDt{-96oBA@ zg?A|Q;b9|;vX2_;GPHCzP~;l0s|HZXH??|%5uV0YHv8{ZlFQ06z~GsH#G4P*cH@{A$_o>LD-BZ*lc)Yhpigg3TgnhT@qns5a8h&DD#>Iu(k(-r!zM9`;J`Rg8 z1XdSaFWg6y*(&7XRMX8TH zE?tc0H! z_%|4uLIf6#kZ3v1H_1zHd@g@G&;N7a(?(fGmcq||4wpKVTKJTNVT;)-N6QCBQG}y$ zo+D@8a{>%jd$U;Bo){W}KE>^=vkUv7cZ7D;&)ANdNrtQ&%FKM}KM3gh`!MDk84^!+ z5xB#^cV-`44hVlV?w#Rthj4w`5HTeLylSj@m&(VGBHYok;dMk_^L-J>*Lv)(SSw^H zYSt&3%lLe4a|vJ+GB8Od3JV6#X&-I1#V+N1+W!Cg4b8j+p_ZBdW9hLQh`Q=)O53k> z$3!M}qX8h2OJoe1*I$6PLAZa~<7^dy=G*|$8295evQ`lN&|vBLL&#>)i;({9tM(kI zc~`-c%K;)KapJ5P5B0olg2%iXCQM80(nM?^mxp ze1G)W-c3m^(rVw=j`)jY`4r|vJPo{RFO+x*&wbK*>4D>3j?xsEyhy4+=pGmZ-$XIp zqPE%yPj$0TZHcB854ZwK+LbbLV3~*~caHTCtmI!vLEMa3SnF?Xj{f;XmEF42+xeY` z2(~6A@{q2nK0<(jwsif&!}Q&pjk9dYO!>Z^>2{lC%!#fEG}yAqA+a8IQiCZFy-~Z> zRw^pJSkNw}Eh@c0?qnS@FmbKve^jTe&lQ>AYiUy%BN4s1RZGvAW!ef|EBVFs_moQU z+9BX(7RKwjcUQ|P2O{55}5COMz1t`_J%+D7XceQRJlUBbP&&X)-rzJt(Zpb z7EvpLhujhhyR#I4_Th=1rQm)C&SZU@I}r%sJEi(1y`Jl3uZ76FFg@f`qJ;Sf@!`#H zPc~aS-Cc`Y%NNk1;AMwHv65|)$6_9jYC3tF-o)UMpkZVxdW_&AAcw`?XiQw*MI>0i zaU88h9+j8Gy9Le{c|I%uR>nV9Lm&8@qoEZFs$>dnK8v6K-#rtpUoQGUn38Xiw_|Pt zDKs}|Un$Ye)X$Y1;r-KMtd@<$`(erj~KV8E`a>MZy``DIi>i_Pi`^N|xr$O1T z0t(gIt7db)I9G5(-;xun4NB0q17IEAz`FF@@ImDc z_|^86hF+Ga3sv)zn$;w7?HjO!pdAHLltf|qljrJK%kGcU=rHfEMP33%KU?E9&X`j@ zkA!)f1PUBO^eWSW&gMmMRdU>~wSPRK*gB`nyw%;3>;On9Iu9$2mj}V$UbN82tfi)_ z_nYF$_$F_9%89G28n7hta1F8$nm>h!u^JC~X1)|)+7ACaaN-sn`lE3bO0Aw;xycAS zD*79K8f5ABg|o6R6X2fe)ow# z5~d6GZq)S$ZPl!INU4_rpm;w)~L=NvFMf>(;vHco zs+a=@1#Z?|@`yq>6qWsm-G-Ks&A#f|Nd~?viYvc^?>Iek=0N1{`V|^=*WT*a6Lq#k zyFlg*+kBT|?@IPP!p1p_=)d~dsYi zL1o{zvl^_i8?? zQR}9}B&^SskxAfsOUSzJ&E zwDg_k31PsE=u--+8V0{|=|`S~`INkyA}~0naU5u|OGH##Fnj)aKsh|1(Ar3T- z2_&%DLK@v+ZyfkE+jUnDRTY}uE~RT1-fG{*yF_vcS$uVf#?&f2lM~%)xs%~zGJw-( zNxR)mL`!NMen&afuD7|YGDe8pHV%+6>B*C44>bnG&Wy!uwfXVvsgx^Bc@{! zc2JZf9QEmhrtiNL$x2gadP@BK$h|DjS0-#7^{|-+_a;}(;0#m^)>cTM=+SgT9T)>F zgb~h$6py#eE(abuI#9gzytJCoIkHmq63w3?rGN7M5V;L(axzFasS+~zk|XtmsCxRqw_9Y`}zDhvsB3?>4~cKI3D_5EdsEfUgHZq<9qPj z2Cn)*sjR1*(bIJ~%lEZ01#7$LwHeQMFy~Zx@MSIY;Uhz8XsVTlnwr}25s8H>mtgS8 z?TI^fr>@!zz8oC9ZF^7iUYkfwjM0Qg#52VU7jJ$Q5Its85516xdRg<}S8Vu8DPf)N z#V2|X_^8A*MwwF{In1Aw5#qY;e`9H$`u5r1>e$B85E8tX5QN?G=H}h~VEnB?b}-3t zMW+5B?~R=jl#z}7>B0n~`zDZNj@?j*YkWw{8F!SQNKj3p&)Emsavbl5@Ik0-@@bis z_%1E%xro+a6kI^pFWot7ucYXFt%m#jROj-qmfRbqW>BM$l6K46c6%#K#RNr~4*sWK z1>ToPpic%W2YG%vlL}3vOqDI(U)&31j;8^yb{?R_?V7#sn@qaK#;y}u>ecSh`#-cY zTcko{&fZzCwTf+IIpi5zQcwI8-D zpKiK5!t2%_Ty$DN@P-G8Z}suV_TROxiDr;PSV?&)`DVcAYcl{4as9|T;JMY#en9B}yK*MF(@NnZ_fo>WXCEzfLvv|A z=2;rrrqJuq^V z_upSFkuHOaGrY1?0K7Tc{Sr6J`j`{0~mf8byX6)$M z%$=4snZW?u_{wZ?kr0r8`E~e2zL^Q>_G}15is+;UhiA* zfYR$anfIIeC`!<*0VH6I5D#yB+z-!M1mkjG>l}xw>i~jMr7b@=Q%1{qiJW4Tv1gEY z8P&|wtlH{DZ&rB_;wOT1rP&S_&y@6jzE<>;ZKB7ILBkvzCUQz5*sJqef?m+m_GmIn znzXegsZ=wAauud{c{@y$94kaO)agsJByD#Wmg)lF9WLB zS=IhW^w~>x9I57WZ(ia(9o(N&%>;9w4$Q*Z&TjEDysh!#I7g#j3gfZT*snT3zG zqhUX(Q%3BqBgo;TxuCG0Rw!uIVmJ%0btw}QZ1Nj|KgecV`meOHX-f})nL-)@<$8)$ z7qr;txJUUBR(65qO`IpI2V!zyBo;F*Sr|JxoFp|x@2lnBlrx$Yxp%rGOZ%|khLsU} z=_THWtu4gu1Ks6+%T(`%IKL2FV^c|XKwOKCwsHT%qTZW=+{ke`dBJJ?>>22uJO&Nj z+CvE)RFMUSwb`f^cXQrIr6b7lI#Qs@Iu$`e377@^f`#YJvFE=cS8?XpCkNq!&<&)P zAmAy@0c?SPz;8>QqnyhCJt*Nk(5Wi#2vD@^z+^+IOIleIn?%P~K`h_vidy#3&n5p>@;7ULE zEh;T2aEN(yuMOJg*K1u3>oh(B@Tb9neQ_v@E5*G(ZUpvlixc zk$X!xE``N}?2t$za#ltPiJjNVgg!{R&#;^N-fB!*X1EH|^>GImsrMg1c6Rx_*m|&j6DNkvQW^^R(wmuPmV8IrDmbsz(*(Xx0vQR40eTC4EruVePr%y z4V05H)5J}`u&zkorS@41o@F=QPC74i7T>g?a;ogA9OrDwWY}_Yn)VrozgwwoI)wB} z@m(vOY@CmzM#$-A>&G+_-oYb^g=kLnr5F+dvB&OZjRp;H7r8^48XfjY^on0{WBRu@ zYL<3#*yyF%mk^ILK0TXF1@+E9scDB!QQYvH&wPJk0-lCOE-M`0w$}4tso>^91rM2> zYWlk2+L!c$edF9*p4MQN48|J4I)qQJqketae2Tt4B6q^ur#A2kPGvD-_TE~u*}szZ z(=MEQWi`$Siu;-S4{F6?*vs?38J{d~Gk(vv2yL?+x4yibnW7y@qU^NF@xIBUaVK?i z$u6_+(fwoPdBdaktOnU-X?fZle#*Awfiy8;7CG;|sU$6UYmX~#{O+H#9Io>Ym^gVR zsKT8^Tp=y9qJ(Ehl7_mjpm}Q`jT;4Tm4r50e0*t{q(U}Um;xhiyZYf1f#CT*vw!h! z_;b$!E31z&{IaW04Fh9TjydS%pb8Bz7)HH5F$Vd&f_@oL5`)fVgURySTFSruP$)4GiIpoJM$62|5?BHYj zjdygl{LzY`;cJk8K{e8H%i|spdB&5kUfH0_a{N1fRmD-#Q zes^!%XQn6tkmXK$io4bN9Rk-DGF4#|cY*N}wHT&;9f=NTn+w6cMrd4zm_IDTI z=yS@;rm$ozHq4+Oi?N~>?>u2vsKc=gMlnPd2*ILdE52y`70_r1O~+y>QD zsa*_Dx(>+hhLPJEQJ{o9z{Uz}b7>mCTTS&vij6-TQY{Rbcly9%{m(*y^F_AH`SHo4bja`$)se-TzSt! zvtMPi7v~K@9ldsM%0ZCRJnvP*eKss|PRLcOZ(zM}0K~Z9b7lz(PDkmz6`17~^oDyH zdl6m5!A#`oF5Jt@W`&X1E`s<&!mR9!(7=#J2Bd~Jg8MhwM~JJaISa#}rzyQ{zKb^#c$%=s zTA63Da%p|@EeTI{f3$g%)HK<+p*}@PT4O$KGGoW~j|DClG6TGx#u<)jx-x3>X%j`3 zTLZCfnV{Fydcy8`i5yFs?V1KaE5o}~Bu=CWbx!|c92 z7JGBSax2~@Z7DtLVxP3tm?{6hz%a_^ILbwto7$HCOIB%1b(Lu@0}H6+sUaG@MaP|- zRofL_0=h&myWO0noq+EwXf>R*6@YmRg_eTY^1bM?hPOw5pyn=Gwy;}<0!$Lhr z(vg-Up$k!#{%t=jw|@Fu#PQSoM#RJXMi>P`X-g`?IB3R%K78Z1rT_Q9w58`z=$gOv zh@GOaIA7jlb_&ZV^qBYL4v>gULVlNALi^CG$T&{Era!b>e?C;r~$~ zXzp@j%vG94)BXE(`lx8+!)CXrXWK)js4rzL4fVV8Z&8)~x?gnIj4f1;3c9JDSlXDD z3=OMapCy9q4BqQ4^!2YwJy68XSa9{%J2;1#Opux-Sg6DdR}V5<;1+SUK4o`N=d-Np zGYYc88rFxKHrkFTQnX=2oWn{r*1qJJ>CjLQUhV;0%4|R**Y9-ZzzJ4n{dP9Oz1{y@YqRZkYeT}ky1Tk1!=Bl zQgFnvyD0%7_U5YSfhrsg!vqZ{~j2jSK%$wiI(C zPYr}oDuacjU1ny3g#dfKolzSU3|BLT68-u`5D2nau*2_-zhNPivS5af_g56&=QIdH zx!tno^=Q^k8PS{gUQi1W@k_C^?o&NTC5!q}+VGh+OKqurM9Yn*!?T%^te=uecGr(& zfK=4PDTi)BOOH4R>sj;b@j6m^;B3%iAt@SjYXAcE@tD-)4c{(`Q!ANuZPtfPiwW^32JW#plhI!N2Gr^JMKc+NL)`l_@sfLf1IS%RO1xwJjzc~Ov`fxn{F0Z(S>0?X zbLs^-ddffH>jZV2vkkgl8uIQY;~F>Ge*24CR5rU8*JMOftVoQ_x?#CKw5lbiV|u!O ztpn%w$o2Yszbsw~wv`F)T26*g_FA$w*n1QFwBELY0nz(LzAJ&S>B0?LS-12C)?y8E z3xyw@Npj{!P6kfnc)lE%(px;gBi=zQLpubzTQ)Y2Su|!uXR8cokctX2KQ~qfT;-I? zx>Y}b@@c7GAHM!c%AflwDdNzX!p1+tc-=!8a=eoYHc2V?u)`{V%`^mQIF5hEFsXP* zMG5z=d>0Rmd$lp?wIAI=%&iP>_-rZFbyc~~5SmZU+m62D+2paATz7 z^wlc{dXItp+<$)k-xVuDfG6)>oF_~?) zI3dzKgoo8eA)FJbj&;+4oD&P92~@cuwNiVKLw#qp=Z;?Kuwq#gI4z3?oasP z`|b?uNrElvP6rV(NJ0ORgb64KfvsztPGXgNt^8rC6)`~v-V(zRayg{?qT9;2+*wETn}7hq>g}Edacy*4=?&niLkOvQY2OyfyBJcZ{qH^?R9Rg519Zx5 zkN(9W0BYgF8w{x~sfFm3K?!Z*7_l#~u40nr0Fyg%#4)vo7*Y$hfzDjrKDBrpT{gx3AblUNO^j>bb z&GB!Sg7k9rYsg4;Tf>n*(*5^h9XIBJZ1_GsR`5=0UJatYFAHRUgD2nd*k&{FZ00pQ zp0T72uO0V@pm2ZcAr(`WT0L;6aZOxT5M^u>2{Kp{OH1s*VVt@b4LkZ~ZYHaB2metC z)Q@aIVCNOdeJXefcm-u`CM(ti(Mh#&O}y^_f6?L_C`~^ksCtM@1tCpk%$Xg^aGHy{g-<>IL5X4ylDcBkcHo8myt&J-GH~bRA2eeQcTnf zxiPTXnVNIE>ALHwO*^HH>mH^IY|j>b=Q>b7>m9i{Nv+csw3bGu>kiHqoN-2ysbN&JlC+zT*Kt5P?u!;fYkUurUsL*35w6;ouBqT z{kYy6L*9sx_4(yQ1bM8>n7!+0HtVGS9{~VfV3z04r)u;+KLG!~g)q1P za>~Kho3{FwGDFsjg#VZ+ufu}C;DRuE_v%&+c$EfL)=atI{Os=_knt0ha6`99XCYc6 zjgW=XskAw?v^b8c^^@RXj4a^ff3JqFD z>E-!v(Ls81(yxFsc^KB=vMOfCvg}Kf&QQ(?g!QWh!y8f-!FABVn6) z<ttV_IO-f+b9M`SL8hc?CK0w>y$>uM5FX%~eeQ}c zfPZ@s__+U$Igk!&yL1m^BZ5ErLR_y(y!N4n0MJxn?e~XtwAX@jN*Uv*O#}n!h#E8v zg)VB0nP@@K-(c1P(e#-HT>e>(@-WevtYMu+c={+vC)xShm{MX_Thmn-+$HuK##1Ft!HD{-6v@ zgV!pzk<63(hio+d3Qk{$)$`6Jp9xtTO5&a>mI1~KRLfW&`b#^bJw()030kAU*&(VoCsFN zz^`2NC}=jj?hvO)AUQI8rbOw-ElSrll5ZwR3aqtEuSL>p`%EEwLrb7fdnR__#-MUu zRJ++qoJH^6H%V4G3{*m&8RsjU6nlL2C?J^(I+Yqx_smTbodFfZih18vVf#`2-`|DC zPVE_h9stHp_g_sQFswlDwUlJ%y^`Vj^QExEJ;S&v_v=#+0w$e%m}PbIZ-RXlu^K(- z%@1XolJtp=smHX{yXYy3m19^l1&?IMgY@rVqrBmrJNHPeE~Yi53ocfWiP7$;I8}dY z2Hv!ik1|PGJQlU-zhcNvw^^?RHLboG?b-~K;Fu-!Jr$M>ZMVfg=0z9)B#r8-7iy z@@Rfu?sd^ZHh8qvD?+Egqj{%g>+XT-cfBEZJvb}adfd!kP=?2j!W@h;yd7x!50rDR zUyr<|WS5Y%m8m(bPhh7Ggt}b4oab$JFi}vXgu2zOSQfplAS-pBf+UCF?E>8)BffWdpQd|;_$QHphmmx1+heX4|&?|LyN2+;VFdJ-^i_Vge{vOypx8u%1PErr_%{{mzG z&ah|I(Fy+@oqAL&Vp&%}yVUuLzkMy@t~{XL*1-1{wL1EGsq-j%AH{tl*Ckys4q`=# z`*n71MmwD$fC1j=6;zg9y|N^0BkJy&&x0Pj!=C?S`Di1rKsluZ%lqwk-FHw@@SB%f z=f`BE>`VQbJ6Np!or~t2bNg}E#2j*RuUpLW%Z+wR4^TU;D#6e!euv0y#9X?8?dCR` z4NX~U8h*bmO4Y*Hx@J^=LPEa`fVVHeFFeLg72Hbq81?Y+n9Z{1aD)&$f4UtEH0sXr zB*UDxeK|kuR8(=_HgDABxLFhZZs03b_F_e`^0&<&Dq+4?(KCVgW~B(fUbT)YY>7jr zph`yKwnDPyUr3unvl`uvTQNSNkAH-{$C$OrzK#$NX>QVwwH@^dk-3!axCuf)83h9y zZ(=wXUtweMJ3);_-JL>;d+&STyj`jLdo2XjwDfQMGGlBM-&*P{X)5k}B_wpG0yJWQ zPGWG*Y;T=)nR?~AxyTy!eoTCB<%8$@@5YAs7P2=UCx+P4ev0e%#nR8?s(8co1O1>* zA#iJTtUlVR=XW!R`lWIE5n{OQF%UsVNd!z>yQyTn6YTT^pIfZ(*5=U8W|EOkw_Zeh zaNEzSCY`}a9x%F5>3Y$T7u+^f)vz9h$k;Q9z$PpOMD$(5)J>ak<|E*}k|Aqf<6()d z6H$_3&wluh8~^sw=nAi}g7SWJPmEys!m8h^Wh9O(U{Q&{ip(qf(u7|f#V(eBOoa7# zZd|ZoWK|2fONQ4wS@y&5X8mXmsd6S5Ix~G_2sBE~i4~XO!+-7jui^<;W@_FE8w9do z)T$`#xok=LmNeBqwpr!4DvUGxHd5Y_^C-AFOw%!Cj(73Dz@Fe<2%%aNgFWPf4K0q& zhS8gH;-oduzDK5m?1)8;)#{=ileM8CXIuNYr>yiyRW-5`Q}WDiBM*b%#xu9@!dLpk zx(x{+WZ0~*5V2DhyE`jyJh|4m);RT|XW`eDV(kdFqU=GkS;DVzj+qDKu~A~^x_{P} z#$u0gPz7%_Ptl;@#VvMN=49k?WY!B|c zh>hM>d0q-?>IN7HmakW=fwoz6MNhfwYg$F96=!Ll?i}N#O6WtUpwWvn8dReKvo{1}oFx2Ohw8V4~!3DbcfFzjzJD-jOKA`41Qnm8Gp6a@U{-TLVE1 zAidmSR`jXD$D_h(69m~+SUI5)xqCsgL4@j@MVm*3T$v`zq3TXoNU)(~ zJS9_fcITd(jt_(ap10%yIZL^W*DXCQsnVZXth(zN0f5G&?&CDPJ3U4#Oojltr4p2m!nnu{P+HK~Rlf(Yc4|g69z>pcRiN zJ7-n=>IEIFW<~LZi;1<$tE7QpK}JThpLe)L?gO%7N!UWR@-dA*H`Wmq@r;mjtz=s; zh(F)+&zQQ3(PZFoGp-;kkp%>!%S`9W#`gpP-p@&h z?(6`a*M9HMJ1b;>i7~$)6j%2I!v)(9yy2lYg2d*tpYxrbgfjCxL0f20q3^?6y!2hj zO59dn$ZEhNM+R6GypC{wpAW|Lb2eFfqu21ZcD1BnJusVL^~E5j`^B6y@=r|@&^pH( zepP$=$+v5GFey;Au6{0u*~4;H`W=i;h%DTBMYT@_o^7-qGEIULK2#{D_G-bWG!#5) z(D!+>&zn9EjMxlr8-E!*h z-UpwXl(}>#VW8=OYc<9{E9N~gfn+mH$DzdBUQo#e@2SvT_`>&EQbrpDjdtu56H0BI z{D>7G!TJ6t7SC-|>GwUj8*gEKsHaC4l-xenc+__b-nRoz^U}{3LMBO|O?}w6pD`(B z>Mi2<7X*O#73P7F1)uDxcd4< zhb*xA`n`~&r6psX;A@tY*r$MP1XGnnWq%v&K9HYDe$E7^rt63gT<1+o#-(efdKp+< zwYPS=zdtcpGSMn6;Vjj3=}sphgECeY1`nFNz#9%CF<35H(>Zz1X_MfmXSNz+4t6__ z-!sfG<&+XSy$>ZY`es1WN~d(3_)3=J6N3i5)okA>kUZURxFFL=J7R1K%+FPPO7AVT z07AEOBqeOeg`Zl^X*h>;harqNZlvD6=GbsF6G`%ferc@j2k!^OlL-DI+JCY3lgG7_ z)eqj<%KT0+@~KD5c&P`$GJuI1n4LdpbYr(kN1ou}SbJ&2aJShzJ(ZT-`8Po_at8?V zljnKEn-*_n(d%xJc5s}FzTlzjG_Xa+?fcsXJH@Uq(^fOg_v-&-B>H{Ew=dH}rF}$4 z3H3?bMj62M%TDj1%+8_hzl z$B#ynWd!Wwqz2$?=9erVg9r3e=7^Ni>ogf-^+Q*d+%Hik9^c*W6646&tIS9QUhQZ0 zeo(AG$(x}%;eGHzwEs@^?r?HT)gwK#=*32qE5=fLW;B$wl?5G=hbi%fw>UkDRiK(8 zRIonh*TDRabkBZ>ogK$*^f8m?X<8EIk&^Ll16~t$R}MIXWc)taF;d+!7l@UU1>TFS z*adh6{bN#8gmfr;yQ-cZGF9D zBXPK>HvYY;g3<}+@~`O@&+hNI(ahi*Hsk^6di zB^?n9vZh@p!tzcGYl1#AcDCYgcixsWPX~?rz=MCctVWr)VJW3Y=lFiYvgXBrW&}7^ zlQ(sk2YF3%}-S$i3cGup{HCk0@lzLWM z9ryj~2R|_BOE;Gjjx)`kj5;?oBncWR2#OfE4&EBQmaS{N>{(i$e{9%!bmRVNmHfNp z+%~ZCgu9V=KknJ=D?ypQ7d4_?nKb@@JQ-!b3%p5$({dsWIb#VxnW@P*H1zimn7}0x zm=p38I*j^hc&|(*`u)AmP(icc7!>_srk{NRVA02t5%nWGu_A1pGi3JOpXlLkf_G&H z^;CB^9jHe))@ysD{+(;F4>|#i446)OocSNO7H)6M2?YPLj1%*&`zUdhZ~q^Zi~c8a z2Qa|@{P2IR5WKASlYD%j)m;M5%okyphn2z3ZKh&CHkd$f-p|#nLb;B%nS`~&emw>q zo#Und#ol`WMb&-#f(OJ;5hJKb5KwYfa%>b8XmXGoC5U865*siJ3Mg4}&Ovf+3+}-F_ z2J`*{>)}pu%-AyElU79Kz>{_rVph1k#y$1j0c0r-syPGqk7UP0mq87 z(wCXeu6!2`c$1)ebSC61k7r!`rx`jyESP8jxSY#D&8iV;2r(CD6)%lzC^vKJt^M7? z5ZjIYN^4$7t1$~0AUg!%XShK1s7q7hYT0Lvfc41xATzjJTZQv(l^($d5=Suu<2jGk z+c?Ah^)RHZYOFxvr%%V28~oM6C8l1zvjH3kQL%V8jASIP1__llo#rbZK5Oe}TpLGvQqT4kGjow3ei*xnO zbrCQ9nTF>S5$o^7c0Li*lp(gX3QPddpl8u&$hcY?c5E<_2CC7bWkn6A))q3t!L6IS zUuip5TrpDGxv>jKmygDyEYuJkzuB=gnw~1aY{#cp=teBkWqY z+=OsG8nIgD>G`ZaW?jbfAs%Mq(EyJtG^ln2>FA)T*SJy>+t~=ER~?lrqaq=og~pczqO1dbSkpbgtPkhwRw7D0loKHP(2XGSZMRjf@(!;z z;!rNu#?p1o)V*-d#Wqs6lDT;ln*NV#&DMbWGDe#AW(5K0liR+?2r?P~cX^GuDsBKu zyCG>ujCEAULC$lBMh3^r>@jQ;Tj@gYzih?KFx-0Y<>dhqg5QNhl{b<;c68BxIhHc0 z>&i>UvN6F{L*-MyoDDgcJB-hT1LXKy6_FZ3euzSafx59y1sf_pamk0~%AmtV4aBas zUy`u441eoj+jU0N=Fb&eFQ?n`?n!MiF3JdyL?}aLTS~c#~2^p@H4j^w%1BZRNDt0B!L+GD^)@2(7_DvfY?Ue?hRv zUP1%bo$JVJx_(3_TMgy4*)znw$B8j=TMpd!diA%_j-Y7W`p5~;qzn5?1Nu0xM2g(+ zp7j=%0Cgm*Wpp2*MXx=d#VE#tgYX0F1!IotWY>4zntvK2I-ReRGg{NO`jAF7q@9*A1496dzQ2RgGj9oni<@VRfb; zy3x=;vjiK%WS{Xb0N2BW;0Z=_ao=U%TRa@karB|GF$4`0#1MXpzcfC;5nM^tUOtVHEmSe&K1MZ<4?_=8|S?D>*h-EmyNR5&L z#!8E3ck7dJN5NhAQVrZ6lsr*^lL2c_nG5R+hi@LcTrqWK!Il5hPM1hvLyAWa@@q1O zAJAkd4yZj8xmk|}xF}^`-_2w@fIm1!p;|)c-n`l3BTfKyk7sNtsC-pVFgh9D=nfY}d|;{`6I7r@{z3LEy64^cXKGi6&d~;efJhU)ricGfuI{;G{ZJ zP)+nRDbhfwluw{es6-rFS~mh1Aa@l(T9L_T#w{h$kGwdka#i|%Ewj6M)c%sVkd#k- zCN_5dN5zs=TXPP+6x0PP?G8VO4F}n}TYP;2R_o=6PkMYvefuqy6!#tHf{S9jp`{`JN>6r9A*?;5pzI#=uSXA;uxmTB&x$)ulM9d$MeAxW>x3eZxx@ z1Jmj+Ty!|0rE`9qi4Wz+ZPX4mJu7pb1PW>DODcx%>XtPPS2=7r;ELkHr?tIAOiuLU zX@IX*S2R@q2;EW{4ylX>9fGUrqGZYvg4+VtiDp#ZN4`}%i8*0 z%psL41zGG+8%m)-W368MGK#Ei-b6s-EV|e04dtb*hCZZ^@m;owL=jd}d(b_v4*UYv&1X>P;0B_}8A_T%N<{$gk3_8t;Z--JJykYI$~nxTL@ z#dexnYIXrXR)AD$mFaS2Wrym-+C@o=8i7(}eB1i`-8JCwO_X8jvuKv#9k?vou{a2A}s-wjfXCa(|Y9N!_ z=yH38&VW?^qdEn-RDE|zYFi6|BN0jte0R4uBw9mbpg24|C!IFO8hYoe;6(=kZd|L- zW9rB-{%jPfcpEgEfj+J|0Zd-9bR|>HUf9Qh{9L5b_RBz7Dd|rG2)f7mTLtEADO=&& zb~exK=-x073hh2Hhf=#mD1+SCe5g-F_RWR}y`QQ8gZd`nTG{CbokGWM(iN(u-X9ZH z{UPS^Po~X!%PKlAyws)Hi%rw~pU^PLxwyLava&FLNsT)kr&a?}Cht-UqL%3A86?Rx z2V=W)*AU3hQG+GPO&Mbf)T|Do;qy1BBWBCoEU{dQ`tx*s?_1G1jm*;Tg)^}USmR^z z?KnkLr@jue3W_=Ad+NimjPmjlBzfnotM%1syIIoeKgB3!rl{#ps*zK7DJGmqXEBhtc4ff9qE_rhnNxNfEL)DgY2--QcX!u#peRr#`MjF*wAJkc2i?G~FdTe2(rLwPFEQSJ}e-suUnj|!FNhTHTQ)8W6Z z7d!8Dp*cKGc?YatjV(SK8OAYsr21$f`Pni8rU==3u~#N={`Y^Z+Ef9$>%{_i zFmVJ@BU3#a9pm)|#gpg4xA9!nDX78LUj2wPF*Wkku}2YPk$pBM_bJbJML@ZV+FnaY zZd)W2bu*vM;J)a}^??lg94AS%I^8#AGl@g8xr%Ua(q?<1CU zVkI^I5o~YPMlsLS5B-@lDmIN9u&7{n+mnCYHKVaLFWg3ZvJowiSI#6&jGtj_XYm?e z*Sql~7tVDXm%f!}@+I`<@EPk(Fxx!z?U50LF~(S8(N^Q4PE(dPLb#oHh4Nj`pWp>{ z=5}HxqoMgkIchY;!|{6Oh8NR++FX8mp(+blGlGTbs~z#jyVXfSB?kt{+5H(UIlI#+ z*}4@kn`7F>wTxer#q6T&RU-j!(dq1C7?Gi2+S@=ip=Jf>-S7A%i$RfW*_NoET*S^E zDVwzwz$Xb-p|vH?%`2!wQKEyyrP)}abGAMvvnVrCfGj|3WRGco&ov<}mv>h+2|f+M zkI`=oZC7ktErJ}`aMc`bsD(I^jpQ3xvf{>m99+`s9XBDXpNgO9e94yZJwgXn6krzB zPFVUJ`@PzK3sj;YFXokKj3@9%J6mq3dYB|D?#hJuBu;BmL$e#XeCO`QEUTO%jr_Ou zqIpbE$kNqlmU(`b`2Z&NzA=BN`}KaZ)xL=F6GQLbZ$#+wL63@{ld&OfqdIhZU!ghk zhA|k39k@K}vDN-jSUjD~(o^vWP_c>E#3OHZ*^gLt*lKU77{(FI=m(`J-+EzfXZF}; zN6A4nc`JFLZgzGQbjoKk#Yl1MGU0rwp$*^Dw+)was2;>teyUG(uw^19Zw2sWjj7kF zD=amE+K!cM4ah*t%$#)br8APE>ZUEcS;3b2rjbf^aWck2v8wNLd5pvAbr33g;92%4 z9S5{<$>gTUcVt_=kJ*4NvG*BdY&+Imel>=I`MxqsWt8?~DF^q??*N4h>K z%32jrSj~Jxi@A|cs(_688@k1`iR62P6b}SNc*a-jP8k$8uv)9{r87jrQ5t@7 z1K)8E!-y{!oDE2|{-lm{L<~hwYaUJ5IO)->Xx?nCwt91tUd$)%dA0YOe0lS#+$!On zyb`jZV1Dd@CIf`=Zj^g%$24R6yZy+BZOM{ijDjk3+out|-H5B)F!7KJ=S>n{9I}j` z$H|}p1OT1HfC?07T}4>~AA?&Mony5+oX3QOd=mR=4uH65w5qPybHCM3 zVXfqjY@4~VcIFH+3GxOyO~s{L+w*uC;1~O78U_J1w%~DtV{0&9RM&nRPmq=-(~OO# z6W3Y<`mf5doRhEA{oZJyQ4!sO+a@U#?sdchMo|<@+AQ-%-rMF@?9V9@C;KqqCjrzd zV{YyItVDWoq>X7fBKWCxt>d31b~QNNS$fwj=5Z@JLJF)eKCr$%Qwf@waboZ=54t-K zh_dWeL^Q!*y>U@R{r;2X_0VXc+H&C%WHLjoSDo0Zq;`x6Z{# zW)2wo+mztk_8yQyUCpp>mwU3&x(R3=w2YMWItGAOgG#$m6%>f2phvQH51)Lgl=|=v zx}V2{+D|)!%DpU$C}1?EOGK(bwT!aw-A>KsE>y6c&=Uqq&+j9XcEeuEPdyHm|61{O zHc%iv;KAQgpPH?+8#d#dPhion-2;_($ND;WlI(X2t&zhrgsG5oUiD*W=bT^FzZ;8r;0=G&)R)2TNhZB0@;&}3o7PihbDadFrg68_4^HjDMI~8qGu3F zTjd7J?d5%DPfb5tPQV;plHyPCd}4u@%#Qvv z4@QUW8R*L+?f{A8R(YyS(tV=~nx^_5s?VoC8Wn;3_A+fMj6`2+oaN zI{=IR1-~D=wc8zto@oBIj^{XB`ETlq!UMIDN%&R27-H#wmx~&YXk|RXV97lnw_TCw zhw6~th>yZA0$rAxg$R4d_v)a!n0b9WkX&uMp-$W38;)Gy6LaI%_hX@v+DGxs{V0A`zt(8R{Pyo2MU0)YMQ`>Bo@%3D3ZX#%vcm|_4YHWW zkkb!Rry?cO4V|6=p-Cw$g40XX8Fw>}iVSF}XdP;k6;{*c{FFe^;?NC@DIwK{OEGnQ zv$8s|FXK2M(GovzP%l{b1vZwTV}5={Z5s~THUc6FWK@JFj@%`}ZN6Kw*nNY1Y)DSh z!_SnS)p`A`J=>3z$CoTzZEZ~>3yqs}`v=|lxK(u9%Vz+=YVxzGWcF0?NW;_K-rN*U z$!gcxHp|BOOZd!g&-Nxsq==WC%M8Vh)nUR;`}&hgWb45DEx3}u^N(iVK0(<7o>e}l zILOXYM&uMfG)$;<-er}H%*}S}wAZe$FV2{#eDg}pF0rgblbd=0UAFIKvf{?aG=chIi$kxhgaW5yWSK}YuYIKH^xn*Tl*c#Q zcS1blIH3Nbb7ZCsiXW6UnJ7Vd;#8_9d>#CfunrM1;*4-T?Hg?~TNwv9=m8?*0wa)P zvSLY7v`s*W^_@0BekzR8KB#*9}wIg@@~*7EvHf=fpSbjBsv1 z)-%5jfwJ%gfX>~UVxF01`w@R`iLNM)rN`*W7*d^W@tVWifJ9&F$t3Q_FDRUZo(SE{ zFo|{b3==P>I8O7X>(#<#L+UFxlPL^J0RA?Yo!}h5Yjl6VZ$>>;)U#hdVb7;%4t1u4 zgV@$^xmIA8@zIR!wNM|KV*~cKtJ1-FLhmB9zF>hCYhlK$dyHH%2iaDP0Lw7bM2%XE z&Q4Zsy(Y%J%V*B4t4Yo0sci=Lk#Re`v3h|aPI8W()9@{hP>4lefTI<5`zqxIIv8{s zhlck40m2U6p=e6TqDH9JlkT|sRZm%fKo4D7l3Mray|2hl4L%l>q(W{Hsr-<`Mfgp^ z?ei8!bhRiTq%Mg&!pg2Oz;HYU8j2J8j>wABR?ik_^;pb`9f0jOL2An6&?NsVEK{L` zfGf$mp&Xd!eD);jj<0IMx3EhSB2M(v9i?%>UWj;C1K{ z%O584{~O-~so4WstrOUNCKy5CgHJbI1rU@YgLJoWw@fdP`ZC~4e0o8Zta}hbSJO1q zZx*IkHe<1#=5<+Nt;-}trnY`L-4pJ7Rkpiv~One+jS)kKwWmqdnH z2R&-592ocj(o(fD;fK3y_^A1uV#W4n=lYd_JwWR)8&#lWxRRoW+GH#a4FzV1zHbN2{wFaSS~prl#I^bw6n#S*N+5q zCfE4OIyd46e6I@|tW3lYzdjnGKI%)86_w(ZE*eiJuLGr2a3{phsyGDTuCTP_or2V4XMRUa1n7HE}d7AEpF1YO~3wi_P~e)OP-Wi zEVNZHm$@^jX&jeFWE6%lK;hSU46*ij4mKEsY#@Iu^`?+E^V@yEpW?k!&09v7OKIai3*5n*r4#$NTnDI`YdrR-k~^;w%dBFapPxrK*eg^ z6}F$cO!LFGDW+b-S&y3C)4Ppmpx!a_ggX=QOT`-i!q*ox;~={x7r9zw*w>u|tPgyG z34;hQ;ug8Uu*P-7q_^r!;LaCmzR7{;g+(LNDjPjHK>z782Aa1goH--2cB9dkcitCp ze#HiytavPVxH@2k@Em%0K+fj!t3Q`-ji@6m1^PDqNGx|i^5Qc7z*&nt91hhfDP2~GJXWycZFPO z?xRlC{o?~p$&VY$=6u6s=QY*I6NRMB4+w*bTd_grMKZWI*~<*INm|6&M`3cLojR)e zj|xgq=CXp1OQy_8tT6ods3B^o{&QDN^`n-0Nf}h)Kg-J+xTm30j~2*r2ihj! zBpd&IQ0|43i;S`%wKfGt%Ej$Gz3%X)9y|br<||F`C*3Q>*O%OSj?S>Lq$+6LWjTBL zGZgkEB=NlB*=v%L+Yp3OLf*c4_xupqi^xQ}yDzl5u1!NndNBU_xF1iV?p9d#HFAw!9K>sstSEKrTsPD_fc5H0(d6@VfS$7*UN6yOX?Cr zy}SlTRF6t1O3Ii1Mg#PA;b@YbOlMAS1HnV&K$7Q#cbVaMPDL8J5@sOn97ihboQHs$ zPK+Ttpk@{@=ZSlO;Z8!&XgxpespT;h%&GopWkhs)SfFAx46sdhrMG$!lR-x~6q!+* zGk{`_tGeI)(+#;%1Ng(?$aAfX?j0WQc^)kfUEij=U~yMME8P^6wsQNRzezMSVw;7_ z&U5JAOEvS3LeKmh;R+M&SW(ZTL2ytj_ZetUyMvW>asdKl;{6oeDdGKnV4FxvP>%-d zMYUCK>J{r;)s=m;NRf$`M!eUB=?c^QdKUgzc;WOqDNkdQ&Pnntz)zT>&dSd$dn#%MtvLF;imWrEimvF)DgB>C!BsRxR8C*)72e46RgyFN(T1q6E+LO*LoGV}JTK^=;?wYaN6jGNOU z&cnKf+U`ZK1=Qt{M9$9nA4s2Jec~nvS%}#^ojTSeN;wW;uWM~7Kt9kN=^D{)33vH zmb(5JUtJ6R$!;Lucubef-0xL+ct^a68=3P%%{TM*vk2B?gI8&|*BWQIfV%GWIpVeA zjOLuctyn;!Z{ljnZz!*FS-R;XsoAkn$L}tW)w(;^Y;Ycp+Ht-`*}XYzAftIz;8gFr zJ~fv>!g*zHUagb?5Z{5@4~TeL9qW_OXl!QAg?(U(_fOO^RUWE2)F5LQ> zYj9SzF8P*nvsE5-tLq52ww6ijx&+_z0X5zA#%?rYbrAr$)oA*DZ*W)0xX)+57N~n5 z7PiGs+r;YJ)Uz!yp4p9FoM&9wAQ`*AD<(6MiCOgO+c&#l28*X9=s-M#J}MP?klmm> z)|3bL8=K}zf_+|8;+?u_*8bWNLk_(~�S8hLuw~4jm?B7RP~JsBdgrSC(5ds{%@; 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 literal 0 HcmV?d00001 diff --git a/docs/.gitbook/assets/airtable_api_key2.png b/docs/.gitbook/assets/airtable_api_key2.png new file mode 100644 index 0000000000000000000000000000000000000000..e5272b49e00e3797ea5ccf66d7af9feb0ba419ce GIT binary patch literal 22154 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 literal 0 HcmV?d00001 diff --git a/docs/.gitbook/assets/airtable_bases_ui_list1.png b/docs/.gitbook/assets/airtable_bases_ui_list1.png new file mode 100644 index 0000000000000000000000000000000000000000..ba83215f2d46398ba330f4ff79749d18173634dd GIT binary patch literal 14773 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 V(5YG51ZRiKNqv;85dR$bKLE%tsObOz literal 0 HcmV?d00001 diff --git a/docs/integrations/sources/airtable.md b/docs/integrations/sources/airtable.md index c7673cc40a6d..b2872c95d5ec 100644 --- a/docs/integrations/sources/airtable.md +++ b/docs/integrations/sources/airtable.md @@ -15,23 +15,25 @@ This source allows you to configure any table in your Airtable base. In case you ## Getting started -**Requirements** +### Requirements -* api_key -* base_id -* tables +* An Airtable account & API key +* Base ID +* Tables you'd like to replicate -**Setup guide** - -Information about how to get credentials you may find [here](https://support.airtable.com/hc/en-us/articles/219046777-How-do-I-get-my-API-key-). +### Setup guide +1. To find your API key, navigate to your [account page](https://airtable.com/account). On your account overview page, under the API heading, there's a button that says "Generate API key." +![img.png](../../.gitbook/assets/airtable_api_key1.png) +2. Generate an API key by clicking the button. If one already exists, click the key to reveal it and copy it. ![img.png](../../.gitbook/assets/airtable_api_key2.png). See [here](https://support.airtable.com/hc/en-us/articles/219046777-How-do-I-get-my-API-key-) for more information on managing your API keys. +3. Find the Airtable base containing the tables you'd like to replicate by visiting https://airtable.com/api and logging in. Once you're logged in, you'll see a list of available bases: ![bases](../../.gitbook/assets/airtable_bases_ui_list1.png). Click the base whose tables you want to replicate. You'll find the base ID on the next page: ![](../../.gitbook/assets/airtable_base_id.png). Copy this ID for use when configuring the connector. ### Performance Considerations (Airbyte Open-Source) -Information about rate limits you may find [here](https://support.airtable.com/hc/en-us/articles/203313985-Public-REST-API). - +See information about rate limits [here](https://support.airtable.com/hc/en-us/articles/203313985-Public-REST-API). ## Changelog | Version | Date | Pull Request | Subject | -| :------ | :-------- | :----- | :------ | -| `0.1.1` | 2021-12-06 | [8425](https://github.com/airbytehq/airbyte/pull/8425) | Update title, description fields in spec | +|:--------| :-------- | :----- | :------ | +| 0.1.2 | 2022-04-30 | [12500](https://github.com/airbytehq/airbyte/pull/12500) | Improve input configuration copy | +| 0.1.1 | 2021-12-06 | [8425](https://github.com/airbytehq/airbyte/pull/8425) | Update title, description fields in spec | diff --git a/docs/integrations/sources/amplitude.md b/docs/integrations/sources/amplitude.md index 9b82e37914ad..e152838e752a 100644 --- a/docs/integrations/sources/amplitude.md +++ b/docs/integrations/sources/amplitude.md @@ -58,7 +58,8 @@ The Amplitude connector should gracefully handle Amplitude API limitations under ## Changelog | Version | Date | Pull Request | Subject | -| :------ | :--------- | :----------------------------------------------------- | :------ | +|:--------| :--------- | :----------------------------------------------------- | :------ | +| 0.1.6 | 2022-04-30 | [12500](https://github.com/airbytehq/airbyte/pull/12500) | Improve input configuration copy | | 0.1.5 | 2022-04-28 | [12430](https://github.com/airbytehq/airbyte/pull/12430) | Added HTTP error descriptions and fixed `Events` stream fail caused by `404` HTTP Error | | 0.1.4 | 2021-12-23 | [8434](https://github.com/airbytehq/airbyte/pull/8434) | Update fields in source-connectors specifications | | 0.1.3 | 2021-10-12 | [6375](https://github.com/airbytehq/airbyte/pull/6375) | Log Transient 404 Error in Events stream | diff --git a/docs/integrations/sources/bing-ads.md b/docs/integrations/sources/bing-ads.md index 322082877f2c..74461c5882b4 100644 --- a/docs/integrations/sources/bing-ads.md +++ b/docs/integrations/sources/bing-ads.md @@ -2,18 +2,18 @@ ## Overview -This source can sync data from the [Bing Ads](https://docs.microsoft.com/en-us/advertising/guides/?view=bingads-13). Connector is based on a [Bing Ads Python SDK](https://github.com/BingAds/BingAds-Python-SDK). +The Bing Ads connector syncs data from the [Bing Ads API](https://docs.microsoft.com/en-us/advertising/guides/?view=bingads-13). -### Output schema +## Output schema -This Source is capable of syncing the following core Streams: +This Source is capable of syncing the following resources: * [Accounts](https://docs.microsoft.com/en-us/advertising/customer-management-service/searchaccounts?view=bingads-13) * [Campaigns](https://docs.microsoft.com/en-us/advertising/campaign-management-service/getcampaignsbyaccountid?view=bingads-13) * [AdGroups](https://docs.microsoft.com/en-us/advertising/campaign-management-service/getadgroupsbycampaignid?view=bingads-13) * [Ads](https://docs.microsoft.com/en-us/advertising/campaign-management-service/getadsbyadgroupid?view=bingads-13) -Supported report streams: +It can also sync the following reports: * [AccountPerformanceReport](https://docs.microsoft.com/en-us/advertising/reporting-service/accountperformancereportrequest?view=bingads-13) * [AdPerformanceReport](https://docs.microsoft.com/en-us/advertising/reporting-service/adperformancereportrequest?view=bingads-13) @@ -22,67 +22,55 @@ Supported report streams: * [BudgetSummaryReport](https://docs.microsoft.com/en-us/advertising/reporting-service/budgetsummaryreportrequest?view=bingads-13) * [KeywordPerformanceReport](https://docs.microsoft.com/en-us/advertising/reporting-service/keywordperformancereportrequest?view=bingads-13) -### Data type mapping +### Report Aggregation +All reports synced by this connector can be aggregated using hourly, daily, weekly, or monthly windows. Performance data is aggregated using the selected window. For example, if you select the daily-aggregation flavor of a report, the report will contain a row for each day for the duration of the report. Each row will indicate the number of impressions recorded on that day. -| Integration Type | Airbyte Type | Notes | -| :--- | :--- | :--- | -| `string` | `string` | | -| `number` | `number` | | -| `array` | `array` | | -| `object` | `object` | | +A report's aggregation window is indicated in its name e.g: `account_performance_report_hourly` is the Account Performance Reported aggregated using an hourly window. ### Features | Feature | Supported?\(Yes/No\) | Notes | -| :--- | :--- | :--- | -| Full Refresh Sync | Yes | | -| Incremental Sync | No | | -| Namespaces | No | | +| :--- |:---------------------| :--- | +| Full Refresh Sync | Yes | | +| Incremental Sync | Yes | | +| Namespaces | No | | ### Performance considerations API limits number of requests for all Microsoft Advertising clients. You can find detailied info [here](https://docs.microsoft.com/en-us/advertising/guides/services-protocol?view=bingads-13#throttling) -## Getting started +## Getting started (Airbyte Open Source) +### Requirements +* A Microsoft User account with access to at least one Microsoft Advertising account +* A Microsoft Ads Customer ID +* Your Microsoft User ID +* A developer application with access to: + * client ID + * client secret + * A developer token + * Optionally, a tenant ID +* A refresh token generated using the above developer application credentials +* (Optional) Ad Account IDs you want to access, if you want to limit replication to specific ad accounts + +### Setup Guide +* Create a developer application using the instructions for [registering an application](https://docs.microsoft.com/en-us/advertising/guides/authentication-oauth-register?view=bingads-13) in Azure portal +* Perform [these steps](https://docs.microsoft.com/en-us/advertising/guides/authentication-oauth-consent?view=bingads-13l) to get auth code, and use that to [get a refresh token](https://docs.microsoft.com/en-us/advertising/guides/authentication-oauth-get-tokens?view=bingads-13). For reference, the full authentication process described [here](https://docs.microsoft.com/en-us/advertising/guides/get-started?view=bingads-13#access-token). Be aware that the refresh token will expire in 90 days. You need to repeat the auth process to get a new refresh token. +* Find your Microsoft developer token by following [these instructions](https://docs.microsoft.com/en-us/advertising/guides/get-started?view=bingads-13#get-developer-token) +* Find your customer ID and User ID by visiting the following URL: https://ui.ads.microsoft.com/campaign/Campaigns.m then copying the CID & UID parameters from the URL in the address bar. For example, once you visit the URL above, you'll notice it will have changed to an address of the form https://ui.ads.microsoft.com/campaign/vnext/overview?uid=USER_ID&cid=CUSTOMER_ID&aid=180534868 -- the customer ID is the value in the part of the URL that looks like `cid=THIS_IS_THE_CUSTOMER_ID&`, and the user ID is the value in front of `uid` e.g: `uid=THIS_IS_THE_USER_ID&`. +* Optionally, if you want to replicate data from specific ad account IDs (you can configure the Bing Ads connector to replicate data from all accounts you have access to, or only from some), then also grab the account IDs you want by visiting the [Accounts Summary](https://ui.ads.microsoft.com/campaign/vnext/accounts/performance) page, clicking on each of the accounts you want under the `Account name` column, then repeating the process described earlier to get the `aid` parameter in the URL that looks like `aid=ACCOUNT_ID&`. You'll need to do this process once for each account from which you want to replicate data. +* Optionally, if your oauth app lives under a custom tenant which cannot use Microsoft's recommended `common` tenant, make sure to get the tenant ID ready for input when configuring the connector. The tenant will be used in the auth URL e.g: `https://login.microsoftonline.com//oauth2/v2.0/authorize`. -### Requirements -* accounts: Has 2 options - * fetch data from all accounts to which you have access - * you need to provide specific account ids for which you a going to pull data. Use this [guide](https://docs.microsoft.com/en-us/advertising/guides/get-started?view=bingads-13#get-ids) to find your account id -* user\_id: Sign in to the Microsoft Advertising web application. The URL will contain a uid key/value pair in the query string that identifies your User ID -* customer\_id: Use this [guide](https://docs.microsoft.com/en-us/advertising/guides/get-started?view=bingads-13#get-ids) to get this id -* developer\_token: You can find this token [here](https://docs.microsoft.com/en-us/advertising/guides/get-started?view=bingads-13#get-developer-token) -* refresh\_token: Token received during [auth process](https://docs.microsoft.com/en-us/advertising/guides/authentication-oauth?view=bingads-13) -* client\_secret: Secret generated during application registration -* client\_id: Id generated during application registration -* tenant_id: Tenant generated during application registration -* redirect\_uri: You can create Redirect URI from azure application configuration. e.g: https://login.microsoftonline.com/{tenant_id}/oauth2/nativeclient -* reports\_start\_date: From which date report generation should start -* report\_aggregation: Defines how report data will be aggregated -* hourly\_reports: includes hourly report streams if true -* daily\_reports: includes daily report streams if true -* weekly\_reports: includes weekly report streams if true -* monthly\_reports: includes monthly report streams if true - -### Setup guide - -* [Register Application](https://docs.microsoft.com/en-us/advertising/guides/authentication-oauth-register?view=bingads-13) in Azure portal -* Perform these [steps](https://docs.microsoft.com/en-us/advertising/guides/authentication-oauth-consent?view=bingads-13l) to get auth code. -* [Get refresh token](https://docs.microsoft.com/en-us/advertising/guides/authentication-oauth-get-tokens?view=bingads-13) using auth code from previous step - -Full authentication process described [here](https://docs.microsoft.com/en-us/advertising/guides/get-started?view=bingads-13#access-token) - -Be aware that `refresh token` will expire in 90 days. You need to repeat auth process to get the new one `refresh token` ## Changelog -| Version | Date | Pull Request | Subject | -| :--- | :--- | :--- | :--- | -| 0.1.5 | 2022-01-01 | [11652](https://github.com/airbytehq/airbyte/pull/11652) | Rebump attempt after DockerHub failure at registring the 0.1.4 | -| 0.1.4 | 2022-03-22 | [9510](https://github.com/airbytehq/airbyte/pull/9510) | Added optional Redirect URI & Tenant ID to spec | -| 0.1.3 | 2022-01-14 | [9510](https://github.com/airbytehq/airbyte/pull/9510) | Fixed broken dependency that blocked connector's operations | -| 0.1.2 | 2021-12-14 | [8429](https://github.com/airbytehq/airbyte/pull/8429) | Update titles and descriptions | -| 0.1.1 | 2021-08-31 | [5750](https://github.com/airbytehq/airbyte/pull/5750) | Added reporting streams\) | -| 0.1.0 | 2021-07-22 | [4911](https://github.com/airbytehq/airbyte/pull/4911) | Initial release supported core streams \(Accounts, Campaigns, Ads, AdGroups\) | +| Version | Date | Pull Request | Subject | +|:--------| :--- |:---------------------------------------------------------| :--- | +| 0.1.6 | 2022-04-30 | [12500](https://github.com/airbytehq/airbyte/pull/12500) | Improve input configuration copy | +| 0.1.5 | 2022-01-01 | [11652](https://github.com/airbytehq/airbyte/pull/11652) | Rebump attempt after DockerHub failure at registring the 0.1.4 | +| 0.1.4 | 2022-03-22 | [11311](https://github.com/airbytehq/airbyte/pull/11311) | Added optional Redirect URI & Tenant ID to spec | +| 0.1.3 | 2022-01-14 | [9510](https://github.com/airbytehq/airbyte/pull/9510) | Fixed broken dependency that blocked connector's operations | +| 0.1.2 | 2021-12-14 | [8429](https://github.com/airbytehq/airbyte/pull/8429) | Update titles and descriptions | +| 0.1.1 | 2021-08-31 | [5750](https://github.com/airbytehq/airbyte/pull/5750) | Added reporting streams\) | +| 0.1.0 | 2021-07-22 | [4911](https://github.com/airbytehq/airbyte/pull/4911) | Initial release supported core streams \(Accounts, Campaigns, Ads, AdGroups\) | diff --git a/docs/integrations/sources/google-analytics-v4.md b/docs/integrations/sources/google-analytics-v4.md index e62dd233d110..d55a94f72e8d 100644 --- a/docs/integrations/sources/google-analytics-v4.md +++ b/docs/integrations/sources/google-analytics-v4.md @@ -90,20 +90,25 @@ Please reach out to us on Slack or [create an issue](https://github.com/airbyteh ## Sampling in reports -Google Analytics API may, under certain circumstances, limit the returned data based on sampling. This is done to reduce the amount of data that is returned as described in [Sampling](https://developers.google.com/analytics/devguides/reporting/core/v4/basics#sampling) section of the Reporting API docs. -The `window_in_day` parameter is used to specify the number of days to look back and can be used to avoid sampling. +For users who are not on the Google Analytics 360 tier, the Google Analytics API may return sampled data if the amount of data in the user's Google Analytics account exceeds Google's [pre-determined compute thresholds](https://support.google.com/analytics/answer/2637192?hl=en&ref_topic=2601030&visit_id=637868645346124317-2833523666&rd=1#thresholds&zippy=%2Cin-this-article). Concretely, this means the data returned in the report is an estimate which may have some inaccuracy. This [Google page](https://support.google.com/analytics/answer/2637192) provides a comprehensive overview of how Google applies sampling to your data. + +In order to minimize the chances of sampling being applied to your data, Airbyte makes data requests to Google in one day increments (the smallest allowed date increment). This reduces the amount of data the Google API processes per request, thus minimizing the chances of sampling being applied. The downside of requesting data in one day increments is that it increases the time it takes to export your Google Analytics data. If sampling is not a concern, users can override this behavior by setting the optional `window_in_day` parameter is used to specify the number of days to look back and can be used to avoid sampling. When sampling occurs, a warning is logged to the sync log. -## IsDataGolden +## Data processing latency + +According to the [Google Analytics API documentation in the "Data Processing Latency" section](https://support.google.com/analytics/answer/1070983?hl=en#DataProcessingLatency&zippy=%2Cin-this-article), all report data may continue to be updated 48 hours after it appears in the Google Analytics API. This means that if you request the same report twice within 48 hours of that data being sent to Google Analytics, the report data might be different across the two requests. This happens when Google Analytics is still processing all events it received. + +When this occurs, the returned data will set the flag `isDataGolden` to false. Like mentioned in the [Google Analytics API docs](https://developers.google.com/analytics/devguides/reporting/core/v4/rest/v4/reports/batchGet#reportdata): +> the `isDataGolden` flag indicates if [data] is golden or not. Data is golden when the exact same request [for a report] will not produce any new results if asked at a later point in time. + +To address this issue, the connector adds a lookback window of 2 days to ensure any previously synced non-golden data is re-synced with its potential updates. For example: If your last sync occurred 5 days ago and a sync kicks off today, it will attempt to sync data from 7 days ago up to the latest data available. -Google Analytics API may return provisional or incomplete data. When this occurs, the returned data will set the flag `isDataGolden` to false, and the connector will log a warning to the sync log. -The connector adds a lookback window of 2 days to ensure any previously synced non-golden data is re-synced with its potential updates. This is done because [Google Analytics takes up to 48 hours](https://support.google.com/analytics/answer/1070983?hl=en#DataProcessingLatency&zippy=%2Cin-this-article) to update the data. For example: -- If your last sync occurred 5 days ago and a sync kicks off today, it will attempt to sync data from 7 days ago up to the latest data available. To determine whether data is finished processing or not, the `isDataGolden` flag is exposed and should be used. -## Reading Custom Reports +## Requesting Custom Reports -You can replicate Google Analytics [Custom Reports](https://support.google.com/analytics/answer/1033013?hl=en) using this source. To do this, input a JSON object as a string in the "Custom Reports" field when setting up the connector. The JSON is an array of objects where each object has the following schema: +You can replicate Google Analytics [Custom Reports](https://support.google.com/analytics/answer/1033013?hl=en) using this connector. To do this, input a JSON object as a string in the "Custom Reports" field when setting up the connector. The JSON is an array of objects where each object has the following schema: ```text {"name": string, "dimensions": [string], "metrics": [string]} @@ -162,6 +167,7 @@ Incremental sync is supported only if you add `ga:date` dimension to your custom | Version | Date | Pull Request | Subject | |:--------|:-----------|:---------------------------------------------------------|:---------------------------------------------------------------------------------------------| +| 0.1.21 | 2022-04-30 | [12500](https://github.com/airbytehq/airbyte/pull/12500) | Improve input configuration copy | | 0.1.20 | 2022-04-28 | [12426](https://github.com/airbytehq/airbyte/pull/12426) | Expose `isDataGOlden` field and always resync data two days back to make sure it is golden | | 0.1.19 | 2022-04-19 | [12150](https://github.com/airbytehq/airbyte/pull/12150) | Minor changes to documentation | | 0.1.18 | 2022-04-07 | [11803](https://github.com/airbytehq/airbyte/pull/11803) | Improved documentation | diff --git a/docs/integrations/sources/s3.md b/docs/integrations/sources/s3.md index d82142914762..1029a08de41a 100644 --- a/docs/integrations/sources/s3.md +++ b/docs/integrations/sources/s3.md @@ -205,15 +205,16 @@ You can find details on [here](https://arrow.apache.org/docs/python/generated/py ## Changelog | Version | Date | Pull Request | Subject | -| :--- | :--- | :--- | :--- | -| 0.1.10 | 2022-01-28 | [8252](https://github.com/airbytehq/airbyte/pull/8252) | Refactoring of files' metadata | -| 0.1.9 | 2022-01-06 | [9163](https://github.com/airbytehq/airbyte/pull/9163) | Work-around for web-UI, `backslash - t` converts to `tab` for `format.delimiter` field. | -| 0.1.7 | 2021-11-08 | [7499](https://github.com/airbytehq/airbyte/pull/7499) | Remove base-python dependencies | -| 0.1.6 | 2021-10-15 | [6615](https://github.com/airbytehq/airbyte/pull/6615) & [7058](https://github.com/airbytehq/airbyte/pull/7058) | Memory and performance optimisation. Advanced options for CSV parsing. | -| 0.1.5 | 2021-09-24 | [6398](https://github.com/airbytehq/airbyte/pull/6398) | Support custom non Amazon S3 services | -| 0.1.4 | 2021-08-13 | [5305](https://github.com/airbytehq/airbyte/pull/5305) | Support of Parquet format | -| 0.1.3 | 2021-08-04 | [5197](https://github.com/airbytehq/airbyte/pull/5197) | Fixed bug where sync could hang indefinitely on schema inference | -| 0.1.2 | 2021-08-02 | [5135](https://github.com/airbytehq/airbyte/pull/5135) | Fixed bug in spec so it displays in UI correctly | -| 0.1.1 | 2021-07-30 | [4990](https://github.com/airbytehq/airbyte/pull/4990/commits/ff5f70662c5f84eabc03526cddfcc9d73c58c0f4) | Fixed documentation url in source definition | -| 0.1.0 | 2021-07-30 | [4990](https://github.com/airbytehq/airbyte/pull/4990) | Created S3 source connector | +|:--------| :--- | :--- | :--- | +| 0.1.11 | 2022-04-30 | [12500](https://github.com/airbytehq/airbyte/pull/12500) | Improve input configuration copy | +| 0.1.10 | 2022-01-28 | [8252](https://github.com/airbytehq/airbyte/pull/8252) | Refactoring of files' metadata | +| 0.1.9 | 2022-01-06 | [9163](https://github.com/airbytehq/airbyte/pull/9163) | Work-around for web-UI, `backslash - t` converts to `tab` for `format.delimiter` field. | +| 0.1.7 | 2021-11-08 | [7499](https://github.com/airbytehq/airbyte/pull/7499) | Remove base-python dependencies | +| 0.1.6 | 2021-10-15 | [6615](https://github.com/airbytehq/airbyte/pull/6615) & [7058](https://github.com/airbytehq/airbyte/pull/7058) | Memory and performance optimisation. Advanced options for CSV parsing. | +| 0.1.5 | 2021-09-24 | [6398](https://github.com/airbytehq/airbyte/pull/6398) | Support custom non Amazon S3 services | +| 0.1.4 | 2021-08-13 | [5305](https://github.com/airbytehq/airbyte/pull/5305) | Support of Parquet format | +| 0.1.3 | 2021-08-04 | [5197](https://github.com/airbytehq/airbyte/pull/5197) | Fixed bug where sync could hang indefinitely on schema inference | +| 0.1.2 | 2021-08-02 | [5135](https://github.com/airbytehq/airbyte/pull/5135) | Fixed bug in spec so it displays in UI correctly | +| 0.1.1 | 2021-07-30 | [4990](https://github.com/airbytehq/airbyte/pull/4990/commits/ff5f70662c5f84eabc03526cddfcc9d73c58c0f4) | Fixed documentation url in source definition | +| 0.1.0 | 2021-07-30 | [4990](https://github.com/airbytehq/airbyte/pull/4990) | Created S3 source connector | diff --git a/docs/integrations/sources/shopify.md b/docs/integrations/sources/shopify.md index 0c408471531d..5e9a78a8625e 100644 --- a/docs/integrations/sources/shopify.md +++ b/docs/integrations/sources/shopify.md @@ -138,39 +138,40 @@ This is expected when the connector hits the 429 - Rate Limit Exceeded HTTP Erro ## Changelog | Version | Date | Pull Request | Subject | -| :--- | :--- | :--- | :--- | -| 0.1.36 | 2022-03-22 | [9850](https://github.com/airbytehq/airbyte/pull/9850) | Added `BalanceTransactions` stream | -| 0.1.35 | 2022-03-07 | [10915](https://github.com/airbytehq/airbyte/pull/10915) | Fix a bug which caused `full-refresh` syncs of child REST entities configured for `incremental` | -| 0.1.34 | 2022-03-02 | [10794](https://github.com/airbytehq/airbyte/pull/10794) | Minor specification re-order, fixed links in documentation | -| 0.1.33 | 2022-02-17 | [10419](https://github.com/airbytehq/airbyte/pull/10419) | Fixed wrong field type for tax_exemptions for `Abandoned_checkouts` stream | -| 0.1.32 | 2022-02-18 | [10449](https://github.com/airbytehq/airbyte/pull/10449) | Added `tender_transactions` stream | -| 0.1.31 | 2022-02-08 | [10175](https://github.com/airbytehq/airbyte/pull/10175) | Fixed compatibility issues for legacy user config | -| 0.1.30 | 2022-01-24 | [9648](https://github.com/airbytehq/airbyte/pull/9648) | Added permission validation before sync | -| 0.1.29 | 2022-01-20 | [9049](https://github.com/airbytehq/airbyte/pull/9248) | Added `shop_url` to the record for all streams | -| 0.1.28 | 2022-01-19 | [9591](https://github.com/airbytehq/airbyte/pull/9591) | Implemented `OAuth2.0` authentication method for Airbyte Cloud | -| 0.1.27 | 2021-12-22 | [9049](https://github.com/airbytehq/airbyte/pull/9049) | Update connector fields title/description | -| 0.1.26 | 2021-12-14 | [8597](https://github.com/airbytehq/airbyte/pull/8597) | Fix `mismatched number of tables` for base-normalization, increased performance of `order_refunds` stream | -| 0.1.25 | 2021-12-02 | [8297](https://github.com/airbytehq/airbyte/pull/8297) | Added Shop stream | -| 0.1.24 | 2021-11-30 | [7783](https://github.com/airbytehq/airbyte/pull/7783) | Reviewed and corrected schemas for all streams | -| 0.1.23 | 2021-11-15 | [7973](https://github.com/airbytehq/airbyte/pull/7973) | Added `InventoryItems` | -| 0.1.22 | 2021-10-18 | [7101](https://github.com/airbytehq/airbyte/pull/7107) | Added FulfillmentOrders, Fulfillments streams | -| 0.1.21 | 2021-10-14 | [7382](https://github.com/airbytehq/airbyte/pull/7382) | Fixed `InventoryLevels` primary key | -| 0.1.20 | 2021-10-14 | [7063](https://github.com/airbytehq/airbyte/pull/7063) | Added `Location` and `InventoryLevels` as streams | -| 0.1.19 | 2021-10-11 | [6951](https://github.com/airbytehq/airbyte/pull/6951) | Added support of `OAuth 2.0` authorisation option | -| 0.1.18 | 2021-09-21 | [6056](https://github.com/airbytehq/airbyte/pull/6056) | Added `pre_tax_price` to the `orders/line_items` schema | -| 0.1.17 | 2021-09-17 | [5244](https://github.com/airbytehq/airbyte/pull/5244) | Created data type enforcer for converting prices into numbers | -| 0.1.16 | 2021-09-09 | [5965](https://github.com/airbytehq/airbyte/pull/5945) | Fixed the connector's performance for `Incremental refresh` | -| 0.1.15 | 2021-09-02 | [5853](https://github.com/airbytehq/airbyte/pull/5853) | Fixed `amount` type in `order_refund` schema | -| 0.1.14 | 2021-09-02 | [5801](https://github.com/airbytehq/airbyte/pull/5801) | Fixed `line_items/discount allocations` & `duties` parts of `orders` schema | -| 0.1.13 | 2021-08-17 | [5470](https://github.com/airbytehq/airbyte/pull/5470) | Fixed rate limits throttling | -| 0.1.12 | 2021-08-09 | [5276](https://github.com/airbytehq/airbyte/pull/5276) | Add status property to product schema | -| 0.1.11 | 2021-07-23 | [4943](https://github.com/airbytehq/airbyte/pull/4943) | Fix products schema up to API 2021-07 | -| 0.1.10 | 2021-07-19 | [4830](https://github.com/airbytehq/airbyte/pull/4830) | Fix for streams json schemas, upgrade to API version 2021-07 | -| 0.1.9 | 2021-07-04 | [4472](https://github.com/airbytehq/airbyte/pull/4472) | Incremental sync is now using updated\_at instead of since\_id by default | -| 0.1.8 | 2021-06-29 | [4121](https://github.com/airbytehq/airbyte/pull/4121) | Add draft orders stream | -| 0.1.7 | 2021-06-26 | [4290](https://github.com/airbytehq/airbyte/pull/4290) | Fixed the bug when limiting output records to 1 caused infinity loop | -| 0.1.6 | 2021-06-24 | [4009](https://github.com/airbytehq/airbyte/pull/4009) | Add pages, price rules and discount codes streams | -| 0.1.5 | 2021-06-10 | [3973](https://github.com/airbytehq/airbyte/pull/3973) | Add `AIRBYTE_ENTRYPOINT` for Kubernetes support | -| 0.1.4 | 2021-06-09 | [3926](https://github.com/airbytehq/airbyte/pull/3926) | New attributes to Orders schema | -| 0.1.3 | 2021-06-08 | [3787](https://github.com/airbytehq/airbyte/pull/3787) | Add Native Shopify Source Connector | +|:--------| :--- | :--- | :--- | +| 0.1.37 | 2022-04-30 | [12500](https://github.com/airbytehq/airbyte/pull/12500) | Improve input configuration copy | +| 0.1.36 | 2022-03-22 | [9850](https://github.com/airbytehq/airbyte/pull/9850) | Added `BalanceTransactions` stream | +| 0.1.35 | 2022-03-07 | [10915](https://github.com/airbytehq/airbyte/pull/10915) | Fix a bug which caused `full-refresh` syncs of child REST entities configured for `incremental` | +| 0.1.34 | 2022-03-02 | [10794](https://github.com/airbytehq/airbyte/pull/10794) | Minor specification re-order, fixed links in documentation | +| 0.1.33 | 2022-02-17 | [10419](https://github.com/airbytehq/airbyte/pull/10419) | Fixed wrong field type for tax_exemptions for `Abandoned_checkouts` stream | +| 0.1.32 | 2022-02-18 | [10449](https://github.com/airbytehq/airbyte/pull/10449) | Added `tender_transactions` stream | +| 0.1.31 | 2022-02-08 | [10175](https://github.com/airbytehq/airbyte/pull/10175) | Fixed compatibility issues for legacy user config | +| 0.1.30 | 2022-01-24 | [9648](https://github.com/airbytehq/airbyte/pull/9648) | Added permission validation before sync | +| 0.1.29 | 2022-01-20 | [9049](https://github.com/airbytehq/airbyte/pull/9248) | Added `shop_url` to the record for all streams | +| 0.1.28 | 2022-01-19 | [9591](https://github.com/airbytehq/airbyte/pull/9591) | Implemented `OAuth2.0` authentication method for Airbyte Cloud | +| 0.1.27 | 2021-12-22 | [9049](https://github.com/airbytehq/airbyte/pull/9049) | Update connector fields title/description | +| 0.1.26 | 2021-12-14 | [8597](https://github.com/airbytehq/airbyte/pull/8597) | Fix `mismatched number of tables` for base-normalization, increased performance of `order_refunds` stream | +| 0.1.25 | 2021-12-02 | [8297](https://github.com/airbytehq/airbyte/pull/8297) | Added Shop stream | +| 0.1.24 | 2021-11-30 | [7783](https://github.com/airbytehq/airbyte/pull/7783) | Reviewed and corrected schemas for all streams | +| 0.1.23 | 2021-11-15 | [7973](https://github.com/airbytehq/airbyte/pull/7973) | Added `InventoryItems` | +| 0.1.22 | 2021-10-18 | [7101](https://github.com/airbytehq/airbyte/pull/7107) | Added FulfillmentOrders, Fulfillments streams | +| 0.1.21 | 2021-10-14 | [7382](https://github.com/airbytehq/airbyte/pull/7382) | Fixed `InventoryLevels` primary key | +| 0.1.20 | 2021-10-14 | [7063](https://github.com/airbytehq/airbyte/pull/7063) | Added `Location` and `InventoryLevels` as streams | +| 0.1.19 | 2021-10-11 | [6951](https://github.com/airbytehq/airbyte/pull/6951) | Added support of `OAuth 2.0` authorisation option | +| 0.1.18 | 2021-09-21 | [6056](https://github.com/airbytehq/airbyte/pull/6056) | Added `pre_tax_price` to the `orders/line_items` schema | +| 0.1.17 | 2021-09-17 | [5244](https://github.com/airbytehq/airbyte/pull/5244) | Created data type enforcer for converting prices into numbers | +| 0.1.16 | 2021-09-09 | [5965](https://github.com/airbytehq/airbyte/pull/5945) | Fixed the connector's performance for `Incremental refresh` | +| 0.1.15 | 2021-09-02 | [5853](https://github.com/airbytehq/airbyte/pull/5853) | Fixed `amount` type in `order_refund` schema | +| 0.1.14 | 2021-09-02 | [5801](https://github.com/airbytehq/airbyte/pull/5801) | Fixed `line_items/discount allocations` & `duties` parts of `orders` schema | +| 0.1.13 | 2021-08-17 | [5470](https://github.com/airbytehq/airbyte/pull/5470) | Fixed rate limits throttling | +| 0.1.12 | 2021-08-09 | [5276](https://github.com/airbytehq/airbyte/pull/5276) | Add status property to product schema | +| 0.1.11 | 2021-07-23 | [4943](https://github.com/airbytehq/airbyte/pull/4943) | Fix products schema up to API 2021-07 | +| 0.1.10 | 2021-07-19 | [4830](https://github.com/airbytehq/airbyte/pull/4830) | Fix for streams json schemas, upgrade to API version 2021-07 | +| 0.1.9 | 2021-07-04 | [4472](https://github.com/airbytehq/airbyte/pull/4472) | Incremental sync is now using updated\_at instead of since\_id by default | +| 0.1.8 | 2021-06-29 | [4121](https://github.com/airbytehq/airbyte/pull/4121) | Add draft orders stream | +| 0.1.7 | 2021-06-26 | [4290](https://github.com/airbytehq/airbyte/pull/4290) | Fixed the bug when limiting output records to 1 caused infinity loop | +| 0.1.6 | 2021-06-24 | [4009](https://github.com/airbytehq/airbyte/pull/4009) | Add pages, price rules and discount codes streams | +| 0.1.5 | 2021-06-10 | [3973](https://github.com/airbytehq/airbyte/pull/3973) | Add `AIRBYTE_ENTRYPOINT` for Kubernetes support | +| 0.1.4 | 2021-06-09 | [3926](https://github.com/airbytehq/airbyte/pull/3926) | New attributes to Orders schema | +| 0.1.3 | 2021-06-08 | [3787](https://github.com/airbytehq/airbyte/pull/3787) | Add Native Shopify Source Connector | diff --git a/docs/integrations/sources/smartsheets.md b/docs/integrations/sources/smartsheets.md index f06e8a20df8a..93729ba6ae7e 100644 --- a/docs/integrations/sources/smartsheets.md +++ b/docs/integrations/sources/smartsheets.md @@ -88,6 +88,7 @@ The remaining column datatypes supported by Smartsheets are more complex types ( | Version | Date | Pull Request | Subject | |:--------|:-----------|:---------------------------------------------------------|:----------------------------------------------------------| +| 0.1.12 | 2022-04-30 | [12500](https://github.com/airbytehq/airbyte/pull/12500) | Improve input configuration copy | | 0.1.11 | 2022-04-27 | [12203](https://github.com/airbytehq/airbyte/pull/12203) | Doc improvements | | 0.1.10 | 2022-04-15 | [12077](https://github.com/airbytehq/airbyte/pull/12077) | Implement incremental read and improve code test coverage | | 0.1.9 | 2022-04-12 | [11911](https://github.com/airbytehq/airbyte/pull/11911) | Bugfix: scrambled columns | diff --git a/docs/integrations/sources/stripe.md b/docs/integrations/sources/stripe.md index 6edb5eac1497..367d9cacd940 100644 --- a/docs/integrations/sources/stripe.md +++ b/docs/integrations/sources/stripe.md @@ -79,6 +79,7 @@ If you would like to test Airbyte using test data on Stripe, `sk_test_` and `rk_ | Version | Date | Pull Request | Subject | |:--------|:-----------| :--- |:---------| +| 0.1.31 | 2022-04-30 | [12500](https://github.com/airbytehq/airbyte/pull/12500) | Improve input configuration copy | | 0.1.30 | 2022-03-21 | [11286](https://github.com/airbytehq/airbyte/pull/11286) | Minor corrections to documentation and connector specification | | 0.1.29 | 2022-03-08 | [10359](https://github.com/airbytehq/airbyte/pull/10359) | Improved performance for streams with substreams: invoice_line_items, subscription_items, bank_accounts | | 0.1.28 | 2022-02-08 | [10165](https://github.com/airbytehq/airbyte/pull/10165) | Improve 404 handling for `CheckoutSessionsLineItems` stream | diff --git a/docs/integrations/sources/tiktok-marketing.md b/docs/integrations/sources/tiktok-marketing.md index bc8aaef78549..84d8eab2a7bf 100644 --- a/docs/integrations/sources/tiktok-marketing.md +++ b/docs/integrations/sources/tiktok-marketing.md @@ -2,25 +2,24 @@ This page guides you through the process of setting up the TikTok Marketing source connector. -## Prerequisites -* Start date -* Report Granularity (LIFETIME, DAY, HOUR) +## Prerequisites (Airbyte Cloud) +* A Tiktok Ads Business account with permission to access data from accounts you want to sync -For Production environment: +## Prerequisites (Airbyte Open Source) +For the Production environment: * Access token * Secret * App ID -For Sandbox environment: +To access the Sandbox environment: * Access token * Advertiser ID - ## Step 1: Set up TikTok 1. Create a TikTok For Business account: [Link](https://ads.tiktok.com/marketing_api/docs?rid=fgvgaumno25&id=1702715936951297) -2. Create developer application: [Link](https://ads.tiktok.com/marketing_api/docs?rid=fgvgaumno25&id=1702716474845185) -3. For sandbox environment: create a Sandbox Ad Account [Link](https://ads.tiktok.com/marketing_api/docs?rid=fgvgaumno25&id=1701890920013825) +2. (Open source only) Create developer application: [Link](https://ads.tiktok.com/marketing_api/docs?rid=fgvgaumno25&id=1702716474845185) +3. (Open source only) For a sandbox environment: create a Sandbox Ad Account [Link](https://ads.tiktok.com/marketing_api/docs?rid=fgvgaumno25&id=1701890920013825) ## Step 2: Set up the source connector in Airbyte @@ -45,21 +44,25 @@ For Sandbox environment: ## Supported streams and sync modes -| Stream | Environment | Granularities | Key | Incremental | -|:----------------------------------|--------------|-------------------|-------------|:---------------| -| Advertisers | Prod,Sandbox | LIFETIME,DAY,HOUR | id | No | -| AdGroups | Prod,Sandbox | LIFETIME,DAY,HOUR | adgroup_id | Yes (DAY,HOUR) | -| Ads | Prod,Sandbox | LIFETIME,DAY,HOUR | ad_id | Yes (DAY,HOUR) | -| Campaigns | Prod,Sandbox | LIFETIME,DAY,HOUR | campaign_id | Yes (DAY,HOUR) | -| AdsReports | Prod,Sandbox | LIFETIME,DAY,HOUR | None | Yes (DAY,HOUR) | -| AdvertisersReports | Prod | LIFETIME,DAY,HOUR | None | Yes (DAY,HOUR) | -| AdGroupsReports | Prod,Sandbox | LIFETIME,DAY,HOUR | None | Yes (DAY,HOUR) | -| CampaignsReports | Prod,Sandbox | LIFETIME,DAY,HOUR | None | Yes (DAY,HOUR) | -| AdvertisersAudienceReports | Prod | LIFETIME,DAY,HOUR | None | Yes (DAY,HOUR) | -| AdGroupAudienceReports | Prod,Sandbox | DAY,HOUR | None | Yes (DAY,HOUR) | -| AdsAudienceReports | Prod,Sandbox | DAY,HOUR | None | Yes (DAY,HOUR) | -| CampaignsAudienceReportsByCountry | Prod,Sandbox | DAY,HOUR | None | Yes (DAY,HOUR) | - +| Stream | Environment | Supported aggregation granularities | Key | Incremental | +|:----------------------------------|--------------|-------------------------------------|-------------|:---------------| +| Advertisers | Prod,Sandbox | LIFETIME,DAY,HOUR | id | No | +| AdGroups | Prod,Sandbox | LIFETIME,DAY,HOUR | adgroup_id | Yes (DAY,HOUR) | +| Ads | Prod,Sandbox | LIFETIME,DAY,HOUR | ad_id | Yes (DAY,HOUR) | +| Campaigns | Prod,Sandbox | LIFETIME,DAY,HOUR | campaign_id | Yes (DAY,HOUR) | +| AdsReports | Prod,Sandbox | LIFETIME,DAY,HOUR | None | Yes (DAY,HOUR) | +| AdvertisersReports | Prod | LIFETIME,DAY,HOUR | None | Yes (DAY,HOUR) | +| AdGroupsReports | Prod,Sandbox | LIFETIME,DAY,HOUR | None | Yes (DAY,HOUR) | +| CampaignsReports | Prod,Sandbox | LIFETIME,DAY,HOUR | None | Yes (DAY,HOUR) | +| AdvertisersAudienceReports | Prod | LIFETIME,DAY,HOUR | None | Yes (DAY,HOUR) | +| AdGroupAudienceReports | Prod,Sandbox | DAY,HOUR | None | Yes (DAY,HOUR) | +| AdsAudienceReports | Prod,Sandbox | DAY,HOUR | None | Yes (DAY,HOUR) | +| CampaignsAudienceReportsByCountry | Prod,Sandbox | DAY,HOUR | None | Yes (DAY,HOUR) | + +### Report Aggregation +Reports synced by this connector can use either hourly, daily, or lifetime granularities for aggregating performance data. For example, if you select the daily-aggregation flavor of a report, the report will contain a row for each day for the duration of the report. Each row will indicate the number of impressions recorded on that day. + +### Output Schemas **[Advertisers](https://ads.tiktok.com/marketing_api/docs?id=1708503202263042) Stream** ``` { @@ -521,6 +524,7 @@ The connector is restricted by [requests limitation](https://ads.tiktok.com/mark | Version | Date | Pull Request | Subject | |:--------|:-----------|:---------------------------------------------------------|:----------------------------------------------------------------------------------------------| +| 0.1.9 | 2022-04-30 | [12500](https://github.com/airbytehq/airbyte/pull/12500) | Improve input configuration copy | | 0.1.8 | 2022-04-28 | [12435](https://github.com/airbytehq/airbyte/pull/12435) | updated spec descriptions | | 0.1.7 | 2022-04-27 | [12380](https://github.com/airbytehq/airbyte/pull/12380) | fixed spec descriptions and documentation | | 0.1.6 | 2022-04-19 | [11378](https://github.com/airbytehq/airbyte/pull/11378) | updated logic for stream initializations, fixed errors in schemas, updated SAT and unit tests |