Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 1.5.0 (2022-09-07)

- Added support for HTML/CSS and Markdown in `CreateEtchPacket`. [See examples here](https://www.useanvil.com/docs/api/e-signatures#generating-a-pdf-from-html-and-css).

# 1.5.0 (2022-08-05)

- Added support for `ForgeSubmit` mutation.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ General API documentation: [Anvil API docs](https://www.useanvil.com/docs)

Install it directly into an activated virtual environment:

```text
```shell
$ pip install python-anvil
```

or add it to your [Poetry](https://python-poetry.org/) project:

```text
```shell
$ poetry add python-anvil
```
2 changes: 1 addition & 1 deletion docs/api_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
All methods assume that a valid API key is already available. Please take a look
at [Anvil API Basics](https://www.useanvil.com/docs/api/basics) for more details on how to get your key.

### Anvil() constructor
### `Anvil` constructor

* `api_key` - Your Anvil API key, either development or production
* `environment` (default: `'dev'`) - The type of key being used. This affects how the library sets rate limits on API
Expand Down
137 changes: 137 additions & 0 deletions examples/create_etch_markdown.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# pylint: disable=duplicate-code

from python_anvil.api import Anvil
from python_anvil.api_resources.mutations.create_etch_packet import CreateEtchPacket
from python_anvil.api_resources.payload import (
DocumentMarkdown,
EtchSigner,
MarkdownContent,
SignatureField,
SignerField,
)


API_KEY = 'my-api-key'


def main():
anvil = Anvil(api_key=API_KEY)

# Create an instance of the builder
packet = CreateEtchPacket(
name="Etch packet with existing template",
#
# Optional changes to email subject and body content
signature_email_subject="Please sign these forms",
signature_email_body="This form requires information from your driver's "
"license. Please have that available.",
#
# URL where Anvil will send POST requests when server events happen.
# Take a look at https://www.useanvil.com/docs/api/e-signatures#webhook-notifications
# for other details on how to configure webhooks on your account.
# You can also use sites like webhook.site, requestbin.com or ngrok to
# test webhooks.
# webhook_url="https://my.webhook.example.com/etch-events/",
#
# Email overrides for the "reply-to" email header for signer emails.
# If used, both `reply_to_email` and `reply_to_name` are required.
# By default, this will point to your organization support email.
# reply_to_email="[email protected]",
# reply_to_name="My Name",
#
# Merge all PDFs into one. Use this if you have many PDF templates
# and/or files, but want the final downloaded package to be only
# 1 PDF file.
# merge_pdfs=True,
)

# Get your file(s) ready to sign.
# For this example, a PDF will not be uploaded. We'll create and style the
# document with HTML and CSS and add signing fields based on coordinates.

# Define the document with Markdown
file1 = DocumentMarkdown(
id="markdownFile",
filename="markdown.pdf",
title="Sign this markdown file",
fields=[
# This is markdown content
MarkdownContent(
table=dict(
rows=[
['Description', 'Quantity', 'Price'],
['3x Roof Shingles', '15', '$60.00'],
['5x Hardwood Plywood', '10', '$300.00'],
['80x Wood Screws', '80', '$45.00'],
],
)
),
SignatureField(
page_num=0,
id="sign1",
type="signature",
# The position and size of the field. The coordinates provided here
# (x=300, y=300) is the top-left of the rectangle.
rect=dict(x=300, y=300, width=250, height=30),
),
],
)

# Gather your signer data
signer1 = EtchSigner(
name="Jackie",
email="[email protected]",
# Fields where the signer needs to sign.
# Check your cast fields via the CLI (`anvil cast [cast_eid]`) or the
# PDF Templates section on the Anvil app.
# This basically says: "In the 'myNewFile' file (defined in
# `file1` above), assign the signature field with cast id of
# 'sign1' to this signer." You can add multiple signer fields here.
fields=[
SignerField(
# this is the `id` in the `DocumentUpload` object above
file_id="markdownFile",
# This is the signing field id in the `SignatureField` above
field_id="sign1",
),
],
signer_type="embedded",
#
# You can also change how signatures will be collected.
# "draw" will allow the signer to draw their signature
# "text" will insert a text version of the signer's name into the
# signature field.
# signature_mode="draw",
#
# Whether or not to the signer is required to click each signature
# field manually. If `False`, the PDF will be signed once the signer
# accepts the PDF without making the user go through the PDF.
# accept_each_field=False,
#
# URL of where the signer will be redirected after signing.
# The URL will also have certain URL params added on, so the page
# can be customized based on the signing action.
# redirect_url="https://www.google.com",
)

# Add your signer.
packet.add_signer(signer1)

# Add files to your payload
packet.add_file(file1)

# If needed, you can also override or add additional payload fields this way.
# This is useful if the Anvil API has new features, but `python-anvil` has not
# yet been updated to support it.
# payload = packet.create_payload()
# payload.aNewFeature = True

# Create your packet
# If overriding/adding new fields, use the modified payload from
# `packet.create_payload()`
res = anvil.create_etch_packet(payload=packet, include_headers=True)
print(res)


if __name__ == '__main__':
main()
142 changes: 142 additions & 0 deletions examples/create_etch_markup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# pylint: disable=duplicate-code

from python_anvil.api import Anvil
from python_anvil.api_resources.mutations.create_etch_packet import CreateEtchPacket
from python_anvil.api_resources.payload import (
DocumentMarkup,
EtchSigner,
SignatureField,
SignerField,
)


API_KEY = 'my-api-key'


def main():
anvil = Anvil(api_key=API_KEY)

# Create an instance of the builder
packet = CreateEtchPacket(
name="Etch packet with existing template",
#
# Optional changes to email subject and body content
signature_email_subject="Please sign these forms",
signature_email_body="This form requires information from your driver's "
"license. Please have that available.",
#
# URL where Anvil will send POST requests when server events happen.
# Take a look at https://www.useanvil.com/docs/api/e-signatures#webhook-notifications
# for other details on how to configure webhooks on your account.
# You can also use sites like webhook.site, requestbin.com or ngrok to
# test webhooks.
# webhook_url="https://my.webhook.example.com/etch-events/",
#
# Email overrides for the "reply-to" email header for signer emails.
# If used, both `reply_to_email` and `reply_to_name` are required.
# By default, this will point to your organization support email.
# reply_to_email="[email protected]",
# reply_to_name="My Name",
#
# Merge all PDFs into one. Use this if you have many PDF templates
# and/or files, but want the final downloaded package to be only
# 1 PDF file.
# merge_pdfs=True,
)

# Get your file(s) ready to sign.
# For this example, a PDF will not be uploaded. We'll create and style the
# document with HTML and CSS and add signing fields based on coordinates.

# Define the document with HTML/CSS
file1 = DocumentMarkup(
id="myNewFile",
title="Please sign this important form",
filename="markup.pdf",
markup={
"html": """
<div class="first">This document is created with HTML.</div>
<br />
<br />
<br />
<div>We can also define signing fields with text tags</div>
<div>{{ signature : First signature : textTag : textTag }}</div>
""",
"css": """"body{ color: red; } div.first { color: blue; } """,
},
fields=[
SignatureField(
id="sign1",
type="signature",
page_num=0,
# The position and size of the field. The coordinates provided here
# (x=300, y=300) is the top-left of the rectangle.
rect=dict(x=300, y=300, width=250, height=30),
)
],
)

# Gather your signer data
signer1 = EtchSigner(
name="Jackie",
email="[email protected]",
# Fields where the signer needs to sign.
# Check your cast fields via the CLI (`anvil cast [cast_eid]`) or the
# PDF Templates section on the Anvil app.
# This basically says: "In the 'myNewFile' file (defined in
# `file1` above), assign the signature field with cast id of
# 'sign1' to this signer." You can add multiple signer fields here.
fields=[
SignerField(
# this is the `id` in the `DocumentUpload` object above
file_id="myNewFile",
# This is the signing field id in the `SignatureField` above
field_id="sign1",
),
SignerField(
# this is the `id` in the `DocumentUpload` object above
file_id="myNewFile",
# This is the signing field id in the `SignatureField` above
field_id="textTag",
),
],
signer_type="embedded",
#
# You can also change how signatures will be collected.
# "draw" will allow the signer to draw their signature
# "text" will insert a text version of the signer's name into the
# signature field.
# signature_mode="draw",
#
# Whether or not to the signer is required to click each signature
# field manually. If `False`, the PDF will be signed once the signer
# accepts the PDF without making the user go through the PDF.
# accept_each_field=False,
#
# URL of where the signer will be redirected after signing.
# The URL will also have certain URL params added on, so the page
# can be customized based on the signing action.
# redirect_url="https://www.google.com",
)

# Add your signer.
packet.add_signer(signer1)

# Add files to your payload
packet.add_file(file1)

# If needed, you can also override or add additional payload fields this way.
# This is useful if the Anvil API has new features, but `python-anvil` has not
# yet been updated to support it.
# payload = packet.create_payload()
# payload.aNewFeature = True

# Create your packet
# If overriding/adding new fields, use the modified payload from
# `packet.create_payload()`
res = anvil.create_etch_packet(payload=packet, include_headers=True)
print(res)


if __name__ == '__main__':
main()
26 changes: 26 additions & 0 deletions examples/generate_pdf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from python_anvil.api import Anvil
from python_anvil.api_resources.payload import GeneratePDFPayload


API_KEY = 'my-api-key'


def main():
anvil = Anvil(api_key=API_KEY)
data = GeneratePDFPayload(
type="html",
title="Some Title",
data=dict(
html="<h2>HTML Heading</h2>",
css="h2 { color: red }",
),
)
response = anvil.generate_pdf(data)

# Write the bytes to disk
with open('./generated.pdf', 'wb') as f:
f.write(response)


if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tool.poetry]

name = "python_anvil"
version = "1.5.0"
version = "1.6.0"
description = "Anvil API"

license = "MIT"
Expand Down
6 changes: 4 additions & 2 deletions python_anvil/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def fill_pdf(
**kwargs,
)

def generate_pdf(self, payload: Union[AnyStr, Dict], **kwargs):
def generate_pdf(self, payload: Union[AnyStr, Dict, GeneratePDFPayload], **kwargs):
if not payload:
raise ValueError("`payload` must be a valid JSON string or a dict")

Expand All @@ -103,10 +103,12 @@ def generate_pdf(self, payload: Union[AnyStr, Dict], **kwargs):
data = GeneratePDFPayload.parse_raw(
payload, content_type="application/json"
)
elif isinstance(payload, GeneratePDFPayload):
data = payload
else:
raise ValueError("`payload` must be a valid JSON string or a dict")

# Any data errors would come from here..
# Any data errors would come from here
api = RestRequest(client=self.client)
return api.post(
"generate-pdf", data=data.dict(by_alias=True, exclude_none=True), **kwargs
Expand Down
Loading