diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d396980..14569f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,7 @@ name: ci on: [push] jobs: compile: - runs-on: ubuntu-24.04 + runs-on: ubuntu-20.04 steps: - name: Checkout repo uses: actions/checkout@v3 @@ -19,7 +19,7 @@ jobs: - name: Compile run: poetry run mypy . test: - runs-on: ubuntu-24.04 + runs-on: ubuntu-20.04 steps: - name: Checkout repo uses: actions/checkout@v3 @@ -36,12 +36,12 @@ jobs: - name: Install Fern run: npm install -g fern-api - name: Test - run: fern test --command "poetry run pytest -rP ./tests/custom/" + run: fern test --command "poetry run pytest -rP ." publish: needs: [compile, test] if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') - runs-on: ubuntu-24.04 + runs-on: ubuntu-20.04 steps: - name: Checkout repo uses: actions/checkout@v3 diff --git a/.mock/definition/__package__.yml b/.mock/definition/__package__.yml index db84636..6825b17 100644 --- a/.mock/definition/__package__.yml +++ b/.mock/definition/__package__.yml @@ -67,10 +67,18 @@ errors: ConflictError: status-code: 409 type: unknown - docs: Site is published to multiple domains at different times + docs: Collection already exists examples: + - value: + code: duplicate_collection + message: Collection already exists - value: message: '''Site is published to multiple domains at different times' + - value: + code: conflict + message: >- + Conflict: Conflict with server data: Live PATCH updates can't be + applied to items that have never been published - value: code: custom_code_max_registered_scripts message: The maximum number of registered scripts has been reached. @@ -226,12 +234,14 @@ types: id: type: string docs: Unique identifier for the Domain + access: read-only url: type: optional docs: The registered Domain name lastPublished: type: optional docs: The date the custom domain was last published to + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml Locale: @@ -348,6 +358,7 @@ types: id: type: optional docs: The ID of the specific redirect rule + access: read-only fromUrl: type: optional docs: The source URL path that will be redirected. @@ -360,13 +371,13 @@ types: docs: Pagination object properties: limit: - type: optional + type: double docs: The limit used for pagination offset: - type: optional + type: double docs: The offset used for pagination total: - type: optional + type: double docs: The total number of records source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -440,6 +451,31 @@ types: docs: URL for more information about Webflow hosting plan pricing. source: openapi: ../../../openapi/referenced-specs/v2.yml + RobotsRulesItem: + properties: + userAgent: + type: string + docs: The user agent the rules apply to. + allows: + type: optional> + docs: List of paths allowed for this user agent. + disallows: + type: optional> + docs: List of paths disallowed for this user agent. + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + Robots: + docs: The robots.txt file for a given site + properties: + rules: + type: optional> + docs: List of rules for user agents. + sitemap: + type: optional + docs: URL to the sitemap. + source: + openapi: ../../../openapi/referenced-specs/v2.yml SiteActivityLogItemEvent: enum: - styles_modified @@ -535,6 +571,7 @@ types: id: type: string docs: Unique identifier for a Collection + access: read-only displayName: type: optional docs: Name given to the Collection @@ -549,9 +586,11 @@ types: createdOn: type: optional docs: The date the collection was created + access: read-only lastUpdated: type: optional docs: The date the collection was last updated + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml CollectionList: @@ -561,6 +600,154 @@ types: docs: An array of Collections source: openapi: ../../../openapi/referenced-specs/v2.yml + StaticFieldType: + enum: + - Color + - DateTime + - Email + - File + - Image + - Link + - MultiImage + - Number + - Phone + - PlainText + - RichText + - Switch + - Video + docs: Choose these appropriate field type for your collection data + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + Static Field: + properties: + id: + type: optional + docs: Unique identifier for a Field + access: read-only + isEditable: + type: optional + docs: Define whether the field is editable + access: read-only + isRequired: + type: optional + docs: define whether a field is required in a collection + type: + type: StaticFieldType + docs: Choose these appropriate field type for your collection data + displayName: + type: string + docs: The name of a field + helpText: + type: optional + docs: Additional text to help anyone filling out this field + source: + openapi: ../../../openapi/referenced-specs/v2.yml + MetadataOptionsItem: + docs: A single option value for the Option field. + properties: + name: + type: string + docs: The name of the option + id: + type: optional + docs: The unique identifier of the option + access: read-only + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + Metadata: + docs: The metadata for the Option field. + properties: + options: + docs: The option values for the Option field. + type: list + source: + openapi: ../../../openapi/referenced-specs/v2.yml + Option Field: + properties: + id: + type: optional + docs: Unique identifier for a Field + access: read-only + isEditable: + type: optional + docs: Define whether the field is editable + access: read-only + isRequired: + type: optional + docs: define whether a field is required in a collection + type: + type: literal<"Option"> + docs: >- + The [Option field + type](/data/reference/field-types-item-values#option) + displayName: + type: string + docs: The name of a field + helpText: + type: optional + docs: Additional text to help anyone filling out this field + metadata: Metadata + source: + openapi: ../../../openapi/referenced-specs/v2.yml + ReferenceFieldType: + enum: + - MultiReference + - Reference + docs: Choose these appropriate field type for your collection data + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml + ReferenceFieldMetadata: + docs: >- + The collectionId for the referenced collection. Only applicable for + Reference and MultiReference fields. + properties: + collectionId: + type: string + docs: The unique identifier of the collection + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + Reference Field: + properties: + id: + type: optional + docs: Unique identifier for a Field + access: read-only + isEditable: + type: optional + docs: Define whether the field is editable + access: read-only + isRequired: + type: optional + docs: define whether a field is required in a collection + type: + type: ReferenceFieldType + docs: Choose these appropriate field type for your collection data + displayName: + type: string + docs: The name of a field + helpText: + type: optional + docs: Additional text to help anyone filling out this field + metadata: + type: ReferenceFieldMetadata + docs: >- + The collectionId for the referenced collection. Only applicable for + Reference and MultiReference fields. + source: + openapi: ../../../openapi/referenced-specs/v2.yml + FieldCreate: + discriminated: false + docs: Details about the field of a collection + union: + - Static Field + - Option Field + - Reference Field + source: + openapi: ../../../openapi/referenced-specs/v2.yml FieldType: enum: - Color @@ -570,9 +757,11 @@ types: - Image - Link - MultiImage + - MultiReference - Number - Phone - PlainText + - Reference - RichText - Switch - Video @@ -586,12 +775,14 @@ types: id: type: string docs: Unique identifier for a Field + access: read-only isRequired: type: boolean docs: define whether a field is required in a collection isEditable: type: optional docs: Define whether the field is editable + access: read-only type: type: FieldType docs: Choose these appropriate field type for your collection data @@ -614,11 +805,12 @@ types: id: type: string docs: Unique identifier for a Collection + access: read-only displayName: - type: optional + type: string docs: Name given to the Collection singularName: - type: optional + type: string docs: >- The name of one Item in Collection (e.g. ”Blog Post” if the Collection is called “Blog Posts”) @@ -628,9 +820,11 @@ types: createdOn: type: optional docs: The date the collection was created + access: read-only lastUpdated: type: optional docs: The date the collection was last updated + access: read-only fields: docs: The list of fields in the Collection type: list @@ -669,18 +863,22 @@ types: id: type: optional docs: Unique identifier for the Item + access: read-only cmsLocaleId: type: optional docs: Identifier for the locale of the CMS item lastPublished: - type: optional + type: string docs: The date the item was last published + access: read-only lastUpdated: - type: optional + type: string docs: The date the item was last updated + access: read-only createdOn: - type: optional + type: string docs: The date the item was created + access: read-only isArchived: type: optional docs: Boolean determining if the Item is set to archived @@ -750,18 +948,22 @@ types: id: type: optional docs: Unique identifier for the Item + access: read-only cmsLocaleId: type: optional docs: Identifier for the locale of the CMS item lastPublished: type: optional docs: The date the item was last published + access: read-only lastUpdated: type: optional docs: The date the item was last updated + access: read-only createdOn: type: optional docs: The date the item was created + access: read-only isArchived: type: optional docs: Boolean determining if the Item is in an archived state. @@ -803,12 +1005,15 @@ types: lastPublished: type: optional docs: The date the item was last published + access: read-only lastUpdated: type: optional docs: The date the item was last updated + access: read-only createdOn: type: optional docs: The date the item was created + access: read-only isArchived: type: optional docs: Boolean determining if the Item is set to archived @@ -826,6 +1031,7 @@ types: docs: List of Items within the collection source: openapi: ../../../openapi/referenced-specs/v2.yml + Conflict: unknown BulkCollectionItemFieldData: properties: name: @@ -850,18 +1056,22 @@ types: id: type: string docs: Unique identifier for the Item + access: read-only cmsLocaleIds: type: optional> docs: Array of identifiers for the locales where the item will be created lastPublished: type: optional docs: The date the item was last published + access: read-only lastUpdated: type: optional docs: The date the item was last updated + access: read-only createdOn: type: optional docs: The date the item was created + access: read-only isArchived: type: optional docs: Boolean determining if the Item is set to archived @@ -897,18 +1107,22 @@ types: id: type: optional docs: Unique identifier for the Item + access: read-only cmsLocaleId: type: optional docs: Identifier for the locale of the CMS item lastPublished: type: optional docs: The date the item was last published + access: read-only lastUpdated: type: optional docs: The date the item was last updated + access: read-only createdOn: type: optional docs: The date the item was created + access: read-only isArchived: type: optional docs: Boolean determining if the Item is set to archived @@ -918,6 +1132,222 @@ types: fieldData: optional source: openapi: ../../../openapi/referenced-specs/v2.yml + CommentThreadAuthor: + properties: + userId: + type: string + docs: The unique identifier of the author + email: + type: string + docs: Email of the author + name: + type: string + docs: Name of the author + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + CommentThreadMentionedUsersItem: + properties: + userId: + type: string + docs: The unique identifier of the mentioned user + email: + type: string + docs: Email of the user + name: + type: string + docs: Name of the User + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + CommentThread: + docs: > + A comment thread represents a conversation between users on a specific + page. Each comment thread has a unique identifier and can contain multiple + comments. Retrieve comment replies using the repiles API endpoint. + properties: + id: + type: string + docs: Unique identifier for the comment thread + access: read-only + siteId: + type: string + docs: The site unique identifier + access: read-only + pageId: + type: string + docs: The page unique identifier + access: read-only + localeId: + type: optional + docs: The locale unique identifier + access: read-only + itemId: + type: optional + docs: The item unique identifier + access: read-only + breakpoint: + type: string + docs: The breakpoint the comment was left on + access: read-only + url: + type: string + docs: The URL of the page the comment was left on + access: read-only + content: + type: string + docs: The content of the comment reply + isResolved: + type: boolean + docs: Boolean determining if the comment thread is resolved + default: false + author: CommentThreadAuthor + mentionedUsers: + docs: >- + List of mentioned users. This is an empty array until email + notifications are sent, which can take up to 5 minutes after the + comment is created. + type: list + createdOn: + type: string + docs: The date the item was created + access: read-only + lastUpdated: + type: string + docs: The date the item was last updated + access: read-only + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentThreadListPagination: + properties: + limit: + type: double + docs: The limit specified in the request (default 100) + default: 100 + offset: + type: double + docs: The offset specified for pagination + default: 0 + total: + type: double + docs: Total number of comment threads + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + CommentThreadList: + docs: > + A list of comment threads on the site. Contains the content of the first + reply. + properties: + comments: list + pagination: CommentThreadListPagination + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentReplyAuthor: + properties: + id: + type: string + docs: The unique identifier of the author + email: + type: string + docs: Email of the author + name: + type: string + docs: Name of the author + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + CommentReplyMentionedUsersItem: + properties: + id: + type: string + docs: The unique identifier of the mentioned user + email: + type: string + docs: Email of the user + name: + type: string + docs: Name of the User + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + CommentReply: + docs: > + A comment thread represents a conversation between users on a specific + page. Each comment thread has a unique identifier and can contain multiple + comments. + properties: + id: + type: string + docs: Unique identifier for the comment thread + access: read-only + commentId: + type: string + docs: The comment reply unique identifier + access: read-only + siteId: + type: string + docs: The site unique identifier + access: read-only + pageId: + type: string + docs: The page unique identifier + access: read-only + localeId: + type: optional + docs: The locale unique identifier + access: read-only + breakpoint: + type: string + docs: The breakpoint the comment was left on + access: read-only + content: + type: string + docs: The content of the comment reply + isResolved: + type: boolean + docs: Boolean determining if the comment thread is resolved + default: false + author: CommentReplyAuthor + mentionedUsers: + type: optional> + docs: >- + List of mentioned users is an empty array until email notifications + are sent. + lastUpdated: + type: string + docs: The date the item was last updated + access: read-only + createdOn: + type: string + docs: The date the item was created + access: read-only + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentReplyListPagination: + properties: + limit: + type: double + docs: The limit specified in the request (default 100) + default: 100 + offset: + type: double + docs: The offset specified for pagination + default: 0 + total: + type: double + docs: Total number of comment replies + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + CommentReplyList: + docs: | + A list of comment replies. + properties: + comments: list + pagination: CommentReplyListPagination + source: + openapi: ../../../openapi/referenced-specs/v2.yml PageSeo: docs: SEO-related fields for the Page properties: @@ -940,6 +1370,7 @@ types: type: optional docs: Indicates the Open Graph title was copied from the SEO title default: true + access: read-only description: type: optional docs: The description supplied to Open Graph annotations @@ -949,6 +1380,7 @@ types: Indicates the Open Graph description was copied from the SEO description default: true + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true @@ -958,9 +1390,11 @@ types: id: type: string docs: Unique identifier for the Page + access: read-only siteId: type: optional docs: Unique identifier for the Site + access: read-only title: type: optional docs: Title of the Page @@ -970,43 +1404,52 @@ types: parentId: type: optional docs: Identifier of the parent folder + access: read-only collectionId: type: optional docs: >- Unique identifier for a linked Collection, value will be null if the Page is not part of a Collection. + access: read-only createdOn: type: optional docs: The date the Page was created + access: read-only lastUpdated: type: optional docs: The date the Page was most recently updated + access: read-only archived: type: optional docs: Whether the Page has been archived default: false + access: read-only draft: type: optional docs: Whether the Page is a draft default: false + access: read-only canBranch: type: optional docs: >- Indicates whether the Page supports [Page Branching](https://university.webflow.com/lesson/page-branching) default: false + access: read-only isBranch: type: optional docs: >- Indicates whether the Page is a Branch of another Page [Page Branching](https://university.webflow.com/lesson/page-branching) default: false + access: read-only isMembersOnly: type: optional docs: >- Indicates whether the Page is restricted by [Memberships Controls](https://university.webflow.com/lesson/webflow-memberships-overview#how-to-manage-page-restrictions) default: false + access: read-only seo: type: optional docs: SEO-related fields for the Page @@ -1016,9 +1459,11 @@ types: localeId: type: optional docs: Unique ID of the page locale + access: read-only publishedPath: type: optional docs: Relative path of the published page URL + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml PageList: @@ -1029,6 +1474,7 @@ types: source: openapi: ../../../openapi/referenced-specs/v2.yml TextNodeText: + docs: The text content of the node properties: html: type: optional @@ -1046,15 +1492,19 @@ types: text for styling or other purposes. properties: id: - type: optional + type: string docs: Node UUID - text: optional + access: read-only + text: + type: TextNodeText + docs: The text content of the node attributes: type: optional> docs: The custom attributes of the node source: openapi: ../../../openapi/referenced-specs/v2.yml ImageNodeImage: + docs: The image details of the node properties: alt: optional assetId: optional @@ -1069,15 +1519,19 @@ types: can be associated with the image for styling or other purposes. properties: id: - type: optional + type: string docs: Node UUID - image: optional + access: read-only + image: + type: ImageNodeImage + docs: The image details of the node attributes: type: optional> docs: The custom attributes of the node source: openapi: ../../../openapi/referenced-specs/v2.yml Text: + docs: The text content of the node properties: html: type: optional @@ -1128,14 +1582,15 @@ types: the component instance, such as its type and properties. properties: id: - type: optional - docs: Node UUID + type: string + docs: The unique identifier of the component instance node + access: read-only componentId: - type: optional - docs: Component ID + type: string + docs: The unique identifier of the component propertyOverrides: - type: optional> docs: List of component properties with overrides for a component instance. + type: list source: openapi: ../../../openapi/referenced-specs/v2.yml Node: @@ -1165,6 +1620,10 @@ types: docs: Page ID nodes: optional> pagination: optional + lastUpdated: + type: optional + docs: The date the page dom was most recently updated + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml TextNodeWrite: @@ -1220,21 +1679,26 @@ types: id: type: string docs: Unique identifier for the Component + access: read-only name: type: optional docs: Component Name + access: read-only group: type: optional docs: The group that the component belongs to + access: read-only description: type: optional docs: Component Description + access: read-only readonly: type: optional docs: >- Indicates whether the component is read-only. Components that cannot be updated within this Site are set to readonly. Workspace Libraries are a good example. + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml ComponentList: @@ -1270,6 +1734,7 @@ types: componentId: type: optional docs: Component ID + access: read-only properties: optional> pagination: optional source: @@ -1314,9 +1779,11 @@ types: lastUpdated: type: optional docs: Date when the Site's scripts were last updated + access: read-only createdOn: type: optional docs: Date when the Site's scripts were created + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml CustomCodeHostedResponse: @@ -1325,6 +1792,7 @@ types: id: type: optional docs: Human readable id, derived from the user-specified display name + access: read-only canCopy: type: optional docs: >- @@ -1347,9 +1815,11 @@ types: createdOn: type: optional docs: Timestamp when the script version was created + access: read-only lastUpdated: type: optional docs: Timestamp when the script version was last updated + access: read-only version: type: optional docs: A Semantic Version (SemVer) string, denoting the version of the script @@ -1367,6 +1837,7 @@ types: id: type: optional docs: Human readable id, derived from the user-specified display name + access: read-only canCopy: type: optional docs: >- @@ -1389,9 +1860,11 @@ types: createdOn: type: optional docs: Timestamp when the script version was created + access: read-only lastUpdated: type: optional docs: Timestamp when the script version was last updated + access: read-only version: type: optional docs: A Semantic Version (SemVer) string, denoting the version of the script @@ -1426,9 +1899,11 @@ types: createdOn: type: optional docs: The date the Block was created + access: read-only lastUpdated: type: optional docs: The date the Block was most recently updated + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml ListCustomCodeBlocks: @@ -1439,29 +1914,30 @@ types: source: openapi: ../../../openapi/referenced-specs/v2.yml AssetVariant: + docs: Asset variant details properties: hostedUrl: - type: optional + type: string docs: URL of where the asset variant is hosted validation: format: uri originalFileName: - type: optional + type: string docs: Original file name of the variant displayName: - type: optional + type: string docs: Display name of the variant format: - type: optional + type: string docs: format of the variant width: - type: optional + type: integer docs: Width in pixels height: - type: optional + type: integer docs: Height in pixels quality: - type: optional + type: integer docs: Value between 0 and 100 representing the image quality error: type: optional @@ -1469,37 +1945,51 @@ types: source: openapi: ../../../openapi/referenced-specs/v2.yml Asset: + docs: Asset details properties: id: - type: optional + type: string docs: Unique identifier for this asset + access: read-only contentType: - type: optional + type: string docs: File format type + access: read-only size: - type: optional + type: integer docs: size in bytes + access: read-only siteId: - type: optional + type: string docs: Unique identifier for the site that hosts this asset + access: read-only hostedUrl: - type: optional + type: string docs: Link to the asset validation: format: uri + access: read-only originalFileName: - type: optional + type: string docs: Original file name at the time of upload + access: read-only displayName: - type: optional + type: string docs: Display name of the asset lastUpdated: - type: optional + type: datetime docs: Date the asset metadata was last updated + access: read-only createdOn: - type: optional + type: datetime docs: Date the asset metadata was created - variants: optional> + access: read-only + variants: + docs: >- + A list of [asset + variants](https://help.webflow.com/hc/en-us/articles/33961378697107-Responsive-images) + created by Webflow to serve your site responsively. + type: list altText: type: optional docs: The visual description of the asset @@ -1509,6 +1999,7 @@ types: docs: A list of assets properties: assets: optional> + pagination: optional source: openapi: ../../../openapi/referenced-specs/v2.yml AssetUploadUploadDetails: @@ -1618,46 +2109,8 @@ types: - collection_item_deleted - collection_item_unpublished docs: > - * `form_submission` - Sends the [form_submission](#form_submission) event - - * `site_publish` - Sends a [site_publish](#site_publish) event - - * `page_created` - Send the [page_created](#page_created) event - - * `page_metadata_updated` - Sends the - [page_metadata_updated](#page_metadata_updated) event - - * `page_deleted` - Sends the [page_deleted](#page_deleted) event - - * `ecomm_new_order` - Sends the new [ecomm_new_order](#ecomm_new_order) - event - - * `ecomm_order_changed` - Sends the - [ecomm_order_changed](#ecomm_order_changed) event - - * `ecomm_inventory_changed` - Sends the - [ecomm_inventory_changed](#ecomm_inventory_changed) event - - * `user_account_added` - Sends the - [user_account_added](#user_account_added) event - - * `user_account_updated` - Sends the - [user_account_updated](#user_account_updated) event - - * `user_account_deleted` - Sends the - [user_account_deleted](#user_account_deleted) event - - * `collection_item_created` - Sends the - [collection_item_created](#collection_item_created) event - - * `collection_item_changed` - Sends the - [collection_item_changed](#collection_item_changed) event - - * `collection_item_deleted` - Sends the - [collection_item_deleted](#collection_item_deleted) event - - * `collection_item_unpublished` - Sends the - [collection_item_unpublished](#collection_item_unpublished) event + The type of event that triggered the request. See the the documentation + for details on [supported events](/data/reference/all-events). source: openapi: ../../../openapi/referenced-specs/v2.yml WebhookFilter: @@ -1676,6 +2129,7 @@ types: id: type: optional docs: Unique identifier for the Webhook registration + access: read-only triggerType: optional url: type: optional @@ -1683,9 +2137,11 @@ types: workspaceId: type: optional docs: Unique identifier for the Workspace the Webhook is registered in + access: read-only siteId: type: optional docs: Unique identifier for the Site the Webhook is registered in + access: read-only filter: type: optional docs: >- @@ -1694,15 +2150,17 @@ types: lastTriggered: type: optional docs: Date the Webhook instance was last triggered + access: read-only createdOn: type: optional docs: Date the Webhook registration was created + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml WebhookList: properties: - pagination: optional webhooks: optional> + pagination: optional source: openapi: ../../../openapi/referenced-specs/v2.yml FormFieldValueType: @@ -1905,24 +2363,31 @@ types: id: type: optional docs: Unique identifier for the User + access: read-only isEmailVerified: type: optional docs: Shows whether the user has verified their email address + access: read-only lastUpdated: type: optional docs: The timestamp the user was updated + access: read-only invitedOn: type: optional docs: The timestamp the user was invited + access: read-only createdOn: type: optional docs: The timestamp the user was created + access: read-only lastLogin: type: optional docs: The timestamp the user was logged in + access: read-only status: type: optional docs: The status of the user + access: read-only accessGroups: type: optional> docs: Access groups the user belongs to @@ -2152,18 +2617,23 @@ types: id: type: optional docs: Unique identifier for the Product + access: read-only cmsLocaleId: type: optional docs: Identifier for the locale of the CMS item + access: read-only lastPublished: type: optional docs: The date the Product was last published + access: read-only lastUpdated: type: optional docs: The date the Product was last updated + access: read-only createdOn: type: optional docs: The date the Product was created + access: read-only isArchived: type: optional docs: Boolean determining if the Product is set to archived @@ -2189,6 +2659,9 @@ types: unit: type: optional docs: Currency of Item + currency: + type: optional + docs: Currency of Item (alternative representation) source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true @@ -2209,6 +2682,10 @@ types: - value: one-time name: OneTime - subscription + docs: >- + [Billing + method](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#billing-methods)for + the SKU inline: true source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -2246,6 +2723,10 @@ types: openapi: ../../../openapi/referenced-specs/v2.yml inline: true SkuFieldDataEcSkuSubscriptionPlan: + docs: >- + [Subscription + plan](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#subscription) + for the SKU properties: interval: type: optional @@ -2256,7 +2737,9 @@ types: trial: type: optional docs: Number of days of a trial - plans: optional> + plans: + type: optional> + access: read-only source: openapi: ../../../openapi/referenced-specs/v2.yml inline: true @@ -2276,8 +2759,18 @@ types: compare-at-price: type: optional docs: comparison price of SKU - ec-sku-billing-method: optional - ec-sku-subscription-plan: optional + ec-sku-billing-method: + type: optional + docs: >- + [Billing + method](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#billing-methods)for + the SKU + ec-sku-subscription-plan: + type: optional + docs: >- + [Subscription + plan](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#subscription) + for the SKU track-inventory: type: optional docs: >- @@ -2287,6 +2780,9 @@ types: quantity: type: optional docs: Quantity of SKU that will be tracked as items are ordered. + main-image: + type: optional + docs: The URL for the main image of the SKU source: openapi: ../../../openapi/referenced-specs/v2.yml Sku: @@ -2295,18 +2791,23 @@ types: id: type: optional docs: Unique identifier for the Product + access: read-only cmsLocaleId: type: optional docs: Identifier for the locale of the CMS item + access: read-only lastPublished: type: optional docs: The date the Product was last published + access: read-only lastUpdated: type: optional docs: The date the Product was last updated + access: read-only createdOn: type: optional docs: The date the Product was created + access: read-only fieldData: optional source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -2472,6 +2973,7 @@ types: productId: type: optional docs: The unique identifier for the Product + access: read-only productName: type: optional docs: User-facing name of the Product @@ -2725,6 +3227,7 @@ types: The order ID. Will usually be 6 hex characters, but can also be 9 hex characters if the site has a very large number of Orders. Randomly assigned. + access: read-only status: type: optional docs: | @@ -2868,6 +3371,7 @@ types: id: type: optional docs: Unique identifier for a SKU item + access: read-only quantity: type: optional docs: >- @@ -2884,9 +3388,11 @@ types: siteId: type: optional docs: The identifier of the Site + access: read-only createdOn: type: optional docs: Date that the Site was created on + access: read-only defaultCurrency: type: optional docs: The three-letter ISO currency code for the Site diff --git a/.mock/definition/accessGroups.yml b/.mock/definition/accessGroups.yml index d8828f8..7689533 100644 --- a/.mock/definition/accessGroups.yml +++ b/.mock/definition/accessGroups.yml @@ -49,6 +49,7 @@ service: response: docs: Request was successful type: root.AccessGroupList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/api.yml b/.mock/definition/api.yml index aee9acd..b881d16 100644 --- a/.mock/definition/api.yml +++ b/.mock/definition/api.yml @@ -3,8 +3,15 @@ error-discrimination: strategy: status-code display-name: Data API environments: - Default: https://api.webflow.com/v2 -default-environment: Default + Data API: + urls: + Base: https://api.webflow.com/v2 + Data API: https://api.webflow.com/v2 + Content Delivery API: https://api-cdn.webflow.com/v2 + Production: https://api.webflow.com/v2 + CDN: https://api-cdn.webflow.com/v2 +default-environment: Data API +default-url: Base auth-schemes: BearerToken: scheme: bearer diff --git a/.mock/definition/assets.yml b/.mock/definition/assets.yml index 35392ec..597a63f 100644 --- a/.mock/definition/assets.yml +++ b/.mock/definition/assets.yml @@ -9,7 +9,7 @@ service: method: GET auth: true docs: | - List assets for a given site + List of assets uploaded to a site Required scope | `assets:read` source: @@ -22,6 +22,7 @@ service: response: docs: Request was successful type: root.Assets + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -55,35 +56,64 @@ service: width: 500 height: 900 quality: 100 - altText: A red chair + altText: A single candy wrapper + - id: 63e5889e7fe4eafa7384cea5 + contentType: image/png + size: 2212772 + siteId: 63938b302ea6b0aa6f3d8745 + hostedUrl: >- + https://s3.amazonaws.com/webflow-prod-assets/63938b302ea6b0aa6f3d8745/63e5889e7fe4eafa7384cea4_Vectors-Wrapper.svg + originalFileName: Gum-Wrapper.svg + displayName: 63e5889e7fe4eafa7384cea5_Gum-Wrapper.png + lastUpdated: '2023-03-01T23:42:57Z' + createdOn: '2023-02-09T23:58:22Z' + variants: + - hostedUrl: >- + https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + originalFileName: >- + Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + displayName: >- + 660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + format: png + width: 500 + height: 900 + quality: 100 + altText: A single gum wrapper + pagination: + limit: 2 + offset: 0 + total: 2 create: path: /sites/{site_id}/assets method: POST auth: true docs: > - Create a new asset entry. + The first step in uploading an asset to a site. This endpoint generates a response with the following information: - `uploadUrl` and `uploadDetails`. + `uploadUrl` and `uploadDetails`. - You can use these two properties to [upload the file to Amazon s3 by - making a - POST](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) - request to the `uploadUrl` with the `uploadDetails` object as your - header information in the request. - - Required scope | `assets:write` + Use these properties in the header of a [POST request to Amazson + s3](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) + to complete the upload. + + + + To learn more about how to upload assets to Webflow, see our [assets + guide](/data/docs/working-with-assets). + + Required scope | `assets:write` source: openapi: ../../../openapi/referenced-specs/v2.yml path-parameters: site_id: type: string docs: Unique identifier for a Site - display-name: Create Asset Metadata + display-name: Upload Asset request: name: AssetsCreateRequest body: @@ -103,6 +133,7 @@ service: response: docs: Request was successful type: root.AssetUpload + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -146,7 +177,7 @@ service: method: GET auth: true docs: | - Get an Asset + Get details about an asset Required scope | `assets:read` source: @@ -159,6 +190,7 @@ service: response: docs: Request was successful type: root.Asset + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -170,25 +202,27 @@ service: asset_id: 580e63fc8c9a982ac9b8b745 response: body: - id: 55131cd036c09f7d07883dfc + id: 63e5889e7fe4eafa7384cea4 contentType: image/png - size: 1500 - siteId: 62749158efef318abc8d5a0f - hostedUrl: example.com/hostedimage.png - originalFileName: image.png - displayName: example-image-123.png - lastUpdated: '2016-09-06T21:12:22Z' - createdOn: '2016-09-02T23:26:22Z' + size: 2212772 + siteId: 63938b302ea6b0aa6f3d8745 + hostedUrl: >- + https://s3.amazonaws.com/webflow-prod-assets/63938b302ea6b0aa6f3d8745/63e5889e7fe4eafa7384cea4_Vectors-Wrapper.svg + originalFileName: Candy-Wrapper.svg + displayName: 63e5889e7fe4eafa7384cea4_Candy-Wrapper.png + lastUpdated: '2023-03-01T23:42:57Z' + createdOn: '2023-02-09T23:58:22Z' variants: - - hostedUrl: example.com/hostedimage.png - originalFileName: image.png - displayName: A brown dog - format: format - width: 1500 + - hostedUrl: >- + https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + originalFileName: Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + displayName: >- + 660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + format: png + width: 500 height: 900 - quality: 1 - error: error - altText: A red chair + quality: 100 + altText: A single candy wrapper delete: path: /assets/{asset_id} method: DELETE @@ -218,7 +252,7 @@ service: method: PATCH auth: true docs: | - Update an Asset + Update details of an Asset. Required scope | `assets:write` source: @@ -244,6 +278,7 @@ service: response: docs: Request was successful type: root.Asset + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -256,25 +291,27 @@ service: request: {} response: body: - id: 55131cd036c09f7d07883dfc + id: 63e5889e7fe4eafa7384cea4 contentType: image/png - size: 1500 - siteId: 62749158efef318abc8d5a0f - hostedUrl: example.com/hostedimage.png - originalFileName: image.png - displayName: example-image-123.png - lastUpdated: '2016-09-06T21:12:22Z' - createdOn: '2016-09-02T23:26:22Z' + size: 2212772 + siteId: 63938b302ea6b0aa6f3d8745 + hostedUrl: >- + https://s3.amazonaws.com/webflow-prod-assets/63938b302ea6b0aa6f3d8745/63e5889e7fe4eafa7384cea4_Vectors-Wrapper.svg + originalFileName: Candy-Wrapper.svg + displayName: 63e5889e7fe4eafa7384cea4_Candy-Wrapper.png + lastUpdated: '2023-03-01T23:42:57Z' + createdOn: '2023-02-09T23:58:22Z' variants: - - hostedUrl: example.com/hostedimage.png - originalFileName: image.png - displayName: A brown dog - format: format - width: 1500 + - hostedUrl: >- + https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + originalFileName: Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + displayName: >- + 660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png + format: png + width: 500 height: 900 - quality: 1 - error: error - altText: A red chair + quality: 100 + altText: A single candy wrapper list-folders: path: /sites/{site_id}/asset_folders method: GET @@ -293,6 +330,7 @@ service: response: docs: Request was successful type: root.AssetFolderList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -307,7 +345,6 @@ service: assetFolders: - id: 6390c49774a71f0e3c1a08ee displayName: emoji icons - parentFolder: 6390c49774a71f99f21a08eb assets: - 63e5889e7fe4eafa7384cea4 - 659595234426a9fcbad57043 @@ -349,6 +386,7 @@ service: response: docs: Request was successful type: root.AssetFolder + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -389,6 +427,7 @@ service: response: docs: Request was successful type: root.AssetFolder + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/collections.yml b/.mock/definition/collections.yml index 661b54b..f3af59a 100644 --- a/.mock/definition/collections.yml +++ b/.mock/definition/collections.yml @@ -22,6 +22,7 @@ service: response: docs: Request was successful type: root.CollectionList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -80,14 +81,19 @@ service: slug: type: optional docs: Part of a URL that identifier + fields: + type: optional> + docs: An array of custom fields to add to the collection content-type: application/json response: docs: Request was successful type: root.Collection + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError - root.NotFoundError + - root.ConflictError - root.TooManyRequestsError - root.InternalServerError examples: @@ -97,22 +103,51 @@ service: displayName: Blog Posts singularName: Blog Post slug: posts + fields: + - isRequired: true + type: PlainText + displayName: Title + helpText: The title of the blog post + - isRequired: true + type: RichText + displayName: Content + helpText: The content of the blog post + - isRequired: true + type: Reference + displayName: Author + helpText: The author of the blog post + metadata: + collectionId: 23cc2d952d4e4631ffd4345d2743db4e response: body: - id: 580e63fc8c9a982ac9b8b745 + id: 562ac0395358780a1f5e6fbd displayName: Blog Posts singularName: Blog Post - slug: post + slug: posts createdOn: '2016-10-24T19:41:48Z' lastUpdated: '2016-10-24T19:42:38Z' fields: - - id: 23cc2d952d4e4631ffd4345d2743db4e + - id: id isRequired: true isEditable: true type: PlainText - slug: name - displayName: Name - helpText: helpText + slug: title + displayName: Title + helpText: The title of the blog post + - id: id + isRequired: true + isEditable: true + type: RichText + slug: content + displayName: Content + helpText: The content of the blog post + - id: id + isRequired: true + isEditable: true + type: Reference + slug: author + displayName: Author + helpText: The author of the blog post get: path: /collections/{collection_id} method: GET @@ -131,6 +166,7 @@ service: response: docs: Request was successful type: root.Collection + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -155,7 +191,6 @@ service: type: PlainText slug: name displayName: Name - helpText: helpText delete: path: /collections/{collection_id} method: DELETE diff --git a/.mock/definition/collections/fields.yml b/.mock/definition/collections/fields.yml index 08dc554..b56a1d8 100644 --- a/.mock/definition/collections/fields.yml +++ b/.mock/definition/collections/fields.yml @@ -1,24 +1,3 @@ -types: - FieldCreateType: - enum: - - Color - - DateTime - - Email - - ExtFileRef - - File - - Image - - Link - - MultiImage - - Number - - Phone - - PlainText - - RichText - - Switch - - Video - docs: Choose these appropriate field type for your collection data - inline: true - source: - openapi: ../../../openapi/referenced-specs/v2.yml imports: root: ../__package__.yml service: @@ -30,7 +9,7 @@ service: method: POST auth: true docs: > - Create a custom field in a collection. + Create a custom field in a collection. Slugs must be all lowercase letters without spaces. @@ -40,10 +19,7 @@ service: convert the slug to lowercase and replace spaces with "-." - - Only some field types can be created through the API. - - This endpoint does not currently support bulk creation. + This endpoint does not currently support bulk creation. Required scope | `cms:write` @@ -55,48 +31,88 @@ service: docs: Unique identifier for a Collection display-name: Create Collection Field request: - name: FieldCreate - body: - properties: - isRequired: - type: optional - docs: define whether a field is required in a collection - type: - type: FieldCreateType - docs: Choose these appropriate field type for your collection data - displayName: - type: string - docs: The name of a field - helpText: - type: optional - docs: Additional text to help anyone filling out this field + body: root.FieldCreate content-type: application/json response: docs: Request was successful - type: root.Field + type: root.FieldCreate + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError - root.NotFoundError + - root.ConflictError - root.TooManyRequestsError - root.InternalServerError examples: - - path-parameters: + - name: StaticField + path-parameters: collection_id: 580e63fc8c9a982ac9b8b745 request: + id: 562ac0395358780a1f5e6fbc + isEditable: true isRequired: false type: RichText displayName: Post Body helpText: Add the body of your post here response: body: - id: 75821f618da60c18383330bcc0ca488b - isRequired: false + id: 562ac0395358780a1f5e6fbc isEditable: true + isRequired: false type: RichText - slug: post-body displayName: Post Body helpText: Add the body of your post here + - name: OptionField + path-parameters: + collection_id: 580e63fc8c9a982ac9b8b745 + request: + id: 562ac0395358780a1f5e6fbc + isEditable: true + isRequired: false + type: Option + displayName: Post Type + helpText: Add the body of your post here + metadata: + options: + - name: Feature + - name: News + - name: Product Highlight + response: + body: + id: 562ac0395358780a1f5e6fbc + isEditable: true + isRequired: false + type: Option + displayName: Post Type + helpText: Add the body of your post here + metadata: + options: + - name: Feature + - name: News + - name: Product Highlight + - name: ReferenceField + path-parameters: + collection_id: 580e63fc8c9a982ac9b8b745 + request: + id: 562ac0395358780a1f5e6fbd + isEditable: true + isRequired: false + type: Reference + displayName: Author + helpText: Add the post author here + metadata: + collectionId: 63692ab61fb2852f582ba8f5 + response: + body: + id: 562ac0395358780a1f5e6fbd + isEditable: true + isRequired: false + type: Reference + displayName: Author + helpText: Add the post author here + metadata: + collectionId: 63692ab61fb2852f582ba8f5 delete: path: /collections/{collection_id}/fields/{field_id} method: DELETE @@ -162,6 +178,7 @@ service: response: docs: Request was successful type: root.Field + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/collections/items.yml b/.mock/definition/collections/items.yml index f765817..1ae8423 100644 --- a/.mock/definition/collections/items.yml +++ b/.mock/definition/collections/items.yml @@ -68,7 +68,7 @@ types: openapi: ../../../openapi/referenced-specs/v2.yml ItemsDeleteItemsLiveRequestItemsItem: properties: - itemId: + id: type: string docs: Unique identifier for the Item cmsLocaleIds: @@ -166,10 +166,10 @@ service: docs: 'Maximum number of records to be returned (max limit: 100)' name: type: optional - docs: The name of the item(s) + docs: Filter by the exact name of the item(s) slug: type: optional - docs: The slug of the item + docs: Filter by the exact slug of the item sortBy: type: optional docs: Sort results by the provided value @@ -179,6 +179,7 @@ service: response: docs: Request was successful type: root.CollectionItemList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -246,6 +247,7 @@ service: response: docs: Request was successful type: root.CollectionItem + status-code: 202 errors: - root.BadRequestError - root.UnauthorizedError @@ -322,8 +324,8 @@ service: Delete Items from a Collection. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the - items are localized, items will be deleted only in the primary locale. + Items will only be deleted in the primary + locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -356,11 +358,14 @@ service: method: PATCH auth: true docs: > - Update a single item or multiple items (up to 100) in a Collection. + Update a single item or multiple items in a Collection. + + + The limit for this endpoint is 100 items. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the - items are localized, items will be updated only in the primary locale. + Items will only be updated in the primary + locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -380,6 +385,7 @@ service: response: docs: Request was successful type: root.CollectionItem + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -560,7 +566,12 @@ service: method: GET auth: true docs: | - List of all live Items within a Collection. + List all published items in a collection. + + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + Required scope | `CMS:read` source: @@ -590,10 +601,10 @@ service: docs: 'Maximum number of records to be returned (max limit: 100)' name: type: optional - docs: The name of the item(s) + docs: Filter by the exact name of the item(s) slug: type: optional - docs: The slug of the item + docs: Filter by the exact slug of the item sortBy: type: optional docs: Sort results by the provided value @@ -603,6 +614,8 @@ service: response: docs: Request was successful type: root.CollectionItemList + status-code: 200 + url: Data API errors: - root.BadRequestError - root.UnauthorizedError @@ -648,8 +661,8 @@ service: method: POST auth: true docs: > - Create live Item(s) in a Collection. The Item(s) will be published to - the live site. + Create item(s) in a collection that will be immediately published to the + live site. @@ -672,6 +685,7 @@ service: response: docs: Request was successful type: root.CollectionItem + status-code: 202 errors: - root.BadRequestError - root.UnauthorizedError @@ -683,6 +697,9 @@ service: path-parameters: collection_id: 580e63fc8c9a982ac9b8b745 request: + lastPublished: '2023-03-17T18:47:35.560Z' + lastUpdated: '2023-03-17T18:47:35.560Z' + createdOn: '2023-03-17T18:47:35.560Z' isArchived: false isDraft: false fieldData: @@ -711,14 +728,20 @@ service: collection_id: 580e63fc8c9a982ac9b8b745 request: items: - - isArchived: false + - lastPublished: '2023-03-17T18:47:35.560Z' + lastUpdated: '2023-03-17T18:47:35.560Z' + createdOn: '2023-03-17T18:47:35.560Z' + isArchived: false isDraft: false fieldData: name: Senior Data Analyst slug: senior-data-analyst url: https://boards.greenhouse.io/webflow/jobs/26567701 department: Data - - isArchived: false + - lastPublished: '2023-03-17T18:47:35.560Z' + lastUpdated: '2023-03-17T18:47:35.560Z' + createdOn: '2023-03-17T18:47:35.560Z' + isArchived: false isDraft: false fieldData: name: Product Manager @@ -746,13 +769,15 @@ service: auth: true docs: > Remove an item or multiple items (up to 100 items) from the live site. - Deleting published items will unpublish the items from the live site and - set them to draft. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the - items are localized, items will be unpublished only in the primary - locale. + Using this endpoint to delete published item(s) will unpublish the + item(s) from the live site and set the item(s) `isDraft` property to + `true`. + + + Items will only be unpublished in the + primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -784,12 +809,12 @@ service: method: PATCH auth: true docs: > - Update a single live item or multiple live items (up to 100) in a - Collection + Update a single published item or multiple published items (up to 100) + in a Collection - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the - items are localized, items will be updated only in the primary locale. + Items will only be updated in the primary + locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -809,10 +834,12 @@ service: response: docs: Request was successful type: root.CollectionItemListNoPagination + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError - root.NotFoundError + - root.ConflictError - root.TooManyRequestsError - root.InternalServerError examples: @@ -1101,9 +1128,11 @@ service: corresponding locales. - **Notes:** + - This endpoint can create up to 100 items in a request. - - If the `cmsLocaleIds` parameter is undefined or empty and localization is enabled, items will only be created in the primary locale. + - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale. + + Required scope | `CMS:write` source: @@ -1135,6 +1164,7 @@ service: response: docs: Request was successful type: root.BulkCollectionItem + status-code: 202 errors: - root.BadRequestError - root.UnauthorizedError @@ -1298,6 +1328,8 @@ service: response: docs: Request was successful type: root.CollectionItem + status-code: 200 + url: Production errors: - root.BadRequestError - root.UnauthorizedError @@ -1327,10 +1359,8 @@ service: path: /collections/{collection_id}/items/{item_id} method: DELETE auth: true - docs: > - Delete an Item from a Collection. This endpoint does not currently - support bulk deletion. - + docs: | + Delete an item from a collection. Required scope | `CMS:write` source: @@ -1387,6 +1417,7 @@ service: response: docs: Request was successful type: root.CollectionItem + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -1428,6 +1459,11 @@ service: docs: | Get details of a selected Collection live Item. + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + + Required scope | `CMS:read` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -1452,6 +1488,8 @@ service: response: docs: Request was successful type: root.CollectionItem + status-code: 200 + url: Data API errors: - root.BadRequestError - root.UnauthorizedError @@ -1546,10 +1584,12 @@ service: response: docs: Request was successful type: root.CollectionItem + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError - root.NotFoundError + - root.ConflictError - root.TooManyRequestsError - root.InternalServerError examples: @@ -1604,6 +1644,7 @@ service: response: docs: Request was successful type: ItemsPublishItemResponse + status-code: 202 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/components.yml b/.mock/definition/components.yml index b9eb7d6..15a0912 100644 --- a/.mock/definition/components.yml +++ b/.mock/definition/components.yml @@ -33,6 +33,7 @@ service: response: docs: Request was successful type: root.ComponentList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -59,13 +60,9 @@ service: readonly: true - id: 6258612d1ee792848f805dcf name: Card - group: Buttons - description: A button component that can be used across the site readonly: true - id: 68a2b1d1ee792848f805dcf name: Nav - group: Buttons - description: A button component that can be used across the site readonly: true pagination: limit: 20 @@ -120,6 +117,7 @@ service: response: docs: Request was successful type: root.ComponentDom + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -137,33 +135,26 @@ service: body: componentId: 69118560-d0bc-15fc-bbf8-b8fe5f6535b5 nodes: - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad623 - componentId: nodes - propertyOverrides: - - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad627 - componentId: nodes + - id: id + text: {} + attributes: + key: value + type: text + - id: id + text: {} + attributes: + key: value + type: text + - id: id + image: {} + attributes: + key: value + type: image + - id: id + componentId: componentId propertyOverrides: - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad629 - componentId: nodes - propertyOverrides: - - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad631 - componentId: 6258612d1ee792848f805dcf - propertyOverrides: - - propertyId: a245c12d-995b-55ee-5ec7-aa36a6cad633 - type: Plain Text - text: - text: Don't Panic! - - propertyId: a245c12d-995b-55ee-5ec7-aa36a6cad635 - type: Rich Text - text: - html:

Always know where your towel is.

+ type: component-instance pagination: limit: 4 offset: 0 @@ -178,21 +169,21 @@ service: body: componentId: 69118560-d0bc-15fc-bbf8-b8fe5f6535b5 nodes: - - type: component-instance - id: 69118560-d0bc-15fc-bbf8-b8fe5f6535b8 - componentId: nodes + - id: id + image: {} + attributes: + key: value + type: image + - id: id + text: {} + attributes: + key: value + type: text + - id: id + componentId: componentId propertyOverrides: - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: 8ebfb409-7493-3bca-5d48-0e547befb960 - componentId: nodes - propertyOverrides: - - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: 69118560-d0bc-15fc-bbf8-b8fe5f6535c2 - componentId: 69118560-d0bc-15fc-bbf8-b8fe5f6535b5 - propertyOverrides: - - propertyId: a245c12d-995b-55ee-5ec7-aa36a6cad623 + type: component-instance pagination: limit: 100 offset: 0 @@ -255,6 +246,7 @@ service: response: docs: Request was successful type: ComponentsUpdateContentResponse + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -291,10 +283,10 @@ service: method: GET auth: true docs: > - Get the property default values of a component definition. + Get the default property values of a component definition. - If you do not provide a Locale ID in your request, the response + If you do not include a `localeId` in your request, the response will return any properties that can be localized from the Primary locale. @@ -329,6 +321,7 @@ service: response: docs: Request was successful type: root.ComponentProperties + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -366,18 +359,17 @@ service: method: POST auth: true docs: > - Update the property default values of a component definition in a + Update the default property values of a component definition in a specificed locale. - Before making updates: - - 1. Use the [get component + Before making updates, use the [get component properties](/data/reference/pages-and-components/components/get-properties) - endpoint to identify available properties + endpoint to identify properties that can be updated in a secondary + locale. - The request requires a secondary locale ID. If a locale is + The request requires a secondary locale ID. If a `localeId` is missing, the request will not be processed and will result in an error. @@ -412,6 +404,7 @@ service: response: docs: Request was successful type: ComponentsUpdatePropertiesResponse + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/ecommerce.yml b/.mock/definition/ecommerce.yml index 1a2ca95..b3e9857 100644 --- a/.mock/definition/ecommerce.yml +++ b/.mock/definition/ecommerce.yml @@ -22,6 +22,7 @@ service: response: docs: Request was successful type: root.EcommerceSettings + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/forms.yml b/.mock/definition/forms.yml index 9eac177..2288b2b 100644 --- a/.mock/definition/forms.yml +++ b/.mock/definition/forms.yml @@ -33,6 +33,7 @@ service: response: docs: Request was successful type: root.FormList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -108,6 +109,7 @@ service: response: docs: Request was successful type: root.Form + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -127,7 +129,6 @@ service: 660d5bcc9c0772150459dfb1: displayName: Name type: Plain - placeholder: Enter your email userVisible: true 589a331aa51e760df7ccb89d: displayName: Email @@ -137,7 +138,6 @@ service: responseSettings: redirectUrl: https://example.com redirectMethod: GET - redirectAction: POST https://example.com sendEmailConfirmation: true id: 589a331aa51e760df7ccb89e siteId: 580e63e98c9a982ac9b8b741 @@ -153,6 +153,12 @@ service: docs: | List form submissions for a given form + + When a form is used in a component definition, each instance of the form is considered a unique form. + + To get a combined list of submissions for a form that appears across multiple component instances, use the [List Form Submissions by Site](/data/reference/forms/form-submissions/list-submissions-by-site) endpoint. + + Required scope | `forms:read` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -175,6 +181,7 @@ service: response: docs: Request was successful type: root.FormSubmissionList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -226,6 +233,7 @@ service: response: docs: Request was successful type: root.FormSubmission + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -246,6 +254,33 @@ service: formResponse: First Name: Arthur Last Name: Dent + delete-submission: + path: /form_submissions/{form_submission_id} + method: DELETE + auth: true + docs: | + Delete a form submission + + + Required scope | `forms:write` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + form_submission_id: + type: string + docs: Unique identifier for a Form Submission + display-name: Delete Form Submission + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.ForbiddenError + - root.NotFoundError + - root.ConflictError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + form_submission_id: 580e63e98c9a982ac9b8b741 update-submission: path: /form_submissions/{form_submission_id} method: PATCH @@ -274,6 +309,7 @@ service: response: docs: Request was successful type: root.FormSubmission + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -296,6 +332,82 @@ service: formResponse: First Name: Arthur Last Name: Dent + list-submissions-by-site: + path: /sites/{site_id}/form_submissions + method: GET + auth: true + docs: > + List form submissions for a given site. This endpoint differs from the + existing [List Form Submissions + endpoint](/data/reference/forms/form-submissions/list-submissions) by + accepting `siteId` as a path parameter and `elementId` as a query + parameter. You can get the `elementId` from the [List forms + endpoint](/data/reference/forms/forms/list). + + + + + Required scope | `forms:read` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: List Form Submissions by Site + request: + name: FormsListSubmissionsBySiteRequest + query-parameters: + elementId: + type: optional + docs: Identifier for an element + offset: + type: optional + docs: >- + Offset used for pagination if the results have more than limit + records + limit: + type: optional + docs: 'Maximum number of records to be returned (max limit: 100)' + response: + docs: Request was successful + type: root.FormSubmissionList + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.ForbiddenError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + query-parameters: + elementId: 18259716-3e5a-646a-5f41-5dc4b9405aa0 + response: + body: + formSubmissions: + - id: 6321ca84df3949bfc6752327 + displayName: Sample Form + siteId: 62749158efef318abc8d5a0f + workspaceId: 62749158efef318abc8d5a0f + dateSubmitted: '2022-09-14T12:35:16Z' + formResponse: + First Name: Arthur + Last Name: Dent + - id: 660d64fabf6e0a0d4edab981 + displayName: Sample Form + siteId: 62749158efef318abc8d5a0f + workspaceId: 62749158efef318abc8d5a0f + dateSubmitted: '2022-09-14T12:35:16Z' + formResponse: + First Name: Ford + Last Name: Prefect + pagination: + limit: 25 + offset: 0 + total: 2 source: openapi: ../../../openapi/referenced-specs/v2.yml display-name: Forms diff --git a/.mock/definition/inventory.yml b/.mock/definition/inventory.yml index 5e69c29..2c4a7c9 100644 --- a/.mock/definition/inventory.yml +++ b/.mock/definition/inventory.yml @@ -25,6 +25,7 @@ service: response: docs: Request was successful type: root.InventoryItem + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -88,6 +89,7 @@ service: response: docs: Request was successful type: root.InventoryItem + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/orders.yml b/.mock/definition/orders.yml index b2802cf..3716634 100644 --- a/.mock/definition/orders.yml +++ b/.mock/definition/orders.yml @@ -57,6 +57,7 @@ service: response: docs: Request was successful type: root.OrderList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -81,11 +82,6 @@ service: Please gift wrap with a personal note saying "Happy Birthday, Ford! 🎉 acceptedOn: '2024-04-10T13:16:21Z' - fulfilledOn: '2018-12-03T22:06:15Z' - refundedOn: '2018-12-03T22:06:15Z' - disputedOn: '2018-12-03T22:06:15Z' - disputeUpdatedOn: '2018-12-03T22:06:15Z' - disputeLastStatus: warning_needs_response customerPaid: unit: USD value: '5892' @@ -201,13 +197,6 @@ service: expires: year: 2025 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: @@ -235,11 +224,7 @@ service: comment: Example comment to myself orderComment: '' acceptedOn: '2024-03-29T21:29:21Z' - fulfilledOn: '2018-12-03T22:06:15Z' refundedOn: '2024-04-08T18:25:04Z' - disputedOn: '2018-12-03T22:06:15Z' - disputeUpdatedOn: '2018-12-03T22:06:15Z' - disputeLastStatus: warning_needs_response customerPaid: unit: USD value: '5892' @@ -359,13 +344,6 @@ service: expires: year: 2024 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: @@ -436,6 +414,7 @@ service: response: docs: Request was successful type: root.Order + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -571,12 +550,10 @@ service: length: 40 purchasedItemsCount: 2 stripeDetails: - subscriptionId: sub_1J6xwG2eZvKYlo2CXu9Zt0Tn paymentMethod: pm_1OzmzBJYFi4lcbXWHKNdXU7j paymentIntentId: pi_3OzmzDJYFi4lcbXW1hTBW6ft customerId: cus_PpRsNHwWdUoRKR chargeId: ch_3OzmzDJYFi4lcbXW1ndkkrH2 - disputeId: disputeId refundId: re_3OzmzDJYFi4lcbXW1kFAmlBk refundReason: fraudulent stripeCard: @@ -586,13 +563,6 @@ service: expires: year: 2024 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: @@ -677,6 +647,7 @@ service: response: docs: Request was successful type: root.Order + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -813,12 +784,10 @@ service: length: 40 purchasedItemsCount: 2 stripeDetails: - subscriptionId: sub_1J6xwG2eZvKYlo2CXu9Zt0Tn paymentMethod: pm_1OzmzBJYFi4lcbXWHKNdXU7j paymentIntentId: pi_3OzmzDJYFi4lcbXW1hTBW6ft customerId: cus_PpRsNHwWdUoRKR chargeId: ch_3OzmzDJYFi4lcbXW1ndkkrH2 - disputeId: disputeId refundId: re_3OzmzDJYFi4lcbXW1kFAmlBk refundReason: fraudulent stripeCard: @@ -828,13 +797,6 @@ service: expires: year: 2024 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: @@ -909,6 +871,7 @@ service: response: docs: Request was successful type: root.Order + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -1045,12 +1008,10 @@ service: length: 40 purchasedItemsCount: 2 stripeDetails: - subscriptionId: sub_1J6xwG2eZvKYlo2CXu9Zt0Tn paymentMethod: pm_1OzmzBJYFi4lcbXWHKNdXU7j paymentIntentId: pi_3OzmzDJYFi4lcbXW1hTBW6ft customerId: cus_PpRsNHwWdUoRKR chargeId: ch_3OzmzDJYFi4lcbXW1ndkkrH2 - disputeId: disputeId refundId: re_3OzmzDJYFi4lcbXW1kFAmlBk refundReason: fraudulent stripeCard: @@ -1060,13 +1021,6 @@ service: expires: year: 2024 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: @@ -1132,6 +1086,7 @@ service: response: docs: Request was successful type: root.Order + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -1267,12 +1222,10 @@ service: length: 40 purchasedItemsCount: 2 stripeDetails: - subscriptionId: sub_1J6xwG2eZvKYlo2CXu9Zt0Tn paymentMethod: pm_1OzmzBJYFi4lcbXWHKNdXU7j paymentIntentId: pi_3OzmzDJYFi4lcbXW1hTBW6ft customerId: cus_PpRsNHwWdUoRKR chargeId: ch_3OzmzDJYFi4lcbXW1ndkkrH2 - disputeId: disputeId refundId: re_3OzmzDJYFi4lcbXW1kFAmlBk refundReason: fraudulent stripeCard: @@ -1282,13 +1235,6 @@ service: expires: year: 2024 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: @@ -1363,6 +1309,7 @@ service: response: docs: Request was successful type: root.Order + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -1499,12 +1446,10 @@ service: length: 40 purchasedItemsCount: 2 stripeDetails: - subscriptionId: sub_1J6xwG2eZvKYlo2CXu9Zt0Tn paymentMethod: pm_1OzmzBJYFi4lcbXWHKNdXU7j paymentIntentId: pi_3OzmzDJYFi4lcbXW1hTBW6ft customerId: cus_PpRsNHwWdUoRKR chargeId: ch_3OzmzDJYFi4lcbXW1ndkkrH2 - disputeId: disputeId refundId: re_3OzmzDJYFi4lcbXW1kFAmlBk refundReason: fraudulent stripeCard: @@ -1514,13 +1459,6 @@ service: expires: year: 2024 month: 4 - paypalDetails: - orderId: 1a2b3c4d5e6f7g8h9i0j - payerId: 9k8j7i6h5g4f3e2d1c0b - captureId: qwe123rty456uio789p - refundId: abcde12345fghij67890 - refundReason: Customer requested refund - disputeId: zxcvbnm987poiuytrewq customData: - key: value metadata: diff --git a/.mock/definition/pages.yml b/.mock/definition/pages.yml index 62de7dc..fbfcd68 100644 --- a/.mock/definition/pages.yml +++ b/.mock/definition/pages.yml @@ -38,6 +38,7 @@ service: response: docs: Request was successful type: root.PageList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -56,8 +57,6 @@ service: siteId: 6258612d1ee792848f805dcf title: Guide to the Galaxy slug: guide-to-the-galaxy - parentId: 6419db964a9c435aa3af6251 - collectionId: 6390c49774a71f12831a08e3 createdOn: '2024-03-11T10:42:00Z' lastUpdated: '2024-03-11T10:42:42Z' archived: false @@ -83,8 +82,6 @@ service: siteId: 6258612d1ee792848f805dcf title: Towel Day Celebrations slug: towel-day - parentId: 6419db964a9c435aa3af6251 - collectionId: 6390c49774a71f12831a08e3 createdOn: '2024-05-25T09:00:00Z' lastUpdated: '2024-05-25T09:42:00Z' archived: false @@ -138,6 +135,7 @@ service: response: docs: Request was successful type: root.Page + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -155,8 +153,6 @@ service: siteId: 6258612d1ee792848f805dcf title: Guide to the Galaxy slug: guide-to-the-galaxy - parentId: 6419db964a9c435aa3af6251 - collectionId: 6390c49774a71f12831a08e3 createdOn: '2024-03-11T10:42:00Z' lastUpdated: '2024-03-11T10:42:42Z' archived: false @@ -185,6 +181,10 @@ service: docs: | Update Page-level metadata, including SEO and Open Graph fields. + + Note: When updating Page Metadata in secondary locales, you may only add `slug` to the request if your Site has the [Advanced or Enterprise Localization](https://webflow.com/localization) add-on. + + Required scope | `pages:write` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -206,6 +206,7 @@ service: response: docs: Request was successful type: root.Page + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -248,8 +249,6 @@ service: siteId: 6258612d1ee792848f805dcf title: Guide to the Galaxy slug: guide-to-the-galaxy - parentId: 6419db964a9c435aa3af6251 - collectionId: 6390c49774a71f12831a08e3 createdOn: '2024-03-11T10:42:00Z' lastUpdated: '2024-03-11T10:42:42Z' archived: false @@ -276,16 +275,18 @@ service: method: GET auth: true docs: > - Get static content from a static page. This includes text nodes, image - nodes and component instances. + Get content from a static page. This includes text nodes, image nodes, + and component instances with [property + overrides](https://help.webflow.com/hc/en-us/articles/33961219350547-Component-properties#how-to-modify-property-values-on-component-instances). - To retrieve the contents of components in the page use the [get - component - content](/data/reference/pages-and-components/components/get-content) + + To retrieve the static content of a component instance, use the [Get + Component + Content](/data/reference/pages-and-components/components/get-content) endpoint. - If you do not provide a Locale ID in your request, the response + If you do not include a `localeId` in your request, the response will return any content that can be localized from the Primary locale. @@ -317,6 +318,7 @@ service: response: docs: Request was successful type: root.Dom + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -334,39 +336,31 @@ service: body: pageId: 658205daa3e8206a523b5ad4 nodes: - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad623 - componentId: nodes + - id: id + text: {} + attributes: + key: value + type: text + - id: id + text: {} + attributes: + key: value + type: text + - id: id + image: {} + attributes: + key: value + type: image + - id: id + componentId: componentId propertyOverrides: - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad627 - componentId: nodes - propertyOverrides: - - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad629 - componentId: nodes - propertyOverrides: - - propertyId: 7dd14c08-2e96-8d3d-2b19-b5c03642a0f0 - - type: component-instance - id: a245c12d-995b-55ee-5ec7-aa36a6cad631 - componentId: 6258612d1ee792848f805dcf - propertyOverrides: - - propertyId: a245c12d-995b-55ee-5ec7-aa36a6cad633 - type: Plain Text - label: Catchphrase - text: - text: Don't Panic! - - propertyId: a245c12d-995b-55ee-5ec7-aa36a6cad635 - type: Rich Text - label: Tagline - text: - html:

Always know where your towel is.

+ type: component-instance pagination: limit: 4 offset: 0 total: 4 + lastUpdated: '2016-10-24T19:42:38Z' update-static-content: path: /pages/{page_id}/dom method: POST @@ -418,6 +412,7 @@ service: response: docs: Request was successful type: UpdateStaticContentResponse + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/pages/scripts.yml b/.mock/definition/pages/scripts.yml index f8ee328..d0971af 100644 --- a/.mock/definition/pages/scripts.yml +++ b/.mock/definition/pages/scripts.yml @@ -8,22 +8,8 @@ service: path: /pages/{page_id}/custom_code method: GET auth: true - docs: > - Get all registered scripts that have been applied to a specific Page. - - - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). - + docs: | + Get all scripts applied to a page. Required scope | `custom_code:read` source: @@ -36,6 +22,7 @@ service: response: docs: Request was successful type: root.ScriptApplyList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -59,25 +46,12 @@ service: path: /pages/{page_id}/custom_code method: PUT auth: true - docs: > - Add a registered script to a Page. - - - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. - - - A site can have a maximum of 800 registered scripts. - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + docs: | + Apply scripts to a page. + + To apply a script to a page, the script must first be registered to a Site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write` source: @@ -93,6 +67,7 @@ service: response: docs: Request was successful type: root.ScriptApplyList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -133,16 +108,7 @@ service: method: DELETE auth: true docs: > - Delete the custom code block that an app has created for a page - - - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. + Delete a custom code block that the App created on a page. Access to this endpoint requires a bearer token from a [Data diff --git a/.mock/definition/products.yml b/.mock/definition/products.yml index 4c6fcd1..f505fc3 100644 --- a/.mock/definition/products.yml +++ b/.mock/definition/products.yml @@ -41,6 +41,7 @@ service: response: docs: Request was successful type: root.ProductAndSkUsList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -83,13 +84,15 @@ service: createdOn: '2023-03-17T18:47:35Z' fieldData: sku-values: - ff42fee0113744f693a764e3431a9cc2: 64a74715c456e36762fc39a1 - name: Blue T-shirt - slug: t-shirt-blue + color: red + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default price: - value: 100 + value: 2499 unit: USD + currency: USD quantity: 10 + main-image: https://www.example.com/image.jpg pagination: limit: 100 offset: 0 @@ -132,12 +135,13 @@ service: body: properties: publishStatus: optional - product: optional - sku: optional + product: ProductSkuCreateProduct + sku: ProductSkuCreateSku content-type: application/json response: docs: Request was successful type: root.ProductAndSkUs + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -149,7 +153,50 @@ service: examples: - path-parameters: site_id: 580e63e98c9a982ac9b8b741 - request: {} + request: + publishStatus: staging + product: + fieldData: + name: Colorful T-shirt + slug: colorful-t-shirt + description: >- + Our best-selling t-shirt available in multiple colors and + sizes + sku-properties: + - id: color + name: Color + enum: + - id: red + name: Red + slug: red + - id: yellow + name: Yellow + slug: yellow + - id: blue + name: Blue + slug: blue + - id: size + name: Size + enum: + - id: small + name: Small + slug: small + - id: medium + name: Medium + slug: medium + - id: large + name: Large + slug: large + sku: + fieldData: + name: Colorful T-shirt - Red Small + slug: colorful-t-shirt-red-small + price: + value: 2499 + unit: USD + currency: USD + main-image: >- + https://rocketamp-sample-store.myshopify.com/cdn/shop/products/Gildan_2000_Antique_Cherry_Red_Front_1024x1024.jpg?v=1527232987 response: body: product: @@ -185,13 +232,15 @@ service: createdOn: '2023-03-17T18:47:35Z' fieldData: sku-values: - ff42fee0113744f693a764e3431a9cc2: 64a74715c456e36762fc39a1 - name: Blue T-shirt - slug: t-shirt-blue + color: red + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default price: - value: 100 + value: 2499 unit: USD + currency: USD quantity: 10 + main-image: https://www.example.com/image.jpg get: path: /sites/{site_id}/products/{product_id} method: GET @@ -214,6 +263,7 @@ service: response: docs: Request was successful type: root.ProductAndSkUs + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -261,13 +311,15 @@ service: createdOn: '2023-03-17T18:47:35Z' fieldData: sku-values: - ff42fee0113744f693a764e3431a9cc2: 64a74715c456e36762fc39a1 - name: Blue T-shirt - slug: t-shirt-blue + color: red + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default price: - value: 100 + value: 2499 unit: USD + currency: USD quantity: 10 + main-image: https://www.example.com/image.jpg update: path: /sites/{site_id}/products/{product_id} method: PATCH @@ -303,6 +355,7 @@ service: response: docs: Request was successful type: root.Product + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -379,6 +432,7 @@ service: response: docs: Request was successful type: ProductsCreateSkuResponse + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -393,7 +447,13 @@ service: product_id: 580e63fc8c9a982ac9b8b745 request: skus: - - {} + - fieldData: + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default + price: + value: 2499 + unit: USD + currency: USD response: body: skus: @@ -404,13 +464,15 @@ service: createdOn: '2023-03-17T18:47:35Z' fieldData: sku-values: - ff42fee0113744f693a764e3431a9cc2: 64a74715c456e36762fc39a1 - name: Blue T-shirt - slug: t-shirt-blue + color: red + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default price: - value: 100 + value: 2499 unit: USD + currency: USD quantity: 10 + main-image: https://www.example.com/image.jpg update-sku: path: /sites/{site_id}/products/{product_id}/skus/{sku_id} method: PATCH @@ -448,6 +510,7 @@ service: response: docs: Request was successful type: root.Sku + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -462,7 +525,14 @@ service: product_id: 580e63fc8c9a982ac9b8b745 sku_id: 5e8518516e147040726cc415 request: - sku: {} + sku: + fieldData: + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default + price: + value: 2499 + unit: USD + currency: USD response: body: id: 580e63fc8c9a982ac9b8b745 @@ -472,12 +542,13 @@ service: createdOn: '2023-03-17T18:47:35Z' fieldData: sku-values: - ff42fee0113744f693a764e3431a9cc2: 64a74715c456e36762fc39a1 - name: Blue T-shirt - slug: t-shirt-blue + color: red + name: Colorful T-shirt - Default + slug: colorful-t-shirt-default price: - value: 100 + value: 2499 unit: USD + currency: USD compare-at-price: value: 100 unit: USD @@ -490,11 +561,24 @@ service: - {} track-inventory: true quantity: 10 + main-image: https://www.example.com/image.jpg source: openapi: ../../../openapi/referenced-specs/v2.yml types: + ProductSkuCreateProduct: + properties: + fieldData: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true + ProductSkuCreateSku: + properties: + fieldData: optional + source: + openapi: ../../../openapi/referenced-specs/v2.yml + inline: true ProductsCreateSkuResponse: properties: - skus: optional> + skus: list source: openapi: ../../../openapi/referenced-specs/v2.yml diff --git a/.mock/definition/scripts.yml b/.mock/definition/scripts.yml index 8236ed2..e761eda 100644 --- a/.mock/definition/scripts.yml +++ b/.mock/definition/scripts.yml @@ -9,23 +9,13 @@ service: method: GET auth: true docs: > - List of scripts registered to a Site. + Get a list of scripts that have been registered to a site. A site can + have a maximum of 800 registered scripts. - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. - - Additionally, Scripts can be remotely hosted, or registered as inline - snippets. - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:read` @@ -39,6 +29,7 @@ service: response: docs: Request was successful type: root.RegisteredScriptList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -55,7 +46,6 @@ service: canCopy: false displayName: Alert hostedLocation: https://cdn.webflow.io/.../alert-0.0.1.js - integrityHash: integrityHash createdOn: '2022-10-26T00:28:54.191Z' lastUpdated: lastUpdated version: 0.0.1 @@ -63,7 +53,6 @@ service: canCopy: false displayName: Alert hostedLocation: https://cdn.webflow.io/.../alert-0.0.2.js - integrityHash: integrityHash createdOn: '2022-10-26T00:28:54.191Z' lastUpdated: lastUpdated version: 0.0.2 @@ -80,25 +69,12 @@ service: path: /sites/{site_id}/registered_scripts/hosted method: POST auth: true - docs: > - Add a script to a Site's Custom Code registry. - - - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. - - Additionally, Scripts can be remotely hosted, or registered as inline - snippets. - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + docs: | + Register a hosted script to a site. + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write` source: @@ -138,6 +114,7 @@ service: response: docs: Request was successful type: root.CustomCodeHostedResponse + status-code: 201 errors: - root.BadRequestError - root.UnauthorizedError @@ -168,21 +145,13 @@ service: method: POST auth: true docs: > - Add a script to a Site's Custom Code registry. Inline scripts can be - between 1 and 2000 characters. - - - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. + Register an inline script to a site. Inline scripts are limited to 2000 + characters. - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write` @@ -225,6 +194,7 @@ service: response: docs: Created type: root.CustomCodeInlineResponse + status-code: 201 errors: - root.BadRequestError - root.UnauthorizedError @@ -245,7 +215,6 @@ service: displayName: Alert hostedLocation: >- https://uploads-ssl.webflow.com/6258612d1ee792848f805dcf%2F64b6c769ff52ba6c3d904a91%2F660d6e15b3d1696f2d2b1447%2Falert-0.0.1.js - integrityHash: integrityHash createdOn: '2022-10-26T00:28:54.191Z' lastUpdated: lastUpdated version: 0.0.1 diff --git a/.mock/definition/sites.yml b/.mock/definition/sites.yml index cea8997..ef1064d 100644 --- a/.mock/definition/sites.yml +++ b/.mock/definition/sites.yml @@ -8,8 +8,13 @@ service: path: /workspaces/{workspace_id}/sites method: POST auth: true - docs: | - Create a site. This endpoint requires an Enterprise workspace. + docs: > + Create a site. + + + This endpoint requires an Enterprise + workspace. + Required scope | `workspace:write` source: @@ -36,6 +41,7 @@ service: response: docs: Request was successful type: root.Site + status-code: 201 errors: - root.BadRequestError - root.UnauthorizedError @@ -56,34 +62,12 @@ service: createdOn: '2024-10-15T20:24:38Z' displayName: The Hitchiker‘s Guide shortName: hitchikers-guide - lastPublished: '2016-10-24T19:43:17Z' lastUpdated: '2024-10-15T20:24:38Z' - previewUrl: >- - https://d1otoma47x30pg.cloudfront.net/580e63e98c9a982ac9b8b741/201610241243.png - timeZone: America/Los_Angeles parentFolderId: 670ece123598db72d9648be1 customDomains: - id: 589a331aa51e760df7ccb89d url: test-api-domain.com lastPublished: '2022-12-07T16:51:37Z' - locales: - primary: - id: 653fd9af6a07fc9cfd7a5e57 - cmsLocaleId: 653ad57de882f528b32e810e - enabled: false - displayName: English (United States) - displayImageId: displayImageId - redirect: true - subdirectory: '' - tag: en-US - secondary: - - id: 653fd9af6a07fc9cfd7a5e57 - cmsLocaleId: 653ad57de882f528b32e810e - enabled: false - displayName: English (United States) - redirect: true - subdirectory: '' - tag: en-US dataCollectionEnabled: false dataCollectionType: always list: @@ -100,6 +84,7 @@ service: response: docs: Request was successful type: root.Sites + status-code: 200 errors: - root.UnauthorizedError - root.NotFoundError @@ -159,7 +144,6 @@ service: previewUrl: >- https://d1otoma47x30pg.cloudfront.net/42e63e98c9a982ac9b8b742/198110121200.png timeZone: DeepSpace/Depression - parentFolderId: 1as2d3f4g5h6j7k8l9z0x1c2v3b4n5m6 customDomains: - id: 589a331aa51e760df7ccb89f url: marvin.blog @@ -193,7 +177,6 @@ service: previewUrl: >- https://d1otoma47x30pg.cloudfront.net/42e63e98c9a982ac9b8b743/198210121200.png timeZone: Vogsphere/PoetryHall - parentFolderId: 1as2d3f4g5h6j7k8l9z0x1c2v3b4n5m6 customDomains: - id: 589a331aa51e760df7ccb8a0 url: vogonpoetry.galaxy @@ -235,6 +218,7 @@ service: response: docs: Request was successful type: root.Site + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -288,8 +272,13 @@ service: path: /sites/{site_id} method: DELETE auth: true - docs: | - Delete a site. This endpoint requires an Enterprise workspace. + docs: > + Delete a site. + + + This endpoint requires an Enterprise + workspace. + Required scope | `sites:write` source: @@ -313,8 +302,13 @@ service: path: /sites/{site_id} method: PATCH auth: true - docs: | - Update a site. This endpoint requires an Enterprise workspace. + docs: > + Update a site. + + + This endpoint requires an Enterprise + workspace. + Required scope | `sites:write` source: @@ -338,6 +332,7 @@ service: response: docs: Request was successful type: root.Site + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -407,6 +402,7 @@ service: response: docs: Request was successful type: root.Domains + status-code: 200 errors: - root.UnauthorizedError - root.ForbiddenError @@ -460,6 +456,7 @@ service: response: docs: Request accepted type: SitesPublishResponse + status-code: 202 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/sites/activityLogs.yml b/.mock/definition/sites/activityLogs.yml index 1468f52..adf24a5 100644 --- a/.mock/definition/sites/activityLogs.yml +++ b/.mock/definition/sites/activityLogs.yml @@ -8,9 +8,15 @@ service: path: /sites/{site_id}/activity_logs method: GET auth: true - docs: >- - Retrieve Activity Logs for a specific Site. Requires Site to be on an - Enterprise plan.

Required scope | `site_activity:read` + docs: > + Retrieve Activity Logs for a specific Site. + + + This endpoint requires an Enterprise + workspace. + + + Required scope: `site_activity:read` source: openapi: ../../../openapi/referenced-specs/v2.yml path-parameters: @@ -32,6 +38,7 @@ service: response: docs: A list of site activity logs type: root.SiteActivityLogResponse + status-code: 200 errors: - root.ForbiddenError - root.NotFoundError @@ -53,10 +60,6 @@ service: displayName: John Doe resourceId: 654c16c7b229e56bcf26870c resourceName: foo-bar - newValue: newValue - previousValue: previousValue - payload: - key: value pagination: limit: 25 offset: 0 diff --git a/.mock/definition/sites/comments.yml b/.mock/definition/sites/comments.yml new file mode 100644 index 0000000..64989c0 --- /dev/null +++ b/.mock/definition/sites/comments.yml @@ -0,0 +1,216 @@ +types: + CommentsListCommentThreadsRequestSortBy: + enum: + - createdOn + - lastUpdated + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentsListCommentThreadsRequestSortOrder: + enum: + - asc + - desc + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentsGetCommentThreadRequestSortBy: + enum: + - createdOn + - lastUpdated + source: + openapi: ../../../openapi/referenced-specs/v2.yml + CommentsGetCommentThreadRequestSortOrder: + enum: + - asc + - desc + source: + openapi: ../../../openapi/referenced-specs/v2.yml +imports: + root: ../__package__.yml +service: + auth: false + base-path: '' + endpoints: + list-comment-threads: + path: /sites/{site_id}/comments + method: GET + auth: true + docs: | + List all comment threads for a site. + + Required scope | `comments:read` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: List Comment Threads + request: + name: CommentsListCommentThreadsRequest + query-parameters: + localeId: + type: optional + docs: >- + Unique identifier for a specific locale. Applicable, when using + localization. + offset: + type: optional + docs: >- + Offset used for pagination if the results have more than limit + records + limit: + type: optional + docs: 'Maximum number of records to be returned (max limit: 100)' + sortBy: + type: optional + docs: >- + Sort results by the provided value. Only allowed when sortOrder is + provided. + sortOrder: + type: optional + docs: Sorts the results by asc or desc + response: + docs: Request was successful + type: root.CommentThreadList + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + query-parameters: + localeId: 65427cf400e02b306eaa04a0 + response: + body: + comments: + - id: 679d2ddb5196117ad04d1ffa + siteId: 679826b3b20b045e176bc4b5 + pageId: 679826b3b20b045e176bc4bc + localeId: 67993753d910db250db64b3e + itemId: 580e64008c9a982ac9b8b754 + breakpoint: main + url: >- + https://webflow.com/design/site-slug-4ec832?workflow=comment&commentId=679d2ddb5196117ad04d1ff8&pageId=679826b3b20b045e176bc4bc + content: 'Let''s go to the pub! [[6287ec36a841b25637c663df]] ' + isResolved: false + author: + userId: 6287ec36a841b25637c663df + email: ford.prefect@heartofgold.spaceship + name: Ford Prefect + mentionedUsers: + - userId: 6287ec36a841b25637c663df + email: arthur.dent@heartofgold.spaceship + name: Arthur Dent + createdOn: '2025-01-31T20:08:59.759Z' + lastUpdated: '2025-01-31T20:08:59.759Z' + - id: 679d2ddb5196117ad04d1ffc + siteId: 679826b3b20b045e176bc4b5 + pageId: 679826b3b20b045e176bc4bc + localeId: 67993753d910db250db64b3e + itemId: 580e64008c9a982ac9b8b754 + breakpoint: main + url: >- + https://webflow.com/design/site-slug-4ec832?workflow=comment&commentId=679d2ddb5196117ad04d1ff8&pageId=679826b3b20b045e176bc4bc + content: >- + You have five minutes left to drink it + [[6287ec36a841b25637c663df]] + isResolved: false + author: + userId: 6287ec36a841b25637c663df + email: ford.prefect@heartofgold.spaceship + name: Ford Prefect + mentionedUsers: + - userId: 6287ec36a841b25637c663df + email: arthur.dent@heartofgold.spaceship + name: Arthur Dent + createdOn: '2025-01-31T20:08:59.759Z' + lastUpdated: '2025-01-31T20:08:59.759Z' + pagination: + limit: 2 + offset: 0 + total: 2 + get-comment-thread: + path: /sites/{site_id}/comments/{comment_thread_id} + method: GET + auth: true + docs: | + Get details of a specific comment thread. + + Required scope | `comments:read` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + comment_thread_id: + type: string + docs: Unique identifier for a Comment Thread + display-name: Get Comment Thread + request: + name: CommentsGetCommentThreadRequest + query-parameters: + localeId: + type: optional + docs: >- + Unique identifier for a specific locale. Applicable, when using + localization. + offset: + type: optional + docs: >- + Offset used for pagination if the results have more than limit + records + limit: + type: optional + docs: 'Maximum number of records to be returned (max limit: 100)' + sortBy: + type: optional + docs: >- + Sort results by the provided value. Only allowed when sortOrder is + provided. + sortOrder: + type: optional + docs: Sorts the results by asc or desc + response: + docs: Request was successful + type: root.CommentThread + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + comment_thread_id: 580e63e98c9a982ac9b8b741 + query-parameters: + localeId: 65427cf400e02b306eaa04a0 + response: + body: + id: 580e64008c9a982ac9b8b754 + siteId: 580e64008c9a982ac9b8b754 + pageId: 580e64008c9a982ac9b8b754 + localeId: 580e64008c9a982ac9b8b754 + itemId: 580e64008c9a982ac9b8b754 + breakpoint: main + url: >- + https://webflow.com/design/site-slug-4ec832?workflow=comment&commentId=679d2ddb5196117ad04d1ff8&pageId=679826b3b20b045e176bc4bc + content: This is a comment reply + isResolved: true + author: + userId: userId + email: email + name: name + mentionedUsers: + - userId: 6287ec36a841b25637c663df + email: arthur.dent@heartofgold.spaceship + name: Arthur Dent + createdOn: '2023-03-17T18:47:35.560Z' + lastUpdated: '2023-03-17T18:47:35.560Z' + source: + openapi: ../../../openapi/referenced-specs/v2.yml diff --git a/.mock/definition/sites/comments/replies.yml b/.mock/definition/sites/comments/replies.yml new file mode 100644 index 0000000..fbfd39f --- /dev/null +++ b/.mock/definition/sites/comments/replies.yml @@ -0,0 +1,106 @@ +types: + RepliesListRepliesRequestSortBy: + enum: + - createdOn + - lastUpdated + source: + openapi: ../../../openapi/referenced-specs/v2.yml + RepliesListRepliesRequestSortOrder: + enum: + - asc + - desc + source: + openapi: ../../../openapi/referenced-specs/v2.yml +imports: + root: ../../__package__.yml +service: + auth: false + base-path: '' + endpoints: + list-replies: + path: /sites/{site_id}/comments/{comment_thread_id}/replies + method: GET + auth: true + docs: | + List all replies to a specific comment thread. + + Required scope | `comments:read` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + comment_thread_id: + type: string + docs: Unique identifier for a Comment Thread + display-name: List Comment Replies + request: + name: RepliesListRepliesRequest + query-parameters: + localeId: + type: optional + docs: >- + Unique identifier for a specific locale. Applicable, when using + localization. + offset: + type: optional + docs: >- + Offset used for pagination if the results have more than limit + records + limit: + type: optional + docs: 'Maximum number of records to be returned (max limit: 100)' + sortBy: + type: optional + docs: >- + Sort results by the provided value. Only allowed when sortOrder is + provided. + sortOrder: + type: optional + docs: Sorts the results by asc or desc + response: + docs: Request was successful + type: root.CommentReplyList + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + comment_thread_id: 580e63e98c9a982ac9b8b741 + query-parameters: + localeId: 65427cf400e02b306eaa04a0 + response: + body: + comments: + - id: 679d2ddb5196117ad04d1ffa + commentId: 679d2ddb5196117ad04d1ff8 + siteId: 679826b3b20b045e176bc4b5 + pageId: 679826b3b20b045e176bc4bc + localeId: 67993753d910db250db64b3e + breakpoint: main + content: >- + This comment mentions another user + [[6287ec36a841b25637c663df]] + isResolved: false + author: + id: id + email: email + name: name + mentionedUsers: + - id: id + email: arthur.dent@example.com + name: Arthur Dent + lastUpdated: '2025-01-31T20:08:59.759Z' + createdOn: '2025-01-31T20:08:59.759Z' + pagination: + limit: 2 + offset: 0 + total: 1 + source: + openapi: ../../../openapi/referenced-specs/v2.yml diff --git a/.mock/definition/sites/plans.yml b/.mock/definition/sites/plans.yml index ae9de6d..f507373 100644 --- a/.mock/definition/sites/plans.yml +++ b/.mock/definition/sites/plans.yml @@ -8,9 +8,14 @@ service: path: /sites/{site_id}/plan method: GET auth: true - docs: | + docs: > Get site plan details for the specified Site. + + This endpoint requires an Enterprise + workspace. + + Required scope | `sites:read` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -22,6 +27,7 @@ service: response: docs: Request was successful type: root.SitePlan + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/sites/redirects.yml b/.mock/definition/sites/redirects.yml index b104d86..8eca766 100644 --- a/.mock/definition/sites/redirects.yml +++ b/.mock/definition/sites/redirects.yml @@ -16,6 +16,9 @@ service: control how traffic is rerouted on your site. + This endpoint requires an Enterprise + workspace. + Required scope: `sites:read` source: @@ -28,6 +31,7 @@ service: response: docs: Request was successful type: root.Redirects + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -64,6 +68,10 @@ service: restructuring URLs, or handling outdated links. + This endpoint requires an Enterprise + workspace. + + Required scope: `sites:write` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -78,6 +86,7 @@ service: response: docs: Request was successful type: root.Redirect + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -103,10 +112,16 @@ service: docs: > Remove a URL redirection rule from a site. + This is useful for cleaning up outdated or unnecessary redirects, ensuring that your site's routing behavior remains efficient and up-to-date. + + This endpoint requires an Enterprise + workspace. + + Required scope: `sites:write` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -121,6 +136,7 @@ service: response: docs: Request was successful type: root.Redirects + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -148,8 +164,14 @@ service: path: /sites/{site_id}/redirects/{redirect_id} method: PATCH auth: true - docs: | + docs: > Update a URL redirection rule from a site. + + + This endpoint requires an Enterprise + workspace. + + Required scope: `sites:write` source: openapi: ../../../openapi/referenced-specs/v2.yml @@ -167,6 +189,7 @@ service: response: docs: Request was successful type: root.Redirect + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/sites/robotsTxt.yml b/.mock/definition/sites/robotsTxt.yml new file mode 100644 index 0000000..032bce5 --- /dev/null +++ b/.mock/definition/sites/robotsTxt.yml @@ -0,0 +1,202 @@ +imports: + root: ../__package__.yml +service: + auth: false + base-path: '' + endpoints: + get: + path: /sites/{site_id}/robots_txt + method: GET + auth: true + docs: | + Retrieve the robots.txt configuration for various user agents. + + Required scope: `site_config:read` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: Get robots.txt + response: + docs: Request was successful + type: root.Robots + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + response: + body: + rules: + - userAgent: googlebot + allows: + - /public + disallows: + - /vogon-poetry + - /total-perspective-vortex + sitemap: https://heartofgold.ship/sitemap.xml + put: + path: /sites/{site_id}/robots_txt + method: PUT + auth: true + docs: | + Replace the `robots.txt` configuration for various user agents. + + Required scope | `site_config:write` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: Replace robots.txt + request: + body: root.Robots + content-type: application/json + response: + docs: Request was successful + type: root.Robots + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + request: + rules: + - userAgent: googlebot + allows: + - /public + disallows: + - /vogon-poetry + - /total-perspective-vortex + sitemap: https://heartofgold.ship/sitemap.xml + response: + body: + rules: + - userAgent: googlebot + allows: + - /public + disallows: + - /vogon-poetry + - /total-perspective-vortex + sitemap: https://heartofgold.ship/sitemap.xml + delete: + path: /sites/{site_id}/robots_txt + method: DELETE + auth: true + docs: > + Remove specific rules for a user-agent in your `robots.txt` file. To + delete all rules for a user-agent, provide an empty rule set. This will + remove the user-agent's entry entirely, leaving it subject to your + site's default crawling behavior. + + + **Note:** Deleting a user-agent with no rules will make the user-agent's + access unrestricted unless other directives apply. + + + Required scope: `site_config:write` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: Delete robots.txt + request: + body: root.Robots + content-type: application/json + response: + docs: Request was successful + type: root.Robots + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + request: + rules: + - userAgent: '*' + allows: + - /public + disallows: + - /bubbles + response: + body: + rules: + - userAgent: googlebot + allows: + - /public + disallows: + - /vogon-poetry + - /total-perspective-vortex + sitemap: https://heartofgold.ship/sitemap.xml + patch: + path: /sites/{site_id}/robots_txt + method: PATCH + auth: true + docs: | + Update the `robots.txt` configuration for various user agents. + + Required scope | `site_config:write` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: Update robots.txt + request: + body: root.Robots + content-type: application/json + response: + docs: Request was successful + type: root.Robots + status-code: 200 + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + request: + rules: + - userAgent: googlebot + allows: + - /public + disallows: + - /vogon-poetry + - /total-perspective-vortex + sitemap: https://heartofgold.ship/sitemap.xml + response: + body: + rules: + - userAgent: googlebot + allows: + - /public + disallows: + - /vogon-poetry + - /total-perspective-vortex + sitemap: https://heartofgold.ship/sitemap.xml + source: + openapi: ../../../openapi/referenced-specs/v2.yml diff --git a/.mock/definition/sites/scripts.yml b/.mock/definition/sites/scripts.yml index 92ad0e4..647e1ec 100644 --- a/.mock/definition/sites/scripts.yml +++ b/.mock/definition/sites/scripts.yml @@ -8,13 +8,12 @@ service: path: /sites/{site_id}/custom_code method: GET auth: true - docs: > - Get all registered scripts that have been applied to a specific Site. - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + docs: | + Get all scripts applied to a site by the App. + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:read` source: @@ -27,6 +26,7 @@ service: response: docs: Request was successful type: root.ScriptApplyList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -55,22 +55,12 @@ service: path: /sites/{site_id}/custom_code method: PUT auth: true - docs: > - Add a registered script to a Site. - - - In order to use the Custom Code APIs for Sites and Pages, Custom Code - Scripts must first be registered - - to a Site via the `registered_scripts` endpoints, and then applied to a - Site or Page using the appropriate - - `custom_code` endpoints. - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + docs: | + Apply registered scripts to a site. + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write` source: @@ -86,6 +76,7 @@ service: response: docs: Request was successful type: root.ScriptApplyList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -125,11 +116,8 @@ service: method: DELETE auth: true docs: > - Delete the custom code block that an app created for a Site - - - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + Remove scripts from a site applied by the App. This endpoint will not + remove scripts from the site's registered scripts. Required scope | `custom_code:write` @@ -154,11 +142,15 @@ service: method: GET auth: true docs: > - Get all instances of Custom Code applied to a Site or Pages. + Get a list of scripts that have been applied to a site and/or individual + pages. - Access to this endpoint requires a bearer token from a [Data - Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. + + See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:read` @@ -183,6 +175,7 @@ service: response: docs: Request was successful type: root.ListCustomCodeBlocks + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -196,7 +189,6 @@ service: body: blocks: - siteId: 6258612d1ee792848f805dcf - pageId: pageId type: site scripts: - id: chartjs diff --git a/.mock/definition/token.yml b/.mock/definition/token.yml index 033c5c3..4b1cc1a 100644 --- a/.mock/definition/token.yml +++ b/.mock/definition/token.yml @@ -18,6 +18,7 @@ service: response: docs: Request was successful type: root.AuthorizedUser + status-code: 200 errors: - root.UnauthorizedError - root.ForbiddenError @@ -44,6 +45,7 @@ service: response: docs: Request was successful type: root.Authorization + status-code: 200 errors: - root.UnauthorizedError examples: diff --git a/.mock/definition/users.yml b/.mock/definition/users.yml index 19a17cc..a61f628 100644 --- a/.mock/definition/users.yml +++ b/.mock/definition/users.yml @@ -93,6 +93,7 @@ service: response: docs: Request was successful type: root.UserList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -181,6 +182,7 @@ service: response: docs: Request was successful type: root.User + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -276,6 +278,7 @@ service: response: docs: Request was successful type: root.User + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -354,6 +357,7 @@ service: response: docs: Request was successful type: root.User + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError diff --git a/.mock/definition/webhooks.yml b/.mock/definition/webhooks.yml index d40e3e4..47dbfc0 100644 --- a/.mock/definition/webhooks.yml +++ b/.mock/definition/webhooks.yml @@ -22,6 +22,7 @@ service: response: docs: Request was successful type: root.WebhookList + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -33,10 +34,6 @@ service: site_id: 580e63e98c9a982ac9b8b741 response: body: - pagination: - limit: 100 - offset: 0 - total: 100 webhooks: - id: 57ca0a9e418c504a6e1acbb6 triggerType: form_submission @@ -65,6 +62,10 @@ service: name: Email Form lastTriggered: '2023-02-08T23:59:28Z' createdOn: '2016-07-19T01:43:40Z' + pagination: + limit: 100 + offset: 0 + total: 100 create: path: /sites/{site_id}/webhooks method: POST @@ -93,6 +94,7 @@ service: response: docs: Request was successful type: root.Webhook + status-code: 201 errors: - root.BadRequestError - root.UnauthorizedError @@ -117,8 +119,6 @@ service: url: https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f workspaceId: 4f4e46fd476ea8c507000001 siteId: 562ac0395358780a1f5e6fbd - filter: - name: My Form lastTriggered: '2023-02-08T23:59:28Z' createdOn: '2022-11-08T23:59:28Z' get: @@ -139,6 +139,7 @@ service: response: docs: Request was successful type: root.Webhook + status-code: 200 errors: - root.BadRequestError - root.UnauthorizedError @@ -155,8 +156,6 @@ service: url: https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f workspaceId: 4f4e46fd476ea8c507000001 siteId: 562ac0395358780a1f5e6fbd - filter: - name: My Form lastTriggered: '2023-02-08T23:59:28Z' createdOn: '2022-11-08T23:59:28Z' delete: diff --git a/.mock/definition/wellKnown.yml b/.mock/definition/wellKnown.yml new file mode 100644 index 0000000..83b8d77 --- /dev/null +++ b/.mock/definition/wellKnown.yml @@ -0,0 +1,105 @@ +types: + WellKnownFileContentType: + enum: + - value: application/json + name: ApplicationJson + - value: text/plain + name: TextPlain + docs: The content type of the file. Defaults to application/json + default: application/json + inline: true + source: + openapi: ../../../openapi/referenced-specs/v2.yml +imports: + root: __package__.yml +service: + auth: false + base-path: '' + endpoints: + put: + path: /sites/{site_id}/well_known + method: PUT + auth: true + docs: | + Upload a supported well-known file to a site. + + The current restrictions on well-known files are as follows: + - Each file must be smaller than 100kb + - Less than 30 total files + - Have one of the following file extensions (or no extension): `.txt`, `.json`, `.noext` + + + `.noext` is a special file extension that removes other extensions. For example, `apple-app-site-association.noext.txt` will be uploaded as `apple-app-site-association`. Use this extension for tools that have trouble uploading extensionless files. + + + Required scope: `site_config:write` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: Set a well-known file + request: + name: WellKnownFile + body: + properties: + fileName: + type: string + docs: The name of the file + fileData: + type: string + docs: The contents of the file + contentType: + type: optional + docs: The content type of the file. Defaults to application/json + default: application/json + content-type: application/json + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + request: + fileName: fileName + fileData: fileData + delete: + path: /sites/{site_id}/well_known + method: DELETE + auth: true + docs: | + Delete existing well-known files from a site. + + + Required scope: `site_config:write` + source: + openapi: ../../../openapi/referenced-specs/v2.yml + path-parameters: + site_id: + type: string + docs: Unique identifier for a Site + display-name: Delete a well-known file + request: + name: WellKnownDeleteRequest + body: + properties: + fileNames: + type: optional> + docs: A list of file names to delete + content-type: application/json + errors: + - root.BadRequestError + - root.UnauthorizedError + - root.NotFoundError + - root.TooManyRequestsError + - root.InternalServerError + examples: + - path-parameters: + site_id: 580e63e98c9a982ac9b8b741 + request: {} + source: + openapi: ../../../openapi/referenced-specs/v2.yml diff --git a/.mock/fern.config.json b/.mock/fern.config.json index 8b3316e..7838cea 100644 --- a/.mock/fern.config.json +++ b/.mock/fern.config.json @@ -1,4 +1,4 @@ { "organization" : "webflow", - "version" : "0.46.19" + "version" : "0.56.34" } \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index a563308..d1637e3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,13 +38,13 @@ trio = ["trio (>=0.26.1)"] [[package]] name = "certifi" -version = "2024.12.14" +version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, - {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, + {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, + {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, ] [[package]] @@ -144,13 +144,13 @@ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2 [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] [[package]] @@ -238,13 +238,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pydantic" -version = "2.10.5" +version = "2.10.6" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, - {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, + {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, + {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, ] [package.dependencies] @@ -525,13 +525,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.12.2" +version = "4.13.1" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, + {file = "typing_extensions-4.13.1-py3-none-any.whl", hash = "sha256:4b6cf02909eb5495cfbc3f6e8fd49217e6cc7944e145cdda8caa3734777f9e69"}, + {file = "typing_extensions-4.13.1.tar.gz", hash = "sha256:98795af00fb9640edec5b8e31fc647597b4691f099ad75f469a2616be1a76dff"}, ] [metadata] diff --git a/pyproject.toml b/pyproject.toml index 749aa8e..66a8846 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "webflow" -version = "2.0.0b1" +version = "1.2.1" description = "" readme = "README.md" authors = [] diff --git a/reference.md b/reference.md index 5001bba..e8f9361 100644 --- a/reference.md +++ b/reference.md @@ -137,7 +137,9 @@ client.token.introspect()
-Create a site. This endpoint requires an Enterprise workspace. +Create a site. + +This endpoint requires an Enterprise workspace. Required scope | `workspace:write`
@@ -368,7 +370,9 @@ client.sites.get(
-Delete a site. This endpoint requires an Enterprise workspace. +Delete a site. + +This endpoint requires an Enterprise workspace. Required scope | `sites:write`
@@ -440,7 +444,9 @@ client.sites.delete(
-Update a site. This endpoint requires an Enterprise workspace. +Update a site. + +This endpoint requires an Enterprise workspace. Required scope | `sites:write`
@@ -674,6 +680,195 @@ client.sites.publish(
+ +
+ + +## WellKnown +
client.well_known.put(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Upload a supported well-known file to a site. + +The current restrictions on well-known files are as follows: + - Each file must be smaller than 100kb + - Less than 30 total files + - Have one of the following file extensions (or no extension): `.txt`, `.json`, `.noext` + + + `.noext` is a special file extension that removes other extensions. For example, `apple-app-site-association.noext.txt` will be uploaded as `apple-app-site-association`. Use this extension for tools that have trouble uploading extensionless files. + + +Required scope: `site_config:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.well_known.put( + site_id="580e63e98c9a982ac9b8b741", + file_name="fileName", + file_data="fileData", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**file_name:** `str` — The name of the file + +
+
+ +
+
+ +**file_data:** `str` — The contents of the file + +
+
+ +
+
+ +**content_type:** `typing.Optional[WellKnownFileContentType]` — The content type of the file. Defaults to application/json + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.well_known.delete(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Delete existing well-known files from a site. + + +Required scope: `site_config:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.well_known.delete( + site_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**file_names:** `typing.Optional[typing.Sequence[str]]` — A list of file names to delete + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ +
@@ -780,7 +975,7 @@ Required scope | `cms:write`
```python -from webflow import Webflow +from webflow import ReferenceField, ReferenceFieldMetadata, StaticField, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", @@ -790,6 +985,29 @@ client.collections.create( display_name="Blog Posts", singular_name="Blog Post", slug="posts", + fields=[ + StaticField( + is_required=True, + type="PlainText", + display_name="Title", + help_text="The title of the blog post", + ), + StaticField( + is_required=True, + type="RichText", + display_name="Content", + help_text="The content of the blog post", + ), + ReferenceField( + is_required=True, + type="Reference", + display_name="Author", + help_text="The author of the blog post", + metadata=ReferenceFieldMetadata( + collection_id="23cc2d952d4e4631ffd4345d2743db4e", + ), + ), + ], ) ``` @@ -838,6 +1056,14 @@ client.collections.create(
+**fields:** `typing.Optional[typing.Sequence[FieldCreate]]` — An array of custom fields to add to the collection + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -1187,6 +1413,10 @@ client.pages.get_metadata( Update Page-level metadata, including SEO and Open Graph fields. + + Note: When updating Page Metadata in secondary locales, you may only add `slug` to the request if your Site has the [Advanced or Enterprise Localization](https://webflow.com/localization) add-on. + + Required scope | `pages:write`
@@ -1430,10 +1660,11 @@ client.pages.update_page_settings(
-Get static content from a static page. This includes text nodes, image nodes and component instances. -To retrieve the contents of components in the page use the [get component content](/data/reference/pages-and-components/components/get-content) endpoint. +Get content from a static page. This includes text nodes, image nodes, and component instances with [property overrides](https://help.webflow.com/hc/en-us/articles/33961219350547-Component-properties#how-to-modify-property-values-on-component-instances). -If you do not provide a Locale ID in your request, the response will return any content that can be localized from the Primary locale. +To retrieve the static content of a component instance, use the [Get Component Content](/data/reference/pages-and-components/components/get-content) endpoint. + +If you do not include a `localeId` in your request, the response will return any content that can be localized from the Primary locale. Required scope | `pages:read`
@@ -1987,9 +2218,9 @@ client.components.update_content(
-Get the property default values of a component definition. +Get the default property values of a component definition. -If you do not provide a Locale ID in your request, the response will return any properties that can be localized from the Primary locale. +If you do not include a `localeId` in your request, the response will return any properties that can be localized from the Primary locale. Required scope | `components:read`
@@ -2095,12 +2326,11 @@ client.components.get_properties(
-Update the property default values of a component definition in a specificed locale. +Update the default property values of a component definition in a specificed locale. -Before making updates: -1. Use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint to identify available properties +Before making updates, use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint to identify properties that can be updated in a secondary locale. -The request requires a secondary locale ID. If a locale is missing, the request will not be processed and will result in an error. +The request requires a secondary locale ID. If a `localeId` is missing, the request will not be processed and will result in an error. Required scope | `components:write`
@@ -2210,14 +2440,11 @@ client.components.update_properties(
-List of scripts registered to a Site. +Get a list of scripts that have been registered to a site. A site can have a maximum of 800 registered scripts. -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. -Additionally, Scripts can be remotely hosted, or registered as inline snippets. - -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:read`
@@ -2289,14 +2516,11 @@ client.scripts.list(
-Add a script to a Site's Custom Code registry. +Register a hosted script to a site. -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. -Additionally, Scripts can be remotely hosted, or registered as inline snippets. - -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write`
@@ -2412,13 +2636,11 @@ client.scripts.register_hosted(
-Add a script to a Site's Custom Code registry. Inline scripts can be between 1 and 2000 characters. +Register an inline script to a site. Inline scripts are limited to 2000 characters. -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. - -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write`
@@ -2534,7 +2756,7 @@ client.scripts.register_inline(
-List assets for a given site +List of assets uploaded to a site Required scope | `assets:read`
@@ -2606,15 +2828,18 @@ client.assets.list(
-Create a new asset entry. +The first step in uploading an asset to a site. -This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`. -You can use these two properties to [upload the file to Amazon s3 by making a POST](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) -request to the `uploadUrl` with the `uploadDetails` object as your header information in the request. +This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`. - -Required scope | `assets:write` + +Use these properties in the header of a [POST request to Amazson s3](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) to complete the upload. + + +To learn more about how to upload assets to Webflow, see our [assets guide](/data/docs/working-with-assets). + + Required scope | `assets:write`
@@ -2710,7 +2935,7 @@ client.assets.create(
-Get an Asset +Get details about an asset Required scope | `assets:read`
@@ -2854,7 +3079,7 @@ client.assets.delete(
-Update an Asset +Update details of an Asset. Required scope | `assets:write`
@@ -3707,6 +3932,12 @@ client.forms.get( List form submissions for a given form + + When a form is used in a component definition, each instance of the form is considered a unique form. + + To get a combined list of submissions for a form that appears across multiple component instances, use the [List Form Submissions by Site](/data/reference/forms/form-submissions/list-submissions-by-site) endpoint. + + Required scope | `forms:read`
@@ -3853,7 +4084,7 @@ client.forms.get_submission(
-
client.forms.update_submission(...) +
client.forms.delete_submission(...)
@@ -3865,7 +4096,8 @@ client.forms.get_submission(
-Update hidden fields on a form submission +Delete a form submission + Required scope | `forms:write`
@@ -3887,7 +4119,7 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.forms.update_submission( +client.forms.delete_submission( form_submission_id="580e63e98c9a982ac9b8b741", ) @@ -3913,14 +4145,6 @@ client.forms.update_submission(
-**form_submission_data:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` — An existing **hidden field** defined on the form schema, and the corresponding value to set - -
-
- -
-
- **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -3933,8 +4157,7 @@ client.forms.update_submission(
-## Users -
client.users.list(...) +
client.forms.update_submission(...)
@@ -3946,9 +4169,9 @@ client.forms.update_submission(
-Get a list of users for a site +Update hidden fields on a form submission -Required scope | `users:read` +Required scope | `forms:write`
@@ -3968,8 +4191,8 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.users.list( - site_id="580e63e98c9a982ac9b8b741", +client.forms.update_submission( + form_submission_id="580e63e98c9a982ac9b8b741", ) ``` @@ -3986,23 +4209,7 @@ client.users.list(
-**site_id:** `str` — Unique identifier for a Site - -
-
- -
-
- -**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records - -
-
- -
-
- -**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) +**form_submission_id:** `str` — Unique identifier for a Form Submission
@@ -4010,13 +4217,7 @@ client.users.list(
-**sort:** `typing.Optional[UsersListRequestSort]` - -Sort string to use when ordering users - -Example(`CreatedOn`, `Email`, `Status`, `LastLogin`, `UpdatedOn`). - -Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`) +**form_submission_data:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` — An existing **hidden field** defined on the form schema, and the corresponding value to set
@@ -4036,7 +4237,7 @@ Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`)
-
client.users.get(...) +
client.forms.list_submissions_by_site(...)
@@ -4048,9 +4249,11 @@ Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`)
-Get a User by ID +List form submissions for a given site. This endpoint differs from the existing [List Form Submissions endpoint](/data/reference/forms/form-submissions/list-submissions) by accepting `siteId` as a path parameter and `elementId` as a query parameter. You can get the `elementId` from the [List forms endpoint](/data/reference/forms/forms/list). -Required scope | `users:read` + + +Required scope | `forms:read`
@@ -4070,7 +4273,207 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.users.get( +client.forms.list_submissions_by_site( + site_id="580e63e98c9a982ac9b8b741", + element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0", +) + +``` + +
+ +
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**element_id:** `typing.Optional[str]` — Identifier for an element + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + + +
+ + +## Users +
client.users.list(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get a list of users for a site + +Required scope | `users:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.users.list( + site_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**sort:** `typing.Optional[UsersListRequestSort]` + +Sort string to use when ordering users + +Example(`CreatedOn`, `Email`, `Status`, `LastLogin`, `UpdatedOn`). + +Can be prefixed with a `-` to reverse the sort (ex. `-CreatedOn`) + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.users.get(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get a User by ID + +Required scope | `users:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.users.get( site_id="580e63e98c9a982ac9b8b741", user_id="580e63e98c9a982ac9b8b741", ) @@ -4286,7 +4689,6 @@ client.users.update(
**access_groups:** `typing.Optional[typing.Sequence[str]]` — An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed. -
@@ -4379,7 +4781,6 @@ client.users.invite(
**access_groups:** `typing.Optional[typing.Sequence[str]]` — An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed. -
@@ -4631,13 +5032,88 @@ Required scope | `ecommerce:write`
```python -from webflow import Webflow +from webflow import ( + ProductFieldData, + SkuFieldData, + SkuFieldDataPrice, + SkuPropertyList, + SkuPropertyListEnumItem, + Webflow, +) +from webflow.resources.products import ( + ProductSkuCreateProduct, + ProductSkuCreateSku, +) client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) client.products.create( site_id="580e63e98c9a982ac9b8b741", + publish_status="staging", + product=ProductSkuCreateProduct( + field_data=ProductFieldData( + name="Colorful T-shirt", + slug="colorful-t-shirt", + description="Our best-selling t-shirt available in multiple colors and sizes", + sku_properties=[ + SkuPropertyList( + id="color", + name="Color", + enum=[ + SkuPropertyListEnumItem( + id="red", + name="Red", + slug="red", + ), + SkuPropertyListEnumItem( + id="yellow", + name="Yellow", + slug="yellow", + ), + SkuPropertyListEnumItem( + id="blue", + name="Blue", + slug="blue", + ), + ], + ), + SkuPropertyList( + id="size", + name="Size", + enum=[ + SkuPropertyListEnumItem( + id="small", + name="Small", + slug="small", + ), + SkuPropertyListEnumItem( + id="medium", + name="Medium", + slug="medium", + ), + SkuPropertyListEnumItem( + id="large", + name="Large", + slug="large", + ), + ], + ), + ], + ), + ), + sku=ProductSkuCreateSku( + field_data=SkuFieldData( + name="Colorful T-shirt - Red Small", + slug="colorful-t-shirt-red-small", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + main_image="https://rocketamp-sample-store.myshopify.com/cdn/shop/products/Gildan_2000_Antique_Cherry_Red_Front_1024x1024.jpg?v=1527232987", + ), + ), ) ``` @@ -4662,7 +5138,7 @@ client.products.create(
-**publish_status:** `typing.Optional[PublishStatus]` +**product:** `ProductSkuCreateProduct`
@@ -4670,7 +5146,7 @@ client.products.create(
-**product:** `typing.Optional[Product]` +**sku:** `ProductSkuCreateSku`
@@ -4678,7 +5154,7 @@ client.products.create(
-**sku:** `typing.Optional[Sku]` +**publish_status:** `typing.Optional[PublishStatus]`
@@ -4918,7 +5394,7 @@ Required scope | `ecommerce:write`
```python -from webflow import Sku, Webflow +from webflow import Sku, SkuFieldData, SkuFieldDataPrice, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", @@ -4926,7 +5402,19 @@ client = Webflow( client.products.create_sku( site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", - skus=[Sku()], + skus=[ + Sku( + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + ), + ) + ], ) ``` @@ -5018,7 +5506,7 @@ Required scope | `ecommerce:write`
```python -from webflow import Sku, Webflow +from webflow import Sku, SkuFieldData, SkuFieldDataPrice, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", @@ -5027,7 +5515,17 @@ client.products.update_sku( site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", sku_id="5e8518516e147040726cc415", - sku=Sku(), + sku=Sku( + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + ), + ), ) ``` @@ -5928,14 +6426,12 @@ client.ecommerce.get_settings(
-Create a custom field in a collection. +Create a custom field in a collection. Slugs must be all lowercase letters without spaces. If you pass a string with uppercase letters and/or spaces to the "Slug" property, Webflow will convert the slug to lowercase and replace spaces with "-." - -Only some field types can be created through the API. -This endpoint does not currently support bulk creation. +This endpoint does not currently support bulk creation. Required scope | `cms:write`
@@ -5952,17 +6448,24 @@ Required scope | `cms:write`
```python -from webflow import Webflow +from webflow import ReferenceField, ReferenceFieldMetadata, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) client.collections.fields.create( collection_id="580e63fc8c9a982ac9b8b745", - is_required=False, - type="RichText", - display_name="Post Body", - help_text="Add the body of your post here", + request=ReferenceField( + id="562ac0395358780a1f5e6fbd", + is_editable=True, + is_required=False, + type="Reference", + display_name="Author", + help_text="Add the post author here", + metadata=ReferenceFieldMetadata( + collection_id="63692ab61fb2852f582ba8f5", + ), + ), ) ``` @@ -5987,31 +6490,7 @@ client.collections.fields.create(
-**type:** `FieldCreateType` — Choose these appropriate field type for your collection data - -
-
- -
-
- -**display_name:** `str` — The name of a field - -
-
- -
-
- -**is_required:** `typing.Optional[bool]` — define whether a field is required in a collection - -
-
- -
-
- -**help_text:** `typing.Optional[str]` — Additional text to help anyone filling out this field +**request:** `FieldCreate`
@@ -6305,7 +6784,7 @@ client.collections.items.list_items(
-**name:** `typing.Optional[str]` — The name of the item(s) +**name:** `typing.Optional[str]` — Filter by the exact name of the item(s)
@@ -6313,7 +6792,7 @@ client.collections.items.list_items(
-**slug:** `typing.Optional[str]` — The slug of the item +**slug:** `typing.Optional[str]` — Filter by the exact slug of the item
@@ -6471,7 +6950,7 @@ client.collections.items.create_item( Delete Items from a Collection. -**Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be deleted only in the primary locale. +Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write`
@@ -6551,9 +7030,11 @@ client.collections.items.delete_items(
-Update a single item or multiple items (up to 100) in a Collection. +Update a single item or multiple items in a Collection. -**Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be updated only in the primary locale. +The limit for this endpoint is 100 items. + +Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write`
@@ -6671,7 +7152,12 @@ client.collections.items.update_items(
-List of all live Items within a Collection. +List all published items in a collection. + + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + Required scope | `CMS:read`
@@ -6743,7 +7229,7 @@ client.collections.items.list_items_live(
-**name:** `typing.Optional[str]` — The name of the item(s) +**name:** `typing.Optional[str]` — Filter by the exact name of the item(s)
@@ -6751,7 +7237,7 @@ client.collections.items.list_items_live(
-**slug:** `typing.Optional[str]` — The slug of the item +**slug:** `typing.Optional[str]` — Filter by the exact slug of the item
@@ -6799,7 +7285,7 @@ client.collections.items.list_items_live(
-Create live Item(s) in a Collection. The Item(s) will be published to the live site. +Create item(s) in a collection that will be immediately published to the live site. To create items across multiple locales, [please use this endpoint.](/v2.0.0/data/reference/cms/collection-items/staged-items/create-items) @@ -6831,6 +7317,9 @@ client.collections.items.create_item_live( request=MultipleLiveItems( items=[ CollectionItem( + last_published="2023-03-17T18:47:35.560Z", + last_updated="2023-03-17T18:47:35.560Z", + created_on="2023-03-17T18:47:35.560Z", is_archived=False, is_draft=False, field_data=CollectionItemFieldData( @@ -6839,6 +7328,9 @@ client.collections.items.create_item_live( ), ), CollectionItem( + last_published="2023-03-17T18:47:35.560Z", + last_updated="2023-03-17T18:47:35.560Z", + created_on="2023-03-17T18:47:35.560Z", is_archived=False, is_draft=False, field_data=CollectionItemFieldData( @@ -6904,9 +7396,11 @@ client.collections.items.create_item_live(
-Remove an item or multiple items (up to 100 items) from the live site. Deleting published items will unpublish the items from the live site and set them to draft. +Remove an item or multiple items (up to 100 items) from the live site. -**Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be unpublished only in the primary locale. +Using this endpoint to delete published item(s) will unpublish the item(s) from the live site and set the item(s) `isDraft` property to `true`. + +Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write`
@@ -6986,9 +7480,9 @@ client.collections.items.delete_items_live(
-Update a single live item or multiple live items (up to 100) in a Collection +Update a single published item or multiple published items (up to 100) in a Collection -**Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be updated only in the primary locale. +Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write`
@@ -7108,9 +7602,10 @@ client.collections.items.update_items_live( Create an item or multiple items in a CMS Collection across multiple corresponding locales. -**Notes:** + - This endpoint can create up to 100 items in a request. - - If the `cmsLocaleIds` parameter is undefined or empty and localization is enabled, items will only be created in the primary locale. + - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale. + Required scope | `CMS:write`
@@ -7315,7 +7810,7 @@ client.collections.items.get_item(
-Delete an Item from a Collection. This endpoint does not currently support bulk deletion. +Delete an item from a collection. Required scope | `CMS:write`
@@ -7557,6 +8052,11 @@ client.collections.items.update_item( Get details of a selected Collection live Item. + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + + Required scope | `CMS:read`
@@ -7968,13 +8468,7 @@ client.collections.items.publish_item(
-Get all registered scripts that have been applied to a specific Page. - -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. - -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). +Get all scripts applied to a page. Required scope | `custom_code:read`
@@ -8046,15 +8540,11 @@ client.pages.scripts.get_custom_code(
-Add a registered script to a Page. - -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. +Apply scripts to a page. -A site can have a maximum of 800 registered scripts. - -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a page, the script must first be registered to a Site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write`
@@ -8163,11 +8653,7 @@ client.pages.scripts.upsert_custom_code(
-Delete the custom code block that an app has created for a page - -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. +Delete a custom code block that the App created on a page. Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). @@ -8246,6 +8732,7 @@ Fetch a list of all URL redirect rules configured for a specific site. Use this endpoint to review, audit, or manage the redirection rules that control how traffic is rerouted on your site. +This endpoint requires an Enterprise workspace. Required scope: `sites:read`
@@ -8321,6 +8808,8 @@ Add a new URL redirection rule to a site. This endpoint allows you to define a source path (`fromUrl`) and its corresponding destination path (`toUrl`), which will dictate how traffic is rerouted on your site. This is useful for managing site changes, restructuring URLs, or handling outdated links. +This endpoint requires an Enterprise workspace. + Required scope: `sites:write`
@@ -8419,7 +8908,11 @@ client.sites.redirects.create(
Remove a URL redirection rule from a site. + This is useful for cleaning up outdated or unnecessary redirects, ensuring that your site's routing behavior remains efficient and up-to-date. + +This endpoint requires an Enterprise workspace. + Required scope: `sites:write`
@@ -8500,6 +8993,9 @@ client.sites.redirects.delete(
Update a URL redirection rule from a site. + +This endpoint requires an Enterprise workspace. + Required scope: `sites:write`
@@ -8609,6 +9105,8 @@ client.sites.redirects.update( Get site plan details for the specified Site. +This endpoint requires an Enterprise workspace. + Required scope | `sites:read`
@@ -8667,8 +9165,8 @@ client.sites.plans.get_site_plan(
-## Sites ActivityLogs -
client.sites.activity_logs.list(...) +## Sites RobotsTxt +
client.sites.robots_txt.get(...)
@@ -8680,7 +9178,9 @@ client.sites.plans.get_site_plan(
-Retrieve Activity Logs for a specific Site. Requires Site to be on an Enterprise plan.

Required scope | `site_activity:read` +Retrieve the robots.txt configuration for various user agents. + +Required scope: `site_config:read`
@@ -8700,7 +9200,7 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.sites.activity_logs.list( +client.sites.robots_txt.get( site_id="580e63e98c9a982ac9b8b741", ) @@ -8726,15 +9226,95 @@ client.sites.activity_logs.list(
-**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+ +
+ + + +
+ +
client.sites.robots_txt.put(...)
-**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records +#### 📝 Description + +
+
+ +
+
+ +Replace the `robots.txt` configuration for various user agents. + +Required scope | `site_config:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import RobotsRulesItem, Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.robots_txt.put( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", + allows=["/public"], + disallows=["/vogon-poetry", "/total-perspective-vortex"], + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**rules:** `typing.Optional[typing.Sequence[RobotsRulesItem]]` — List of rules for user agents. + +
+
+ +
+
+ +**sitemap:** `typing.Optional[str]` — URL to the sitemap.
@@ -8754,8 +9334,7 @@ client.sites.activity_logs.list(
-## Sites Scripts -
client.sites.scripts.get_custom_code(...) +
client.sites.robots_txt.delete(...)
@@ -8767,11 +9346,11 @@ client.sites.activity_logs.list(
-Get all registered scripts that have been applied to a specific Site. +Remove specific rules for a user-agent in your `robots.txt` file. To delete all rules for a user-agent, provide an empty rule set. This will remove the user-agent's entry entirely, leaving it subject to your site's default crawling behavior. -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). +**Note:** Deleting a user-agent with no rules will make the user-agent's access unrestricted unless other directives apply. -Required scope | `custom_code:read` +Required scope: `site_config:write`
@@ -8786,13 +9365,20 @@ Required scope | `custom_code:read`
```python -from webflow import Webflow +from webflow import RobotsRulesItem, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.sites.scripts.get_custom_code( +client.sites.robots_txt.delete( site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="*", + allows=["/public"], + disallows=["/bubbles"], + ) + ], ) ``` @@ -8817,6 +9403,22 @@ client.sites.scripts.get_custom_code(
+**rules:** `typing.Optional[typing.Sequence[RobotsRulesItem]]` — List of rules for user agents. + +
+
+ +
+
+ +**sitemap:** `typing.Optional[str]` — URL to the sitemap. + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -8829,7 +9431,7 @@ client.sites.scripts.get_custom_code(
-
client.sites.scripts.upsert_custom_code(...) +
client.sites.robots_txt.patch(...)
@@ -8841,15 +9443,9 @@ client.sites.scripts.get_custom_code(
-Add a registered script to a Site. +Update the `robots.txt` configuration for various user agents. -In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered -to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate -`custom_code` endpoints. - -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). - -Required scope | `custom_code:write` +Required scope | `site_config:write`
@@ -8864,26 +9460,21 @@ Required scope | `custom_code:write`
```python -from webflow import ScriptApply, Webflow +from webflow import RobotsRulesItem, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.sites.scripts.upsert_custom_code( +client.sites.robots_txt.patch( site_id="580e63e98c9a982ac9b8b741", - scripts=[ - ScriptApply( - id="cms_slider", - location="header", - version="1.0.0", - attributes={"my-attribute": "some-value"}, - ), - ScriptApply( - id="alert", - location="header", - version="0.0.1", - ), + rules=[ + RobotsRulesItem( + user_agent="googlebot", + allows=["/public"], + disallows=["/vogon-poetry", "/total-perspective-vortex"], + ) ], + sitemap="https://heartofgold.ship/sitemap.xml", ) ``` @@ -8908,15 +9499,7 @@ client.sites.scripts.upsert_custom_code(
-**scripts:** `typing.Optional[typing.Sequence[ScriptApply]]` — A list of scripts applied to a Site or a Page - -
-
- -
-
- -**last_updated:** `typing.Optional[str]` — Date when the Site's scripts were last updated +**rules:** `typing.Optional[typing.Sequence[RobotsRulesItem]]` — List of rules for user agents.
@@ -8924,7 +9507,7 @@ client.sites.scripts.upsert_custom_code(
-**created_on:** `typing.Optional[str]` — Date when the Site's scripts were created +**sitemap:** `typing.Optional[str]` — URL to the sitemap.
@@ -8944,7 +9527,8 @@ client.sites.scripts.upsert_custom_code(
-
client.sites.scripts.delete_custom_code(...) +## Sites ActivityLogs +
client.sites.activity_logs.list(...)
@@ -8956,11 +9540,11 @@ client.sites.scripts.upsert_custom_code(
-Delete the custom code block that an app created for a Site +Retrieve Activity Logs for a specific Site. -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). +This endpoint requires an Enterprise workspace. -Required scope | `custom_code:write` +Required scope: `site_activity:read`
@@ -8980,7 +9564,7 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.sites.scripts.delete_custom_code( +client.sites.activity_logs.list( site_id="580e63e98c9a982ac9b8b741", ) @@ -9006,6 +9590,22 @@ client.sites.scripts.delete_custom_code(
+**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -9018,7 +9618,8 @@ client.sites.scripts.delete_custom_code(
-
client.sites.scripts.list_custom_code_blocks(...) +## Sites Comments +
client.sites.comments.list_comment_threads(...)
@@ -9030,11 +9631,9 @@ client.sites.scripts.delete_custom_code(
-Get all instances of Custom Code applied to a Site or Pages. +List all comment threads for a site. -Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). - -Required scope | `custom_code:read` +Required scope | `comments:read`
@@ -9054,8 +9653,9 @@ from webflow import Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) -client.sites.scripts.list_custom_code_blocks( +client.sites.comments.list_comment_threads( site_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", ) ``` @@ -9080,6 +9680,14 @@ client.sites.scripts.list_custom_code_blocks(
+**locale_id:** `typing.Optional[str]` — Unique identifier for a specific locale. Applicable, when using localization. + +
+
+ +
+
+ **offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records
@@ -9096,6 +9704,623 @@ client.sites.scripts.list_custom_code_blocks(
+**sort_by:** `typing.Optional[CommentsListCommentThreadsRequestSortBy]` — Sort results by the provided value. Only allowed when sortOrder is provided. + +
+
+ +
+
+ +**sort_order:** `typing.Optional[CommentsListCommentThreadsRequestSortOrder]` — Sorts the results by asc or desc + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+ +
+ + + +
+
+ +
client.sites.comments.get_comment_thread(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get details of a specific comment thread. + +Required scope | `comments:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.comments.get_comment_thread( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**comment_thread_id:** `str` — Unique identifier for a Comment Thread + +
+
+ +
+
+ +**locale_id:** `typing.Optional[str]` — Unique identifier for a specific locale. Applicable, when using localization. + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**sort_by:** `typing.Optional[CommentsGetCommentThreadRequestSortBy]` — Sort results by the provided value. Only allowed when sortOrder is provided. + +
+
+ +
+
+ +**sort_order:** `typing.Optional[CommentsGetCommentThreadRequestSortOrder]` — Sorts the results by asc or desc + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +## Sites Scripts +
client.sites.scripts.get_custom_code(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get all scripts applied to a site by the App. + + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + + +Required scope | `custom_code:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.scripts.get_custom_code( + site_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.sites.scripts.upsert_custom_code(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Apply registered scripts to a site. + + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + + +Required scope | `custom_code:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import ScriptApply, Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.scripts.upsert_custom_code( + site_id="580e63e98c9a982ac9b8b741", + scripts=[ + ScriptApply( + id="cms_slider", + location="header", + version="1.0.0", + attributes={"my-attribute": "some-value"}, + ), + ScriptApply( + id="alert", + location="header", + version="0.0.1", + ), + ], +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**scripts:** `typing.Optional[typing.Sequence[ScriptApply]]` — A list of scripts applied to a Site or a Page + +
+
+ +
+
+ +**last_updated:** `typing.Optional[str]` — Date when the Site's scripts were last updated + +
+
+ +
+
+ +**created_on:** `typing.Optional[str]` — Date when the Site's scripts were created + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.sites.scripts.delete_custom_code(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Remove scripts from a site applied by the App. This endpoint will not remove scripts from the site's registered scripts. + +Required scope | `custom_code:write` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.scripts.delete_custom_code( + site_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.sites.scripts.list_custom_code_blocks(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get a list of scripts that have been applied to a site and/or individual pages. + + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. + + See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + + +Required scope | `custom_code:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.scripts.list_custom_code_blocks( + site_id="580e63e98c9a982ac9b8b741", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +## Sites Comments Replies +
client.sites.comments.replies.list_replies(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +List all replies to a specific comment thread. + +Required scope | `comments:read` +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from webflow import Webflow + +client = Webflow( + access_token="YOUR_ACCESS_TOKEN", +) +client.sites.comments.replies.list_replies( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**site_id:** `str` — Unique identifier for a Site + +
+
+ +
+
+ +**comment_thread_id:** `str` — Unique identifier for a Comment Thread + +
+
+ +
+
+ +**locale_id:** `typing.Optional[str]` — Unique identifier for a specific locale. Applicable, when using localization. + +
+
+ +
+
+ +**offset:** `typing.Optional[float]` — Offset used for pagination if the results have more than limit records + +
+
+ +
+
+ +**limit:** `typing.Optional[float]` — Maximum number of records to be returned (max limit: 100) + +
+
+ +
+
+ +**sort_by:** `typing.Optional[RepliesListRepliesRequestSortBy]` — Sort results by the provided value. Only allowed when sortOrder is provided. + +
+
+ +
+
+ +**sort_order:** `typing.Optional[RepliesListRepliesRequestSortOrder]` — Sorts the results by asc or desc + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
diff --git a/src/webflow/__init__.py b/src/webflow/__init__.py index 0d82d59..9935cbc 100644 --- a/src/webflow/__init__.py +++ b/src/webflow/__init__.py @@ -32,6 +32,16 @@ CollectionItemWithIdInputFieldData, CollectionList, CollectionListArrayItem, + CommentReply, + CommentReplyAuthor, + CommentReplyList, + CommentReplyListPagination, + CommentReplyMentionedUsersItem, + CommentThread, + CommentThreadAuthor, + CommentThreadList, + CommentThreadListPagination, + CommentThreadMentionedUsersItem, Component, ComponentDom, ComponentInstanceNodePropertyOverridesWrite, @@ -41,6 +51,7 @@ ComponentProperties, ComponentProperty, ComponentPropertyType, + Conflict, ConflictErrorBody, CustomCodeBlock, CustomCodeBlockType, @@ -54,6 +65,7 @@ Error, ErrorCode, Field, + FieldCreate, FieldType, ForbiddenErrorBody, Form, @@ -73,6 +85,8 @@ ListCustomCodeBlocks, Locale, Locales, + Metadata, + MetadataOptionsItem, NoDomains, Node, Node_ComponentInstance, @@ -80,6 +94,7 @@ Node_Text, NotEnterprisePlanSite, NotEnterprisePlanWorkspace, + OptionField, Order, OrderAddress, OrderAddressJapanType, @@ -113,7 +128,12 @@ PublishStatus, Redirect, Redirects, + ReferenceField, + ReferenceFieldMetadata, + ReferenceFieldType, RegisteredScriptList, + Robots, + RobotsRulesItem, ScriptApply, ScriptApplyList, ScriptApplyLocation, @@ -141,6 +161,8 @@ SkuPropertyList, SkuPropertyListEnumItem, SkuValueList, + StaticField, + StaticFieldType, StripeCard, StripeCardBrand, StripeCardExpires, @@ -182,11 +204,14 @@ OrdersListRequestStatus, OrdersRefundRequestReason, PageDomWriteNodesItem, + ProductSkuCreateProduct, + ProductSkuCreateSku, ProductsCreateSkuResponse, SitesPublishResponse, UpdateStaticContentResponse, UsersListRequestSort, UsersUpdateRequestData, + WellKnownFileContentType, access_groups, assets, collections, @@ -202,6 +227,7 @@ token, users, webhooks, + well_known, ) from .client import AsyncWebflow, Webflow from .environment import WebflowEnvironment @@ -242,6 +268,16 @@ "CollectionItemWithIdInputFieldData", "CollectionList", "CollectionListArrayItem", + "CommentReply", + "CommentReplyAuthor", + "CommentReplyList", + "CommentReplyListPagination", + "CommentReplyMentionedUsersItem", + "CommentThread", + "CommentThreadAuthor", + "CommentThreadList", + "CommentThreadListPagination", + "CommentThreadMentionedUsersItem", "Component", "ComponentDom", "ComponentDomWriteNodesItem", @@ -255,6 +291,7 @@ "ComponentPropertyType", "ComponentsUpdateContentResponse", "ComponentsUpdatePropertiesResponse", + "Conflict", "ConflictError", "ConflictErrorBody", "CustomCodeBlock", @@ -269,6 +306,7 @@ "Error", "ErrorCode", "Field", + "FieldCreate", "FieldType", "ForbiddenError", "ForbiddenErrorBody", @@ -291,6 +329,8 @@ "ListCustomCodeBlocks", "Locale", "Locales", + "Metadata", + "MetadataOptionsItem", "NoDomains", "Node", "Node_ComponentInstance", @@ -299,6 +339,7 @@ "NotEnterprisePlanSite", "NotEnterprisePlanWorkspace", "NotFoundError", + "OptionField", "Order", "OrderAddress", "OrderAddressJapanType", @@ -332,11 +373,18 @@ "ProductFieldData", "ProductFieldDataEcProductType", "ProductFieldDataTaxCategory", + "ProductSkuCreateProduct", + "ProductSkuCreateSku", "ProductsCreateSkuResponse", "PublishStatus", "Redirect", "Redirects", + "ReferenceField", + "ReferenceFieldMetadata", + "ReferenceFieldType", "RegisteredScriptList", + "Robots", + "RobotsRulesItem", "ScriptApply", "ScriptApplyList", "ScriptApplyLocation", @@ -365,6 +413,8 @@ "SkuPropertyList", "SkuPropertyListEnumItem", "SkuValueList", + "StaticField", + "StaticFieldType", "StripeCard", "StripeCardBrand", "StripeCardExpires", @@ -393,6 +443,7 @@ "Webhook", "WebhookFilter", "WebhookList", + "WellKnownFileContentType", "__version__", "access_groups", "assets", @@ -409,4 +460,5 @@ "token", "users", "webhooks", + "well_known", ] diff --git a/src/webflow/client.py b/src/webflow/client.py index 90c233d..e054a88 100644 --- a/src/webflow/client.py +++ b/src/webflow/client.py @@ -1,11 +1,12 @@ # This file was auto-generated by Fern from our API Definition. -import typing from .environment import WebflowEnvironment +import typing import httpx from .core.client_wrapper import SyncClientWrapper from .resources.token.client import TokenClient from .resources.sites.client import SitesClient +from .resources.well_known.client import WellKnownClient from .resources.collections.client import CollectionsClient from .resources.pages.client import PagesClient from .resources.components.client import ComponentsClient @@ -22,6 +23,7 @@ from .core.client_wrapper import AsyncClientWrapper from .resources.token.client import AsyncTokenClient from .resources.sites.client import AsyncSitesClient +from .resources.well_known.client import AsyncWellKnownClient from .resources.collections.client import AsyncCollectionsClient from .resources.pages.client import AsyncPagesClient from .resources.components.client import AsyncComponentsClient @@ -43,15 +45,12 @@ class Webflow: Parameters ---------- - base_url : typing.Optional[str] - The base url to use for requests from the client. - environment : WebflowEnvironment The environment to use for requests from the client. from .environment import WebflowEnvironment - Defaults to WebflowEnvironment.DEFAULT + Defaults to WebflowEnvironment.DATA_API @@ -77,8 +76,7 @@ class Webflow: def __init__( self, *, - base_url: typing.Optional[str] = None, - environment: WebflowEnvironment = WebflowEnvironment.DEFAULT, + environment: WebflowEnvironment = WebflowEnvironment.DATA_API, access_token: typing.Union[str, typing.Callable[[], str]], timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, @@ -86,7 +84,7 @@ def __init__( ): _defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None self._client_wrapper = SyncClientWrapper( - base_url=_get_base_url(base_url=base_url, environment=environment), + environment=environment, access_token=access_token, httpx_client=httpx_client if httpx_client is not None @@ -97,6 +95,7 @@ def __init__( ) self.token = TokenClient(client_wrapper=self._client_wrapper) self.sites = SitesClient(client_wrapper=self._client_wrapper) + self.well_known = WellKnownClient(client_wrapper=self._client_wrapper) self.collections = CollectionsClient(client_wrapper=self._client_wrapper) self.pages = PagesClient(client_wrapper=self._client_wrapper) self.components = ComponentsClient(client_wrapper=self._client_wrapper) @@ -118,15 +117,12 @@ class AsyncWebflow: Parameters ---------- - base_url : typing.Optional[str] - The base url to use for requests from the client. - environment : WebflowEnvironment The environment to use for requests from the client. from .environment import WebflowEnvironment - Defaults to WebflowEnvironment.DEFAULT + Defaults to WebflowEnvironment.DATA_API @@ -152,8 +148,7 @@ class AsyncWebflow: def __init__( self, *, - base_url: typing.Optional[str] = None, - environment: WebflowEnvironment = WebflowEnvironment.DEFAULT, + environment: WebflowEnvironment = WebflowEnvironment.DATA_API, access_token: typing.Union[str, typing.Callable[[], str]], timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, @@ -161,7 +156,7 @@ def __init__( ): _defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None self._client_wrapper = AsyncClientWrapper( - base_url=_get_base_url(base_url=base_url, environment=environment), + environment=environment, access_token=access_token, httpx_client=httpx_client if httpx_client is not None @@ -172,6 +167,7 @@ def __init__( ) self.token = AsyncTokenClient(client_wrapper=self._client_wrapper) self.sites = AsyncSitesClient(client_wrapper=self._client_wrapper) + self.well_known = AsyncWellKnownClient(client_wrapper=self._client_wrapper) self.collections = AsyncCollectionsClient(client_wrapper=self._client_wrapper) self.pages = AsyncPagesClient(client_wrapper=self._client_wrapper) self.components = AsyncComponentsClient(client_wrapper=self._client_wrapper) @@ -185,12 +181,3 @@ def __init__( self.orders = AsyncOrdersClient(client_wrapper=self._client_wrapper) self.inventory = AsyncInventoryClient(client_wrapper=self._client_wrapper) self.ecommerce = AsyncEcommerceClient(client_wrapper=self._client_wrapper) - - -def _get_base_url(*, base_url: typing.Optional[str] = None, environment: WebflowEnvironment) -> str: - if base_url is not None: - return base_url - elif environment is not None: - return environment.value - else: - raise Exception("Please pass in either base_url or environment to construct the client") diff --git a/src/webflow/core/client_wrapper.py b/src/webflow/core/client_wrapper.py index 84ed6fb..e363dd0 100644 --- a/src/webflow/core/client_wrapper.py +++ b/src/webflow/core/client_wrapper.py @@ -1,6 +1,7 @@ # This file was auto-generated by Fern from our API Definition. import typing +from ..environment import WebflowEnvironment import httpx from .http_client import HttpClient from .http_client import AsyncHttpClient @@ -11,18 +12,18 @@ def __init__( self, *, access_token: typing.Union[str, typing.Callable[[], str]], - base_url: str, + environment: WebflowEnvironment, timeout: typing.Optional[float] = None, ): self._access_token = access_token - self._base_url = base_url + self._environment = environment self._timeout = timeout def get_headers(self) -> typing.Dict[str, str]: headers: typing.Dict[str, str] = { "X-Fern-Language": "Python", "X-Fern-SDK-Name": "webflow", - "X-Fern-SDK-Version": "2.0.0b1", + "X-Fern-SDK-Version": "1.2.1", } headers["Authorization"] = f"Bearer {self._get_access_token()}" return headers @@ -33,8 +34,8 @@ def _get_access_token(self) -> str: else: return self._access_token() - def get_base_url(self) -> str: - return self._base_url + def get_environment(self) -> WebflowEnvironment: + return self._environment def get_timeout(self) -> typing.Optional[float]: return self._timeout @@ -45,16 +46,13 @@ def __init__( self, *, access_token: typing.Union[str, typing.Callable[[], str]], - base_url: str, + environment: WebflowEnvironment, timeout: typing.Optional[float] = None, httpx_client: httpx.Client, ): - super().__init__(access_token=access_token, base_url=base_url, timeout=timeout) + super().__init__(access_token=access_token, environment=environment, timeout=timeout) self.httpx_client = HttpClient( - httpx_client=httpx_client, - base_headers=self.get_headers, - base_timeout=self.get_timeout, - base_url=self.get_base_url, + httpx_client=httpx_client, base_headers=self.get_headers, base_timeout=self.get_timeout ) @@ -63,14 +61,11 @@ def __init__( self, *, access_token: typing.Union[str, typing.Callable[[], str]], - base_url: str, + environment: WebflowEnvironment, timeout: typing.Optional[float] = None, httpx_client: httpx.AsyncClient, ): - super().__init__(access_token=access_token, base_url=base_url, timeout=timeout) + super().__init__(access_token=access_token, environment=environment, timeout=timeout) self.httpx_client = AsyncHttpClient( - httpx_client=httpx_client, - base_headers=self.get_headers, - base_timeout=self.get_timeout, - base_url=self.get_base_url, + httpx_client=httpx_client, base_headers=self.get_headers, base_timeout=self.get_timeout ) diff --git a/src/webflow/environment.py b/src/webflow/environment.py index ed0e03d..e6fd331 100644 --- a/src/webflow/environment.py +++ b/src/webflow/environment.py @@ -1,7 +1,23 @@ # This file was auto-generated by Fern from our API Definition. -import enum +from __future__ import annotations -class WebflowEnvironment(enum.Enum): - DEFAULT = "https://api.webflow.com/v2" +class WebflowEnvironment: + DATA_API: WebflowEnvironment + + def __init__(self, *, base: str, data_api: str, content_delivery_api: str, production: str, cdn: str): + self.base = base + self.data_api = data_api + self.content_delivery_api = content_delivery_api + self.production = production + self.cdn = cdn + + +WebflowEnvironment.DATA_API = WebflowEnvironment( + base="https://api.webflow.com/v2", + data_api="https://api.webflow.com/v2", + content_delivery_api="https://api-cdn.webflow.com/v2", + production="https://api.webflow.com/v2", + cdn="https://api-cdn.webflow.com/v2", +) diff --git a/src/webflow/resources/__init__.py b/src/webflow/resources/__init__.py index 9122eee..47b4a00 100644 --- a/src/webflow/resources/__init__.py +++ b/src/webflow/resources/__init__.py @@ -16,6 +16,7 @@ token, users, webhooks, + well_known, ) from .access_groups import AccessGroupsListRequestSort from .components import ( @@ -27,9 +28,10 @@ from .inventory import InventoryUpdateRequestInventoryType from .orders import OrdersListRequestStatus, OrdersRefundRequestReason from .pages import PageDomWriteNodesItem, UpdateStaticContentResponse -from .products import ProductsCreateSkuResponse +from .products import ProductSkuCreateProduct, ProductSkuCreateSku, ProductsCreateSkuResponse from .sites import SitesPublishResponse from .users import UsersListRequestSort, UsersUpdateRequestData +from .well_known import WellKnownFileContentType __all__ = [ "AccessGroupsListRequestSort", @@ -41,11 +43,14 @@ "OrdersListRequestStatus", "OrdersRefundRequestReason", "PageDomWriteNodesItem", + "ProductSkuCreateProduct", + "ProductSkuCreateSku", "ProductsCreateSkuResponse", "SitesPublishResponse", "UpdateStaticContentResponse", "UsersListRequestSort", "UsersUpdateRequestData", + "WellKnownFileContentType", "access_groups", "assets", "collections", @@ -61,4 +66,5 @@ "token", "users", "webhooks", + "well_known", ] diff --git a/src/webflow/resources/access_groups/client.py b/src/webflow/resources/access_groups/client.py index ee7668a..71654e3 100644 --- a/src/webflow/resources/access_groups/client.py +++ b/src/webflow/resources/access_groups/client.py @@ -73,6 +73,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/accessgroups", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -218,6 +219,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/accessgroups", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, diff --git a/src/webflow/resources/assets/client.py b/src/webflow/resources/assets/client.py index 61e141a..c6e39ef 100644 --- a/src/webflow/resources/assets/client.py +++ b/src/webflow/resources/assets/client.py @@ -30,7 +30,7 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Assets: """ - List assets for a given site + List of assets uploaded to a site Required scope | `assets:read` @@ -60,6 +60,7 @@ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/assets", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -137,15 +138,18 @@ def create( request_options: typing.Optional[RequestOptions] = None, ) -> AssetUpload: """ - Create a new asset entry. + The first step in uploading an asset to a site. This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`. - You can use these two properties to [upload the file to Amazon s3 by making a POST](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) - request to the `uploadUrl` with the `uploadDetails` object as your header information in the request. - Required scope | `assets:write` + Use these properties in the header of a [POST request to Amazson s3](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) to complete the upload. + + + To learn more about how to upload assets to Webflow, see our [assets guide](/data/docs/working-with-assets). + + Required scope | `assets:write` Parameters ---------- @@ -184,6 +188,7 @@ def create( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/assets", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "fileName": file_name, @@ -262,7 +267,7 @@ def create( def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Asset: """ - Get an Asset + Get details about an asset Required scope | `assets:read` @@ -292,6 +297,7 @@ def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"assets/{jsonable_encoder(asset_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -390,6 +396,7 @@ def delete(self, asset_id: str, *, request_options: typing.Optional[RequestOptio """ _response = self._client_wrapper.httpx_client.request( f"assets/{jsonable_encoder(asset_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -460,7 +467,7 @@ def update( request_options: typing.Optional[RequestOptions] = None, ) -> Asset: """ - Update an Asset + Update details of an Asset. Required scope | `assets:write` @@ -496,6 +503,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"assets/{jsonable_encoder(asset_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "localeId": locale_id, @@ -603,6 +611,7 @@ def list_folders(self, site_id: str, *, request_options: typing.Optional[Request """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/asset_folders", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -716,6 +725,7 @@ def create_folder( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/asset_folders", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "displayName": display_name, @@ -825,6 +835,7 @@ def get_folder( """ _response = self._client_wrapper.httpx_client.request( f"asset_folders/{jsonable_encoder(asset_folder_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -899,7 +910,7 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): async def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Assets: """ - List assets for a given site + List of assets uploaded to a site Required scope | `assets:read` @@ -937,6 +948,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/assets", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1014,15 +1026,18 @@ async def create( request_options: typing.Optional[RequestOptions] = None, ) -> AssetUpload: """ - Create a new asset entry. + The first step in uploading an asset to a site. This endpoint generates a response with the following information: `uploadUrl` and `uploadDetails`. - You can use these two properties to [upload the file to Amazon s3 by making a POST](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) - request to the `uploadUrl` with the `uploadDetails` object as your header information in the request. - Required scope | `assets:write` + Use these properties in the header of a [POST request to Amazson s3](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html) to complete the upload. + + + To learn more about how to upload assets to Webflow, see our [assets guide](/data/docs/working-with-assets). + + Required scope | `assets:write` Parameters ---------- @@ -1069,6 +1084,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/assets", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "fileName": file_name, @@ -1147,7 +1163,7 @@ async def main() -> None: async def get(self, asset_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Asset: """ - Get an Asset + Get details about an asset Required scope | `assets:read` @@ -1185,6 +1201,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"assets/{jsonable_encoder(asset_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1291,6 +1308,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"assets/{jsonable_encoder(asset_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -1361,7 +1379,7 @@ async def update( request_options: typing.Optional[RequestOptions] = None, ) -> Asset: """ - Update an Asset + Update details of an Asset. Required scope | `assets:write` @@ -1405,6 +1423,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"assets/{jsonable_encoder(asset_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "localeId": locale_id, @@ -1522,6 +1541,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/asset_folders", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1643,6 +1663,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/asset_folders", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "displayName": display_name, @@ -1760,6 +1781,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"asset_folders/{jsonable_encoder(asset_folder_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) diff --git a/src/webflow/resources/collections/__init__.py b/src/webflow/resources/collections/__init__.py index cb6aaf8..ab6a9da 100644 --- a/src/webflow/resources/collections/__init__.py +++ b/src/webflow/resources/collections/__init__.py @@ -3,7 +3,6 @@ from .resources import ( CreateBulkCollectionItemRequestBodyFieldData, CreateBulkCollectionItemRequestBodyFieldDataItem, - FieldCreateType, ItemsCreateItemLiveRequest, ItemsCreateItemRequest, ItemsDeleteItemsLiveRequestItemsItem, @@ -23,7 +22,6 @@ __all__ = [ "CreateBulkCollectionItemRequestBodyFieldData", "CreateBulkCollectionItemRequestBodyFieldDataItem", - "FieldCreateType", "ItemsCreateItemLiveRequest", "ItemsCreateItemRequest", "ItemsDeleteItemsLiveRequestItemsItem", diff --git a/src/webflow/resources/collections/client.py b/src/webflow/resources/collections/client.py index 1e44aae..bf84fb8 100644 --- a/src/webflow/resources/collections/client.py +++ b/src/webflow/resources/collections/client.py @@ -16,7 +16,10 @@ from ...errors.internal_server_error import InternalServerError from json.decoder import JSONDecodeError from ...core.api_error import ApiError +from ...types.field_create import FieldCreate from ...types.collection import Collection +from ...core.serialization import convert_and_respect_annotation_metadata +from ...errors.conflict_error import ConflictError from ...core.client_wrapper import AsyncClientWrapper from .resources.fields.client import AsyncFieldsClient from .resources.items.client import AsyncItemsClient @@ -63,6 +66,7 @@ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/collections", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -137,6 +141,7 @@ def create( display_name: str, singular_name: str, slug: typing.Optional[str] = OMIT, + fields: typing.Optional[typing.Sequence[FieldCreate]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> Collection: """ @@ -158,6 +163,9 @@ def create( slug : typing.Optional[str] Part of a URL that identifier + fields : typing.Optional[typing.Sequence[FieldCreate]] + An array of custom fields to add to the collection + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -168,7 +176,7 @@ def create( Examples -------- - from webflow import Webflow + from webflow import ReferenceField, ReferenceFieldMetadata, StaticField, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", @@ -178,15 +186,42 @@ def create( display_name="Blog Posts", singular_name="Blog Post", slug="posts", + fields=[ + StaticField( + is_required=True, + type="PlainText", + display_name="Title", + help_text="The title of the blog post", + ), + StaticField( + is_required=True, + type="RichText", + display_name="Content", + help_text="The content of the blog post", + ), + ReferenceField( + is_required=True, + type="Reference", + display_name="Author", + help_text="The author of the blog post", + metadata=ReferenceFieldMetadata( + collection_id="23cc2d952d4e4631ffd4345d2743db4e", + ), + ), + ], ) """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/collections", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "displayName": display_name, "singularName": singular_name, "slug": slug, + "fields": convert_and_respect_annotation_metadata( + object_=fields, annotation=typing.Sequence[FieldCreate], direction="write" + ), }, headers={ "content-type": "application/json", @@ -233,6 +268,16 @@ def create( ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -290,6 +335,7 @@ def get(self, collection_id: str, *, request_options: typing.Optional[RequestOpt """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -388,6 +434,7 @@ def delete(self, collection_id: str, *, request_options: typing.Optional[Request """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -496,6 +543,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/collections", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -570,6 +618,7 @@ async def create( display_name: str, singular_name: str, slug: typing.Optional[str] = OMIT, + fields: typing.Optional[typing.Sequence[FieldCreate]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> Collection: """ @@ -591,6 +640,9 @@ async def create( slug : typing.Optional[str] Part of a URL that identifier + fields : typing.Optional[typing.Sequence[FieldCreate]] + An array of custom fields to add to the collection + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -603,7 +655,12 @@ async def create( -------- import asyncio - from webflow import AsyncWebflow + from webflow import ( + AsyncWebflow, + ReferenceField, + ReferenceFieldMetadata, + StaticField, + ) client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -616,6 +673,29 @@ async def main() -> None: display_name="Blog Posts", singular_name="Blog Post", slug="posts", + fields=[ + StaticField( + is_required=True, + type="PlainText", + display_name="Title", + help_text="The title of the blog post", + ), + StaticField( + is_required=True, + type="RichText", + display_name="Content", + help_text="The content of the blog post", + ), + ReferenceField( + is_required=True, + type="Reference", + display_name="Author", + help_text="The author of the blog post", + metadata=ReferenceFieldMetadata( + collection_id="23cc2d952d4e4631ffd4345d2743db4e", + ), + ), + ], ) @@ -623,11 +703,15 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/collections", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "displayName": display_name, "singularName": singular_name, "slug": slug, + "fields": convert_and_respect_annotation_metadata( + object_=fields, annotation=typing.Sequence[FieldCreate], direction="write" + ), }, headers={ "content-type": "application/json", @@ -674,6 +758,16 @@ async def main() -> None: ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -739,6 +833,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -845,6 +940,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) diff --git a/src/webflow/resources/collections/resources/__init__.py b/src/webflow/resources/collections/resources/__init__.py index f9325ee..4dd489a 100644 --- a/src/webflow/resources/collections/resources/__init__.py +++ b/src/webflow/resources/collections/resources/__init__.py @@ -1,7 +1,6 @@ # This file was auto-generated by Fern from our API Definition. from . import fields, items -from .fields import FieldCreateType from .items import ( CreateBulkCollectionItemRequestBodyFieldData, CreateBulkCollectionItemRequestBodyFieldDataItem, @@ -22,7 +21,6 @@ __all__ = [ "CreateBulkCollectionItemRequestBodyFieldData", "CreateBulkCollectionItemRequestBodyFieldDataItem", - "FieldCreateType", "ItemsCreateItemLiveRequest", "ItemsCreateItemRequest", "ItemsDeleteItemsLiveRequestItemsItem", diff --git a/src/webflow/resources/collections/resources/fields/__init__.py b/src/webflow/resources/collections/resources/fields/__init__.py index 5a5b167..f3ea265 100644 --- a/src/webflow/resources/collections/resources/fields/__init__.py +++ b/src/webflow/resources/collections/resources/fields/__init__.py @@ -1,5 +1,2 @@ # This file was auto-generated by Fern from our API Definition. -from .types import FieldCreateType - -__all__ = ["FieldCreateType"] diff --git a/src/webflow/resources/collections/resources/fields/client.py b/src/webflow/resources/collections/resources/fields/client.py index 40b66cf..8b7a24a 100644 --- a/src/webflow/resources/collections/resources/fields/client.py +++ b/src/webflow/resources/collections/resources/fields/client.py @@ -2,19 +2,21 @@ import typing from .....core.client_wrapper import SyncClientWrapper -from .types.field_create_type import FieldCreateType +from .....types.field_create import FieldCreate from .....core.request_options import RequestOptions -from .....types.field import Field from .....core.jsonable_encoder import jsonable_encoder +from .....core.serialization import convert_and_respect_annotation_metadata from .....core.pydantic_utilities import parse_obj_as from .....errors.bad_request_error import BadRequestError from .....errors.unauthorized_error import UnauthorizedError from .....types.error import Error from .....errors.not_found_error import NotFoundError +from .....errors.conflict_error import ConflictError from .....errors.too_many_requests_error import TooManyRequestsError from .....errors.internal_server_error import InternalServerError from json.decoder import JSONDecodeError from .....core.api_error import ApiError +from .....types.field import Field from .....core.client_wrapper import AsyncClientWrapper # this is used as the default value for optional parameters @@ -26,23 +28,14 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper def create( - self, - collection_id: str, - *, - type: FieldCreateType, - display_name: str, - is_required: typing.Optional[bool] = OMIT, - help_text: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Field: + self, collection_id: str, *, request: FieldCreate, request_options: typing.Optional[RequestOptions] = None + ) -> FieldCreate: """ Create a custom field in a collection. Slugs must be all lowercase letters without spaces. If you pass a string with uppercase letters and/or spaces to the "Slug" property, Webflow will convert the slug to lowercase and replace spaces with "-." - - Only some field types can be created through the API. This endpoint does not currently support bulk creation. Required scope | `cms:write` @@ -52,62 +45,49 @@ def create( collection_id : str Unique identifier for a Collection - type : FieldCreateType - Choose these appropriate field type for your collection data - - display_name : str - The name of a field - - is_required : typing.Optional[bool] - define whether a field is required in a collection - - help_text : typing.Optional[str] - Additional text to help anyone filling out this field + request : FieldCreate request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Field + FieldCreate Request was successful Examples -------- - from webflow import Webflow + from webflow import StaticField, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) client.collections.fields.create( collection_id="580e63fc8c9a982ac9b8b745", - is_required=False, - type="RichText", - display_name="Post Body", - help_text="Add the body of your post here", + request=StaticField( + id="562ac0395358780a1f5e6fbc", + is_editable=True, + is_required=False, + type="RichText", + display_name="Post Body", + help_text="Add the body of your post here", + ), ) """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/fields", + base_url=self._client_wrapper.get_environment().base, method="POST", - json={ - "isRequired": is_required, - "type": type, - "displayName": display_name, - "helpText": help_text, - }, - headers={ - "content-type": "application/json", - }, + json=convert_and_respect_annotation_metadata(object_=request, annotation=FieldCreate, direction="write"), request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: return typing.cast( - Field, + FieldCreate, parse_obj_as( - type_=Field, # type: ignore + type_=FieldCreate, # type: ignore object_=_response.json(), ), ) @@ -141,6 +121,16 @@ def create( ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -203,6 +193,7 @@ def delete( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/fields/{jsonable_encoder(field_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -321,6 +312,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/fields/{jsonable_encoder(field_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "isRequired": is_required, @@ -403,23 +395,14 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper async def create( - self, - collection_id: str, - *, - type: FieldCreateType, - display_name: str, - is_required: typing.Optional[bool] = OMIT, - help_text: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Field: + self, collection_id: str, *, request: FieldCreate, request_options: typing.Optional[RequestOptions] = None + ) -> FieldCreate: """ Create a custom field in a collection. Slugs must be all lowercase letters without spaces. If you pass a string with uppercase letters and/or spaces to the "Slug" property, Webflow will convert the slug to lowercase and replace spaces with "-." - - Only some field types can be created through the API. This endpoint does not currently support bulk creation. Required scope | `cms:write` @@ -429,31 +412,21 @@ async def create( collection_id : str Unique identifier for a Collection - type : FieldCreateType - Choose these appropriate field type for your collection data - - display_name : str - The name of a field - - is_required : typing.Optional[bool] - define whether a field is required in a collection - - help_text : typing.Optional[str] - Additional text to help anyone filling out this field + request : FieldCreate request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - Field + FieldCreate Request was successful Examples -------- import asyncio - from webflow import AsyncWebflow + from webflow import AsyncWebflow, StaticField client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -463,10 +436,14 @@ async def create( async def main() -> None: await client.collections.fields.create( collection_id="580e63fc8c9a982ac9b8b745", - is_required=False, - type="RichText", - display_name="Post Body", - help_text="Add the body of your post here", + request=StaticField( + id="562ac0395358780a1f5e6fbc", + is_editable=True, + is_required=False, + type="RichText", + display_name="Post Body", + help_text="Add the body of your post here", + ), ) @@ -474,25 +451,18 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/fields", + base_url=self._client_wrapper.get_environment().base, method="POST", - json={ - "isRequired": is_required, - "type": type, - "displayName": display_name, - "helpText": help_text, - }, - headers={ - "content-type": "application/json", - }, + json=convert_and_respect_annotation_metadata(object_=request, annotation=FieldCreate, direction="write"), request_options=request_options, omit=OMIT, ) try: if 200 <= _response.status_code < 300: return typing.cast( - Field, + FieldCreate, parse_obj_as( - type_=Field, # type: ignore + type_=FieldCreate, # type: ignore object_=_response.json(), ), ) @@ -526,6 +496,16 @@ async def main() -> None: ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -596,6 +576,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/fields/{jsonable_encoder(field_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -722,6 +703,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/fields/{jsonable_encoder(field_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "isRequired": is_required, diff --git a/src/webflow/resources/collections/resources/fields/types/__init__.py b/src/webflow/resources/collections/resources/fields/types/__init__.py deleted file mode 100644 index c17230e..0000000 --- a/src/webflow/resources/collections/resources/fields/types/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .field_create_type import FieldCreateType - -__all__ = ["FieldCreateType"] diff --git a/src/webflow/resources/collections/resources/items/client.py b/src/webflow/resources/collections/resources/items/client.py index 47f8f90..a0cd554 100644 --- a/src/webflow/resources/collections/resources/items/client.py +++ b/src/webflow/resources/collections/resources/items/client.py @@ -74,10 +74,10 @@ def list_items( Maximum number of records to be returned (max limit: 100) name : typing.Optional[str] - The name of the item(s) + Filter by the exact name of the item(s) slug : typing.Optional[str] - The slug of the item + Filter by the exact slug of the item sort_by : typing.Optional[ItemsListItemsRequestSortBy] Sort results by the provided value @@ -106,6 +106,7 @@ def list_items( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -237,6 +238,7 @@ def create_item( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="POST", json=convert_and_respect_annotation_metadata( object_=request, annotation=ItemsCreateItemRequest, direction="write" @@ -318,7 +320,7 @@ def delete_items( """ Delete Items from a Collection. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be deleted only in the primary locale. + Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -349,6 +351,7 @@ def delete_items( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="DELETE", json={ "items": convert_and_respect_annotation_metadata( @@ -437,9 +440,11 @@ def update_items( request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItem: """ - Update a single item or multiple items (up to 100) in a Collection. + Update a single item or multiple items in a Collection. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be updated only in the primary locale. + The limit for this endpoint is 100 items. + + Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -509,6 +514,7 @@ def update_items( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "items": convert_and_respect_annotation_metadata( @@ -599,7 +605,12 @@ def list_items_live( request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItemList: """ - List of all live Items within a Collection. + List all published items in a collection. + + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + Required scope | `CMS:read` @@ -618,10 +629,10 @@ def list_items_live( Maximum number of records to be returned (max limit: 100) name : typing.Optional[str] - The name of the item(s) + Filter by the exact name of the item(s) slug : typing.Optional[str] - The slug of the item + Filter by the exact slug of the item sort_by : typing.Optional[ItemsListItemsLiveRequestSortBy] Sort results by the provided value @@ -650,6 +661,7 @@ def list_items_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().data_api, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -734,7 +746,7 @@ def create_item_live( request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItem: """ - Create live Item(s) in a Collection. The Item(s) will be published to the live site. + Create item(s) in a collection that will be immediately published to the live site. To create items across multiple locales, [please use this endpoint.](/v2.0.0/data/reference/cms/collection-items/staged-items/create-items) @@ -767,6 +779,9 @@ def create_item_live( client.collections.items.create_item_live( collection_id="580e63fc8c9a982ac9b8b745", request=CollectionItem( + last_published="2023-03-17T18:47:35.560Z", + last_updated="2023-03-17T18:47:35.560Z", + created_on="2023-03-17T18:47:35.560Z", is_archived=False, is_draft=False, field_data=CollectionItemFieldData( @@ -778,6 +793,7 @@ def create_item_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().base, method="POST", json=convert_and_respect_annotation_metadata( object_=request, annotation=ItemsCreateItemLiveRequest, direction="write" @@ -857,9 +873,11 @@ def delete_items_live( request_options: typing.Optional[RequestOptions] = None, ) -> None: """ - Remove an item or multiple items (up to 100 items) from the live site. Deleting published items will unpublish the items from the live site and set them to draft. + Remove an item or multiple items (up to 100 items) from the live site. + + Using this endpoint to delete published item(s) will unpublish the item(s) from the live site and set the item(s) `isDraft` property to `true`. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be unpublished only in the primary locale. + Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -890,6 +908,7 @@ def delete_items_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().base, method="DELETE", json={ "items": convert_and_respect_annotation_metadata( @@ -968,9 +987,9 @@ def update_items_live( request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItemListNoPagination: """ - Update a single live item or multiple live items (up to 100) in a Collection + Update a single published item or multiple published items (up to 100) in a Collection - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be updated only in the primary locale. + Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -1040,6 +1059,7 @@ def update_items_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "items": convert_and_respect_annotation_metadata( @@ -1091,6 +1111,16 @@ def update_items_live( ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -1129,9 +1159,10 @@ def create_items( """ Create an item or multiple items in a CMS Collection across multiple corresponding locales. - **Notes:** + - This endpoint can create up to 100 items in a request. - - If the `cmsLocaleIds` parameter is undefined or empty and localization is enabled, items will only be created in the primary locale. + - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale. + Required scope | `CMS:write` @@ -1184,6 +1215,7 @@ def create_items( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/bulk", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "cmsLocaleIds": cms_locale_ids, @@ -1309,6 +1341,7 @@ def get_item( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}", + base_url=self._client_wrapper.get_environment().production, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -1388,7 +1421,7 @@ def delete_item( request_options: typing.Optional[RequestOptions] = None, ) -> None: """ - Delete an Item from a Collection. This endpoint does not currently support bulk deletion. + Delete an item from a collection. Required scope | `CMS:write` @@ -1424,6 +1457,7 @@ def delete_item( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", params={ "cmsLocaleId": cms_locale_id, @@ -1567,6 +1601,7 @@ def update_item( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "id": id, @@ -1658,6 +1693,11 @@ def get_item_live( """ Get details of a selected Collection live Item. + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + + Required scope | `CMS:read` Parameters @@ -1693,6 +1733,7 @@ def get_item_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live", + base_url=self._client_wrapper.get_environment().data_api, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -1810,6 +1851,7 @@ def delete_item_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live", + base_url=self._client_wrapper.get_environment().base, method="DELETE", params={ "cmsLocaleId": cms_locale_id, @@ -1953,6 +1995,7 @@ def update_item_live( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "id": id, @@ -2008,6 +2051,16 @@ def update_item_live( ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -2074,6 +2127,7 @@ def publish_item( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/publish", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "itemIds": item_ids, @@ -2196,10 +2250,10 @@ async def list_items( Maximum number of records to be returned (max limit: 100) name : typing.Optional[str] - The name of the item(s) + Filter by the exact name of the item(s) slug : typing.Optional[str] - The slug of the item + Filter by the exact slug of the item sort_by : typing.Optional[ItemsListItemsRequestSortBy] Sort results by the provided value @@ -2236,6 +2290,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -2375,6 +2430,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="POST", json=convert_and_respect_annotation_metadata( object_=request, annotation=ItemsCreateItemRequest, direction="write" @@ -2456,7 +2512,7 @@ async def delete_items( """ Delete Items from a Collection. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be deleted only in the primary locale. + Items will only be deleted in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -2495,6 +2551,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="DELETE", json={ "items": convert_and_respect_annotation_metadata( @@ -2583,9 +2640,11 @@ async def update_items( request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItem: """ - Update a single item or multiple items (up to 100) in a Collection. + Update a single item or multiple items in a Collection. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be updated only in the primary locale. + The limit for this endpoint is 100 items. + + Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -2663,6 +2722,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "items": convert_and_respect_annotation_metadata( @@ -2753,7 +2813,12 @@ async def list_items_live( request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItemList: """ - List of all live Items within a Collection. + List all published items in a collection. + + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + Required scope | `CMS:read` @@ -2772,10 +2837,10 @@ async def list_items_live( Maximum number of records to be returned (max limit: 100) name : typing.Optional[str] - The name of the item(s) + Filter by the exact name of the item(s) slug : typing.Optional[str] - The slug of the item + Filter by the exact slug of the item sort_by : typing.Optional[ItemsListItemsLiveRequestSortBy] Sort results by the provided value @@ -2812,6 +2877,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().data_api, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -2896,7 +2962,7 @@ async def create_item_live( request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItem: """ - Create live Item(s) in a Collection. The Item(s) will be published to the live site. + Create item(s) in a collection that will be immediately published to the live site. To create items across multiple locales, [please use this endpoint.](/v2.0.0/data/reference/cms/collection-items/staged-items/create-items) @@ -2934,6 +3000,9 @@ async def main() -> None: await client.collections.items.create_item_live( collection_id="580e63fc8c9a982ac9b8b745", request=CollectionItem( + last_published="2023-03-17T18:47:35.560Z", + last_updated="2023-03-17T18:47:35.560Z", + created_on="2023-03-17T18:47:35.560Z", is_archived=False, is_draft=False, field_data=CollectionItemFieldData( @@ -2948,6 +3017,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().base, method="POST", json=convert_and_respect_annotation_metadata( object_=request, annotation=ItemsCreateItemLiveRequest, direction="write" @@ -3027,9 +3097,11 @@ async def delete_items_live( request_options: typing.Optional[RequestOptions] = None, ) -> None: """ - Remove an item or multiple items (up to 100 items) from the live site. Deleting published items will unpublish the items from the live site and set them to draft. + Remove an item or multiple items (up to 100 items) from the live site. + + Using this endpoint to delete published item(s) will unpublish the item(s) from the live site and set the item(s) `isDraft` property to `true`. - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be unpublished only in the primary locale. + Items will only be unpublished in the primary locale unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -3068,6 +3140,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().base, method="DELETE", json={ "items": convert_and_respect_annotation_metadata( @@ -3146,9 +3219,9 @@ async def update_items_live( request_options: typing.Optional[RequestOptions] = None, ) -> CollectionItemListNoPagination: """ - Update a single live item or multiple live items (up to 100) in a Collection + Update a single published item or multiple published items (up to 100) in a Collection - **Note:** If the `cmsLocaleId` parameter is undefined or empty and the items are localized, items will be updated only in the primary locale. + Items will only be updated in the primary locale, unless a `cmsLocaleId` is included in the request. Required scope | `CMS:write` @@ -3226,6 +3299,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/live", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "items": convert_and_respect_annotation_metadata( @@ -3277,6 +3351,16 @@ async def main() -> None: ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -3315,9 +3399,10 @@ async def create_items( """ Create an item or multiple items in a CMS Collection across multiple corresponding locales. - **Notes:** + - This endpoint can create up to 100 items in a request. - - If the `cmsLocaleIds` parameter is undefined or empty and localization is enabled, items will only be created in the primary locale. + - If the `cmsLocaleIds` parameter is not included in the request, an item will only be created in the primary locale. + Required scope | `CMS:write` @@ -3378,6 +3463,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/bulk", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "cmsLocaleIds": cms_locale_ids, @@ -3511,6 +3597,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}", + base_url=self._client_wrapper.get_environment().production, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -3590,7 +3677,7 @@ async def delete_item( request_options: typing.Optional[RequestOptions] = None, ) -> None: """ - Delete an Item from a Collection. This endpoint does not currently support bulk deletion. + Delete an item from a collection. Required scope | `CMS:write` @@ -3634,6 +3721,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", params={ "cmsLocaleId": cms_locale_id, @@ -3785,6 +3873,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "id": id, @@ -3876,6 +3965,11 @@ async def get_item_live( """ Get details of a selected Collection live Item. + + To serve content to your other frontends applications, enterprise sites have access to a dedicated [content delivery API](/data/docs/cms-content-delivery), available at api-cdn.webflow.com. + + + Required scope | `CMS:read` Parameters @@ -3919,6 +4013,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live", + base_url=self._client_wrapper.get_environment().data_api, method="GET", params={ "cmsLocaleId": cms_locale_id, @@ -4044,6 +4139,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live", + base_url=self._client_wrapper.get_environment().base, method="DELETE", params={ "cmsLocaleId": cms_locale_id, @@ -4195,6 +4291,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/live", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "id": id, @@ -4250,6 +4347,16 @@ async def main() -> None: ), ) ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) if _response.status_code == 429: raise TooManyRequestsError( typing.cast( @@ -4324,6 +4431,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/publish", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "itemIds": item_ids, diff --git a/src/webflow/resources/collections/resources/items/types/items_delete_items_live_request_items_item.py b/src/webflow/resources/collections/resources/items/types/items_delete_items_live_request_items_item.py index 63e00bc..544df88 100644 --- a/src/webflow/resources/collections/resources/items/types/items_delete_items_live_request_items_item.py +++ b/src/webflow/resources/collections/resources/items/types/items_delete_items_live_request_items_item.py @@ -1,15 +1,15 @@ # This file was auto-generated by Fern from our API Definition. from ......core.pydantic_utilities import UniversalBaseModel -import typing_extensions -from ......core.serialization import FieldMetadata import pydantic +import typing_extensions import typing +from ......core.serialization import FieldMetadata from ......core.pydantic_utilities import IS_PYDANTIC_V2 class ItemsDeleteItemsLiveRequestItemsItem(UniversalBaseModel): - item_id: typing_extensions.Annotated[str, FieldMetadata(alias="itemId")] = pydantic.Field() + id: str = pydantic.Field() """ Unique identifier for the Item """ diff --git a/src/webflow/resources/components/client.py b/src/webflow/resources/components/client.py index ef50ac9..6899a57 100644 --- a/src/webflow/resources/components/client.py +++ b/src/webflow/resources/components/client.py @@ -77,6 +77,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "limit": limit, @@ -206,6 +207,7 @@ def get_content( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -365,6 +367,7 @@ def update_content( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="POST", params={ "localeId": locale_id, @@ -465,9 +468,9 @@ def get_properties( request_options: typing.Optional[RequestOptions] = None, ) -> ComponentProperties: """ - Get the property default values of a component definition. + Get the default property values of a component definition. - If you do not provide a Locale ID in your request, the response will return any properties that can be localized from the Primary locale. + If you do not include a `localeId` in your request, the response will return any properties that can be localized from the Primary locale. Required scope | `components:read` @@ -511,6 +514,7 @@ def get_properties( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/properties", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -593,12 +597,11 @@ def update_properties( request_options: typing.Optional[RequestOptions] = None, ) -> ComponentsUpdatePropertiesResponse: """ - Update the property default values of a component definition in a specificed locale. + Update the default property values of a component definition in a specificed locale. - Before making updates: - 1. Use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint to identify available properties + Before making updates, use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint to identify properties that can be updated in a secondary locale. - The request requires a secondary locale ID. If a locale is missing, the request will not be processed and will result in an error. + The request requires a secondary locale ID. If a `localeId` is missing, the request will not be processed and will result in an error. Required scope | `components:write` @@ -650,6 +653,7 @@ def update_properties( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/properties", + base_url=self._client_wrapper.get_environment().base, method="POST", params={ "localeId": locale_id, @@ -789,6 +793,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "limit": limit, @@ -926,6 +931,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -1093,6 +1099,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="POST", params={ "localeId": locale_id, @@ -1193,9 +1200,9 @@ async def get_properties( request_options: typing.Optional[RequestOptions] = None, ) -> ComponentProperties: """ - Get the property default values of a component definition. + Get the default property values of a component definition. - If you do not provide a Locale ID in your request, the response will return any properties that can be localized from the Primary locale. + If you do not include a `localeId` in your request, the response will return any properties that can be localized from the Primary locale. Required scope | `components:read` @@ -1247,6 +1254,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/properties", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -1329,12 +1337,11 @@ async def update_properties( request_options: typing.Optional[RequestOptions] = None, ) -> ComponentsUpdatePropertiesResponse: """ - Update the property default values of a component definition in a specificed locale. + Update the default property values of a component definition in a specificed locale. - Before making updates: - 1. Use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint to identify available properties + Before making updates, use the [get component properties](/data/reference/pages-and-components/components/get-properties) endpoint to identify properties that can be updated in a secondary locale. - The request requires a secondary locale ID. If a locale is missing, the request will not be processed and will result in an error. + The request requires a secondary locale ID. If a `localeId` is missing, the request will not be processed and will result in an error. Required scope | `components:write` @@ -1394,6 +1401,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/components/{jsonable_encoder(component_id)}/properties", + base_url=self._client_wrapper.get_environment().base, method="POST", params={ "localeId": locale_id, diff --git a/src/webflow/resources/ecommerce/client.py b/src/webflow/resources/ecommerce/client.py index bbd3a5d..04ddba6 100644 --- a/src/webflow/resources/ecommerce/client.py +++ b/src/webflow/resources/ecommerce/client.py @@ -57,6 +57,7 @@ def get_settings( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/ecommerce/settings", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -191,6 +192,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/ecommerce/settings", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) diff --git a/src/webflow/resources/forms/client.py b/src/webflow/resources/forms/client.py index 515b631..05b3da5 100644 --- a/src/webflow/resources/forms/client.py +++ b/src/webflow/resources/forms/client.py @@ -74,6 +74,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/forms", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "limit": limit, @@ -197,6 +198,7 @@ def get(self, form_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"forms/{jsonable_encoder(form_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -285,6 +287,12 @@ def list_submissions( """ List form submissions for a given form + + When a form is used in a component definition, each instance of the form is considered a unique form. + + To get a combined list of submissions for a form that appears across multiple component instances, use the [List Form Submissions by Site](/data/reference/forms/form-submissions/list-submissions-by-site) endpoint. + + Required scope | `forms:read` Parameters @@ -319,6 +327,7 @@ def list_submissions( """ _response = self._client_wrapper.httpx_client.request( f"forms/{jsonable_encoder(form_id)}/submissions", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -434,6 +443,7 @@ def get_submission( """ _response = self._client_wrapper.httpx_client.request( f"form_submissions/{jsonable_encoder(form_submission_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -511,6 +521,122 @@ def get_submission( raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + def delete_submission( + self, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> None: + """ + Delete a form submission + + + Required scope | `forms:write` + + Parameters + ---------- + form_submission_id : str + Unique identifier for a Form Submission + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.forms.delete_submission( + form_submission_id="580e63e98c9a982ac9b8b741", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"form_submissions/{jsonable_encoder(form_submission_id)}", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + def update_submission( self, form_submission_id: str, @@ -552,6 +678,7 @@ def update_submission( """ _response = self._client_wrapper.httpx_client.request( f"form_submissions/{jsonable_encoder(form_submission_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "formSubmissionData": form_submission_data, @@ -646,6 +773,141 @@ def update_submission( raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + def list_submissions_by_site( + self, + site_id: str, + *, + element_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> FormSubmissionList: + """ + List form submissions for a given site. This endpoint differs from the existing [List Form Submissions endpoint](/data/reference/forms/form-submissions/list-submissions) by accepting `siteId` as a path parameter and `elementId` as a query parameter. You can get the `elementId` from the [List forms endpoint](/data/reference/forms/forms/list). + + + + Required scope | `forms:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + element_id : typing.Optional[str] + Identifier for an element + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + FormSubmissionList + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.forms.list_submissions_by_site( + site_id="580e63e98c9a982ac9b8b741", + element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/form_submissions", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "elementId": element_id, + "offset": offset, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + FormSubmissionList, + parse_obj_as( + type_=FormSubmissionList, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + class AsyncFormsClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): @@ -704,6 +966,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/forms", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "limit": limit, @@ -835,6 +1098,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"forms/{jsonable_encoder(form_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -923,6 +1187,12 @@ async def list_submissions( """ List form submissions for a given form + + When a form is used in a component definition, each instance of the form is considered a unique form. + + To get a combined list of submissions for a form that appears across multiple component instances, use the [List Form Submissions by Site](/data/reference/forms/form-submissions/list-submissions-by-site) endpoint. + + Required scope | `forms:read` Parameters @@ -965,6 +1235,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"forms/{jsonable_encoder(form_id)}/submissions", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -1088,6 +1359,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"form_submissions/{jsonable_encoder(form_submission_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1165,6 +1437,130 @@ async def main() -> None: raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + async def delete_submission( + self, form_submission_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> None: + """ + Delete a form submission + + + Required scope | `forms:write` + + Parameters + ---------- + form_submission_id : str + Unique identifier for a Form Submission + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.forms.delete_submission( + form_submission_id="580e63e98c9a982ac9b8b741", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"form_submissions/{jsonable_encoder(form_submission_id)}", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 409: + raise ConflictError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + async def update_submission( self, form_submission_id: str, @@ -1214,6 +1610,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"form_submissions/{jsonable_encoder(form_submission_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "formSubmissionData": form_submission_data, @@ -1307,3 +1704,146 @@ async def main() -> None: except JSONDecodeError: raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + + async def list_submissions_by_site( + self, + site_id: str, + *, + element_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> FormSubmissionList: + """ + List form submissions for a given site. This endpoint differs from the existing [List Form Submissions endpoint](/data/reference/forms/form-submissions/list-submissions) by accepting `siteId` as a path parameter and `elementId` as a query parameter. You can get the `elementId` from the [List forms endpoint](/data/reference/forms/forms/list). + + + + Required scope | `forms:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + element_id : typing.Optional[str] + Identifier for an element + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + FormSubmissionList + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.forms.list_submissions_by_site( + site_id="580e63e98c9a982ac9b8b741", + element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/form_submissions", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "elementId": element_id, + "offset": offset, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + FormSubmissionList, + parse_obj_as( + type_=FormSubmissionList, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 403: + raise ForbiddenError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/webflow/resources/inventory/client.py b/src/webflow/resources/inventory/client.py index 27e4f3c..4f51334 100644 --- a/src/webflow/resources/inventory/client.py +++ b/src/webflow/resources/inventory/client.py @@ -65,6 +65,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/inventory", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -211,6 +212,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/inventory", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "inventoryType": inventory_type, @@ -358,6 +360,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/inventory", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -512,6 +515,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"collections/{jsonable_encoder(collection_id)}/items/{jsonable_encoder(item_id)}/inventory", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "inventoryType": inventory_type, diff --git a/src/webflow/resources/orders/client.py b/src/webflow/resources/orders/client.py index 4aa4b77..9b79918 100644 --- a/src/webflow/resources/orders/client.py +++ b/src/webflow/resources/orders/client.py @@ -78,6 +78,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "status": status, @@ -207,6 +208,7 @@ def get(self, site_id: str, order_id: str, *, request_options: typing.Optional[R """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -354,6 +356,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "comment": comment, @@ -497,6 +500,7 @@ def update_fulfill( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/fulfill", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "sendOrderFulfilledEmail": send_order_fulfilled_email, @@ -629,6 +633,7 @@ def update_unfulfill( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/unfulfill", + base_url=self._client_wrapper.get_environment().base, method="POST", request_options=request_options, ) @@ -763,6 +768,7 @@ def refund( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/refund", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "reason": reason, @@ -919,6 +925,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "status": status, @@ -1058,6 +1065,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1213,6 +1221,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "comment": comment, @@ -1364,6 +1373,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/fulfill", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "sendOrderFulfilledEmail": send_order_fulfilled_email, @@ -1504,6 +1514,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/unfulfill", + base_url=self._client_wrapper.get_environment().base, method="POST", request_options=request_options, ) @@ -1646,6 +1657,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/orders/{jsonable_encoder(order_id)}/refund", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "reason": reason, diff --git a/src/webflow/resources/pages/client.py b/src/webflow/resources/pages/client.py index 851f4e7..8facc50 100644 --- a/src/webflow/resources/pages/client.py +++ b/src/webflow/resources/pages/client.py @@ -86,6 +86,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/pages", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -200,6 +201,7 @@ def get_metadata( """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -297,6 +299,10 @@ def update_page_settings( """ Update Page-level metadata, including SEO and Open Graph fields. + + Note: When updating Page Metadata in secondary locales, you may only add `slug` to the request if your Site has the [Advanced or Enterprise Localization](https://webflow.com/localization) add-on. + + Required scope | `pages:write` Parameters @@ -408,6 +414,7 @@ def update_page_settings( """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}", + base_url=self._client_wrapper.get_environment().base, method="PUT", params={ "localeId": locale_id, @@ -510,10 +517,11 @@ def get_content( request_options: typing.Optional[RequestOptions] = None, ) -> Dom: """ - Get static content from a static page. This includes text nodes, image nodes and component instances. - To retrieve the contents of components in the page use the [get component content](/data/reference/pages-and-components/components/get-content) endpoint. + Get content from a static page. This includes text nodes, image nodes, and component instances with [property overrides](https://help.webflow.com/hc/en-us/articles/33961219350547-Component-properties#how-to-modify-property-values-on-component-instances). + + To retrieve the static content of a component instance, use the [Get Component Content](/data/reference/pages-and-components/components/get-content) endpoint. - If you do not provide a Locale ID in your request, the response will return any content that can be localized from the Primary locale. + If you do not include a `localeId` in your request, the response will return any content that can be localized from the Primary locale. Required scope | `pages:read` @@ -553,6 +561,7 @@ def get_content( """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -717,6 +726,7 @@ def update_static_content( """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="POST", params={ "localeId": locale_id, @@ -870,6 +880,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/pages", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -992,6 +1003,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -1089,6 +1101,10 @@ async def update_page_settings( """ Update Page-level metadata, including SEO and Open Graph fields. + + Note: When updating Page Metadata in secondary locales, you may only add `slug` to the request if your Site has the [Advanced or Enterprise Localization](https://webflow.com/localization) add-on. + + Required scope | `pages:write` Parameters @@ -1207,6 +1223,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}", + base_url=self._client_wrapper.get_environment().base, method="PUT", params={ "localeId": locale_id, @@ -1309,10 +1326,11 @@ async def get_content( request_options: typing.Optional[RequestOptions] = None, ) -> Dom: """ - Get static content from a static page. This includes text nodes, image nodes and component instances. - To retrieve the contents of components in the page use the [get component content](/data/reference/pages-and-components/components/get-content) endpoint. + Get content from a static page. This includes text nodes, image nodes, and component instances with [property overrides](https://help.webflow.com/hc/en-us/articles/33961219350547-Component-properties#how-to-modify-property-values-on-component-instances). + + To retrieve the static content of a component instance, use the [Get Component Content](/data/reference/pages-and-components/components/get-content) endpoint. - If you do not provide a Locale ID in your request, the response will return any content that can be localized from the Primary locale. + If you do not include a `localeId` in your request, the response will return any content that can be localized from the Primary locale. Required scope | `pages:read` @@ -1360,6 +1378,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "localeId": locale_id, @@ -1532,6 +1551,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/dom", + base_url=self._client_wrapper.get_environment().base, method="POST", params={ "localeId": locale_id, diff --git a/src/webflow/resources/pages/resources/scripts/client.py b/src/webflow/resources/pages/resources/scripts/client.py index 56bd39a..a0e22e8 100644 --- a/src/webflow/resources/pages/resources/scripts/client.py +++ b/src/webflow/resources/pages/resources/scripts/client.py @@ -31,13 +31,7 @@ def get_custom_code( self, page_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> ScriptApplyList: """ - Get all registered scripts that have been applied to a specific Page. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Get all scripts applied to a page. Required scope | `custom_code:read` @@ -67,6 +61,7 @@ def get_custom_code( """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -144,15 +139,11 @@ def upsert_custom_code( request_options: typing.Optional[RequestOptions] = None, ) -> ScriptApplyList: """ - Add a registered script to a Page. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. + Apply scripts to a page. - A site can have a maximum of 800 registered scripts. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a page, the script must first be registered to a Site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write` @@ -204,6 +195,7 @@ def upsert_custom_code( """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="PUT", json={ "scripts": convert_and_respect_annotation_metadata( @@ -291,11 +283,7 @@ def upsert_custom_code( def delete_custom_code(self, page_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: """ - Delete the custom code block that an app has created for a page - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. + Delete a custom code block that the App created on a page. Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). @@ -326,6 +314,7 @@ def delete_custom_code(self, page_id: str, *, request_options: typing.Optional[R """ _response = self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -396,13 +385,7 @@ async def get_custom_code( self, page_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> ScriptApplyList: """ - Get all registered scripts that have been applied to a specific Page. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Get all scripts applied to a page. Required scope | `custom_code:read` @@ -440,6 +423,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -517,15 +501,11 @@ async def upsert_custom_code( request_options: typing.Optional[RequestOptions] = None, ) -> ScriptApplyList: """ - Add a registered script to a Page. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. + Apply scripts to a page. - A site can have a maximum of 800 registered scripts. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a page, the script must first be registered to a Site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write` @@ -585,6 +565,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="PUT", json={ "scripts": convert_and_respect_annotation_metadata( @@ -674,11 +655,7 @@ async def delete_custom_code( self, page_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> None: """ - Delete the custom code block that an app has created for a page - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. + Delete a custom code block that the App created on a page. Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). @@ -717,6 +694,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"pages/{jsonable_encoder(page_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) diff --git a/src/webflow/resources/products/__init__.py b/src/webflow/resources/products/__init__.py index 9fced2c..adf933b 100644 --- a/src/webflow/resources/products/__init__.py +++ b/src/webflow/resources/products/__init__.py @@ -1,5 +1,5 @@ # This file was auto-generated by Fern from our API Definition. -from .types import ProductsCreateSkuResponse +from .types import ProductSkuCreateProduct, ProductSkuCreateSku, ProductsCreateSkuResponse -__all__ = ["ProductsCreateSkuResponse"] +__all__ = ["ProductSkuCreateProduct", "ProductSkuCreateSku", "ProductsCreateSkuResponse"] diff --git a/src/webflow/resources/products/client.py b/src/webflow/resources/products/client.py index c856fef..2308a90 100644 --- a/src/webflow/resources/products/client.py +++ b/src/webflow/resources/products/client.py @@ -16,11 +16,13 @@ from ...errors.internal_server_error import InternalServerError from json.decoder import JSONDecodeError from ...core.api_error import ApiError +from .types.product_sku_create_product import ProductSkuCreateProduct +from .types.product_sku_create_sku import ProductSkuCreateSku from ...types.publish_status import PublishStatus -from ...types.product import Product -from ...types.sku import Sku from ...types.product_and_sk_us import ProductAndSkUs from ...core.serialization import convert_and_respect_annotation_metadata +from ...types.product import Product +from ...types.sku import Sku from .types.products_create_sku_response import ProductsCreateSkuResponse from ...core.client_wrapper import AsyncClientWrapper @@ -80,6 +82,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -175,9 +178,9 @@ def create( self, site_id: str, *, + product: ProductSkuCreateProduct, + sku: ProductSkuCreateSku, publish_status: typing.Optional[PublishStatus] = OMIT, - product: typing.Optional[Product] = OMIT, - sku: typing.Optional[Sku] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> ProductAndSkUs: """ @@ -201,11 +204,11 @@ def create( site_id : str Unique identifier for a Site - publish_status : typing.Optional[PublishStatus] + product : ProductSkuCreateProduct - product : typing.Optional[Product] + sku : ProductSkuCreateSku - sku : typing.Optional[Sku] + publish_status : typing.Optional[PublishStatus] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -217,24 +220,102 @@ def create( Examples -------- - from webflow import Webflow + from webflow import ( + ProductFieldData, + SkuFieldData, + SkuFieldDataPrice, + SkuPropertyList, + SkuPropertyListEnumItem, + Webflow, + ) + from webflow.resources.products import ( + ProductSkuCreateProduct, + ProductSkuCreateSku, + ) client = Webflow( access_token="YOUR_ACCESS_TOKEN", ) client.products.create( site_id="580e63e98c9a982ac9b8b741", + publish_status="staging", + product=ProductSkuCreateProduct( + field_data=ProductFieldData( + name="Colorful T-shirt", + slug="colorful-t-shirt", + description="Our best-selling t-shirt available in multiple colors and sizes", + sku_properties=[ + SkuPropertyList( + id="color", + name="Color", + enum=[ + SkuPropertyListEnumItem( + id="red", + name="Red", + slug="red", + ), + SkuPropertyListEnumItem( + id="yellow", + name="Yellow", + slug="yellow", + ), + SkuPropertyListEnumItem( + id="blue", + name="Blue", + slug="blue", + ), + ], + ), + SkuPropertyList( + id="size", + name="Size", + enum=[ + SkuPropertyListEnumItem( + id="small", + name="Small", + slug="small", + ), + SkuPropertyListEnumItem( + id="medium", + name="Medium", + slug="medium", + ), + SkuPropertyListEnumItem( + id="large", + name="Large", + slug="large", + ), + ], + ), + ], + ), + ), + sku=ProductSkuCreateSku( + field_data=SkuFieldData( + name="Colorful T-shirt - Red Small", + slug="colorful-t-shirt-red-small", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + main_image="https://rocketamp-sample-store.myshopify.com/cdn/shop/products/Gildan_2000_Antique_Cherry_Red_Front_1024x1024.jpg?v=1527232987", + ), + ), ) """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "publishStatus": publish_status, "product": convert_and_respect_annotation_metadata( - object_=product, annotation=Product, direction="write" + object_=product, annotation=ProductSkuCreateProduct, direction="write" + ), + "sku": convert_and_respect_annotation_metadata( + object_=sku, annotation=ProductSkuCreateSku, direction="write" ), - "sku": convert_and_respect_annotation_metadata(object_=sku, annotation=Sku, direction="write"), }, headers={ "content-type": "application/json", @@ -365,6 +446,7 @@ def get( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -505,6 +587,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "publishStatus": publish_status, @@ -642,7 +725,7 @@ def create_sku( Examples -------- - from webflow import Sku, Webflow + from webflow import Sku, SkuFieldData, SkuFieldDataPrice, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", @@ -650,11 +733,24 @@ def create_sku( client.products.create_sku( site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", - skus=[Sku()], + skus=[ + Sku( + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + ), + ) + ], ) """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}/skus", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "publishStatus": publish_status, @@ -794,7 +890,7 @@ def update_sku( Examples -------- - from webflow import Sku, Webflow + from webflow import Sku, SkuFieldData, SkuFieldDataPrice, Webflow client = Webflow( access_token="YOUR_ACCESS_TOKEN", @@ -803,11 +899,22 @@ def update_sku( site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", sku_id="5e8518516e147040726cc415", - sku=Sku(), + sku=Sku( + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + ), + ), ) """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}/skus/{jsonable_encoder(sku_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "publishStatus": publish_status, @@ -964,6 +1071,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -1059,9 +1167,9 @@ async def create( self, site_id: str, *, + product: ProductSkuCreateProduct, + sku: ProductSkuCreateSku, publish_status: typing.Optional[PublishStatus] = OMIT, - product: typing.Optional[Product] = OMIT, - sku: typing.Optional[Sku] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> ProductAndSkUs: """ @@ -1085,11 +1193,11 @@ async def create( site_id : str Unique identifier for a Site - publish_status : typing.Optional[PublishStatus] + product : ProductSkuCreateProduct - product : typing.Optional[Product] + sku : ProductSkuCreateSku - sku : typing.Optional[Sku] + publish_status : typing.Optional[PublishStatus] request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1103,7 +1211,18 @@ async def create( -------- import asyncio - from webflow import AsyncWebflow + from webflow import ( + AsyncWebflow, + ProductFieldData, + SkuFieldData, + SkuFieldDataPrice, + SkuPropertyList, + SkuPropertyListEnumItem, + ) + from webflow.resources.products import ( + ProductSkuCreateProduct, + ProductSkuCreateSku, + ) client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -1113,6 +1232,70 @@ async def create( async def main() -> None: await client.products.create( site_id="580e63e98c9a982ac9b8b741", + publish_status="staging", + product=ProductSkuCreateProduct( + field_data=ProductFieldData( + name="Colorful T-shirt", + slug="colorful-t-shirt", + description="Our best-selling t-shirt available in multiple colors and sizes", + sku_properties=[ + SkuPropertyList( + id="color", + name="Color", + enum=[ + SkuPropertyListEnumItem( + id="red", + name="Red", + slug="red", + ), + SkuPropertyListEnumItem( + id="yellow", + name="Yellow", + slug="yellow", + ), + SkuPropertyListEnumItem( + id="blue", + name="Blue", + slug="blue", + ), + ], + ), + SkuPropertyList( + id="size", + name="Size", + enum=[ + SkuPropertyListEnumItem( + id="small", + name="Small", + slug="small", + ), + SkuPropertyListEnumItem( + id="medium", + name="Medium", + slug="medium", + ), + SkuPropertyListEnumItem( + id="large", + name="Large", + slug="large", + ), + ], + ), + ], + ), + ), + sku=ProductSkuCreateSku( + field_data=SkuFieldData( + name="Colorful T-shirt - Red Small", + slug="colorful-t-shirt-red-small", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + main_image="https://rocketamp-sample-store.myshopify.com/cdn/shop/products/Gildan_2000_Antique_Cherry_Red_Front_1024x1024.jpg?v=1527232987", + ), + ), ) @@ -1120,13 +1303,16 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "publishStatus": publish_status, "product": convert_and_respect_annotation_metadata( - object_=product, annotation=Product, direction="write" + object_=product, annotation=ProductSkuCreateProduct, direction="write" + ), + "sku": convert_and_respect_annotation_metadata( + object_=sku, annotation=ProductSkuCreateSku, direction="write" ), - "sku": convert_and_respect_annotation_metadata(object_=sku, annotation=Sku, direction="write"), }, headers={ "content-type": "application/json", @@ -1265,6 +1451,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1413,6 +1600,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "publishStatus": publish_status, @@ -1552,7 +1740,7 @@ async def create_sku( -------- import asyncio - from webflow import AsyncWebflow, Sku + from webflow import AsyncWebflow, Sku, SkuFieldData, SkuFieldDataPrice client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -1563,7 +1751,19 @@ async def main() -> None: await client.products.create_sku( site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", - skus=[Sku()], + skus=[ + Sku( + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + ), + ) + ], ) @@ -1571,6 +1771,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}/skus", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "publishStatus": publish_status, @@ -1712,7 +1913,7 @@ async def update_sku( -------- import asyncio - from webflow import AsyncWebflow, Sku + from webflow import AsyncWebflow, Sku, SkuFieldData, SkuFieldDataPrice client = AsyncWebflow( access_token="YOUR_ACCESS_TOKEN", @@ -1724,7 +1925,17 @@ async def main() -> None: site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", sku_id="5e8518516e147040726cc415", - sku=Sku(), + sku=Sku( + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice( + value=2499.0, + unit="USD", + currency="USD", + ), + ), + ), ) @@ -1732,6 +1943,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/products/{jsonable_encoder(product_id)}/skus/{jsonable_encoder(sku_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "publishStatus": publish_status, diff --git a/src/webflow/resources/products/types/__init__.py b/src/webflow/resources/products/types/__init__.py index b078afe..5b6d9b4 100644 --- a/src/webflow/resources/products/types/__init__.py +++ b/src/webflow/resources/products/types/__init__.py @@ -1,5 +1,7 @@ # This file was auto-generated by Fern from our API Definition. +from .product_sku_create_product import ProductSkuCreateProduct +from .product_sku_create_sku import ProductSkuCreateSku from .products_create_sku_response import ProductsCreateSkuResponse -__all__ = ["ProductsCreateSkuResponse"] +__all__ = ["ProductSkuCreateProduct", "ProductSkuCreateSku", "ProductsCreateSkuResponse"] diff --git a/src/webflow/resources/products/types/product_sku_create_product.py b/src/webflow/resources/products/types/product_sku_create_product.py new file mode 100644 index 0000000..750e5f4 --- /dev/null +++ b/src/webflow/resources/products/types/product_sku_create_product.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from ....types.product_field_data import ProductFieldData +from ....core.serialization import FieldMetadata +from ....core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ProductSkuCreateProduct(UniversalBaseModel): + field_data: typing_extensions.Annotated[typing.Optional[ProductFieldData], FieldMetadata(alias="fieldData")] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/resources/products/types/product_sku_create_sku.py b/src/webflow/resources/products/types/product_sku_create_sku.py new file mode 100644 index 0000000..2762a9a --- /dev/null +++ b/src/webflow/resources/products/types/product_sku_create_sku.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +from ....core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from ....types.sku_field_data import SkuFieldData +from ....core.serialization import FieldMetadata +from ....core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ProductSkuCreateSku(UniversalBaseModel): + field_data: typing_extensions.Annotated[typing.Optional[SkuFieldData], FieldMetadata(alias="fieldData")] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/resources/products/types/products_create_sku_response.py b/src/webflow/resources/products/types/products_create_sku_response.py index e694930..cd68c3d 100644 --- a/src/webflow/resources/products/types/products_create_sku_response.py +++ b/src/webflow/resources/products/types/products_create_sku_response.py @@ -8,7 +8,7 @@ class ProductsCreateSkuResponse(UniversalBaseModel): - skus: typing.Optional[typing.List[Sku]] = None + skus: typing.List[Sku] if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/webflow/resources/scripts/client.py b/src/webflow/resources/scripts/client.py index e9112fb..80026d9 100644 --- a/src/webflow/resources/scripts/client.py +++ b/src/webflow/resources/scripts/client.py @@ -28,14 +28,11 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> RegisteredScriptList: """ - List of scripts registered to a Site. + Get a list of scripts that have been registered to a site. A site can have a maximum of 800 registered scripts. - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - Additionally, Scripts can be remotely hosted, or registered as inline snippets. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:read` @@ -65,6 +62,7 @@ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/registered_scripts", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -144,14 +142,11 @@ def register_hosted( request_options: typing.Optional[RequestOptions] = None, ) -> CustomCodeHostedResponse: """ - Add a script to a Site's Custom Code registry. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - Additionally, Scripts can be remotely hosted, or registered as inline snippets. + Register a hosted script to a site. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write` @@ -200,6 +195,7 @@ def register_hosted( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/registered_scripts/hosted", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "hostedLocation": hosted_location, @@ -290,13 +286,11 @@ def register_inline( request_options: typing.Optional[RequestOptions] = None, ) -> CustomCodeInlineResponse: """ - Add a script to a Site's Custom Code registry. Inline scripts can be between 1 and 2000 characters. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. + Register an inline script to a site. Inline scripts are limited to 2000 characters. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write` @@ -344,6 +338,7 @@ def register_inline( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/registered_scripts/inline", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "sourceCode": source_code, @@ -431,14 +426,11 @@ async def list( self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> RegisteredScriptList: """ - List of scripts registered to a Site. + Get a list of scripts that have been registered to a site. A site can have a maximum of 800 registered scripts. - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - Additionally, Scripts can be remotely hosted, or registered as inline snippets. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:read` @@ -476,6 +468,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/registered_scripts", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -555,14 +548,11 @@ async def register_hosted( request_options: typing.Optional[RequestOptions] = None, ) -> CustomCodeHostedResponse: """ - Add a script to a Site's Custom Code registry. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - Additionally, Scripts can be remotely hosted, or registered as inline snippets. + Register a hosted script to a site. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write` @@ -619,6 +609,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/registered_scripts/hosted", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "hostedLocation": hosted_location, @@ -709,13 +700,11 @@ async def register_inline( request_options: typing.Optional[RequestOptions] = None, ) -> CustomCodeInlineResponse: """ - Add a script to a Site's Custom Code registry. Inline scripts can be between 1 and 2000 characters. - - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. + Register an inline script to a site. Inline scripts are limited to 2000 characters. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write` @@ -771,6 +760,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/registered_scripts/inline", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "sourceCode": source_code, diff --git a/src/webflow/resources/sites/__init__.py b/src/webflow/resources/sites/__init__.py index 3ec19db..468a53e 100644 --- a/src/webflow/resources/sites/__init__.py +++ b/src/webflow/resources/sites/__init__.py @@ -1,6 +1,29 @@ # This file was auto-generated by Fern from our API Definition. from .types import SitesPublishResponse -from .resources import activity_logs, plans, redirects, scripts +from .resources import ( + CommentsGetCommentThreadRequestSortBy, + CommentsGetCommentThreadRequestSortOrder, + CommentsListCommentThreadsRequestSortBy, + CommentsListCommentThreadsRequestSortOrder, + activity_logs, + comments, + plans, + redirects, + robots_txt, + scripts, +) -__all__ = ["SitesPublishResponse", "activity_logs", "plans", "redirects", "scripts"] +__all__ = [ + "CommentsGetCommentThreadRequestSortBy", + "CommentsGetCommentThreadRequestSortOrder", + "CommentsListCommentThreadsRequestSortBy", + "CommentsListCommentThreadsRequestSortOrder", + "SitesPublishResponse", + "activity_logs", + "comments", + "plans", + "redirects", + "robots_txt", + "scripts", +] diff --git a/src/webflow/resources/sites/client.py b/src/webflow/resources/sites/client.py index c2a4468..cb72972 100644 --- a/src/webflow/resources/sites/client.py +++ b/src/webflow/resources/sites/client.py @@ -4,7 +4,9 @@ from ...core.client_wrapper import SyncClientWrapper from .resources.redirects.client import RedirectsClient from .resources.plans.client import PlansClient +from .resources.robots_txt.client import RobotsTxtClient from .resources.activity_logs.client import ActivityLogsClient +from .resources.comments.client import CommentsClient from .resources.scripts.client import ScriptsClient from ...core.request_options import RequestOptions from ...types.site import Site @@ -25,7 +27,9 @@ from ...core.client_wrapper import AsyncClientWrapper from .resources.redirects.client import AsyncRedirectsClient from .resources.plans.client import AsyncPlansClient +from .resources.robots_txt.client import AsyncRobotsTxtClient from .resources.activity_logs.client import AsyncActivityLogsClient +from .resources.comments.client import AsyncCommentsClient from .resources.scripts.client import AsyncScriptsClient # this is used as the default value for optional parameters @@ -37,7 +41,9 @@ def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper self.redirects = RedirectsClient(client_wrapper=self._client_wrapper) self.plans = PlansClient(client_wrapper=self._client_wrapper) + self.robots_txt = RobotsTxtClient(client_wrapper=self._client_wrapper) self.activity_logs = ActivityLogsClient(client_wrapper=self._client_wrapper) + self.comments = CommentsClient(client_wrapper=self._client_wrapper) self.scripts = ScriptsClient(client_wrapper=self._client_wrapper) def create( @@ -50,7 +56,9 @@ def create( request_options: typing.Optional[RequestOptions] = None, ) -> Site: """ - Create a site. This endpoint requires an Enterprise workspace. + Create a site. + + This endpoint requires an Enterprise workspace. Required scope | `workspace:write` @@ -90,6 +98,7 @@ def create( """ _response = self._client_wrapper.httpx_client.request( f"workspaces/{jsonable_encoder(workspace_id)}/sites", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "name": name, @@ -203,6 +212,7 @@ def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> Si """ _response = self._client_wrapper.httpx_client.request( "sites", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -282,6 +292,7 @@ def get(self, site_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -351,7 +362,9 @@ def get(self, site_id: str, *, request_options: typing.Optional[RequestOptions] def delete(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: """ - Delete a site. This endpoint requires an Enterprise workspace. + Delete a site. + + This endpoint requires an Enterprise workspace. Required scope | `sites:write` @@ -380,6 +393,7 @@ def delete(self, site_id: str, *, request_options: typing.Optional[RequestOption """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -460,7 +474,9 @@ def update( request_options: typing.Optional[RequestOptions] = None, ) -> Site: """ - Update a site. This endpoint requires an Enterprise workspace. + Update a site. + + This endpoint requires an Enterprise workspace. Required scope | `sites:write` @@ -496,6 +512,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "name": name, @@ -613,6 +630,7 @@ def get_custom_domain(self, site_id: str, *, request_options: typing.Optional[Re """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_domains", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -727,6 +745,7 @@ def publish( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/publish", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "customDomains": custom_domains, @@ -808,7 +827,9 @@ def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper self.redirects = AsyncRedirectsClient(client_wrapper=self._client_wrapper) self.plans = AsyncPlansClient(client_wrapper=self._client_wrapper) + self.robots_txt = AsyncRobotsTxtClient(client_wrapper=self._client_wrapper) self.activity_logs = AsyncActivityLogsClient(client_wrapper=self._client_wrapper) + self.comments = AsyncCommentsClient(client_wrapper=self._client_wrapper) self.scripts = AsyncScriptsClient(client_wrapper=self._client_wrapper) async def create( @@ -821,7 +842,9 @@ async def create( request_options: typing.Optional[RequestOptions] = None, ) -> Site: """ - Create a site. This endpoint requires an Enterprise workspace. + Create a site. + + This endpoint requires an Enterprise workspace. Required scope | `workspace:write` @@ -869,6 +892,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"workspaces/{jsonable_encoder(workspace_id)}/sites", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "name": name, @@ -990,6 +1014,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( "sites", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1077,6 +1102,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1146,7 +1172,9 @@ async def main() -> None: async def delete(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: """ - Delete a site. This endpoint requires an Enterprise workspace. + Delete a site. + + This endpoint requires an Enterprise workspace. Required scope | `sites:write` @@ -1183,6 +1211,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -1263,7 +1292,9 @@ async def update( request_options: typing.Optional[RequestOptions] = None, ) -> Site: """ - Update a site. This endpoint requires an Enterprise workspace. + Update a site. + + This endpoint requires an Enterprise workspace. Required scope | `sites:write` @@ -1307,6 +1338,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "name": name, @@ -1434,6 +1466,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_domains", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -1556,6 +1589,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/publish", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "customDomains": custom_domains, diff --git a/src/webflow/resources/sites/resources/__init__.py b/src/webflow/resources/sites/resources/__init__.py index 1197a83..2bc2a27 100644 --- a/src/webflow/resources/sites/resources/__init__.py +++ b/src/webflow/resources/sites/resources/__init__.py @@ -1,5 +1,22 @@ # This file was auto-generated by Fern from our API Definition. -from . import activity_logs, plans, redirects, scripts +from . import activity_logs, comments, plans, redirects, robots_txt, scripts +from .comments import ( + CommentsGetCommentThreadRequestSortBy, + CommentsGetCommentThreadRequestSortOrder, + CommentsListCommentThreadsRequestSortBy, + CommentsListCommentThreadsRequestSortOrder, +) -__all__ = ["activity_logs", "plans", "redirects", "scripts"] +__all__ = [ + "CommentsGetCommentThreadRequestSortBy", + "CommentsGetCommentThreadRequestSortOrder", + "CommentsListCommentThreadsRequestSortBy", + "CommentsListCommentThreadsRequestSortOrder", + "activity_logs", + "comments", + "plans", + "redirects", + "robots_txt", + "scripts", +] diff --git a/src/webflow/resources/sites/resources/activity_logs/client.py b/src/webflow/resources/sites/resources/activity_logs/client.py index cf4e1b3..1a1eb8e 100644 --- a/src/webflow/resources/sites/resources/activity_logs/client.py +++ b/src/webflow/resources/sites/resources/activity_logs/client.py @@ -29,7 +29,11 @@ def list( request_options: typing.Optional[RequestOptions] = None, ) -> SiteActivityLogResponse: """ - Retrieve Activity Logs for a specific Site. Requires Site to be on an Enterprise plan.

Required scope | `site_activity:read` + Retrieve Activity Logs for a specific Site. + + This endpoint requires an Enterprise workspace. + + Required scope: `site_activity:read` Parameters ---------- @@ -63,6 +67,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/activity_logs", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "limit": limit, @@ -138,7 +143,11 @@ async def list( request_options: typing.Optional[RequestOptions] = None, ) -> SiteActivityLogResponse: """ - Retrieve Activity Logs for a specific Site. Requires Site to be on an Enterprise plan.

Required scope | `site_activity:read` + Retrieve Activity Logs for a specific Site. + + This endpoint requires an Enterprise workspace. + + Required scope: `site_activity:read` Parameters ---------- @@ -180,6 +189,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/activity_logs", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "limit": limit, diff --git a/src/webflow/resources/sites/resources/comments/__init__.py b/src/webflow/resources/sites/resources/comments/__init__.py new file mode 100644 index 0000000..7db32b5 --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/__init__.py @@ -0,0 +1,19 @@ +# This file was auto-generated by Fern from our API Definition. + +from .types import ( + CommentsGetCommentThreadRequestSortBy, + CommentsGetCommentThreadRequestSortOrder, + CommentsListCommentThreadsRequestSortBy, + CommentsListCommentThreadsRequestSortOrder, +) +from .resources import RepliesListRepliesRequestSortBy, RepliesListRepliesRequestSortOrder, replies + +__all__ = [ + "CommentsGetCommentThreadRequestSortBy", + "CommentsGetCommentThreadRequestSortOrder", + "CommentsListCommentThreadsRequestSortBy", + "CommentsListCommentThreadsRequestSortOrder", + "RepliesListRepliesRequestSortBy", + "RepliesListRepliesRequestSortOrder", + "replies", +] diff --git a/src/webflow/resources/sites/resources/comments/client.py b/src/webflow/resources/sites/resources/comments/client.py new file mode 100644 index 0000000..c7c59ab --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/client.py @@ -0,0 +1,594 @@ +# This file was auto-generated by Fern from our API Definition. + +from .....core.client_wrapper import SyncClientWrapper +from .resources.replies.client import RepliesClient +import typing +from .types.comments_list_comment_threads_request_sort_by import CommentsListCommentThreadsRequestSortBy +from .types.comments_list_comment_threads_request_sort_order import CommentsListCommentThreadsRequestSortOrder +from .....core.request_options import RequestOptions +from .....types.comment_thread_list import CommentThreadList +from .....core.jsonable_encoder import jsonable_encoder +from .....core.pydantic_utilities import parse_obj_as +from .....errors.bad_request_error import BadRequestError +from .....errors.unauthorized_error import UnauthorizedError +from .....types.error import Error +from .....errors.not_found_error import NotFoundError +from .....errors.too_many_requests_error import TooManyRequestsError +from .....errors.internal_server_error import InternalServerError +from json.decoder import JSONDecodeError +from .....core.api_error import ApiError +from .types.comments_get_comment_thread_request_sort_by import CommentsGetCommentThreadRequestSortBy +from .types.comments_get_comment_thread_request_sort_order import CommentsGetCommentThreadRequestSortOrder +from .....types.comment_thread import CommentThread +from .....core.client_wrapper import AsyncClientWrapper +from .resources.replies.client import AsyncRepliesClient + + +class CommentsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + self.replies = RepliesClient(client_wrapper=self._client_wrapper) + + def list_comment_threads( + self, + site_id: str, + *, + locale_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + sort_by: typing.Optional[CommentsListCommentThreadsRequestSortBy] = None, + sort_order: typing.Optional[CommentsListCommentThreadsRequestSortOrder] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CommentThreadList: + """ + List all comment threads for a site. + + Required scope | `comments:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + locale_id : typing.Optional[str] + Unique identifier for a specific locale. Applicable, when using localization. + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + sort_by : typing.Optional[CommentsListCommentThreadsRequestSortBy] + Sort results by the provided value. Only allowed when sortOrder is provided. + + sort_order : typing.Optional[CommentsListCommentThreadsRequestSortOrder] + Sorts the results by asc or desc + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CommentThreadList + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.comments.list_comment_threads( + site_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/comments", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "localeId": locale_id, + "offset": offset, + "limit": limit, + "sortBy": sort_by, + "sortOrder": sort_order, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CommentThreadList, + parse_obj_as( + type_=CommentThreadList, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + def get_comment_thread( + self, + site_id: str, + comment_thread_id: str, + *, + locale_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + sort_by: typing.Optional[CommentsGetCommentThreadRequestSortBy] = None, + sort_order: typing.Optional[CommentsGetCommentThreadRequestSortOrder] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CommentThread: + """ + Get details of a specific comment thread. + + Required scope | `comments:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + comment_thread_id : str + Unique identifier for a Comment Thread + + locale_id : typing.Optional[str] + Unique identifier for a specific locale. Applicable, when using localization. + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + sort_by : typing.Optional[CommentsGetCommentThreadRequestSortBy] + Sort results by the provided value. Only allowed when sortOrder is provided. + + sort_order : typing.Optional[CommentsGetCommentThreadRequestSortOrder] + Sorts the results by asc or desc + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CommentThread + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.comments.get_comment_thread( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/comments/{jsonable_encoder(comment_thread_id)}", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "localeId": locale_id, + "offset": offset, + "limit": limit, + "sortBy": sort_by, + "sortOrder": sort_order, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CommentThread, + parse_obj_as( + type_=CommentThread, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + +class AsyncCommentsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + self.replies = AsyncRepliesClient(client_wrapper=self._client_wrapper) + + async def list_comment_threads( + self, + site_id: str, + *, + locale_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + sort_by: typing.Optional[CommentsListCommentThreadsRequestSortBy] = None, + sort_order: typing.Optional[CommentsListCommentThreadsRequestSortOrder] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CommentThreadList: + """ + List all comment threads for a site. + + Required scope | `comments:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + locale_id : typing.Optional[str] + Unique identifier for a specific locale. Applicable, when using localization. + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + sort_by : typing.Optional[CommentsListCommentThreadsRequestSortBy] + Sort results by the provided value. Only allowed when sortOrder is provided. + + sort_order : typing.Optional[CommentsListCommentThreadsRequestSortOrder] + Sorts the results by asc or desc + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CommentThreadList + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.comments.list_comment_threads( + site_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/comments", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "localeId": locale_id, + "offset": offset, + "limit": limit, + "sortBy": sort_by, + "sortOrder": sort_order, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CommentThreadList, + parse_obj_as( + type_=CommentThreadList, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def get_comment_thread( + self, + site_id: str, + comment_thread_id: str, + *, + locale_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + sort_by: typing.Optional[CommentsGetCommentThreadRequestSortBy] = None, + sort_order: typing.Optional[CommentsGetCommentThreadRequestSortOrder] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CommentThread: + """ + Get details of a specific comment thread. + + Required scope | `comments:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + comment_thread_id : str + Unique identifier for a Comment Thread + + locale_id : typing.Optional[str] + Unique identifier for a specific locale. Applicable, when using localization. + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + sort_by : typing.Optional[CommentsGetCommentThreadRequestSortBy] + Sort results by the provided value. Only allowed when sortOrder is provided. + + sort_order : typing.Optional[CommentsGetCommentThreadRequestSortOrder] + Sorts the results by asc or desc + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CommentThread + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.comments.get_comment_thread( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/comments/{jsonable_encoder(comment_thread_id)}", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "localeId": locale_id, + "offset": offset, + "limit": limit, + "sortBy": sort_by, + "sortOrder": sort_order, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CommentThread, + parse_obj_as( + type_=CommentThread, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/webflow/resources/sites/resources/comments/resources/__init__.py b/src/webflow/resources/sites/resources/comments/resources/__init__.py new file mode 100644 index 0000000..2897b99 --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/resources/__init__.py @@ -0,0 +1,6 @@ +# This file was auto-generated by Fern from our API Definition. + +from . import replies +from .replies import RepliesListRepliesRequestSortBy, RepliesListRepliesRequestSortOrder + +__all__ = ["RepliesListRepliesRequestSortBy", "RepliesListRepliesRequestSortOrder", "replies"] diff --git a/src/webflow/resources/sites/resources/comments/resources/replies/__init__.py b/src/webflow/resources/sites/resources/comments/resources/replies/__init__.py new file mode 100644 index 0000000..752cc68 --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/resources/replies/__init__.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .types import RepliesListRepliesRequestSortBy, RepliesListRepliesRequestSortOrder + +__all__ = ["RepliesListRepliesRequestSortBy", "RepliesListRepliesRequestSortOrder"] diff --git a/src/webflow/resources/sites/resources/comments/resources/replies/client.py b/src/webflow/resources/sites/resources/comments/resources/replies/client.py new file mode 100644 index 0000000..42f5d91 --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/resources/replies/client.py @@ -0,0 +1,313 @@ +# This file was auto-generated by Fern from our API Definition. + +from .......core.client_wrapper import SyncClientWrapper +import typing +from .types.replies_list_replies_request_sort_by import RepliesListRepliesRequestSortBy +from .types.replies_list_replies_request_sort_order import RepliesListRepliesRequestSortOrder +from .......core.request_options import RequestOptions +from .......types.comment_reply_list import CommentReplyList +from .......core.jsonable_encoder import jsonable_encoder +from .......core.pydantic_utilities import parse_obj_as +from .......errors.bad_request_error import BadRequestError +from .......errors.unauthorized_error import UnauthorizedError +from .......types.error import Error +from .......errors.not_found_error import NotFoundError +from .......errors.too_many_requests_error import TooManyRequestsError +from .......errors.internal_server_error import InternalServerError +from json.decoder import JSONDecodeError +from .......core.api_error import ApiError +from .......core.client_wrapper import AsyncClientWrapper + + +class RepliesClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def list_replies( + self, + site_id: str, + comment_thread_id: str, + *, + locale_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + sort_by: typing.Optional[RepliesListRepliesRequestSortBy] = None, + sort_order: typing.Optional[RepliesListRepliesRequestSortOrder] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CommentReplyList: + """ + List all replies to a specific comment thread. + + Required scope | `comments:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + comment_thread_id : str + Unique identifier for a Comment Thread + + locale_id : typing.Optional[str] + Unique identifier for a specific locale. Applicable, when using localization. + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + sort_by : typing.Optional[RepliesListRepliesRequestSortBy] + Sort results by the provided value. Only allowed when sortOrder is provided. + + sort_order : typing.Optional[RepliesListRepliesRequestSortOrder] + Sorts the results by asc or desc + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CommentReplyList + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.comments.replies.list_replies( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/comments/{jsonable_encoder(comment_thread_id)}/replies", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "localeId": locale_id, + "offset": offset, + "limit": limit, + "sortBy": sort_by, + "sortOrder": sort_order, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CommentReplyList, + parse_obj_as( + type_=CommentReplyList, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + +class AsyncRepliesClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def list_replies( + self, + site_id: str, + comment_thread_id: str, + *, + locale_id: typing.Optional[str] = None, + offset: typing.Optional[float] = None, + limit: typing.Optional[float] = None, + sort_by: typing.Optional[RepliesListRepliesRequestSortBy] = None, + sort_order: typing.Optional[RepliesListRepliesRequestSortOrder] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> CommentReplyList: + """ + List all replies to a specific comment thread. + + Required scope | `comments:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + comment_thread_id : str + Unique identifier for a Comment Thread + + locale_id : typing.Optional[str] + Unique identifier for a specific locale. Applicable, when using localization. + + offset : typing.Optional[float] + Offset used for pagination if the results have more than limit records + + limit : typing.Optional[float] + Maximum number of records to be returned (max limit: 100) + + sort_by : typing.Optional[RepliesListRepliesRequestSortBy] + Sort results by the provided value. Only allowed when sortOrder is provided. + + sort_order : typing.Optional[RepliesListRepliesRequestSortOrder] + Sorts the results by asc or desc + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CommentReplyList + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.comments.replies.list_replies( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/comments/{jsonable_encoder(comment_thread_id)}/replies", + base_url=self._client_wrapper.get_environment().base, + method="GET", + params={ + "localeId": locale_id, + "offset": offset, + "limit": limit, + "sortBy": sort_by, + "sortOrder": sort_order, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CommentReplyList, + parse_obj_as( + type_=CommentReplyList, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/webflow/resources/sites/resources/comments/resources/replies/types/__init__.py b/src/webflow/resources/sites/resources/comments/resources/replies/types/__init__.py new file mode 100644 index 0000000..8f288df --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/resources/replies/types/__init__.py @@ -0,0 +1,6 @@ +# This file was auto-generated by Fern from our API Definition. + +from .replies_list_replies_request_sort_by import RepliesListRepliesRequestSortBy +from .replies_list_replies_request_sort_order import RepliesListRepliesRequestSortOrder + +__all__ = ["RepliesListRepliesRequestSortBy", "RepliesListRepliesRequestSortOrder"] diff --git a/src/webflow/resources/sites/resources/comments/resources/replies/types/replies_list_replies_request_sort_by.py b/src/webflow/resources/sites/resources/comments/resources/replies/types/replies_list_replies_request_sort_by.py new file mode 100644 index 0000000..35cbeff --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/resources/replies/types/replies_list_replies_request_sort_by.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +RepliesListRepliesRequestSortBy = typing.Union[typing.Literal["createdOn", "lastUpdated"], typing.Any] diff --git a/src/webflow/resources/sites/resources/comments/resources/replies/types/replies_list_replies_request_sort_order.py b/src/webflow/resources/sites/resources/comments/resources/replies/types/replies_list_replies_request_sort_order.py new file mode 100644 index 0000000..cd8891e --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/resources/replies/types/replies_list_replies_request_sort_order.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +RepliesListRepliesRequestSortOrder = typing.Union[typing.Literal["asc", "desc"], typing.Any] diff --git a/src/webflow/resources/sites/resources/comments/types/__init__.py b/src/webflow/resources/sites/resources/comments/types/__init__.py new file mode 100644 index 0000000..e72e29e --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/types/__init__.py @@ -0,0 +1,13 @@ +# This file was auto-generated by Fern from our API Definition. + +from .comments_get_comment_thread_request_sort_by import CommentsGetCommentThreadRequestSortBy +from .comments_get_comment_thread_request_sort_order import CommentsGetCommentThreadRequestSortOrder +from .comments_list_comment_threads_request_sort_by import CommentsListCommentThreadsRequestSortBy +from .comments_list_comment_threads_request_sort_order import CommentsListCommentThreadsRequestSortOrder + +__all__ = [ + "CommentsGetCommentThreadRequestSortBy", + "CommentsGetCommentThreadRequestSortOrder", + "CommentsListCommentThreadsRequestSortBy", + "CommentsListCommentThreadsRequestSortOrder", +] diff --git a/src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_by.py b/src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_by.py new file mode 100644 index 0000000..14daabb --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_by.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CommentsGetCommentThreadRequestSortBy = typing.Union[typing.Literal["createdOn", "lastUpdated"], typing.Any] diff --git a/src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_order.py b/src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_order.py new file mode 100644 index 0000000..3da3ffc --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/types/comments_get_comment_thread_request_sort_order.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CommentsGetCommentThreadRequestSortOrder = typing.Union[typing.Literal["asc", "desc"], typing.Any] diff --git a/src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_by.py b/src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_by.py new file mode 100644 index 0000000..1d541ce --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_by.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CommentsListCommentThreadsRequestSortBy = typing.Union[typing.Literal["createdOn", "lastUpdated"], typing.Any] diff --git a/src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_order.py b/src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_order.py new file mode 100644 index 0000000..d2c2606 --- /dev/null +++ b/src/webflow/resources/sites/resources/comments/types/comments_list_comment_threads_request_sort_order.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CommentsListCommentThreadsRequestSortOrder = typing.Union[typing.Literal["asc", "desc"], typing.Any] diff --git a/src/webflow/resources/sites/resources/plans/client.py b/src/webflow/resources/sites/resources/plans/client.py index 291231a..a3309bb 100644 --- a/src/webflow/resources/sites/resources/plans/client.py +++ b/src/webflow/resources/sites/resources/plans/client.py @@ -25,6 +25,8 @@ def get_site_plan(self, site_id: str, *, request_options: typing.Optional[Reques """ Get site plan details for the specified Site. + This endpoint requires an Enterprise workspace. + Required scope | `sites:read` Parameters @@ -53,6 +55,7 @@ def get_site_plan(self, site_id: str, *, request_options: typing.Optional[Reques """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/plan", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -129,6 +132,8 @@ async def get_site_plan(self, site_id: str, *, request_options: typing.Optional[ """ Get site plan details for the specified Site. + This endpoint requires an Enterprise workspace. + Required scope | `sites:read` Parameters @@ -165,6 +170,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/plan", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) diff --git a/src/webflow/resources/sites/resources/redirects/client.py b/src/webflow/resources/sites/resources/redirects/client.py index 4bc0e7b..8289457 100644 --- a/src/webflow/resources/sites/resources/redirects/client.py +++ b/src/webflow/resources/sites/resources/redirects/client.py @@ -31,6 +31,7 @@ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] Use this endpoint to review, audit, or manage the redirection rules that control how traffic is rerouted on your site. + This endpoint requires an Enterprise workspace. Required scope: `sites:read` @@ -60,6 +61,7 @@ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -141,6 +143,8 @@ def create( This endpoint allows you to define a source path (`fromUrl`) and its corresponding destination path (`toUrl`), which will dictate how traffic is rerouted on your site. This is useful for managing site changes, restructuring URLs, or handling outdated links. + This endpoint requires an Enterprise workspace. + Required scope: `sites:write` Parameters @@ -181,6 +185,7 @@ def create( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "id": id, @@ -259,7 +264,11 @@ def delete( ) -> Redirects: """ Remove a URL redirection rule from a site. + This is useful for cleaning up outdated or unnecessary redirects, ensuring that your site's routing behavior remains efficient and up-to-date. + + This endpoint requires an Enterprise workspace. + Required scope: `sites:write` Parameters @@ -292,6 +301,7 @@ def delete( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects/{jsonable_encoder(redirect_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -371,6 +381,9 @@ def update( ) -> Redirect: """ Update a URL redirection rule from a site. + + This endpoint requires an Enterprise workspace. + Required scope: `sites:write` Parameters @@ -415,6 +428,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects/{jsonable_encoder(redirect_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "id": id, @@ -499,6 +513,7 @@ async def list(self, site_id: str, *, request_options: typing.Optional[RequestOp Use this endpoint to review, audit, or manage the redirection rules that control how traffic is rerouted on your site. + This endpoint requires an Enterprise workspace. Required scope: `sites:read` @@ -536,6 +551,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -617,6 +633,8 @@ async def create( This endpoint allows you to define a source path (`fromUrl`) and its corresponding destination path (`toUrl`), which will dictate how traffic is rerouted on your site. This is useful for managing site changes, restructuring URLs, or handling outdated links. + This endpoint requires an Enterprise workspace. + Required scope: `sites:write` Parameters @@ -665,6 +683,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "id": id, @@ -743,7 +762,11 @@ async def delete( ) -> Redirects: """ Remove a URL redirection rule from a site. + This is useful for cleaning up outdated or unnecessary redirects, ensuring that your site's routing behavior remains efficient and up-to-date. + + This endpoint requires an Enterprise workspace. + Required scope: `sites:write` Parameters @@ -784,6 +807,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects/{jsonable_encoder(redirect_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -863,6 +887,9 @@ async def update( ) -> Redirect: """ Update a URL redirection rule from a site. + + This endpoint requires an Enterprise workspace. + Required scope: `sites:write` Parameters @@ -915,6 +942,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/redirects/{jsonable_encoder(redirect_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "id": id, diff --git a/src/webflow/resources/sites/resources/robots_txt/__init__.py b/src/webflow/resources/sites/resources/robots_txt/__init__.py new file mode 100644 index 0000000..f3ea265 --- /dev/null +++ b/src/webflow/resources/sites/resources/robots_txt/__init__.py @@ -0,0 +1,2 @@ +# This file was auto-generated by Fern from our API Definition. + diff --git a/src/webflow/resources/sites/resources/robots_txt/client.py b/src/webflow/resources/sites/resources/robots_txt/client.py new file mode 100644 index 0000000..8be1362 --- /dev/null +++ b/src/webflow/resources/sites/resources/robots_txt/client.py @@ -0,0 +1,1034 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from .....core.client_wrapper import SyncClientWrapper +from .....core.request_options import RequestOptions +from .....types.robots import Robots +from .....core.jsonable_encoder import jsonable_encoder +from .....core.pydantic_utilities import parse_obj_as +from .....errors.bad_request_error import BadRequestError +from .....errors.unauthorized_error import UnauthorizedError +from .....types.error import Error +from .....errors.not_found_error import NotFoundError +from .....errors.too_many_requests_error import TooManyRequestsError +from .....errors.internal_server_error import InternalServerError +from json.decoder import JSONDecodeError +from .....core.api_error import ApiError +from .....types.robots_rules_item import RobotsRulesItem +from .....core.serialization import convert_and_respect_annotation_metadata +from .....core.client_wrapper import AsyncClientWrapper + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RobotsTxtClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Robots: + """ + Retrieve the robots.txt configuration for various user agents. + + Required scope: `site_config:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.robots_txt.get( + site_id="580e63e98c9a982ac9b8b741", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + def put( + self, + site_id: str, + *, + rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT, + sitemap: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Robots: + """ + Replace the `robots.txt` configuration for various user agents. + + Required scope | `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + rules : typing.Optional[typing.Sequence[RobotsRulesItem]] + List of rules for user agents. + + sitemap : typing.Optional[str] + URL to the sitemap. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + from webflow import RobotsRulesItem, Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.robots_txt.put( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", + allows=["/public"], + disallows=["/vogon-poetry", "/total-perspective-vortex"], + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="PUT", + json={ + "rules": convert_and_respect_annotation_metadata( + object_=rules, annotation=typing.Sequence[RobotsRulesItem], direction="write" + ), + "sitemap": sitemap, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + def delete( + self, + site_id: str, + *, + rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT, + sitemap: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Robots: + """ + Remove specific rules for a user-agent in your `robots.txt` file. To delete all rules for a user-agent, provide an empty rule set. This will remove the user-agent's entry entirely, leaving it subject to your site's default crawling behavior. + + **Note:** Deleting a user-agent with no rules will make the user-agent's access unrestricted unless other directives apply. + + Required scope: `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + rules : typing.Optional[typing.Sequence[RobotsRulesItem]] + List of rules for user agents. + + sitemap : typing.Optional[str] + URL to the sitemap. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + from webflow import RobotsRulesItem, Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.robots_txt.delete( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="*", + allows=["/public"], + disallows=["/bubbles"], + ) + ], + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + json={ + "rules": convert_and_respect_annotation_metadata( + object_=rules, annotation=typing.Sequence[RobotsRulesItem], direction="write" + ), + "sitemap": sitemap, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + def patch( + self, + site_id: str, + *, + rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT, + sitemap: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Robots: + """ + Update the `robots.txt` configuration for various user agents. + + Required scope | `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + rules : typing.Optional[typing.Sequence[RobotsRulesItem]] + List of rules for user agents. + + sitemap : typing.Optional[str] + URL to the sitemap. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + from webflow import RobotsRulesItem, Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.sites.robots_txt.patch( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", + allows=["/public"], + disallows=["/vogon-poetry", "/total-perspective-vortex"], + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="PATCH", + json={ + "rules": convert_and_respect_annotation_metadata( + object_=rules, annotation=typing.Sequence[RobotsRulesItem], direction="write" + ), + "sitemap": sitemap, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + +class AsyncRobotsTxtClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Robots: + """ + Retrieve the robots.txt configuration for various user agents. + + Required scope: `site_config:read` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.robots_txt.get( + site_id="580e63e98c9a982ac9b8b741", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def put( + self, + site_id: str, + *, + rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT, + sitemap: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Robots: + """ + Replace the `robots.txt` configuration for various user agents. + + Required scope | `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + rules : typing.Optional[typing.Sequence[RobotsRulesItem]] + List of rules for user agents. + + sitemap : typing.Optional[str] + URL to the sitemap. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow, RobotsRulesItem + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.robots_txt.put( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", + allows=["/public"], + disallows=["/vogon-poetry", "/total-perspective-vortex"], + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="PUT", + json={ + "rules": convert_and_respect_annotation_metadata( + object_=rules, annotation=typing.Sequence[RobotsRulesItem], direction="write" + ), + "sitemap": sitemap, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def delete( + self, + site_id: str, + *, + rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT, + sitemap: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Robots: + """ + Remove specific rules for a user-agent in your `robots.txt` file. To delete all rules for a user-agent, provide an empty rule set. This will remove the user-agent's entry entirely, leaving it subject to your site's default crawling behavior. + + **Note:** Deleting a user-agent with no rules will make the user-agent's access unrestricted unless other directives apply. + + Required scope: `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + rules : typing.Optional[typing.Sequence[RobotsRulesItem]] + List of rules for user agents. + + sitemap : typing.Optional[str] + URL to the sitemap. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow, RobotsRulesItem + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.robots_txt.delete( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="*", + allows=["/public"], + disallows=["/bubbles"], + ) + ], + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + json={ + "rules": convert_and_respect_annotation_metadata( + object_=rules, annotation=typing.Sequence[RobotsRulesItem], direction="write" + ), + "sitemap": sitemap, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def patch( + self, + site_id: str, + *, + rules: typing.Optional[typing.Sequence[RobotsRulesItem]] = OMIT, + sitemap: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Robots: + """ + Update the `robots.txt` configuration for various user agents. + + Required scope | `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + rules : typing.Optional[typing.Sequence[RobotsRulesItem]] + List of rules for user agents. + + sitemap : typing.Optional[str] + URL to the sitemap. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Robots + Request was successful + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow, RobotsRulesItem + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.sites.robots_txt.patch( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", + allows=["/public"], + disallows=["/vogon-poetry", "/total-perspective-vortex"], + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/robots_txt", + base_url=self._client_wrapper.get_environment().base, + method="PATCH", + json={ + "rules": convert_and_respect_annotation_metadata( + object_=rules, annotation=typing.Sequence[RobotsRulesItem], direction="write" + ), + "sitemap": sitemap, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + Robots, + parse_obj_as( + type_=Robots, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/webflow/resources/sites/resources/scripts/client.py b/src/webflow/resources/sites/resources/scripts/client.py index 1954842..8af188b 100644 --- a/src/webflow/resources/sites/resources/scripts/client.py +++ b/src/webflow/resources/sites/resources/scripts/client.py @@ -31,9 +31,11 @@ def get_custom_code( self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> ScriptApplyList: """ - Get all registered scripts that have been applied to a specific Site. + Get all scripts applied to a site by the App. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:read` @@ -63,6 +65,7 @@ def get_custom_code( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -140,13 +143,11 @@ def upsert_custom_code( request_options: typing.Optional[RequestOptions] = None, ) -> ScriptApplyList: """ - Add a registered script to a Site. + Apply registered scripts to a site. - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write` @@ -198,6 +199,7 @@ def upsert_custom_code( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="PUT", json={ "scripts": convert_and_respect_annotation_metadata( @@ -275,9 +277,7 @@ def upsert_custom_code( def delete_custom_code(self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: """ - Delete the custom code block that an app created for a Site - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Remove scripts from a site applied by the App. This endpoint will not remove scripts from the site's registered scripts. Required scope | `custom_code:write` @@ -306,6 +306,7 @@ def delete_custom_code(self, site_id: str, *, request_options: typing.Optional[R """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -376,9 +377,13 @@ def list_custom_code_blocks( request_options: typing.Optional[RequestOptions] = None, ) -> ListCustomCodeBlocks: """ - Get all instances of Custom Code applied to a Site or Pages. + Get a list of scripts that have been applied to a site and/or individual pages. + + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:read` @@ -414,6 +419,7 @@ def list_custom_code_blocks( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code/blocks", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -494,9 +500,11 @@ async def get_custom_code( self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> ScriptApplyList: """ - Get all registered scripts that have been applied to a specific Site. + Get all scripts applied to a site by the App. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:read` @@ -534,6 +542,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -611,13 +620,11 @@ async def upsert_custom_code( request_options: typing.Optional[RequestOptions] = None, ) -> ScriptApplyList: """ - Add a registered script to a Site. + Apply registered scripts to a site. - In order to use the Custom Code APIs for Sites and Pages, Custom Code Scripts must first be registered - to a Site via the `registered_scripts` endpoints, and then applied to a Site or Page using the appropriate - `custom_code` endpoints. - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:write` @@ -677,6 +684,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="PUT", json={ "scripts": convert_and_respect_annotation_metadata( @@ -756,9 +764,7 @@ async def delete_custom_code( self, site_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> None: """ - Delete the custom code block that an app created for a Site - - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + Remove scripts from a site applied by the App. This endpoint will not remove scripts from the site's registered scripts. Required scope | `custom_code:write` @@ -795,6 +801,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -865,9 +872,13 @@ async def list_custom_code_blocks( request_options: typing.Optional[RequestOptions] = None, ) -> ListCustomCodeBlocks: """ - Get all instances of Custom Code applied to a Site or Pages. + Get a list of scripts that have been applied to a site and/or individual pages. + + + To apply a script to a site or page, the script must first be registered to a site via the [Register Script](/data/reference/custom-code/custom-code/register-hosted) endpoints. Once registered, the script can be applied to a Site or Page using the appropriate endpoints. - Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients). + See the documentation on [working with Custom Code](/data/docs/custom-code) for more information. + Required scope | `custom_code:read` @@ -911,6 +922,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/custom_code/blocks", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, diff --git a/src/webflow/resources/token/client.py b/src/webflow/resources/token/client.py index 628ce3a..d8cfd16 100644 --- a/src/webflow/resources/token/client.py +++ b/src/webflow/resources/token/client.py @@ -45,6 +45,7 @@ def authorized_by(self, *, request_options: typing.Optional[RequestOptions] = No """ _response = self._client_wrapper.httpx_client.request( "token/authorized_by", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -109,6 +110,7 @@ def introspect(self, *, request_options: typing.Optional[RequestOptions] = None) """ _response = self._client_wrapper.httpx_client.request( "token/introspect", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -176,6 +178,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( "token/authorized_by", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -248,6 +251,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( "token/introspect", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) diff --git a/src/webflow/resources/users/client.py b/src/webflow/resources/users/client.py index d690c0f..52cd4c7 100644 --- a/src/webflow/resources/users/client.py +++ b/src/webflow/resources/users/client.py @@ -83,6 +83,7 @@ def list( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -201,6 +202,7 @@ def get(self, site_id: str, user_id: str, *, request_options: typing.Optional[Re """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -313,6 +315,7 @@ def delete(self, site_id: str, user_id: str, *, request_options: typing.Optional """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -414,7 +417,6 @@ def update( access_groups : typing.Optional[typing.Sequence[str]] An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed. - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -444,6 +446,7 @@ def update( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "data": convert_and_respect_annotation_metadata( @@ -557,7 +560,6 @@ def invite( access_groups : typing.Optional[typing.Sequence[str]] An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed. - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -581,6 +583,7 @@ def invite( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/invite", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "email": email, @@ -742,6 +745,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users", + base_url=self._client_wrapper.get_environment().base, method="GET", params={ "offset": offset, @@ -868,6 +872,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -990,6 +995,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -1091,7 +1097,6 @@ async def update( access_groups : typing.Optional[typing.Sequence[str]] An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed. - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1129,6 +1134,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/{jsonable_encoder(user_id)}", + base_url=self._client_wrapper.get_environment().base, method="PATCH", json={ "data": convert_and_respect_annotation_metadata( @@ -1242,7 +1248,6 @@ async def invite( access_groups : typing.Optional[typing.Sequence[str]] An array of access group slugs. Access groups are assigned to the user as type `admin` and the user remains in the group until removed. - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1274,6 +1279,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/users/invite", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "email": email, diff --git a/src/webflow/resources/webhooks/client.py b/src/webflow/resources/webhooks/client.py index ded9a2f..c6821a9 100644 --- a/src/webflow/resources/webhooks/client.py +++ b/src/webflow/resources/webhooks/client.py @@ -61,6 +61,7 @@ def list(self, site_id: str, *, request_options: typing.Optional[RequestOptions] """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/webhooks", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -212,6 +213,7 @@ def create( """ _response = self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id_)}/webhooks", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "id": id, @@ -324,6 +326,7 @@ def get(self, webhook_id: str, *, request_options: typing.Optional[RequestOption """ _response = self._client_wrapper.httpx_client.request( f"webhooks/{jsonable_encoder(webhook_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -422,6 +425,7 @@ def delete(self, webhook_id: str, *, request_options: typing.Optional[RequestOpt """ _response = self._client_wrapper.httpx_client.request( f"webhooks/{jsonable_encoder(webhook_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) @@ -528,6 +532,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id)}/webhooks", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -686,6 +691,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"sites/{jsonable_encoder(site_id_)}/webhooks", + base_url=self._client_wrapper.get_environment().base, method="POST", json={ "id": id, @@ -806,6 +812,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"webhooks/{jsonable_encoder(webhook_id)}", + base_url=self._client_wrapper.get_environment().base, method="GET", request_options=request_options, ) @@ -912,6 +919,7 @@ async def main() -> None: """ _response = await self._client_wrapper.httpx_client.request( f"webhooks/{jsonable_encoder(webhook_id)}", + base_url=self._client_wrapper.get_environment().base, method="DELETE", request_options=request_options, ) diff --git a/src/webflow/resources/well_known/__init__.py b/src/webflow/resources/well_known/__init__.py new file mode 100644 index 0000000..323b6bd --- /dev/null +++ b/src/webflow/resources/well_known/__init__.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .types import WellKnownFileContentType + +__all__ = ["WellKnownFileContentType"] diff --git a/src/webflow/resources/well_known/client.py b/src/webflow/resources/well_known/client.py new file mode 100644 index 0000000..42b7f93 --- /dev/null +++ b/src/webflow/resources/well_known/client.py @@ -0,0 +1,526 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from ...core.client_wrapper import SyncClientWrapper +from .types.well_known_file_content_type import WellKnownFileContentType +from ...core.request_options import RequestOptions +from ...core.jsonable_encoder import jsonable_encoder +from ...errors.bad_request_error import BadRequestError +from ...core.pydantic_utilities import parse_obj_as +from ...errors.unauthorized_error import UnauthorizedError +from ...types.error import Error +from ...errors.not_found_error import NotFoundError +from ...errors.too_many_requests_error import TooManyRequestsError +from ...errors.internal_server_error import InternalServerError +from json.decoder import JSONDecodeError +from ...core.api_error import ApiError +from ...core.client_wrapper import AsyncClientWrapper + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class WellKnownClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def put( + self, + site_id: str, + *, + file_name: str, + file_data: str, + content_type: typing.Optional[WellKnownFileContentType] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + Upload a supported well-known file to a site. + + The current restrictions on well-known files are as follows: + - Each file must be smaller than 100kb + - Less than 30 total files + - Have one of the following file extensions (or no extension): `.txt`, `.json`, `.noext` + + + `.noext` is a special file extension that removes other extensions. For example, `apple-app-site-association.noext.txt` will be uploaded as `apple-app-site-association`. Use this extension for tools that have trouble uploading extensionless files. + + + Required scope: `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + file_name : str + The name of the file + + file_data : str + The contents of the file + + content_type : typing.Optional[WellKnownFileContentType] + The content type of the file. Defaults to application/json + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.well_known.put( + site_id="580e63e98c9a982ac9b8b741", + file_name="fileName", + file_data="fileData", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/well_known", + base_url=self._client_wrapper.get_environment().base, + method="PUT", + json={ + "fileName": file_name, + "fileData": file_data, + "contentType": content_type, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + def delete( + self, + site_id: str, + *, + file_names: typing.Optional[typing.Sequence[str]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + Delete existing well-known files from a site. + + + Required scope: `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + file_names : typing.Optional[typing.Sequence[str]] + A list of file names to delete + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + from webflow import Webflow + + client = Webflow( + access_token="YOUR_ACCESS_TOKEN", + ) + client.well_known.delete( + site_id="580e63e98c9a982ac9b8b741", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/well_known", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + json={ + "fileNames": file_names, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + +class AsyncWellKnownClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def put( + self, + site_id: str, + *, + file_name: str, + file_data: str, + content_type: typing.Optional[WellKnownFileContentType] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + Upload a supported well-known file to a site. + + The current restrictions on well-known files are as follows: + - Each file must be smaller than 100kb + - Less than 30 total files + - Have one of the following file extensions (or no extension): `.txt`, `.json`, `.noext` + + + `.noext` is a special file extension that removes other extensions. For example, `apple-app-site-association.noext.txt` will be uploaded as `apple-app-site-association`. Use this extension for tools that have trouble uploading extensionless files. + + + Required scope: `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + file_name : str + The name of the file + + file_data : str + The contents of the file + + content_type : typing.Optional[WellKnownFileContentType] + The content type of the file. Defaults to application/json + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.well_known.put( + site_id="580e63e98c9a982ac9b8b741", + file_name="fileName", + file_data="fileData", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/well_known", + base_url=self._client_wrapper.get_environment().base, + method="PUT", + json={ + "fileName": file_name, + "fileData": file_data, + "contentType": content_type, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def delete( + self, + site_id: str, + *, + file_names: typing.Optional[typing.Sequence[str]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + Delete existing well-known files from a site. + + + Required scope: `site_config:write` + + Parameters + ---------- + site_id : str + Unique identifier for a Site + + file_names : typing.Optional[typing.Sequence[str]] + A list of file names to delete + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + import asyncio + + from webflow import AsyncWebflow + + client = AsyncWebflow( + access_token="YOUR_ACCESS_TOKEN", + ) + + + async def main() -> None: + await client.well_known.delete( + site_id="580e63e98c9a982ac9b8b741", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"sites/{jsonable_encoder(site_id)}/well_known", + base_url=self._client_wrapper.get_environment().base, + method="DELETE", + json={ + "fileNames": file_names, + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequestError( + typing.cast( + typing.Optional[typing.Any], + parse_obj_as( + type_=typing.Optional[typing.Any], # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise UnauthorizedError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFoundError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise TooManyRequestsError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/webflow/resources/well_known/types/__init__.py b/src/webflow/resources/well_known/types/__init__.py new file mode 100644 index 0000000..4fc9c09 --- /dev/null +++ b/src/webflow/resources/well_known/types/__init__.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .well_known_file_content_type import WellKnownFileContentType + +__all__ = ["WellKnownFileContentType"] diff --git a/src/webflow/resources/well_known/types/well_known_file_content_type.py b/src/webflow/resources/well_known/types/well_known_file_content_type.py new file mode 100644 index 0000000..be135b4 --- /dev/null +++ b/src/webflow/resources/well_known/types/well_known_file_content_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +WellKnownFileContentType = typing.Union[typing.Literal["application/json", "text/plain"], typing.Any] diff --git a/src/webflow/types/__init__.py b/src/webflow/types/__init__.py index 5b2d8c6..af20dcd 100644 --- a/src/webflow/types/__init__.py +++ b/src/webflow/types/__init__.py @@ -31,6 +31,16 @@ from .collection_item_with_id_input_field_data import CollectionItemWithIdInputFieldData from .collection_list import CollectionList from .collection_list_array_item import CollectionListArrayItem +from .comment_reply import CommentReply +from .comment_reply_author import CommentReplyAuthor +from .comment_reply_list import CommentReplyList +from .comment_reply_list_pagination import CommentReplyListPagination +from .comment_reply_mentioned_users_item import CommentReplyMentionedUsersItem +from .comment_thread import CommentThread +from .comment_thread_author import CommentThreadAuthor +from .comment_thread_list import CommentThreadList +from .comment_thread_list_pagination import CommentThreadListPagination +from .comment_thread_mentioned_users_item import CommentThreadMentionedUsersItem from .component import Component from .component_dom import ComponentDom from .component_instance_node_property_overrides_write import ComponentInstanceNodePropertyOverridesWrite @@ -42,6 +52,7 @@ from .component_properties import ComponentProperties from .component_property import ComponentProperty from .component_property_type import ComponentPropertyType +from .conflict import Conflict from .conflict_error_body import ConflictErrorBody from .custom_code_block import CustomCodeBlock from .custom_code_block_type import CustomCodeBlockType @@ -55,6 +66,7 @@ from .error import Error from .error_code import ErrorCode from .field import Field +from .field_create import FieldCreate from .field_type import FieldType from .forbidden_error_body import ForbiddenErrorBody from .form import Form @@ -74,10 +86,13 @@ from .list_custom_code_blocks import ListCustomCodeBlocks from .locale import Locale from .locales import Locales +from .metadata import Metadata +from .metadata_options_item import MetadataOptionsItem from .no_domains import NoDomains from .node import Node, Node_ComponentInstance, Node_Image, Node_Text from .not_enterprise_plan_site import NotEnterprisePlanSite from .not_enterprise_plan_workspace import NotEnterprisePlanWorkspace +from .option_field import OptionField from .order import Order from .order_address import OrderAddress from .order_address_japan_type import OrderAddressJapanType @@ -111,7 +126,12 @@ from .publish_status import PublishStatus from .redirect import Redirect from .redirects import Redirects +from .reference_field import ReferenceField +from .reference_field_metadata import ReferenceFieldMetadata +from .reference_field_type import ReferenceFieldType from .registered_script_list import RegisteredScriptList +from .robots import Robots +from .robots_rules_item import RobotsRulesItem from .script_apply import ScriptApply from .script_apply_list import ScriptApplyList from .script_apply_location import ScriptApplyLocation @@ -139,6 +159,8 @@ from .sku_property_list import SkuPropertyList from .sku_property_list_enum_item import SkuPropertyListEnumItem from .sku_value_list import SkuValueList +from .static_field import StaticField +from .static_field_type import StaticFieldType from .stripe_card import StripeCard from .stripe_card_brand import StripeCardBrand from .stripe_card_expires import StripeCardExpires @@ -193,6 +215,16 @@ "CollectionItemWithIdInputFieldData", "CollectionList", "CollectionListArrayItem", + "CommentReply", + "CommentReplyAuthor", + "CommentReplyList", + "CommentReplyListPagination", + "CommentReplyMentionedUsersItem", + "CommentThread", + "CommentThreadAuthor", + "CommentThreadList", + "CommentThreadListPagination", + "CommentThreadMentionedUsersItem", "Component", "ComponentDom", "ComponentInstanceNodePropertyOverridesWrite", @@ -202,6 +234,7 @@ "ComponentProperties", "ComponentProperty", "ComponentPropertyType", + "Conflict", "ConflictErrorBody", "CustomCodeBlock", "CustomCodeBlockType", @@ -215,6 +248,7 @@ "Error", "ErrorCode", "Field", + "FieldCreate", "FieldType", "ForbiddenErrorBody", "Form", @@ -234,6 +268,8 @@ "ListCustomCodeBlocks", "Locale", "Locales", + "Metadata", + "MetadataOptionsItem", "NoDomains", "Node", "Node_ComponentInstance", @@ -241,6 +277,7 @@ "Node_Text", "NotEnterprisePlanSite", "NotEnterprisePlanWorkspace", + "OptionField", "Order", "OrderAddress", "OrderAddressJapanType", @@ -274,7 +311,12 @@ "PublishStatus", "Redirect", "Redirects", + "ReferenceField", + "ReferenceFieldMetadata", + "ReferenceFieldType", "RegisteredScriptList", + "Robots", + "RobotsRulesItem", "ScriptApply", "ScriptApplyList", "ScriptApplyLocation", @@ -302,6 +344,8 @@ "SkuPropertyList", "SkuPropertyListEnumItem", "SkuValueList", + "StaticField", + "StaticFieldType", "StripeCard", "StripeCardBrand", "StripeCardExpires", diff --git a/src/webflow/types/asset.py b/src/webflow/types/asset.py index b67cefa..d2212b0 100644 --- a/src/webflow/types/asset.py +++ b/src/webflow/types/asset.py @@ -1,76 +1,70 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel -import typing import pydantic import typing_extensions from ..core.serialization import FieldMetadata import datetime as dt +import typing from .asset_variant import AssetVariant from ..core.pydantic_utilities import IS_PYDANTIC_V2 class Asset(UniversalBaseModel): - id: typing.Optional[str] = pydantic.Field(default=None) + """ + Asset details + """ + + id: str = pydantic.Field() """ Unique identifier for this asset """ - content_type: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="contentType")] = ( - pydantic.Field(default=None) - ) + content_type: typing_extensions.Annotated[str, FieldMetadata(alias="contentType")] = pydantic.Field() """ File format type """ - size: typing.Optional[int] = pydantic.Field(default=None) + size: int = pydantic.Field() """ size in bytes """ - site_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="siteId")] = pydantic.Field( - default=None - ) + site_id: typing_extensions.Annotated[str, FieldMetadata(alias="siteId")] = pydantic.Field() """ Unique identifier for the site that hosts this asset """ - hosted_url: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="hostedUrl")] = pydantic.Field( - default=None - ) + hosted_url: typing_extensions.Annotated[str, FieldMetadata(alias="hostedUrl")] = pydantic.Field() """ Link to the asset """ - original_file_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="originalFileName")] = ( - pydantic.Field(default=None) - ) + original_file_name: typing_extensions.Annotated[str, FieldMetadata(alias="originalFileName")] = pydantic.Field() """ Original file name at the time of upload """ - display_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="displayName")] = ( - pydantic.Field(default=None) - ) + display_name: typing_extensions.Annotated[str, FieldMetadata(alias="displayName")] = pydantic.Field() """ Display name of the asset """ - last_updated: typing_extensions.Annotated[typing.Optional[dt.datetime], FieldMetadata(alias="lastUpdated")] = ( - pydantic.Field(default=None) - ) + last_updated: typing_extensions.Annotated[dt.datetime, FieldMetadata(alias="lastUpdated")] = pydantic.Field() """ Date the asset metadata was last updated """ - created_on: typing_extensions.Annotated[typing.Optional[dt.datetime], FieldMetadata(alias="createdOn")] = ( - pydantic.Field(default=None) - ) + created_on: typing_extensions.Annotated[dt.datetime, FieldMetadata(alias="createdOn")] = pydantic.Field() """ Date the asset metadata was created """ - variants: typing.Optional[typing.List[AssetVariant]] = None + variants: typing.List[AssetVariant] = pydantic.Field() + """ + A list of [asset variants](https://help.webflow.com/hc/en-us/articles/33961378697107-Responsive-images) created by Webflow to serve your site responsively. + """ + alt_text: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="altText")] = pydantic.Field( default=None ) diff --git a/src/webflow/types/asset_variant.py b/src/webflow/types/asset_variant.py index 5278667..bc023dc 100644 --- a/src/webflow/types/asset_variant.py +++ b/src/webflow/types/asset_variant.py @@ -2,50 +2,48 @@ from ..core.pydantic_utilities import UniversalBaseModel import typing_extensions -import typing from ..core.serialization import FieldMetadata import pydantic +import typing from ..core.pydantic_utilities import IS_PYDANTIC_V2 class AssetVariant(UniversalBaseModel): - hosted_url: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="hostedUrl")] = pydantic.Field( - default=None - ) + """ + Asset variant details + """ + + hosted_url: typing_extensions.Annotated[str, FieldMetadata(alias="hostedUrl")] = pydantic.Field() """ URL of where the asset variant is hosted """ - original_file_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="originalFileName")] = ( - pydantic.Field(default=None) - ) + original_file_name: typing_extensions.Annotated[str, FieldMetadata(alias="originalFileName")] = pydantic.Field() """ Original file name of the variant """ - display_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="displayName")] = ( - pydantic.Field(default=None) - ) + display_name: typing_extensions.Annotated[str, FieldMetadata(alias="displayName")] = pydantic.Field() """ Display name of the variant """ - format: typing.Optional[str] = pydantic.Field(default=None) + format: str = pydantic.Field() """ format of the variant """ - width: typing.Optional[int] = pydantic.Field(default=None) + width: int = pydantic.Field() """ Width in pixels """ - height: typing.Optional[int] = pydantic.Field(default=None) + height: int = pydantic.Field() """ Height in pixels """ - quality: typing.Optional[int] = pydantic.Field(default=None) + quality: int = pydantic.Field() """ Value between 0 and 100 representing the image quality """ diff --git a/src/webflow/types/assets.py b/src/webflow/types/assets.py index 380b0de..bd5f8ea 100644 --- a/src/webflow/types/assets.py +++ b/src/webflow/types/assets.py @@ -3,6 +3,7 @@ from ..core.pydantic_utilities import UniversalBaseModel import typing from .asset import Asset +from .pagination import Pagination from ..core.pydantic_utilities import IS_PYDANTIC_V2 import pydantic @@ -13,6 +14,7 @@ class Assets(UniversalBaseModel): """ assets: typing.Optional[typing.List[Asset]] = None + pagination: typing.Optional[Pagination] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/webflow/types/collection.py b/src/webflow/types/collection.py index 81e0f90..561a535 100644 --- a/src/webflow/types/collection.py +++ b/src/webflow/types/collection.py @@ -3,8 +3,8 @@ from ..core.pydantic_utilities import UniversalBaseModel import pydantic import typing_extensions -import typing from ..core.serialization import FieldMetadata +import typing import datetime as dt from .field import Field from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -20,16 +20,12 @@ class Collection(UniversalBaseModel): Unique identifier for a Collection """ - display_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="displayName")] = ( - pydantic.Field(default=None) - ) + display_name: typing_extensions.Annotated[str, FieldMetadata(alias="displayName")] = pydantic.Field() """ Name given to the Collection """ - singular_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="singularName")] = ( - pydantic.Field(default=None) - ) + singular_name: typing_extensions.Annotated[str, FieldMetadata(alias="singularName")] = pydantic.Field() """ The name of one Item in Collection (e.g. ”Blog Post” if the Collection is called “Blog Posts”) """ diff --git a/src/webflow/types/collection_item.py b/src/webflow/types/collection_item.py index 6551900..ab8396d 100644 --- a/src/webflow/types/collection_item.py +++ b/src/webflow/types/collection_item.py @@ -30,23 +30,17 @@ class CollectionItem(UniversalBaseModel): Identifier for the locale of the CMS item """ - last_published: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="lastPublished")] = ( - pydantic.Field(default=None) - ) + last_published: typing_extensions.Annotated[str, FieldMetadata(alias="lastPublished")] = pydantic.Field() """ The date the item was last published """ - last_updated: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="lastUpdated")] = ( - pydantic.Field(default=None) - ) + last_updated: typing_extensions.Annotated[str, FieldMetadata(alias="lastUpdated")] = pydantic.Field() """ The date the item was last updated """ - created_on: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="createdOn")] = pydantic.Field( - default=None - ) + created_on: typing_extensions.Annotated[str, FieldMetadata(alias="createdOn")] = pydantic.Field() """ The date the item was created """ diff --git a/src/webflow/types/comment_reply.py b/src/webflow/types/comment_reply.py new file mode 100644 index 0000000..9c0a482 --- /dev/null +++ b/src/webflow/types/comment_reply.py @@ -0,0 +1,85 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +import typing +from .comment_reply_author import CommentReplyAuthor +from .comment_reply_mentioned_users_item import CommentReplyMentionedUsersItem +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class CommentReply(UniversalBaseModel): + """ + A comment thread represents a conversation between users on a specific page. Each comment thread has a unique identifier and can contain multiple comments. + """ + + id: str = pydantic.Field() + """ + Unique identifier for the comment thread + """ + + comment_id: typing_extensions.Annotated[str, FieldMetadata(alias="commentId")] = pydantic.Field() + """ + The comment reply unique identifier + """ + + site_id: typing_extensions.Annotated[str, FieldMetadata(alias="siteId")] = pydantic.Field() + """ + The site unique identifier + """ + + page_id: typing_extensions.Annotated[str, FieldMetadata(alias="pageId")] = pydantic.Field() + """ + The page unique identifier + """ + + locale_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="localeId")] = pydantic.Field( + default=None + ) + """ + The locale unique identifier + """ + + breakpoint: str = pydantic.Field() + """ + The breakpoint the comment was left on + """ + + content: str = pydantic.Field() + """ + The content of the comment reply + """ + + is_resolved: typing_extensions.Annotated[bool, FieldMetadata(alias="isResolved")] = pydantic.Field() + """ + Boolean determining if the comment thread is resolved + """ + + author: CommentReplyAuthor + mentioned_users: typing_extensions.Annotated[ + typing.Optional[typing.List[CommentReplyMentionedUsersItem]], FieldMetadata(alias="mentionedUsers") + ] = pydantic.Field(default=None) + """ + List of mentioned users is an empty array until email notifications are sent. + """ + + last_updated: typing_extensions.Annotated[str, FieldMetadata(alias="lastUpdated")] = pydantic.Field() + """ + The date the item was last updated + """ + + created_on: typing_extensions.Annotated[str, FieldMetadata(alias="createdOn")] = pydantic.Field() + """ + The date the item was created + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/comment_reply_author.py b/src/webflow/types/comment_reply_author.py new file mode 100644 index 0000000..7509b7e --- /dev/null +++ b/src/webflow/types/comment_reply_author.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class CommentReplyAuthor(UniversalBaseModel): + id: str = pydantic.Field() + """ + The unique identifier of the author + """ + + email: str = pydantic.Field() + """ + Email of the author + """ + + name: str = pydantic.Field() + """ + Name of the author + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/comment_reply_list.py b/src/webflow/types/comment_reply_list.py new file mode 100644 index 0000000..c382932 --- /dev/null +++ b/src/webflow/types/comment_reply_list.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .comment_reply import CommentReply +from .comment_reply_list_pagination import CommentReplyListPagination +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class CommentReplyList(UniversalBaseModel): + """ + A list of comment replies. + """ + + comments: typing.List[CommentReply] + pagination: CommentReplyListPagination + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/comment_reply_list_pagination.py b/src/webflow/types/comment_reply_list_pagination.py new file mode 100644 index 0000000..7fa5c8e --- /dev/null +++ b/src/webflow/types/comment_reply_list_pagination.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class CommentReplyListPagination(UniversalBaseModel): + limit: float = pydantic.Field() + """ + The limit specified in the request (default 100) + """ + + offset: float = pydantic.Field() + """ + The offset specified for pagination + """ + + total: float = pydantic.Field() + """ + Total number of comment replies + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/comment_reply_mentioned_users_item.py b/src/webflow/types/comment_reply_mentioned_users_item.py new file mode 100644 index 0000000..12324d9 --- /dev/null +++ b/src/webflow/types/comment_reply_mentioned_users_item.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class CommentReplyMentionedUsersItem(UniversalBaseModel): + id: str = pydantic.Field() + """ + The unique identifier of the mentioned user + """ + + email: str = pydantic.Field() + """ + Email of the user + """ + + name: str = pydantic.Field() + """ + Name of the User + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/comment_thread.py b/src/webflow/types/comment_thread.py new file mode 100644 index 0000000..c550fdf --- /dev/null +++ b/src/webflow/types/comment_thread.py @@ -0,0 +1,92 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +import typing +from .comment_thread_author import CommentThreadAuthor +from .comment_thread_mentioned_users_item import CommentThreadMentionedUsersItem +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class CommentThread(UniversalBaseModel): + """ + A comment thread represents a conversation between users on a specific page. Each comment thread has a unique identifier and can contain multiple comments. Retrieve comment replies using the repiles API endpoint. + """ + + id: str = pydantic.Field() + """ + Unique identifier for the comment thread + """ + + site_id: typing_extensions.Annotated[str, FieldMetadata(alias="siteId")] = pydantic.Field() + """ + The site unique identifier + """ + + page_id: typing_extensions.Annotated[str, FieldMetadata(alias="pageId")] = pydantic.Field() + """ + The page unique identifier + """ + + locale_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="localeId")] = pydantic.Field( + default=None + ) + """ + The locale unique identifier + """ + + item_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="itemId")] = pydantic.Field( + default=None + ) + """ + The item unique identifier + """ + + breakpoint: str = pydantic.Field() + """ + The breakpoint the comment was left on + """ + + url: str = pydantic.Field() + """ + The URL of the page the comment was left on + """ + + content: str = pydantic.Field() + """ + The content of the comment reply + """ + + is_resolved: typing_extensions.Annotated[bool, FieldMetadata(alias="isResolved")] = pydantic.Field() + """ + Boolean determining if the comment thread is resolved + """ + + author: CommentThreadAuthor + mentioned_users: typing_extensions.Annotated[ + typing.List[CommentThreadMentionedUsersItem], FieldMetadata(alias="mentionedUsers") + ] = pydantic.Field() + """ + List of mentioned users. This is an empty array until email notifications are sent, which can take up to 5 minutes after the comment is created. + """ + + created_on: typing_extensions.Annotated[str, FieldMetadata(alias="createdOn")] = pydantic.Field() + """ + The date the item was created + """ + + last_updated: typing_extensions.Annotated[str, FieldMetadata(alias="lastUpdated")] = pydantic.Field() + """ + The date the item was last updated + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/comment_thread_author.py b/src/webflow/types/comment_thread_author.py new file mode 100644 index 0000000..c2f1b1e --- /dev/null +++ b/src/webflow/types/comment_thread_author.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +from ..core.serialization import FieldMetadata +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class CommentThreadAuthor(UniversalBaseModel): + user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] = pydantic.Field() + """ + The unique identifier of the author + """ + + email: str = pydantic.Field() + """ + Email of the author + """ + + name: str = pydantic.Field() + """ + Name of the author + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/comment_thread_list.py b/src/webflow/types/comment_thread_list.py new file mode 100644 index 0000000..f46e6bd --- /dev/null +++ b/src/webflow/types/comment_thread_list.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .comment_thread import CommentThread +from .comment_thread_list_pagination import CommentThreadListPagination +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class CommentThreadList(UniversalBaseModel): + """ + A list of comment threads on the site. Contains the content of the first reply. + """ + + comments: typing.List[CommentThread] + pagination: CommentThreadListPagination + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/comment_thread_list_pagination.py b/src/webflow/types/comment_thread_list_pagination.py new file mode 100644 index 0000000..e5d55bb --- /dev/null +++ b/src/webflow/types/comment_thread_list_pagination.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class CommentThreadListPagination(UniversalBaseModel): + limit: float = pydantic.Field() + """ + The limit specified in the request (default 100) + """ + + offset: float = pydantic.Field() + """ + The offset specified for pagination + """ + + total: float = pydantic.Field() + """ + Total number of comment threads + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/comment_thread_mentioned_users_item.py b/src/webflow/types/comment_thread_mentioned_users_item.py new file mode 100644 index 0000000..f9a20df --- /dev/null +++ b/src/webflow/types/comment_thread_mentioned_users_item.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +from ..core.serialization import FieldMetadata +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class CommentThreadMentionedUsersItem(UniversalBaseModel): + user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] = pydantic.Field() + """ + The unique identifier of the mentioned user + """ + + email: str = pydantic.Field() + """ + Email of the user + """ + + name: str = pydantic.Field() + """ + Name of the User + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/component_node.py b/src/webflow/types/component_node.py index fa5f69d..6735289 100644 --- a/src/webflow/types/component_node.py +++ b/src/webflow/types/component_node.py @@ -1,10 +1,10 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel -import typing import pydantic import typing_extensions from ..core.serialization import FieldMetadata +import typing from .component_property import ComponentProperty from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -14,21 +14,19 @@ class ComponentNode(UniversalBaseModel): Represents a component instance within the DOM. It contains details about the component instance, such as its type and properties. """ - id: typing.Optional[str] = pydantic.Field(default=None) + id: str = pydantic.Field() """ - Node UUID + The unique identifier of the component instance node """ - component_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="componentId")] = ( - pydantic.Field(default=None) - ) + component_id: typing_extensions.Annotated[str, FieldMetadata(alias="componentId")] = pydantic.Field() """ - Component ID + The unique identifier of the component """ property_overrides: typing_extensions.Annotated[ - typing.Optional[typing.List[ComponentProperty]], FieldMetadata(alias="propertyOverrides") - ] = pydantic.Field(default=None) + typing.List[ComponentProperty], FieldMetadata(alias="propertyOverrides") + ] = pydantic.Field() """ List of component properties with overrides for a component instance. """ diff --git a/src/webflow/types/conflict.py b/src/webflow/types/conflict.py new file mode 100644 index 0000000..30b9809 --- /dev/null +++ b/src/webflow/types/conflict.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +Conflict = typing.Optional[typing.Any] diff --git a/src/webflow/types/dom.py b/src/webflow/types/dom.py index ce15a6a..693da07 100644 --- a/src/webflow/types/dom.py +++ b/src/webflow/types/dom.py @@ -7,6 +7,7 @@ import pydantic from .node import Node from .pagination import Pagination +import datetime as dt from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -24,6 +25,12 @@ class Dom(UniversalBaseModel): nodes: typing.Optional[typing.List[Node]] = None pagination: typing.Optional[Pagination] = None + last_updated: typing_extensions.Annotated[typing.Optional[dt.datetime], FieldMetadata(alias="lastUpdated")] = ( + pydantic.Field(default=None) + ) + """ + The date the page dom was most recently updated + """ if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/webflow/types/field_create.py b/src/webflow/types/field_create.py new file mode 100644 index 0000000..1c9cf61 --- /dev/null +++ b/src/webflow/types/field_create.py @@ -0,0 +1,8 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from .static_field import StaticField +from .option_field import OptionField +from .reference_field import ReferenceField + +FieldCreate = typing.Union[StaticField, OptionField, ReferenceField] diff --git a/src/webflow/types/field_type.py b/src/webflow/types/field_type.py index 6318a3d..eccf61d 100644 --- a/src/webflow/types/field_type.py +++ b/src/webflow/types/field_type.py @@ -11,9 +11,11 @@ "Image", "Link", "MultiImage", + "MultiReference", "Number", "Phone", "PlainText", + "Reference", "RichText", "Switch", "Video", diff --git a/src/webflow/types/image_node.py b/src/webflow/types/image_node.py index 2351cea..c4e7eac 100644 --- a/src/webflow/types/image_node.py +++ b/src/webflow/types/image_node.py @@ -1,9 +1,9 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel -import typing import pydantic from .image_node_image import ImageNodeImage +import typing from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -12,12 +12,16 @@ class ImageNode(UniversalBaseModel): Represents an image within the DOM. It contains details about the image, such as its alternative text (alt) for accessibility and an asset identifier for fetching the actual image resource. Additional attributes can be associated with the image for styling or other purposes. """ - id: typing.Optional[str] = pydantic.Field(default=None) + id: str = pydantic.Field() """ Node UUID """ - image: typing.Optional[ImageNodeImage] = None + image: ImageNodeImage = pydantic.Field() + """ + The image details of the node + """ + attributes: typing.Optional[typing.Dict[str, str]] = pydantic.Field(default=None) """ The custom attributes of the node diff --git a/src/webflow/types/image_node_image.py b/src/webflow/types/image_node_image.py index 2ef819f..f8d9379 100644 --- a/src/webflow/types/image_node_image.py +++ b/src/webflow/types/image_node_image.py @@ -9,6 +9,10 @@ class ImageNodeImage(UniversalBaseModel): + """ + The image details of the node + """ + alt: typing.Optional[str] = None asset_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="assetId")] = None diff --git a/src/webflow/types/metadata.py b/src/webflow/types/metadata.py new file mode 100644 index 0000000..1c9caa7 --- /dev/null +++ b/src/webflow/types/metadata.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .metadata_options_item import MetadataOptionsItem +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class Metadata(UniversalBaseModel): + """ + The metadata for the Option field. + """ + + options: typing.List[MetadataOptionsItem] = pydantic.Field() + """ + The option values for the Option field. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/metadata_options_item.py b/src/webflow/types/metadata_options_item.py new file mode 100644 index 0000000..91eb360 --- /dev/null +++ b/src/webflow/types/metadata_options_item.py @@ -0,0 +1,31 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import pydantic +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class MetadataOptionsItem(UniversalBaseModel): + """ + A single option value for the Option field. + """ + + name: str = pydantic.Field() + """ + The name of the option + """ + + id: typing.Optional[str] = pydantic.Field(default=None) + """ + The unique identifier of the option + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/node.py b/src/webflow/types/node.py index cd0942f..462a30b 100644 --- a/src/webflow/types/node.py +++ b/src/webflow/types/node.py @@ -18,8 +18,8 @@ class Node_Text(UniversalBaseModel): """ type: typing.Literal["text"] = "text" - id: typing.Optional[str] = None - text: typing.Optional[TextNodeText] = None + id: str + text: TextNodeText attributes: typing.Optional[typing.Dict[str, str]] = None if IS_PYDANTIC_V2: @@ -38,8 +38,8 @@ class Node_Image(UniversalBaseModel): """ type: typing.Literal["image"] = "image" - id: typing.Optional[str] = None - image: typing.Optional[ImageNodeImage] = None + id: str + image: ImageNodeImage attributes: typing.Optional[typing.Dict[str, str]] = None if IS_PYDANTIC_V2: @@ -58,11 +58,11 @@ class Node_ComponentInstance(UniversalBaseModel): """ type: typing.Literal["component-instance"] = "component-instance" - id: typing.Optional[str] = None - component_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="componentId")] = None + id: str + component_id: typing_extensions.Annotated[str, FieldMetadata(alias="componentId")] property_overrides: typing_extensions.Annotated[ - typing.Optional[typing.List[ComponentProperty]], FieldMetadata(alias="propertyOverrides") - ] = None + typing.List[ComponentProperty], FieldMetadata(alias="propertyOverrides") + ] if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/webflow/types/option_field.py b/src/webflow/types/option_field.py new file mode 100644 index 0000000..7f7c6d5 --- /dev/null +++ b/src/webflow/types/option_field.py @@ -0,0 +1,58 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +from .metadata import Metadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class OptionField(UniversalBaseModel): + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Unique identifier for a Field + """ + + is_editable: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isEditable")] = pydantic.Field( + default=None + ) + """ + Define whether the field is editable + """ + + is_required: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isRequired")] = pydantic.Field( + default=None + ) + """ + define whether a field is required in a collection + """ + + type: typing.Literal["Option"] = pydantic.Field(default="Option") + """ + The [Option field type](/data/reference/field-types-item-values#option) + """ + + display_name: typing_extensions.Annotated[str, FieldMetadata(alias="displayName")] = pydantic.Field() + """ + The name of a field + """ + + help_text: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="helpText")] = pydantic.Field( + default=None + ) + """ + Additional text to help anyone filling out this field + """ + + metadata: Metadata + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/pagination.py b/src/webflow/types/pagination.py index aa38c46..6b8d4ee 100644 --- a/src/webflow/types/pagination.py +++ b/src/webflow/types/pagination.py @@ -1,9 +1,9 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel -import typing import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing class Pagination(UniversalBaseModel): @@ -11,17 +11,17 @@ class Pagination(UniversalBaseModel): Pagination object """ - limit: typing.Optional[float] = pydantic.Field(default=None) + limit: float = pydantic.Field() """ The limit used for pagination """ - offset: typing.Optional[float] = pydantic.Field(default=None) + offset: float = pydantic.Field() """ The offset used for pagination """ - total: typing.Optional[float] = pydantic.Field(default=None) + total: float = pydantic.Field() """ The total number of records """ diff --git a/src/webflow/types/reference_field.py b/src/webflow/types/reference_field.py new file mode 100644 index 0000000..3c75552 --- /dev/null +++ b/src/webflow/types/reference_field.py @@ -0,0 +1,62 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +from .reference_field_type import ReferenceFieldType +from .reference_field_metadata import ReferenceFieldMetadata +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class ReferenceField(UniversalBaseModel): + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Unique identifier for a Field + """ + + is_editable: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isEditable")] = pydantic.Field( + default=None + ) + """ + Define whether the field is editable + """ + + is_required: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isRequired")] = pydantic.Field( + default=None + ) + """ + define whether a field is required in a collection + """ + + type: ReferenceFieldType = pydantic.Field() + """ + Choose these appropriate field type for your collection data + """ + + display_name: typing_extensions.Annotated[str, FieldMetadata(alias="displayName")] = pydantic.Field() + """ + The name of a field + """ + + help_text: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="helpText")] = pydantic.Field( + default=None + ) + """ + Additional text to help anyone filling out this field + """ + + metadata: ReferenceFieldMetadata = pydantic.Field() + """ + The collectionId for the referenced collection. Only applicable for Reference and MultiReference fields. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/reference_field_metadata.py b/src/webflow/types/reference_field_metadata.py new file mode 100644 index 0000000..164c4a6 --- /dev/null +++ b/src/webflow/types/reference_field_metadata.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +from ..core.serialization import FieldMetadata +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 +import typing + + +class ReferenceFieldMetadata(UniversalBaseModel): + """ + The collectionId for the referenced collection. Only applicable for Reference and MultiReference fields. + """ + + collection_id: typing_extensions.Annotated[str, FieldMetadata(alias="collectionId")] = pydantic.Field() + """ + The unique identifier of the collection + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/reference_field_type.py b/src/webflow/types/reference_field_type.py new file mode 100644 index 0000000..b80f3e1 --- /dev/null +++ b/src/webflow/types/reference_field_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ReferenceFieldType = typing.Union[typing.Literal["MultiReference", "Reference"], typing.Any] diff --git a/src/webflow/types/robots.py b/src/webflow/types/robots.py new file mode 100644 index 0000000..7489660 --- /dev/null +++ b/src/webflow/types/robots.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +from .robots_rules_item import RobotsRulesItem +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class Robots(UniversalBaseModel): + """ + The robots.txt file for a given site + """ + + rules: typing.Optional[typing.List[RobotsRulesItem]] = pydantic.Field(default=None) + """ + List of rules for user agents. + """ + + sitemap: typing.Optional[str] = pydantic.Field(default=None) + """ + URL to the sitemap. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/robots_rules_item.py b/src/webflow/types/robots_rules_item.py new file mode 100644 index 0000000..048f239 --- /dev/null +++ b/src/webflow/types/robots_rules_item.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing_extensions +from ..core.serialization import FieldMetadata +import pydantic +import typing +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class RobotsRulesItem(UniversalBaseModel): + user_agent: typing_extensions.Annotated[str, FieldMetadata(alias="userAgent")] = pydantic.Field() + """ + The user agent the rules apply to. + """ + + allows: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + List of paths allowed for this user agent. + """ + + disallows: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + List of paths disallowed for this user agent. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/types/sku_field_data.py b/src/webflow/types/sku_field_data.py index e20efdb..d281d18 100644 --- a/src/webflow/types/sku_field_data.py +++ b/src/webflow/types/sku_field_data.py @@ -43,10 +43,18 @@ class SkuFieldData(UniversalBaseModel): ec_sku_billing_method: typing_extensions.Annotated[ typing.Optional[SkuFieldDataEcSkuBillingMethod], FieldMetadata(alias="ec-sku-billing-method") - ] = None + ] = pydantic.Field(default=None) + """ + [Billing method](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#billing-methods)for the SKU + """ + ec_sku_subscription_plan: typing_extensions.Annotated[ typing.Optional[SkuFieldDataEcSkuSubscriptionPlan], FieldMetadata(alias="ec-sku-subscription-plan") - ] = None + ] = pydantic.Field(default=None) + """ + [Subscription plan](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#subscription) for the SKU + """ + track_inventory: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="track-inventory")] = ( pydantic.Field(default=None) ) @@ -59,6 +67,13 @@ class SkuFieldData(UniversalBaseModel): Quantity of SKU that will be tracked as items are ordered. """ + main_image: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="main-image")] = pydantic.Field( + default=None + ) + """ + The URL for the main image of the SKU + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/webflow/types/sku_field_data_ec_sku_subscription_plan.py b/src/webflow/types/sku_field_data_ec_sku_subscription_plan.py index 24c85a7..ed2e484 100644 --- a/src/webflow/types/sku_field_data_ec_sku_subscription_plan.py +++ b/src/webflow/types/sku_field_data_ec_sku_subscription_plan.py @@ -9,6 +9,10 @@ class SkuFieldDataEcSkuSubscriptionPlan(UniversalBaseModel): + """ + [Subscription plan](https://help.webflow.com/hc/en-us/articles/33961432087955-Add-and-manage-products-and-categories#subscription) for the SKU + """ + interval: typing.Optional[SkuFieldDataEcSkuSubscriptionPlanInterval] = pydantic.Field(default=None) """ Interval of subscription renewal diff --git a/src/webflow/types/sku_field_data_price.py b/src/webflow/types/sku_field_data_price.py index 45ff611..cb31f4a 100644 --- a/src/webflow/types/sku_field_data_price.py +++ b/src/webflow/types/sku_field_data_price.py @@ -21,6 +21,11 @@ class SkuFieldDataPrice(UniversalBaseModel): Currency of Item """ + currency: typing.Optional[str] = pydantic.Field(default=None) + """ + Currency of Item (alternative representation) + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/webflow/types/static_field.py b/src/webflow/types/static_field.py new file mode 100644 index 0000000..c6e6162 --- /dev/null +++ b/src/webflow/types/static_field.py @@ -0,0 +1,56 @@ +# This file was auto-generated by Fern from our API Definition. + +from ..core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +import typing_extensions +from ..core.serialization import FieldMetadata +from .static_field_type import StaticFieldType +from ..core.pydantic_utilities import IS_PYDANTIC_V2 + + +class StaticField(UniversalBaseModel): + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Unique identifier for a Field + """ + + is_editable: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isEditable")] = pydantic.Field( + default=None + ) + """ + Define whether the field is editable + """ + + is_required: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="isRequired")] = pydantic.Field( + default=None + ) + """ + define whether a field is required in a collection + """ + + type: StaticFieldType = pydantic.Field() + """ + Choose these appropriate field type for your collection data + """ + + display_name: typing_extensions.Annotated[str, FieldMetadata(alias="displayName")] = pydantic.Field() + """ + The name of a field + """ + + help_text: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="helpText")] = pydantic.Field( + default=None + ) + """ + Additional text to help anyone filling out this field + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/webflow/resources/collections/resources/fields/types/field_create_type.py b/src/webflow/types/static_field_type.py similarity index 86% rename from src/webflow/resources/collections/resources/fields/types/field_create_type.py rename to src/webflow/types/static_field_type.py index c8ec44b..36c0947 100644 --- a/src/webflow/resources/collections/resources/fields/types/field_create_type.py +++ b/src/webflow/types/static_field_type.py @@ -2,12 +2,11 @@ import typing -FieldCreateType = typing.Union[ +StaticFieldType = typing.Union[ typing.Literal[ "Color", "DateTime", "Email", - "ExtFileRef", "File", "Image", "Link", diff --git a/src/webflow/types/text.py b/src/webflow/types/text.py index 18f8501..913d5d1 100644 --- a/src/webflow/types/text.py +++ b/src/webflow/types/text.py @@ -7,6 +7,10 @@ class Text(UniversalBaseModel): + """ + The text content of the node + """ + html: typing.Optional[str] = pydantic.Field(default=None) """ The HTML content of the text node. diff --git a/src/webflow/types/text_node.py b/src/webflow/types/text_node.py index 1e16717..aa15d4b 100644 --- a/src/webflow/types/text_node.py +++ b/src/webflow/types/text_node.py @@ -1,9 +1,9 @@ # This file was auto-generated by Fern from our API Definition. from ..core.pydantic_utilities import UniversalBaseModel -import typing import pydantic from .text_node_text import TextNodeText +import typing from ..core.pydantic_utilities import IS_PYDANTIC_V2 @@ -12,12 +12,16 @@ class TextNode(UniversalBaseModel): Represents text content within the DOM. It contains both the raw text and its HTML representation. Additional attributes can be associated with the text for styling or other purposes. """ - id: typing.Optional[str] = pydantic.Field(default=None) + id: str = pydantic.Field() """ Node UUID """ - text: typing.Optional[TextNodeText] = None + text: TextNodeText = pydantic.Field() + """ + The text content of the node + """ + attributes: typing.Optional[typing.Dict[str, str]] = pydantic.Field(default=None) """ The custom attributes of the node diff --git a/src/webflow/types/text_node_text.py b/src/webflow/types/text_node_text.py index 895dc0b..5add2f0 100644 --- a/src/webflow/types/text_node_text.py +++ b/src/webflow/types/text_node_text.py @@ -7,6 +7,10 @@ class TextNodeText(UniversalBaseModel): + """ + The text content of the node + """ + html: typing.Optional[str] = pydantic.Field(default=None) """ The HTML content of the text node. diff --git a/src/webflow/types/webhook_list.py b/src/webflow/types/webhook_list.py index ea705c4..1740272 100644 --- a/src/webflow/types/webhook_list.py +++ b/src/webflow/types/webhook_list.py @@ -2,15 +2,15 @@ from ..core.pydantic_utilities import UniversalBaseModel import typing -from .pagination import Pagination from .webhook import Webhook +from .pagination import Pagination from ..core.pydantic_utilities import IS_PYDANTIC_V2 import pydantic class WebhookList(UniversalBaseModel): - pagination: typing.Optional[Pagination] = None webhooks: typing.Optional[typing.List[Webhook]] = None + pagination: typing.Optional[Pagination] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/tests/collections/test_fields.py b/tests/collections/test_fields.py index f64c447..8cb0fa0 100644 --- a/tests/collections/test_fields.py +++ b/tests/collections/test_fields.py @@ -3,43 +3,50 @@ from webflow import Webflow from webflow import AsyncWebflow import typing +from webflow import StaticField from ..utilities import validate_response async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "id": "75821f618da60c18383330bcc0ca488b", - "isRequired": False, + "id": "562ac0395358780a1f5e6fbc", "isEditable": True, + "isRequired": False, "type": "RichText", - "slug": "post-body", "displayName": "Post Body", "helpText": "Add the body of your post here", } expected_types: typing.Any = { "id": None, - "isRequired": None, "isEditable": None, + "isRequired": None, "type": None, - "slug": None, "displayName": None, "helpText": None, } response = client.collections.fields.create( collection_id="580e63fc8c9a982ac9b8b745", - is_required=False, - type="RichText", - display_name="Post Body", - help_text="Add the body of your post here", + request=StaticField( + id="562ac0395358780a1f5e6fbc", + is_editable=True, + is_required=False, + type="RichText", + display_name="Post Body", + help_text="Add the body of your post here", + ), ) validate_response(response, expected_response, expected_types) async_response = await async_client.collections.fields.create( collection_id="580e63fc8c9a982ac9b8b745", - is_required=False, - type="RichText", - display_name="Post Body", - help_text="Add the body of your post here", + request=StaticField( + id="562ac0395358780a1f5e6fbc", + is_editable=True, + is_required=False, + type="RichText", + display_name="Post Body", + help_text="Add the body of your post here", + ), ) validate_response(async_response, expected_response, expected_types) diff --git a/tests/collections/test_items.py b/tests/collections/test_items.py index fc926a7..de4eb75 100644 --- a/tests/collections/test_items.py +++ b/tests/collections/test_items.py @@ -341,6 +341,9 @@ async def test_create_item_live(client: Webflow, async_client: AsyncWebflow) -> response = client.collections.items.create_item_live( collection_id="580e63fc8c9a982ac9b8b745", request=CollectionItem( + last_published="2023-03-17T18:47:35.560Z", + last_updated="2023-03-17T18:47:35.560Z", + created_on="2023-03-17T18:47:35.560Z", is_archived=False, is_draft=False, field_data=CollectionItemFieldData( @@ -353,6 +356,9 @@ async def test_create_item_live(client: Webflow, async_client: AsyncWebflow) -> async_response = await async_client.collections.items.create_item_live( collection_id="580e63fc8c9a982ac9b8b745", request=CollectionItem( + last_published="2023-03-17T18:47:35.560Z", + last_updated="2023-03-17T18:47:35.560Z", + created_on="2023-03-17T18:47:35.560Z", is_archived=False, is_draft=False, field_data=CollectionItemFieldData( diff --git a/tests/conftest.py b/tests/conftest.py index 019aab8..8d87434 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,7 @@ from webflow import Webflow import os +from webflow.environment import WebflowEnvironment import pytest from webflow import AsyncWebflow @@ -9,12 +10,26 @@ @pytest.fixture def client() -> Webflow: return Webflow( - access_token=os.getenv("ENV_ACCESS_TOKEN", "access_token"), base_url=os.getenv("TESTS_BASE_URL", "base_url") + access_token=os.getenv("ENV_ACCESS_TOKEN", "access_token"), + environment=WebflowEnvironment( + base=os.getenv("TESTS_BASE_URL", "base_url"), + data_api=os.getenv("TESTS_BASE_URL", "base_url"), + content_delivery_api=os.getenv("TESTS_BASE_URL", "base_url"), + production=os.getenv("TESTS_BASE_URL", "base_url"), + cdn=os.getenv("TESTS_BASE_URL", "base_url"), + ), ) @pytest.fixture def async_client() -> AsyncWebflow: return AsyncWebflow( - access_token=os.getenv("ENV_ACCESS_TOKEN", "access_token"), base_url=os.getenv("TESTS_BASE_URL", "base_url") + access_token=os.getenv("ENV_ACCESS_TOKEN", "access_token"), + environment=WebflowEnvironment( + base=os.getenv("TESTS_BASE_URL", "base_url"), + data_api=os.getenv("TESTS_BASE_URL", "base_url"), + content_delivery_api=os.getenv("TESTS_BASE_URL", "base_url"), + production=os.getenv("TESTS_BASE_URL", "base_url"), + cdn=os.getenv("TESTS_BASE_URL", "base_url"), + ), ) diff --git a/tests/sites/comments/__init__.py b/tests/sites/comments/__init__.py new file mode 100644 index 0000000..f3ea265 --- /dev/null +++ b/tests/sites/comments/__init__.py @@ -0,0 +1,2 @@ +# This file was auto-generated by Fern from our API Definition. + diff --git a/tests/sites/comments/test_replies.py b/tests/sites/comments/test_replies.py new file mode 100644 index 0000000..4cc91dd --- /dev/null +++ b/tests/sites/comments/test_replies.py @@ -0,0 +1,63 @@ +# This file was auto-generated by Fern from our API Definition. + +from webflow import Webflow +from webflow import AsyncWebflow +import typing +from ...utilities import validate_response + + +async def test_list_replies(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "comments": [ + { + "id": "679d2ddb5196117ad04d1ffa", + "commentId": "679d2ddb5196117ad04d1ff8", + "siteId": "679826b3b20b045e176bc4b5", + "pageId": "679826b3b20b045e176bc4bc", + "localeId": "67993753d910db250db64b3e", + "breakpoint": "main", + "content": "This comment mentions another user [[6287ec36a841b25637c663df]] ", + "isResolved": False, + "author": {"id": "id", "email": "email", "name": "name"}, + "mentionedUsers": [{"id": "id", "email": "arthur.dent@example.com", "name": "Arthur Dent"}], + "lastUpdated": "2025-01-31T20:08:59.759Z", + "createdOn": "2025-01-31T20:08:59.759Z", + } + ], + "pagination": {"limit": 2, "offset": 0, "total": 1}, + } + expected_types: typing.Any = { + "comments": ( + "list", + { + 0: { + "id": None, + "commentId": None, + "siteId": None, + "pageId": None, + "localeId": None, + "breakpoint": None, + "content": None, + "isResolved": None, + "author": {"id": None, "email": None, "name": None}, + "mentionedUsers": ("list", {0: {"id": None, "email": None, "name": None}}), + "lastUpdated": None, + "createdOn": None, + } + }, + ), + "pagination": {"limit": None, "offset": None, "total": None}, + } + response = client.sites.comments.replies.list_replies( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.comments.replies.list_replies( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + validate_response(async_response, expected_response, expected_types) diff --git a/tests/sites/test_activity_logs.py b/tests/sites/test_activity_logs.py index f289464..722a4f2 100644 --- a/tests/sites/test_activity_logs.py +++ b/tests/sites/test_activity_logs.py @@ -18,9 +18,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "user": {"id": "6509cd56e90eec668b009712", "displayName": "John Doe"}, "resourceId": "654c16c7b229e56bcf26870c", "resourceName": "foo-bar", - "newValue": "newValue", - "previousValue": "previousValue", - "payload": {"key": "value"}, } ], "pagination": {"limit": 25, "offset": 0, "total": 1}, @@ -38,9 +35,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "user": {"id": None, "displayName": None}, "resourceId": None, "resourceName": None, - "newValue": None, - "previousValue": None, - "payload": ("dict", {0: (None, None)}), } }, ), diff --git a/tests/sites/test_comments.py b/tests/sites/test_comments.py new file mode 100644 index 0000000..b3abe92 --- /dev/null +++ b/tests/sites/test_comments.py @@ -0,0 +1,159 @@ +# This file was auto-generated by Fern from our API Definition. + +from webflow import Webflow +from webflow import AsyncWebflow +import typing +from ..utilities import validate_response + + +async def test_list_comment_threads(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "comments": [ + { + "id": "679d2ddb5196117ad04d1ffa", + "siteId": "679826b3b20b045e176bc4b5", + "pageId": "679826b3b20b045e176bc4bc", + "localeId": "67993753d910db250db64b3e", + "itemId": "580e64008c9a982ac9b8b754", + "breakpoint": "main", + "url": "https://webflow.com/design/site-slug-4ec832?workflow=comment&commentId=679d2ddb5196117ad04d1ff8&pageId=679826b3b20b045e176bc4bc", + "content": "Let's go to the pub! [[6287ec36a841b25637c663df]] ", + "isResolved": False, + "author": { + "userId": "6287ec36a841b25637c663df", + "email": "ford.prefect@heartofgold.spaceship", + "name": "Ford Prefect", + }, + "mentionedUsers": [ + { + "userId": "6287ec36a841b25637c663df", + "email": "arthur.dent@heartofgold.spaceship", + "name": "Arthur Dent", + } + ], + "createdOn": "2025-01-31T20:08:59.759Z", + "lastUpdated": "2025-01-31T20:08:59.759Z", + }, + { + "id": "679d2ddb5196117ad04d1ffc", + "siteId": "679826b3b20b045e176bc4b5", + "pageId": "679826b3b20b045e176bc4bc", + "localeId": "67993753d910db250db64b3e", + "itemId": "580e64008c9a982ac9b8b754", + "breakpoint": "main", + "url": "https://webflow.com/design/site-slug-4ec832?workflow=comment&commentId=679d2ddb5196117ad04d1ff8&pageId=679826b3b20b045e176bc4bc", + "content": "You have five minutes left to drink it [[6287ec36a841b25637c663df]] ", + "isResolved": False, + "author": { + "userId": "6287ec36a841b25637c663df", + "email": "ford.prefect@heartofgold.spaceship", + "name": "Ford Prefect", + }, + "mentionedUsers": [ + { + "userId": "6287ec36a841b25637c663df", + "email": "arthur.dent@heartofgold.spaceship", + "name": "Arthur Dent", + } + ], + "createdOn": "2025-01-31T20:08:59.759Z", + "lastUpdated": "2025-01-31T20:08:59.759Z", + }, + ], + "pagination": {"limit": 2, "offset": 0, "total": 2}, + } + expected_types: typing.Any = { + "comments": ( + "list", + { + 0: { + "id": None, + "siteId": None, + "pageId": None, + "localeId": None, + "itemId": None, + "breakpoint": None, + "url": None, + "content": None, + "isResolved": None, + "author": {"userId": None, "email": None, "name": None}, + "mentionedUsers": ("list", {0: {"userId": None, "email": None, "name": None}}), + "createdOn": None, + "lastUpdated": None, + }, + 1: { + "id": None, + "siteId": None, + "pageId": None, + "localeId": None, + "itemId": None, + "breakpoint": None, + "url": None, + "content": None, + "isResolved": None, + "author": {"userId": None, "email": None, "name": None}, + "mentionedUsers": ("list", {0: {"userId": None, "email": None, "name": None}}), + "createdOn": None, + "lastUpdated": None, + }, + }, + ), + "pagination": {"limit": None, "offset": None, "total": None}, + } + response = client.sites.comments.list_comment_threads( + site_id="580e63e98c9a982ac9b8b741", locale_id="65427cf400e02b306eaa04a0" + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.comments.list_comment_threads( + site_id="580e63e98c9a982ac9b8b741", locale_id="65427cf400e02b306eaa04a0" + ) + validate_response(async_response, expected_response, expected_types) + + +async def test_get_comment_thread(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "id": "580e64008c9a982ac9b8b754", + "siteId": "580e64008c9a982ac9b8b754", + "pageId": "580e64008c9a982ac9b8b754", + "localeId": "580e64008c9a982ac9b8b754", + "itemId": "580e64008c9a982ac9b8b754", + "breakpoint": "main", + "url": "https://webflow.com/design/site-slug-4ec832?workflow=comment&commentId=679d2ddb5196117ad04d1ff8&pageId=679826b3b20b045e176bc4bc", + "content": "This is a comment reply", + "isResolved": True, + "author": {"userId": "userId", "email": "email", "name": "name"}, + "mentionedUsers": [ + {"userId": "6287ec36a841b25637c663df", "email": "arthur.dent@heartofgold.spaceship", "name": "Arthur Dent"} + ], + "createdOn": "2023-03-17T18:47:35.560Z", + "lastUpdated": "2023-03-17T18:47:35.560Z", + } + expected_types: typing.Any = { + "id": None, + "siteId": None, + "pageId": None, + "localeId": None, + "itemId": None, + "breakpoint": None, + "url": None, + "content": None, + "isResolved": None, + "author": {"userId": None, "email": None, "name": None}, + "mentionedUsers": ("list", {0: {"userId": None, "email": None, "name": None}}), + "createdOn": None, + "lastUpdated": None, + } + response = client.sites.comments.get_comment_thread( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.comments.get_comment_thread( + site_id="580e63e98c9a982ac9b8b741", + comment_thread_id="580e63e98c9a982ac9b8b741", + locale_id="65427cf400e02b306eaa04a0", + ) + validate_response(async_response, expected_response, expected_types) diff --git a/tests/sites/test_robots_txt.py b/tests/sites/test_robots_txt.py new file mode 100644 index 0000000..cb38204 --- /dev/null +++ b/tests/sites/test_robots_txt.py @@ -0,0 +1,145 @@ +# This file was auto-generated by Fern from our API Definition. + +from webflow import Webflow +from webflow import AsyncWebflow +import typing +from ..utilities import validate_response +from webflow import RobotsRulesItem + + +async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "rules": [ + { + "userAgent": "googlebot", + "allows": ["/public"], + "disallows": ["/vogon-poetry", "/total-perspective-vortex"], + } + ], + "sitemap": "https://heartofgold.ship/sitemap.xml", + } + expected_types: typing.Any = { + "rules": ( + "list", + {0: {"userAgent": None, "allows": ("list", {0: None}), "disallows": ("list", {0: None, 1: None})}}, + ), + "sitemap": None, + } + response = client.sites.robots_txt.get(site_id="580e63e98c9a982ac9b8b741") + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.robots_txt.get(site_id="580e63e98c9a982ac9b8b741") + validate_response(async_response, expected_response, expected_types) + + +async def test_put(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "rules": [ + { + "userAgent": "googlebot", + "allows": ["/public"], + "disallows": ["/vogon-poetry", "/total-perspective-vortex"], + } + ], + "sitemap": "https://heartofgold.ship/sitemap.xml", + } + expected_types: typing.Any = { + "rules": ( + "list", + {0: {"userAgent": None, "allows": ("list", {0: None}), "disallows": ("list", {0: None, 1: None})}}, + ), + "sitemap": None, + } + response = client.sites.robots_txt.put( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", allows=["/public"], disallows=["/vogon-poetry", "/total-perspective-vortex"] + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.robots_txt.put( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", allows=["/public"], disallows=["/vogon-poetry", "/total-perspective-vortex"] + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", + ) + validate_response(async_response, expected_response, expected_types) + + +async def test_delete(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "rules": [ + { + "userAgent": "googlebot", + "allows": ["/public"], + "disallows": ["/vogon-poetry", "/total-perspective-vortex"], + } + ], + "sitemap": "https://heartofgold.ship/sitemap.xml", + } + expected_types: typing.Any = { + "rules": ( + "list", + {0: {"userAgent": None, "allows": ("list", {0: None}), "disallows": ("list", {0: None, 1: None})}}, + ), + "sitemap": None, + } + response = client.sites.robots_txt.delete( + site_id="580e63e98c9a982ac9b8b741", + rules=[RobotsRulesItem(user_agent="*", allows=["/public"], disallows=["/bubbles"])], + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.robots_txt.delete( + site_id="580e63e98c9a982ac9b8b741", + rules=[RobotsRulesItem(user_agent="*", allows=["/public"], disallows=["/bubbles"])], + ) + validate_response(async_response, expected_response, expected_types) + + +async def test_patch(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "rules": [ + { + "userAgent": "googlebot", + "allows": ["/public"], + "disallows": ["/vogon-poetry", "/total-perspective-vortex"], + } + ], + "sitemap": "https://heartofgold.ship/sitemap.xml", + } + expected_types: typing.Any = { + "rules": ( + "list", + {0: {"userAgent": None, "allows": ("list", {0: None}), "disallows": ("list", {0: None, 1: None})}}, + ), + "sitemap": None, + } + response = client.sites.robots_txt.patch( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", allows=["/public"], disallows=["/vogon-poetry", "/total-perspective-vortex"] + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.sites.robots_txt.patch( + site_id="580e63e98c9a982ac9b8b741", + rules=[ + RobotsRulesItem( + user_agent="googlebot", allows=["/public"], disallows=["/vogon-poetry", "/total-perspective-vortex"] + ) + ], + sitemap="https://heartofgold.ship/sitemap.xml", + ) + validate_response(async_response, expected_response, expected_types) diff --git a/tests/sites/test_scripts.py b/tests/sites/test_scripts.py index cc5d71c..beb0949 100644 --- a/tests/sites/test_scripts.py +++ b/tests/sites/test_scripts.py @@ -101,7 +101,6 @@ async def test_list_custom_code_blocks(client: Webflow, async_client: AsyncWebfl "blocks": [ { "siteId": "6258612d1ee792848f805dcf", - "pageId": "pageId", "type": "site", "scripts": [ {"id": "chartjs", "location": "header", "version": "4.4.2", "attributes": {"key": "value"}} @@ -126,7 +125,6 @@ async def test_list_custom_code_blocks(client: Webflow, async_client: AsyncWebfl { 0: { "siteId": None, - "pageId": None, "type": None, "scripts": ( "list", diff --git a/tests/test_assets.py b/tests/test_assets.py index af158ef..f755951 100644 --- a/tests/test_assets.py +++ b/tests/test_assets.py @@ -30,9 +30,33 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "quality": 100, } ], - "altText": "A red chair", - } - ] + "altText": "A single candy wrapper", + }, + { + "id": "63e5889e7fe4eafa7384cea5", + "contentType": "image/png", + "size": 2212772, + "siteId": "63938b302ea6b0aa6f3d8745", + "hostedUrl": "https://s3.amazonaws.com/webflow-prod-assets/63938b302ea6b0aa6f3d8745/63e5889e7fe4eafa7384cea4_Vectors-Wrapper.svg", + "originalFileName": "Gum-Wrapper.svg", + "displayName": "63e5889e7fe4eafa7384cea5_Gum-Wrapper.png", + "lastUpdated": "2023-03-01T23:42:57Z", + "createdOn": "2023-02-09T23:58:22Z", + "variants": [ + { + "hostedUrl": "https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "originalFileName": "Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "displayName": "660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "format": "png", + "width": 500, + "height": 900, + "quality": 100, + } + ], + "altText": "A single gum wrapper", + }, + ], + "pagination": {"limit": 2, "offset": 0, "total": 2}, } expected_types: typing.Any = { "assets": ( @@ -63,9 +87,36 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: }, ), "altText": None, - } + }, + 1: { + "id": None, + "contentType": None, + "size": "integer", + "siteId": None, + "hostedUrl": None, + "originalFileName": None, + "displayName": None, + "lastUpdated": "datetime", + "createdOn": "datetime", + "variants": ( + "list", + { + 0: { + "hostedUrl": None, + "originalFileName": None, + "displayName": None, + "format": None, + "width": "integer", + "height": "integer", + "quality": "integer", + } + }, + ), + "altText": None, + }, }, - ) + ), + "pagination": {"limit": None, "offset": None, "total": None}, } response = client.assets.list(site_id="580e63e98c9a982ac9b8b741") validate_response(response, expected_response, expected_types) @@ -136,28 +187,27 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "id": "55131cd036c09f7d07883dfc", + "id": "63e5889e7fe4eafa7384cea4", "contentType": "image/png", - "size": 1500, - "siteId": "62749158efef318abc8d5a0f", - "hostedUrl": "example.com/hostedimage.png", - "originalFileName": "image.png", - "displayName": "example-image-123.png", - "lastUpdated": "2016-09-06T21:12:22Z", - "createdOn": "2016-09-02T23:26:22Z", + "size": 2212772, + "siteId": "63938b302ea6b0aa6f3d8745", + "hostedUrl": "https://s3.amazonaws.com/webflow-prod-assets/63938b302ea6b0aa6f3d8745/63e5889e7fe4eafa7384cea4_Vectors-Wrapper.svg", + "originalFileName": "Candy-Wrapper.svg", + "displayName": "63e5889e7fe4eafa7384cea4_Candy-Wrapper.png", + "lastUpdated": "2023-03-01T23:42:57Z", + "createdOn": "2023-02-09T23:58:22Z", "variants": [ { - "hostedUrl": "example.com/hostedimage.png", - "originalFileName": "image.png", - "displayName": "A brown dog", - "format": "format", - "width": 1500, + "hostedUrl": "https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "originalFileName": "Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "displayName": "660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "format": "png", + "width": 500, "height": 900, - "quality": 1, - "error": "error", + "quality": 100, } ], - "altText": "A red chair", + "altText": "A single candy wrapper", } expected_types: typing.Any = { "id": None, @@ -180,7 +230,6 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "width": "integer", "height": "integer", "quality": "integer", - "error": None, } }, ), @@ -208,28 +257,27 @@ async def test_delete(client: Webflow, async_client: AsyncWebflow) -> None: async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "id": "55131cd036c09f7d07883dfc", + "id": "63e5889e7fe4eafa7384cea4", "contentType": "image/png", - "size": 1500, - "siteId": "62749158efef318abc8d5a0f", - "hostedUrl": "example.com/hostedimage.png", - "originalFileName": "image.png", - "displayName": "example-image-123.png", - "lastUpdated": "2016-09-06T21:12:22Z", - "createdOn": "2016-09-02T23:26:22Z", + "size": 2212772, + "siteId": "63938b302ea6b0aa6f3d8745", + "hostedUrl": "https://s3.amazonaws.com/webflow-prod-assets/63938b302ea6b0aa6f3d8745/63e5889e7fe4eafa7384cea4_Vectors-Wrapper.svg", + "originalFileName": "Candy-Wrapper.svg", + "displayName": "63e5889e7fe4eafa7384cea4_Candy-Wrapper.png", + "lastUpdated": "2023-03-01T23:42:57Z", + "createdOn": "2023-02-09T23:58:22Z", "variants": [ { - "hostedUrl": "example.com/hostedimage.png", - "originalFileName": "image.png", - "displayName": "A brown dog", - "format": "format", - "width": 1500, + "hostedUrl": "https://s3.amazonaws.com/webflow-prod-assets/6258612d1ee792848f805dcf/660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "originalFileName": "Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "displayName": "660d83ce30f3a599ddb0bdb3_Screenshot%202024-03-20%20at%209.03.24%E2%80%AFPM-p-500.png", + "format": "png", + "width": 500, "height": 900, - "quality": 1, - "error": "error", + "quality": 100, } ], - "altText": "A red chair", + "altText": "A single candy wrapper", } expected_types: typing.Any = { "id": None, @@ -252,7 +300,6 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: "width": "integer", "height": "integer", "quality": "integer", - "error": None, } }, ), @@ -271,7 +318,6 @@ async def test_list_folders(client: Webflow, async_client: AsyncWebflow) -> None { "id": "6390c49774a71f0e3c1a08ee", "displayName": "emoji icons", - "parentFolder": "6390c49774a71f99f21a08eb", "assets": ["63e5889e7fe4eafa7384cea4", "659595234426a9fcbad57043"], "siteId": "6390c49674a71f84b51a08d8", "createdOn": "2018-10-14T21:55:49Z", @@ -287,7 +333,6 @@ async def test_list_folders(client: Webflow, async_client: AsyncWebflow) -> None 0: { "id": None, "displayName": None, - "parentFolder": None, "assets": ("list", {0: None, 1: None}), "siteId": None, "createdOn": "datetime", diff --git a/tests/test_collections.py b/tests/test_collections.py index 1e76945..b811d80 100644 --- a/tests/test_collections.py +++ b/tests/test_collections.py @@ -4,6 +4,9 @@ from webflow import AsyncWebflow import typing from .utilities import validate_response +from webflow import StaticField +from webflow import ReferenceField +from webflow import ReferenceFieldMetadata async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: @@ -75,22 +78,40 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "id": "580e63fc8c9a982ac9b8b745", + "id": "562ac0395358780a1f5e6fbd", "displayName": "Blog Posts", "singularName": "Blog Post", - "slug": "post", + "slug": "posts", "createdOn": "2016-10-24T19:41:48Z", "lastUpdated": "2016-10-24T19:42:38Z", "fields": [ { - "id": "23cc2d952d4e4631ffd4345d2743db4e", + "id": "id", "isRequired": True, "isEditable": True, "type": "PlainText", - "slug": "name", - "displayName": "Name", - "helpText": "helpText", - } + "slug": "title", + "displayName": "Title", + "helpText": "The title of the blog post", + }, + { + "id": "id", + "isRequired": True, + "isEditable": True, + "type": "RichText", + "slug": "content", + "displayName": "Content", + "helpText": "The content of the blog post", + }, + { + "id": "id", + "isRequired": True, + "isEditable": True, + "type": "Reference", + "slug": "author", + "displayName": "Author", + "helpText": "The author of the blog post", + }, ], } expected_types: typing.Any = { @@ -111,17 +132,71 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "slug": None, "displayName": None, "helpText": None, - } + }, + 1: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, + 2: { + "id": None, + "isRequired": None, + "isEditable": None, + "type": None, + "slug": None, + "displayName": None, + "helpText": None, + }, }, ), } response = client.collections.create( - site_id="580e63e98c9a982ac9b8b741", display_name="Blog Posts", singular_name="Blog Post", slug="posts" + site_id="580e63e98c9a982ac9b8b741", + display_name="Blog Posts", + singular_name="Blog Post", + slug="posts", + fields=[ + StaticField( + is_required=True, type="PlainText", display_name="Title", help_text="The title of the blog post" + ), + StaticField( + is_required=True, type="RichText", display_name="Content", help_text="The content of the blog post" + ), + ReferenceField( + is_required=True, + type="Reference", + display_name="Author", + help_text="The author of the blog post", + metadata=ReferenceFieldMetadata(collection_id="23cc2d952d4e4631ffd4345d2743db4e"), + ), + ], ) validate_response(response, expected_response, expected_types) async_response = await async_client.collections.create( - site_id="580e63e98c9a982ac9b8b741", display_name="Blog Posts", singular_name="Blog Post", slug="posts" + site_id="580e63e98c9a982ac9b8b741", + display_name="Blog Posts", + singular_name="Blog Post", + slug="posts", + fields=[ + StaticField( + is_required=True, type="PlainText", display_name="Title", help_text="The title of the blog post" + ), + StaticField( + is_required=True, type="RichText", display_name="Content", help_text="The content of the blog post" + ), + ReferenceField( + is_required=True, + type="Reference", + display_name="Author", + help_text="The author of the blog post", + metadata=ReferenceFieldMetadata(collection_id="23cc2d952d4e4631ffd4345d2743db4e"), + ), + ], ) validate_response(async_response, expected_response, expected_types) @@ -142,7 +217,6 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "type": "PlainText", "slug": "name", "displayName": "Name", - "helpText": "helpText", } ], } @@ -155,17 +229,7 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "datetime", "fields": ( "list", - { - 0: { - "id": None, - "isRequired": None, - "isEditable": None, - "type": None, - "slug": None, - "displayName": None, - "helpText": None, - } - }, + {0: {"id": None, "isRequired": None, "isEditable": None, "type": None, "slug": None, "displayName": None}}, ), } response = client.collections.get(collection_id="580e63fc8c9a982ac9b8b745") diff --git a/tests/test_components.py b/tests/test_components.py index 2f5a42d..1824287 100644 --- a/tests/test_components.py +++ b/tests/test_components.py @@ -27,20 +27,8 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "description": "A secondary button component that can be used across the site", "readonly": True, }, - { - "id": "6258612d1ee792848f805dcf", - "name": "Card", - "group": "Buttons", - "description": "A button component that can be used across the site", - "readonly": True, - }, - { - "id": "68a2b1d1ee792848f805dcf", - "name": "Nav", - "group": "Buttons", - "description": "A button component that can be used across the site", - "readonly": True, - }, + {"id": "6258612d1ee792848f805dcf", "name": "Card", "readonly": True}, + {"id": "68a2b1d1ee792848f805dcf", "name": "Nav", "readonly": True}, ], "pagination": {"limit": 20, "offset": 0, "total": 4}, } @@ -50,8 +38,8 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: { 0: {"id": None, "name": None, "group": None, "description": None, "readonly": None}, 1: {"id": None, "name": None, "group": None, "description": None, "readonly": None}, - 2: {"id": None, "name": None, "group": None, "description": None, "readonly": None}, - 3: {"id": None, "name": None, "group": None, "description": None, "readonly": None}, + 2: {"id": None, "name": None, "readonly": None}, + 3: {"id": None, "name": None, "readonly": None}, }, ), "pagination": {"limit": None, "offset": None, "total": None}, @@ -67,40 +55,14 @@ async def test_get_content(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { "componentId": "69118560-d0bc-15fc-bbf8-b8fe5f6535b5", "nodes": [ + {"id": "id", "text": {}, "attributes": {"key": "value"}, "type": "text"}, + {"id": "id", "text": {}, "attributes": {"key": "value"}, "type": "text"}, + {"id": "id", "image": {}, "attributes": {"key": "value"}, "type": "image"}, { - "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad623", - "componentId": "nodes", - "propertyOverrides": [{"propertyId": "7dd14c08-2e96-8d3d-2b19-b5c03642a0f0"}], - }, - { - "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad627", - "componentId": "nodes", - "propertyOverrides": [{"propertyId": "7dd14c08-2e96-8d3d-2b19-b5c03642a0f0"}], - }, - { - "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad629", - "componentId": "nodes", + "id": "id", + "componentId": "componentId", "propertyOverrides": [{"propertyId": "7dd14c08-2e96-8d3d-2b19-b5c03642a0f0"}], - }, - { "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad631", - "componentId": "6258612d1ee792848f805dcf", - "propertyOverrides": [ - { - "propertyId": "a245c12d-995b-55ee-5ec7-aa36a6cad633", - "type": "Plain Text", - "text": {"text": "Don't Panic!"}, - }, - { - "propertyId": "a245c12d-995b-55ee-5ec7-aa36a6cad635", - "type": "Rich Text", - "text": {"html": "

Always know where your towel is.

"}, - }, - ], }, ], "pagination": {"limit": 4, "offset": 0, "total": 4}, diff --git a/tests/test_forms.py b/tests/test_forms.py index ee88977..f653d93 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -106,12 +106,7 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "createdOn": "2016-10-24T19:41:29Z", "lastUpdated": "2016-10-24T19:43:17Z", "fields": { - "660d5bcc9c0772150459dfb1": { - "displayName": "Name", - "type": "Plain", - "placeholder": "Enter your email", - "userVisible": True, - }, + "660d5bcc9c0772150459dfb1": {"displayName": "Name", "type": "Plain", "userVisible": True}, "589a331aa51e760df7ccb89d": { "displayName": "Email", "type": "Email", @@ -122,7 +117,6 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "responseSettings": { "redirectUrl": "https://example.com", "redirectMethod": "GET", - "redirectAction": "POST https://example.com", "sendEmailConfirmation": True, }, "id": "589a331aa51e760df7ccb89e", @@ -140,16 +134,11 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "fields": ( "dict", { - 0: (None, {"displayName": None, "type": None, "placeholder": None, "userVisible": None}), + 0: (None, {"displayName": None, "type": None, "userVisible": None}), 1: (None, {"displayName": None, "type": None, "placeholder": None, "userVisible": None}), }, ), - "responseSettings": { - "redirectUrl": None, - "redirectMethod": None, - "redirectAction": None, - "sendEmailConfirmation": None, - }, + "responseSettings": {"redirectUrl": None, "redirectMethod": None, "sendEmailConfirmation": None}, "id": None, "siteId": None, "siteDomainId": None, @@ -242,6 +231,19 @@ async def test_get_submission(client: Webflow, async_client: AsyncWebflow) -> No validate_response(async_response, expected_response, expected_types) +async def test_delete_submission(client: Webflow, async_client: AsyncWebflow) -> None: + # Type ignore to avoid mypy complaining about the function not being meant to return a value + assert ( + client.forms.delete_submission(form_submission_id="580e63e98c9a982ac9b8b741") # type: ignore[func-returns-value] + is None + ) + + assert ( + await async_client.forms.delete_submission(form_submission_id="580e63e98c9a982ac9b8b741") # type: ignore[func-returns-value] + is None + ) + + async def test_update_submission(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { "id": "6321ca84df3949bfc6752327", @@ -264,3 +266,60 @@ async def test_update_submission(client: Webflow, async_client: AsyncWebflow) -> async_response = await async_client.forms.update_submission(form_submission_id="580e63e98c9a982ac9b8b741") validate_response(async_response, expected_response, expected_types) + + +async def test_list_submissions_by_site(client: Webflow, async_client: AsyncWebflow) -> None: + expected_response: typing.Any = { + "formSubmissions": [ + { + "id": "6321ca84df3949bfc6752327", + "displayName": "Sample Form", + "siteId": "62749158efef318abc8d5a0f", + "workspaceId": "62749158efef318abc8d5a0f", + "dateSubmitted": "2022-09-14T12:35:16Z", + "formResponse": {"First Name": "Arthur", "Last Name": "Dent"}, + }, + { + "id": "660d64fabf6e0a0d4edab981", + "displayName": "Sample Form", + "siteId": "62749158efef318abc8d5a0f", + "workspaceId": "62749158efef318abc8d5a0f", + "dateSubmitted": "2022-09-14T12:35:16Z", + "formResponse": {"First Name": "Ford", "Last Name": "Prefect"}, + }, + ], + "pagination": {"limit": 25, "offset": 0, "total": 2}, + } + expected_types: typing.Any = { + "formSubmissions": ( + "list", + { + 0: { + "id": None, + "displayName": None, + "siteId": None, + "workspaceId": None, + "dateSubmitted": "datetime", + "formResponse": ("dict", {0: (None, None), 1: (None, None)}), + }, + 1: { + "id": None, + "displayName": None, + "siteId": None, + "workspaceId": None, + "dateSubmitted": "datetime", + "formResponse": ("dict", {0: (None, None), 1: (None, None)}), + }, + }, + ), + "pagination": {"limit": None, "offset": None, "total": None}, + } + response = client.forms.list_submissions_by_site( + site_id="580e63e98c9a982ac9b8b741", element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0" + ) + validate_response(response, expected_response, expected_types) + + async_response = await async_client.forms.list_submissions_by_site( + site_id="580e63e98c9a982ac9b8b741", element_id="18259716-3e5a-646a-5f41-5dc4b9405aa0" + ) + validate_response(async_response, expected_response, expected_types) diff --git a/tests/test_orders.py b/tests/test_orders.py index a874784..a8b6880 100644 --- a/tests/test_orders.py +++ b/tests/test_orders.py @@ -15,11 +15,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "comment": "Customer requested gift wrapping and a personalized note saying: Happy Birthday, Ford! 🎉 Please ensure the item is packed with extra bubble wrap for safe transit.", "orderComment": 'Please gift wrap with a personal note saying "Happy Birthday, Ford! 🎉', "acceptedOn": "2024-04-10T13:16:21Z", - "fulfilledOn": "2018-12-03T22:06:15Z", - "refundedOn": "2018-12-03T22:06:15Z", - "disputedOn": "2018-12-03T22:06:15Z", - "disputeUpdatedOn": "2018-12-03T22:06:15Z", - "disputeLastStatus": "warning_needs_response", "customerPaid": {"unit": "USD", "value": "5892", "string": " 211.55 USD"}, "netAmount": {"unit": "USD", "value": "5892", "string": " 200.89 USD"}, "applicationFee": {"unit": "USD", "value": "5892", "string": " 4.23 USD"}, @@ -122,14 +117,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": "Arthur Dent", "expires": {"year": 2025, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -160,11 +147,7 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "comment": "Example comment to myself", "orderComment": "", "acceptedOn": "2024-03-29T21:29:21Z", - "fulfilledOn": "2018-12-03T22:06:15Z", "refundedOn": "2024-04-08T18:25:04Z", - "disputedOn": "2018-12-03T22:06:15Z", - "disputeUpdatedOn": "2018-12-03T22:06:15Z", - "disputeLastStatus": "warning_needs_response", "customerPaid": {"unit": "USD", "value": "5892", "string": " 118.73 USD"}, "netAmount": {"unit": "USD", "value": "5892", "string": " 112.62 USD"}, "applicationFee": {"unit": "USD", "value": "5892", "string": " 2.37 USD"}, @@ -269,14 +252,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": "Arthur Dent", "expires": {"year": 2024, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -328,11 +303,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "comment": None, "orderComment": None, "acceptedOn": "datetime", - "fulfilledOn": "datetime", - "refundedOn": "datetime", - "disputedOn": "datetime", - "disputeUpdatedOn": "datetime", - "disputeLastStatus": None, "customerPaid": {"unit": None, "value": None, "string": None}, "netAmount": {"unit": None, "value": None, "string": None}, "applicationFee": {"unit": None, "value": None, "string": None}, @@ -437,14 +407,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": None, "expires": {"year": None, "month": None}, }, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, @@ -472,11 +434,7 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "comment": None, "orderComment": None, "acceptedOn": "datetime", - "fulfilledOn": "datetime", "refundedOn": "datetime", - "disputedOn": "datetime", - "disputeUpdatedOn": "datetime", - "disputeLastStatus": None, "customerPaid": {"unit": None, "value": None, "string": None}, "netAmount": {"unit": None, "value": None, "string": None}, "applicationFee": {"unit": None, "value": None, "string": None}, @@ -583,14 +541,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": None, "expires": {"year": None, "month": None}, }, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, @@ -744,12 +694,10 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: ], "purchasedItemsCount": 2, "stripeDetails": { - "subscriptionId": "sub_1J6xwG2eZvKYlo2CXu9Zt0Tn", "paymentMethod": "pm_1OzmzBJYFi4lcbXWHKNdXU7j", "paymentIntentId": "pi_3OzmzDJYFi4lcbXW1hTBW6ft", "customerId": "cus_PpRsNHwWdUoRKR", "chargeId": "ch_3OzmzDJYFi4lcbXW1ndkkrH2", - "disputeId": "disputeId", "refundId": "re_3OzmzDJYFi4lcbXW1kFAmlBk", "refundReason": "fraudulent", }, @@ -759,14 +707,6 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": "Arthur Dent", "expires": {"year": 2024, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -913,24 +853,14 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: ), "purchasedItemsCount": None, "stripeDetails": { - "subscriptionId": None, "paymentMethod": None, "paymentIntentId": None, "customerId": None, "chargeId": None, - "disputeId": None, "refundId": None, "refundReason": None, }, "stripeCard": {"last4": None, "brand": None, "ownerName": None, "expires": {"year": None, "month": None}}, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, @@ -1082,12 +1012,10 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: ], "purchasedItemsCount": 2, "stripeDetails": { - "subscriptionId": "sub_1J6xwG2eZvKYlo2CXu9Zt0Tn", "paymentMethod": "pm_1OzmzBJYFi4lcbXWHKNdXU7j", "paymentIntentId": "pi_3OzmzDJYFi4lcbXW1hTBW6ft", "customerId": "cus_PpRsNHwWdUoRKR", "chargeId": "ch_3OzmzDJYFi4lcbXW1ndkkrH2", - "disputeId": "disputeId", "refundId": "re_3OzmzDJYFi4lcbXW1kFAmlBk", "refundReason": "fraudulent", }, @@ -1097,14 +1025,6 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": "Arthur Dent", "expires": {"year": 2024, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -1251,24 +1171,14 @@ async def test_update(client: Webflow, async_client: AsyncWebflow) -> None: ), "purchasedItemsCount": None, "stripeDetails": { - "subscriptionId": None, "paymentMethod": None, "paymentIntentId": None, "customerId": None, "chargeId": None, - "disputeId": None, "refundId": None, "refundReason": None, }, "stripeCard": {"last4": None, "brand": None, "ownerName": None, "expires": {"year": None, "month": None}}, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, @@ -1420,12 +1330,10 @@ async def test_update_fulfill(client: Webflow, async_client: AsyncWebflow) -> No ], "purchasedItemsCount": 2, "stripeDetails": { - "subscriptionId": "sub_1J6xwG2eZvKYlo2CXu9Zt0Tn", "paymentMethod": "pm_1OzmzBJYFi4lcbXWHKNdXU7j", "paymentIntentId": "pi_3OzmzDJYFi4lcbXW1hTBW6ft", "customerId": "cus_PpRsNHwWdUoRKR", "chargeId": "ch_3OzmzDJYFi4lcbXW1ndkkrH2", - "disputeId": "disputeId", "refundId": "re_3OzmzDJYFi4lcbXW1kFAmlBk", "refundReason": "fraudulent", }, @@ -1435,14 +1343,6 @@ async def test_update_fulfill(client: Webflow, async_client: AsyncWebflow) -> No "ownerName": "Arthur Dent", "expires": {"year": 2024, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -1589,24 +1489,14 @@ async def test_update_fulfill(client: Webflow, async_client: AsyncWebflow) -> No ), "purchasedItemsCount": None, "stripeDetails": { - "subscriptionId": None, "paymentMethod": None, "paymentIntentId": None, "customerId": None, "chargeId": None, - "disputeId": None, "refundId": None, "refundReason": None, }, "stripeCard": {"last4": None, "brand": None, "ownerName": None, "expires": {"year": None, "month": None}}, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, @@ -1758,12 +1648,10 @@ async def test_update_unfulfill(client: Webflow, async_client: AsyncWebflow) -> ], "purchasedItemsCount": 2, "stripeDetails": { - "subscriptionId": "sub_1J6xwG2eZvKYlo2CXu9Zt0Tn", "paymentMethod": "pm_1OzmzBJYFi4lcbXWHKNdXU7j", "paymentIntentId": "pi_3OzmzDJYFi4lcbXW1hTBW6ft", "customerId": "cus_PpRsNHwWdUoRKR", "chargeId": "ch_3OzmzDJYFi4lcbXW1ndkkrH2", - "disputeId": "disputeId", "refundId": "re_3OzmzDJYFi4lcbXW1kFAmlBk", "refundReason": "fraudulent", }, @@ -1773,14 +1661,6 @@ async def test_update_unfulfill(client: Webflow, async_client: AsyncWebflow) -> "ownerName": "Arthur Dent", "expires": {"year": 2024, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -1927,24 +1807,14 @@ async def test_update_unfulfill(client: Webflow, async_client: AsyncWebflow) -> ), "purchasedItemsCount": None, "stripeDetails": { - "subscriptionId": None, "paymentMethod": None, "paymentIntentId": None, "customerId": None, "chargeId": None, - "disputeId": None, "refundId": None, "refundReason": None, }, "stripeCard": {"last4": None, "brand": None, "ownerName": None, "expires": {"year": None, "month": None}}, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, @@ -2096,12 +1966,10 @@ async def test_refund(client: Webflow, async_client: AsyncWebflow) -> None: ], "purchasedItemsCount": 2, "stripeDetails": { - "subscriptionId": "sub_1J6xwG2eZvKYlo2CXu9Zt0Tn", "paymentMethod": "pm_1OzmzBJYFi4lcbXWHKNdXU7j", "paymentIntentId": "pi_3OzmzDJYFi4lcbXW1hTBW6ft", "customerId": "cus_PpRsNHwWdUoRKR", "chargeId": "ch_3OzmzDJYFi4lcbXW1ndkkrH2", - "disputeId": "disputeId", "refundId": "re_3OzmzDJYFi4lcbXW1kFAmlBk", "refundReason": "fraudulent", }, @@ -2111,14 +1979,6 @@ async def test_refund(client: Webflow, async_client: AsyncWebflow) -> None: "ownerName": "Arthur Dent", "expires": {"year": 2024, "month": 4}, }, - "paypalDetails": { - "orderId": "1a2b3c4d5e6f7g8h9i0j", - "payerId": "9k8j7i6h5g4f3e2d1c0b", - "captureId": "qwe123rty456uio789p", - "refundId": "abcde12345fghij67890", - "refundReason": "Customer requested refund", - "disputeId": "zxcvbnm987poiuytrewq", - }, "customData": [{"key": "value"}], "metadata": {"isBuyNow": False}, "isCustomerDeleted": False, @@ -2265,24 +2125,14 @@ async def test_refund(client: Webflow, async_client: AsyncWebflow) -> None: ), "purchasedItemsCount": None, "stripeDetails": { - "subscriptionId": None, "paymentMethod": None, "paymentIntentId": None, "customerId": None, "chargeId": None, - "disputeId": None, "refundId": None, "refundReason": None, }, "stripeCard": {"last4": None, "brand": None, "ownerName": None, "expires": {"year": None, "month": None}}, - "paypalDetails": { - "orderId": None, - "payerId": None, - "captureId": None, - "refundId": None, - "refundReason": None, - "disputeId": None, - }, "customData": ("list", {0: ("dict", {0: (None, None)})}), "metadata": {"isBuyNow": None}, "isCustomerDeleted": None, diff --git a/tests/test_pages.py b/tests/test_pages.py index 716c201..8580c1b 100644 --- a/tests/test_pages.py +++ b/tests/test_pages.py @@ -20,8 +20,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "siteId": "6258612d1ee792848f805dcf", "title": "Guide to the Galaxy", "slug": "guide-to-the-galaxy", - "parentId": "6419db964a9c435aa3af6251", - "collectionId": "6390c49774a71f12831a08e3", "createdOn": "2024-03-11T10:42:00Z", "lastUpdated": "2024-03-11T10:42:42Z", "archived": False, @@ -47,8 +45,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "siteId": "6258612d1ee792848f805dcf", "title": "Towel Day Celebrations", "slug": "towel-day", - "parentId": "6419db964a9c435aa3af6251", - "collectionId": "6390c49774a71f12831a08e3", "createdOn": "2024-05-25T09:00:00Z", "lastUpdated": "2024-05-25T09:42:00Z", "archived": False, @@ -81,8 +77,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "siteId": None, "title": None, "slug": None, - "parentId": None, - "collectionId": None, "createdOn": "datetime", "lastUpdated": "datetime", "archived": None, @@ -100,8 +94,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "siteId": None, "title": None, "slug": None, - "parentId": None, - "collectionId": None, "createdOn": "datetime", "lastUpdated": "datetime", "archived": None, @@ -133,8 +125,6 @@ async def test_get_metadata(client: Webflow, async_client: AsyncWebflow) -> None "siteId": "6258612d1ee792848f805dcf", "title": "Guide to the Galaxy", "slug": "guide-to-the-galaxy", - "parentId": "6419db964a9c435aa3af6251", - "collectionId": "6390c49774a71f12831a08e3", "createdOn": "2024-03-11T10:42:00Z", "lastUpdated": "2024-03-11T10:42:42Z", "archived": False, @@ -160,8 +150,6 @@ async def test_get_metadata(client: Webflow, async_client: AsyncWebflow) -> None "siteId": None, "title": None, "slug": None, - "parentId": None, - "collectionId": None, "createdOn": "datetime", "lastUpdated": "datetime", "archived": None, @@ -189,8 +177,6 @@ async def test_update_page_settings(client: Webflow, async_client: AsyncWebflow) "siteId": "6258612d1ee792848f805dcf", "title": "Guide to the Galaxy", "slug": "guide-to-the-galaxy", - "parentId": "6419db964a9c435aa3af6251", - "collectionId": "6390c49774a71f12831a08e3", "createdOn": "2024-03-11T10:42:00Z", "lastUpdated": "2024-03-11T10:42:42Z", "archived": False, @@ -216,8 +202,6 @@ async def test_update_page_settings(client: Webflow, async_client: AsyncWebflow) "siteId": None, "title": None, "slug": None, - "parentId": None, - "collectionId": None, "createdOn": "datetime", "lastUpdated": "datetime", "archived": None, @@ -291,50 +275,24 @@ async def test_get_content(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { "pageId": "658205daa3e8206a523b5ad4", "nodes": [ + {"id": "id", "text": {}, "attributes": {"key": "value"}, "type": "text"}, + {"id": "id", "text": {}, "attributes": {"key": "value"}, "type": "text"}, + {"id": "id", "image": {}, "attributes": {"key": "value"}, "type": "image"}, { - "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad623", - "componentId": "nodes", + "id": "id", + "componentId": "componentId", "propertyOverrides": [{"propertyId": "7dd14c08-2e96-8d3d-2b19-b5c03642a0f0"}], - }, - { "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad627", - "componentId": "nodes", - "propertyOverrides": [{"propertyId": "7dd14c08-2e96-8d3d-2b19-b5c03642a0f0"}], - }, - { - "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad629", - "componentId": "nodes", - "propertyOverrides": [{"propertyId": "7dd14c08-2e96-8d3d-2b19-b5c03642a0f0"}], - }, - { - "type": "component-instance", - "id": "a245c12d-995b-55ee-5ec7-aa36a6cad631", - "componentId": "6258612d1ee792848f805dcf", - "propertyOverrides": [ - { - "propertyId": "a245c12d-995b-55ee-5ec7-aa36a6cad633", - "type": "Plain Text", - "label": "Catchphrase", - "text": {"text": "Don't Panic!"}, - }, - { - "propertyId": "a245c12d-995b-55ee-5ec7-aa36a6cad635", - "type": "Rich Text", - "label": "Tagline", - "text": {"html": "

Always know where your towel is.

"}, - }, - ], }, ], "pagination": {"limit": 4, "offset": 0, "total": 4}, + "lastUpdated": "2016-10-24T19:42:38Z", } expected_types: typing.Any = { "pageId": None, "nodes": ("list", {0: "no_validate", 1: "no_validate", 2: "no_validate", 3: "no_validate"}), "pagination": {"limit": None, "offset": None, "total": None}, + "lastUpdated": "datetime", } response = client.pages.get_content(page_id="63c720f9347c2139b248e552", locale_id="65427cf400e02b306eaa04a0") validate_response(response, expected_response, expected_types) diff --git a/tests/test_products.py b/tests/test_products.py index 03d28db..57fd11c 100644 --- a/tests/test_products.py +++ b/tests/test_products.py @@ -4,6 +4,13 @@ from webflow import AsyncWebflow import typing from .utilities import validate_response +from webflow.resources.products import ProductSkuCreateProduct +from webflow import ProductFieldData +from webflow import SkuPropertyList +from webflow import SkuPropertyListEnumItem +from webflow.resources.products import ProductSkuCreateSku +from webflow import SkuFieldData +from webflow import SkuFieldDataPrice from webflow import Sku @@ -41,11 +48,12 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "2023-03-17T18:47:35Z", "createdOn": "2023-03-17T18:47:35Z", "fieldData": { - "sku-values": {"ff42fee0113744f693a764e3431a9cc2": "64a74715c456e36762fc39a1"}, - "name": "Blue T-shirt", - "slug": "t-shirt-blue", - "price": {"value": 100, "unit": "USD"}, + "sku-values": {"color": "red"}, + "name": "Colorful T-shirt - Default", + "slug": "colorful-t-shirt-default", + "price": {"value": 2499, "unit": "USD", "currency": "USD"}, "quantity": 10, + "main-image": "https://www.example.com/image.jpg", }, } ], @@ -96,8 +104,9 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "sku-values": ("dict", {0: (None, None)}), "name": None, "slug": None, - "price": {"value": None, "unit": None}, + "price": {"value": None, "unit": None, "currency": None}, "quantity": None, + "main-image": None, }, } }, @@ -146,11 +155,12 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "2023-03-17T18:47:35Z", "createdOn": "2023-03-17T18:47:35Z", "fieldData": { - "sku-values": {"ff42fee0113744f693a764e3431a9cc2": "64a74715c456e36762fc39a1"}, - "name": "Blue T-shirt", - "slug": "t-shirt-blue", - "price": {"value": 100, "unit": "USD"}, + "sku-values": {"color": "red"}, + "name": "Colorful T-shirt - Default", + "slug": "colorful-t-shirt-default", + "price": {"value": 2499, "unit": "USD", "currency": "USD"}, "quantity": 10, + "main-image": "https://www.example.com/image.jpg", }, } ], @@ -192,17 +202,94 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "sku-values": ("dict", {0: (None, None)}), "name": None, "slug": None, - "price": {"value": None, "unit": None}, + "price": {"value": None, "unit": None, "currency": None}, "quantity": None, + "main-image": None, }, } }, ), } - response = client.products.create(site_id="580e63e98c9a982ac9b8b741") + response = client.products.create( + site_id="580e63e98c9a982ac9b8b741", + publish_status="staging", + product=ProductSkuCreateProduct( + field_data=ProductFieldData( + name="Colorful T-shirt", + slug="colorful-t-shirt", + description="Our best-selling t-shirt available in multiple colors and sizes", + sku_properties=[ + SkuPropertyList( + id="color", + name="Color", + enum=[ + SkuPropertyListEnumItem(id="red", name="Red", slug="red"), + SkuPropertyListEnumItem(id="yellow", name="Yellow", slug="yellow"), + SkuPropertyListEnumItem(id="blue", name="Blue", slug="blue"), + ], + ), + SkuPropertyList( + id="size", + name="Size", + enum=[ + SkuPropertyListEnumItem(id="small", name="Small", slug="small"), + SkuPropertyListEnumItem(id="medium", name="Medium", slug="medium"), + SkuPropertyListEnumItem(id="large", name="Large", slug="large"), + ], + ), + ], + ) + ), + sku=ProductSkuCreateSku( + field_data=SkuFieldData( + name="Colorful T-shirt - Red Small", + slug="colorful-t-shirt-red-small", + price=SkuFieldDataPrice(value=2499.0, unit="USD", currency="USD"), + main_image="https://rocketamp-sample-store.myshopify.com/cdn/shop/products/Gildan_2000_Antique_Cherry_Red_Front_1024x1024.jpg?v=1527232987", + ) + ), + ) validate_response(response, expected_response, expected_types) - async_response = await async_client.products.create(site_id="580e63e98c9a982ac9b8b741") + async_response = await async_client.products.create( + site_id="580e63e98c9a982ac9b8b741", + publish_status="staging", + product=ProductSkuCreateProduct( + field_data=ProductFieldData( + name="Colorful T-shirt", + slug="colorful-t-shirt", + description="Our best-selling t-shirt available in multiple colors and sizes", + sku_properties=[ + SkuPropertyList( + id="color", + name="Color", + enum=[ + SkuPropertyListEnumItem(id="red", name="Red", slug="red"), + SkuPropertyListEnumItem(id="yellow", name="Yellow", slug="yellow"), + SkuPropertyListEnumItem(id="blue", name="Blue", slug="blue"), + ], + ), + SkuPropertyList( + id="size", + name="Size", + enum=[ + SkuPropertyListEnumItem(id="small", name="Small", slug="small"), + SkuPropertyListEnumItem(id="medium", name="Medium", slug="medium"), + SkuPropertyListEnumItem(id="large", name="Large", slug="large"), + ], + ), + ], + ) + ), + sku=ProductSkuCreateSku( + field_data=SkuFieldData( + name="Colorful T-shirt - Red Small", + slug="colorful-t-shirt-red-small", + price=SkuFieldDataPrice(value=2499.0, unit="USD", currency="USD"), + main_image="https://rocketamp-sample-store.myshopify.com/cdn/shop/products/Gildan_2000_Antique_Cherry_Red_Front_1024x1024.jpg?v=1527232987", + ) + ), + ) validate_response(async_response, expected_response, expected_types) @@ -238,11 +325,12 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "2023-03-17T18:47:35Z", "createdOn": "2023-03-17T18:47:35Z", "fieldData": { - "sku-values": {"ff42fee0113744f693a764e3431a9cc2": "64a74715c456e36762fc39a1"}, - "name": "Blue T-shirt", - "slug": "t-shirt-blue", - "price": {"value": 100, "unit": "USD"}, + "sku-values": {"color": "red"}, + "name": "Colorful T-shirt - Default", + "slug": "colorful-t-shirt-default", + "price": {"value": 2499, "unit": "USD", "currency": "USD"}, "quantity": 10, + "main-image": "https://www.example.com/image.jpg", }, } ], @@ -284,8 +372,9 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "sku-values": ("dict", {0: (None, None)}), "name": None, "slug": None, - "price": {"value": None, "unit": None}, + "price": {"value": None, "unit": None, "currency": None}, "quantity": None, + "main-image": None, }, } }, @@ -365,11 +454,12 @@ async def test_create_sku(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "2023-03-17T18:47:35Z", "createdOn": "2023-03-17T18:47:35Z", "fieldData": { - "sku-values": {"ff42fee0113744f693a764e3431a9cc2": "64a74715c456e36762fc39a1"}, - "name": "Blue T-shirt", - "slug": "t-shirt-blue", - "price": {"value": 100, "unit": "USD"}, + "sku-values": {"color": "red"}, + "name": "Colorful T-shirt - Default", + "slug": "colorful-t-shirt-default", + "price": {"value": 2499, "unit": "USD", "currency": "USD"}, "quantity": 10, + "main-image": "https://www.example.com/image.jpg", }, } ] @@ -388,20 +478,41 @@ async def test_create_sku(client: Webflow, async_client: AsyncWebflow) -> None: "sku-values": ("dict", {0: (None, None)}), "name": None, "slug": None, - "price": {"value": None, "unit": None}, + "price": {"value": None, "unit": None, "currency": None}, "quantity": None, + "main-image": None, }, } }, ) } response = client.products.create_sku( - site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", skus=[Sku()] + site_id="580e63e98c9a982ac9b8b741", + product_id="580e63fc8c9a982ac9b8b745", + skus=[ + Sku( + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice(value=2499.0, unit="USD", currency="USD"), + ) + ) + ], ) validate_response(response, expected_response, expected_types) async_response = await async_client.products.create_sku( - site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", skus=[Sku()] + site_id="580e63e98c9a982ac9b8b741", + product_id="580e63fc8c9a982ac9b8b745", + skus=[ + Sku( + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice(value=2499.0, unit="USD", currency="USD"), + ) + ) + ], ) validate_response(async_response, expected_response, expected_types) @@ -414,15 +525,16 @@ async def test_update_sku(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "2023-03-17T18:47:35Z", "createdOn": "2023-03-17T18:47:35Z", "fieldData": { - "sku-values": {"ff42fee0113744f693a764e3431a9cc2": "64a74715c456e36762fc39a1"}, - "name": "Blue T-shirt", - "slug": "t-shirt-blue", - "price": {"value": 100, "unit": "USD"}, + "sku-values": {"color": "red"}, + "name": "Colorful T-shirt - Default", + "slug": "colorful-t-shirt-default", + "price": {"value": 2499, "unit": "USD", "currency": "USD"}, "compare-at-price": {"value": 100, "unit": "USD"}, "ec-sku-billing-method": "one-time", "ec-sku-subscription-plan": {"interval": "day", "frequency": 1, "trial": 7, "plans": [{}]}, "track-inventory": True, "quantity": 10, + "main-image": "https://www.example.com/image.jpg", }, } expected_types: typing.Any = { @@ -435,7 +547,7 @@ async def test_update_sku(client: Webflow, async_client: AsyncWebflow) -> None: "sku-values": ("dict", {0: (None, None)}), "name": None, "slug": None, - "price": {"value": None, "unit": None}, + "price": {"value": None, "unit": None, "currency": None}, "compare-at-price": {"value": None, "unit": None}, "ec-sku-billing-method": None, "ec-sku-subscription-plan": { @@ -446,13 +558,20 @@ async def test_update_sku(client: Webflow, async_client: AsyncWebflow) -> None: }, "track-inventory": None, "quantity": None, + "main-image": None, }, } response = client.products.update_sku( site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", sku_id="5e8518516e147040726cc415", - sku=Sku(), + sku=Sku( + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice(value=2499.0, unit="USD", currency="USD"), + ) + ), ) validate_response(response, expected_response, expected_types) @@ -460,6 +579,12 @@ async def test_update_sku(client: Webflow, async_client: AsyncWebflow) -> None: site_id="580e63e98c9a982ac9b8b741", product_id="580e63fc8c9a982ac9b8b745", sku_id="5e8518516e147040726cc415", - sku=Sku(), + sku=Sku( + field_data=SkuFieldData( + name="Colorful T-shirt - Default", + slug="colorful-t-shirt-default", + price=SkuFieldDataPrice(value=2499.0, unit="USD", currency="USD"), + ) + ), ) validate_response(async_response, expected_response, expected_types) diff --git a/tests/test_scripts.py b/tests/test_scripts.py index 6432530..145ff8c 100644 --- a/tests/test_scripts.py +++ b/tests/test_scripts.py @@ -14,7 +14,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "canCopy": False, "displayName": "Alert", "hostedLocation": "https://cdn.webflow.io/.../alert-0.0.1.js", - "integrityHash": "integrityHash", "createdOn": "2022-10-26T00:28:54.191Z", "lastUpdated": "lastUpdated", "version": "0.0.1", @@ -24,7 +23,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "canCopy": False, "displayName": "Alert", "hostedLocation": "https://cdn.webflow.io/.../alert-0.0.2.js", - "integrityHash": "integrityHash", "createdOn": "2022-10-26T00:28:54.191Z", "lastUpdated": "lastUpdated", "version": "0.0.2", @@ -50,7 +48,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "canCopy": None, "displayName": None, "hostedLocation": None, - "integrityHash": None, "createdOn": None, "lastUpdated": None, "version": None, @@ -60,7 +57,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "canCopy": None, "displayName": None, "hostedLocation": None, - "integrityHash": None, "createdOn": None, "lastUpdated": None, "version": None, @@ -131,7 +127,6 @@ async def test_register_inline(client: Webflow, async_client: AsyncWebflow) -> N "canCopy": False, "displayName": "Alert", "hostedLocation": "https://uploads-ssl.webflow.com/6258612d1ee792848f805dcf%2F64b6c769ff52ba6c3d904a91%2F660d6e15b3d1696f2d2b1447%2Falert-0.0.1.js", - "integrityHash": "integrityHash", "createdOn": "2022-10-26T00:28:54.191Z", "lastUpdated": "lastUpdated", "version": "0.0.1", @@ -141,7 +136,6 @@ async def test_register_inline(client: Webflow, async_client: AsyncWebflow) -> N "canCopy": None, "displayName": None, "hostedLocation": None, - "integrityHash": None, "createdOn": None, "lastUpdated": None, "version": None, diff --git a/tests/test_sites.py b/tests/test_sites.py index 6e9dd9b..3c604e7 100644 --- a/tests/test_sites.py +++ b/tests/test_sites.py @@ -13,37 +13,11 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "createdOn": "2024-10-15T20:24:38Z", "displayName": "The Hitchiker‘s Guide", "shortName": "hitchikers-guide", - "lastPublished": "2016-10-24T19:43:17Z", "lastUpdated": "2024-10-15T20:24:38Z", - "previewUrl": "https://d1otoma47x30pg.cloudfront.net/580e63e98c9a982ac9b8b741/201610241243.png", - "timeZone": "America/Los_Angeles", "parentFolderId": "670ece123598db72d9648be1", "customDomains": [ {"id": "589a331aa51e760df7ccb89d", "url": "test-api-domain.com", "lastPublished": "2022-12-07T16:51:37Z"} ], - "locales": { - "primary": { - "id": "653fd9af6a07fc9cfd7a5e57", - "cmsLocaleId": "653ad57de882f528b32e810e", - "enabled": False, - "displayName": "English (United States)", - "displayImageId": "displayImageId", - "redirect": True, - "subdirectory": "", - "tag": "en-US", - }, - "secondary": [ - { - "id": "653fd9af6a07fc9cfd7a5e57", - "cmsLocaleId": "653ad57de882f528b32e810e", - "enabled": False, - "displayName": "English (United States)", - "redirect": True, - "subdirectory": "", - "tag": "en-US", - } - ], - }, "dataCollectionEnabled": False, "dataCollectionType": "always", } @@ -53,38 +27,9 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "createdOn": "datetime", "displayName": None, "shortName": None, - "lastPublished": "datetime", "lastUpdated": "datetime", - "previewUrl": None, - "timeZone": None, "parentFolderId": None, "customDomains": ("list", {0: {"id": None, "url": None, "lastPublished": "datetime"}}), - "locales": { - "primary": { - "id": None, - "cmsLocaleId": None, - "enabled": None, - "displayName": None, - "displayImageId": None, - "redirect": None, - "subdirectory": None, - "tag": None, - }, - "secondary": ( - "list", - { - 0: { - "id": None, - "cmsLocaleId": None, - "enabled": None, - "displayName": None, - "redirect": None, - "subdirectory": None, - "tag": None, - } - }, - ), - }, "dataCollectionEnabled": None, "dataCollectionType": None, } @@ -162,7 +107,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "2016-10-24T19:43:17Z", "previewUrl": "https://d1otoma47x30pg.cloudfront.net/42e63e98c9a982ac9b8b742/198110121200.png", "timeZone": "DeepSpace/Depression", - "parentFolderId": "1as2d3f4g5h6j7k8l9z0x1c2v3b4n5m6", "customDomains": [ {"id": "589a331aa51e760df7ccb89f", "url": "marvin.blog", "lastPublished": "2022-12-07T16:51:37Z"} ], @@ -201,7 +145,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "2016-10-24T19:43:17Z", "previewUrl": "https://d1otoma47x30pg.cloudfront.net/42e63e98c9a982ac9b8b743/198210121200.png", "timeZone": "Vogsphere/PoetryHall", - "parentFolderId": "1as2d3f4g5h6j7k8l9z0x1c2v3b4n5m6", "customDomains": [ { "id": "589a331aa51e760df7ccb8a0", @@ -299,7 +242,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "datetime", "previewUrl": None, "timeZone": None, - "parentFolderId": None, "customDomains": ("list", {0: {"id": None, "url": None, "lastPublished": "datetime"}}), "locales": { "primary": { @@ -339,7 +281,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "lastUpdated": "datetime", "previewUrl": None, "timeZone": None, - "parentFolderId": None, "customDomains": ("list", {0: {"id": None, "url": None, "lastPublished": "datetime"}}), "locales": { "primary": { diff --git a/tests/test_webhooks.py b/tests/test_webhooks.py index 4c19188..2607cf1 100644 --- a/tests/test_webhooks.py +++ b/tests/test_webhooks.py @@ -9,7 +9,6 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: expected_response: typing.Any = { - "pagination": {"limit": 100, "offset": 0, "total": 100}, "webhooks": [ { "id": "57ca0a9e418c504a6e1acbb6", @@ -42,9 +41,9 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: "createdOn": "2016-07-19T01:43:40Z", }, ], + "pagination": {"limit": 100, "offset": 0, "total": 100}, } expected_types: typing.Any = { - "pagination": {"limit": None, "offset": None, "total": None}, "webhooks": ( "list", { @@ -80,6 +79,7 @@ async def test_list_(client: Webflow, async_client: AsyncWebflow) -> None: }, }, ), + "pagination": {"limit": None, "offset": None, "total": None}, } response = client.webhooks.list(site_id="580e63e98c9a982ac9b8b741") validate_response(response, expected_response, expected_types) @@ -95,7 +95,6 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "url": "https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f", "workspaceId": "4f4e46fd476ea8c507000001", "siteId": "562ac0395358780a1f5e6fbd", - "filter": {"name": "My Form"}, "lastTriggered": "2023-02-08T23:59:28Z", "createdOn": "2022-11-08T23:59:28Z", } @@ -105,7 +104,6 @@ async def test_create(client: Webflow, async_client: AsyncWebflow) -> None: "url": None, "workspaceId": None, "siteId": None, - "filter": {"name": None}, "lastTriggered": "datetime", "createdOn": "datetime", } @@ -141,7 +139,6 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "url": "https://webhook.site/7f7f7f7f-7f7f-7f7f-7f7f-7f7f7f7f7f7f", "workspaceId": "4f4e46fd476ea8c507000001", "siteId": "562ac0395358780a1f5e6fbd", - "filter": {"name": "My Form"}, "lastTriggered": "2023-02-08T23:59:28Z", "createdOn": "2022-11-08T23:59:28Z", } @@ -151,7 +148,6 @@ async def test_get(client: Webflow, async_client: AsyncWebflow) -> None: "url": None, "workspaceId": None, "siteId": None, - "filter": {"name": None}, "lastTriggered": "datetime", "createdOn": "datetime", } diff --git a/tests/test_well_known.py b/tests/test_well_known.py new file mode 100644 index 0000000..7c36619 --- /dev/null +++ b/tests/test_well_known.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +from webflow import Webflow +from webflow import AsyncWebflow + + +async def test_put(client: Webflow, async_client: AsyncWebflow) -> None: + # Type ignore to avoid mypy complaining about the function not being meant to return a value + assert ( + client.well_known.put(site_id="580e63e98c9a982ac9b8b741", file_name="fileName", file_data="fileData") # type: ignore[func-returns-value] + is None + ) + + assert ( + await async_client.well_known.put( + site_id="580e63e98c9a982ac9b8b741", file_name="fileName", file_data="fileData" + ) # type: ignore[func-returns-value] + is None + ) + + +async def test_delete(client: Webflow, async_client: AsyncWebflow) -> None: + # Type ignore to avoid mypy complaining about the function not being meant to return a value + assert ( + client.well_known.delete(site_id="580e63e98c9a982ac9b8b741") # type: ignore[func-returns-value] + is None + ) + + assert ( + await async_client.well_known.delete(site_id="580e63e98c9a982ac9b8b741") # type: ignore[func-returns-value] + is None + )