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
100 changes: 97 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,25 @@ client = AccessGrid(account_id, secret_key)
card = client.access_cards.provision(
card_template_id="0xd3adb00b5",
employee_id="123456789",
tag_id="DDEADB33FB00B5",
full_name="Employee name",
email="employee@yourwebsite.com",
phone_number="+19547212241",
classification="full_time",
department="Engineering",
location="San Francisco",
site_name="HQ Building A",
workstation="4F-207",
mail_stop="MS-401",
company_address="123 Main St, San Francisco, CA 94105",
start_date="2025-01-31T22:46:25.601Z",
expiration_date="2025-04-30T22:46:25.601Z",
employee_photo="[image_in_base64_encoded_format]"
employee_photo="[image_in_base64_encoded_format]",
title="Engineering Manager",
metadata={
"department": "engineering",
"badge_type": "contractor"
}
)
```

Expand All @@ -47,8 +59,15 @@ card = client.access_cards.update(
employee_id="987654321",
full_name="Updated Employee Name",
classification="contractor",
department="Marketing",
location="New York",
site_name="NYC Office",
workstation="2F-105",
mail_stop="MS-200",
company_address="456 Broadway, New York, NY 10013",
expiration_date="2025-02-22T21:04:03.664Z",
employee_photo="[image_in_base64_encoded_format]"
employee_photo="[image_in_base64_encoded_format]",
title="Senior Developer"
)
```

Expand Down Expand Up @@ -112,7 +131,7 @@ template = client.console.create_template(

```python
template = client.console.update_template(
template_id="0xd3adb00b5",
card_template_id="0xd3adb00b5",
name="Updated Employee NFC key",
allow_on_multiple_devices=True,
watch_count=2,
Expand Down Expand Up @@ -184,6 +203,76 @@ for item in result['ledger_items']:
print(f" Card Template: {item['access_pass']['pass_template']['ex_id']}")
```

### Landing Pages

#### List landing pages

```python
landing_pages = client.console.list_landing_pages()

for page in landing_pages:
print(f"ID: {page.id}, Name: {page.name}, Kind: {page.kind}")
print(f" Password Protected: {page.password_protected}")
if page.logo_url:
print(f" Logo URL: {page.logo_url}")
```

#### Create a landing page

```python
landing_page = client.console.create_landing_page(
name="Miami Office Access Pass",
kind="universal",
additional_text="Welcome to the Miami Office",
bg_color="#f1f5f9",
allow_immediate_download=True
)

print(f"Landing page created: {landing_page.id}")
print(f"Name: {landing_page.name}, Kind: {landing_page.kind}")
```

#### Update a landing page

```python
landing_page = client.console.update_landing_page(
landing_page_id="0xlandingpage1d",
name="Updated Miami Office Access Pass",
additional_text="Welcome! Tap below to get your access pass.",
bg_color="#e2e8f0"
)

print(f"Landing page updated: {landing_page.id}")
print(f"Name: {landing_page.name}")
```

### Credential Profiles

#### List credential profiles

```python
profiles = client.console.credential_profiles.list()

for profile in profiles:
print(f"ID: {profile.id}, Name: {profile.name}, AID: {profile.aid}")
```

#### Create a credential profile

```python
profile = client.console.credential_profiles.create(
name='Main Office Profile',
app_name='KEY-ID-main',
keys=[
{'value': 'your_32_char_hex_master_key_here'},
{'value': 'your_32_char_hex__read_key__here'}
]
)

print(f"Profile created: {profile.id}")
print(f"AID: {profile.aid}")
```

### Webhooks

#### Create a webhook
Expand Down Expand Up @@ -325,6 +414,11 @@ MIT License - See LICENSE file for details.
| GET /v1/console/pass-template-pairs | `console.list_pass_template_pairs()` | Y |
| POST /v1/console/card-templates/{id}/ios_preflight | `console.ios_preflight()` | Y |
| GET /v1/console/ledger-items | `console.ledger_items()` | Y |
| GET /v1/console/landing-pages | `console.list_landing_pages()` | Y |
| POST /v1/console/landing-pages | `console.create_landing_page()` | Y |
| PUT /v1/console/landing-pages/{id} | `console.update_landing_page()` | Y |
| GET /v1/console/credential-profiles | `console.credential_profiles.list()` | Y |
| POST /v1/console/credential-profiles | `console.credential_profiles.create()` | Y |
| GET /v1/console/webhooks | `console.webhooks.list()` | Y |
| POST /v1/console/webhooks | `console.webhooks.create()` | Y |
| DELETE /v1/console/webhooks/{id} | `console.webhooks.delete()` | Y |
Expand Down
6 changes: 5 additions & 1 deletion accessgrid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
AccessGrid,
AccessGridError,
AuthenticationError,
CredentialProfile,
IosPreflight,
LandingPage,
Org,
PassTemplatePair,
Template,
Expand All @@ -33,7 +35,7 @@
)

# Version of the accessgrid package
__version__ = "0.3.0"
__version__ = "0.4.0"

# List of public objects that will be exported with "from accessgrid import *"
__all__ = [
Expand All @@ -48,4 +50,6 @@
"IosPreflight",
"Webhook",
"Org",
"LandingPage",
"CredentialProfile",
]
158 changes: 153 additions & 5 deletions accessgrid/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,16 @@ def __init__(self, client, data: Dict[str, Any]):
self.details = data.get("details")
self.state = data.get("state")
self.full_name = data.get("full_name")
self.employee_id = data.get("employee_id")
self.expiration_date = data.get("expiration_date")
self.card_template_id = data.get("card_template_id")
self.card_number = data.get("card_number")
self.site_code = data.get("site_code")
self.file_data = data.get("file_data")
self.direct_install_url = data.get("direct_install_url")
self.organization_name = data.get("organization_name")
self.temporary = data.get("temporary")
self.created_at = data.get("created_at")
self.devices = data.get("devices", [])
self.metadata = data.get("metadata", {})

Expand Down Expand Up @@ -91,6 +95,7 @@ def __init__(self, client, data: Dict[str, Any]):
self.support_settings = data.get("support_settings")
self.terms_settings = data.get("terms_settings")
self.style_settings = data.get("style_settings")
self.metadata = data.get("metadata", {})


class Org:
Expand Down Expand Up @@ -177,6 +182,47 @@ def __repr__(self) -> str:
return self.__str__()


class LandingPage:
def __init__(self, client, data: Dict[str, Any]):
self._client = client
self.id = data.get("id")
self.name = data.get("name")
self.created_at = data.get("created_at")
self.kind = data.get("kind")
self.password_protected = data.get("password_protected")
self.logo_url = data.get("logo_url")

def __str__(self) -> str:
return (
f"LandingPage(id='{self.id}', " f"name='{self.name}', kind='{self.kind}')"
)

def __repr__(self) -> str:
return self.__str__()


class CredentialProfile:
def __init__(self, client, data: Dict[str, Any]):
self._client = client
self.id = data.get("id")
self.aid = data.get("aid")
self.name = data.get("name")
self.apple_id = data.get("apple_id")
self.created_at = data.get("created_at")
self.card_storage = data.get("card_storage")
self.keys = data.get("keys", [])
self.files = data.get("files", [])

def __str__(self) -> str:
return (
f"CredentialProfile(id='{self.id}', "
f"name='{self.name}', aid='{self.aid}')"
)

def __repr__(self) -> str:
return self.__str__()


class IosPreflight:
def __init__(self, client, data: Dict[str, Any]):
self._client = client
Expand Down Expand Up @@ -315,7 +361,8 @@ def list(self) -> List["Org"]:
List of Org objects
"""
response = self._client._get("/v1/console/hid/orgs")
return [Org(self._client, org) for org in response.get("orgs", [])]
orgs = response if isinstance(response, list) else response.get("orgs", [])
return [Org(self._client, org) for org in orgs]

def create(
self, name: str, full_address: str, phone: str, first_name: str, last_name: str
Expand Down Expand Up @@ -381,27 +428,76 @@ def delete(self, webhook_id: str) -> None:
self._client._delete(f"/v1/console/webhooks/{webhook_id}")


class CredentialProfiles:
def __init__(self, client):
self._client = client

def create(
self,
name: str,
app_name: str = "KEY-ID-main",
keys: Optional[List[Dict]] = None,
file_id: Optional[str] = None,
) -> CredentialProfile:
"""
Create a new credential profile.

Args:
name: Profile name
app_name: Application name (default: KEY-ID-main)
keys: List of key dicts with 'value' and optional
'keys_diversified', 'source_key_index'
file_id: Optional file ID (default: "00")

Returns:
CredentialProfile object
"""
data: Dict[str, Any] = {"name": name, "app_name": app_name}
if keys is not None:
data["keys"] = keys
if file_id is not None:
data["file_id"] = file_id
response = self._client._post("/v1/console/credential-profiles", data)
return CredentialProfile(self._client, response)

def list(self) -> List[CredentialProfile]:
"""
List all credential profiles.

Returns:
List of CredentialProfile objects
"""
response = self._client._get("/v1/console/credential-profiles")
profiles = (
response
if isinstance(response, list)
else response.get("credential_profiles", [])
)
return [CredentialProfile(self._client, p) for p in profiles]


class Console:
def __init__(self, client):
self._client = client
self.hid = HID(client)
self.webhooks = Webhooks(client)
self.credential_profiles = CredentialProfiles(client)

def create_template(self, **kwargs) -> Template:
"""Create a new card template"""
response = self._client._post("/v1/console/card-templates", kwargs)
return Template(self._client, response)

def update_template(self, template_id: str, **kwargs) -> Template:
def update_template(self, card_template_id: str, **kwargs) -> Template:
"""Update an existing card template"""
response = self._client._put(
f"/v1/console/card-templates/{template_id}", kwargs
f"/v1/console/card-templates/{card_template_id}", kwargs
)
return Template(self._client, response)

def read_template(self, template_id: str) -> Union[Template, List[Template]]:
def read_template(self, card_template_id: str) -> Union[Template, List[Template]]:
"Read card template by id or list the card template pairs"
response = self._client._get(f"/v1/console/card-templates/{template_id}")
response = self._client._get(f"/v1/console/card-templates/{card_template_id}")
if "templates" in response:
return [Template(self._client, item) for item in response["templates"]]
return Template(self._client, response)
Expand Down Expand Up @@ -441,6 +537,58 @@ def ledger_items(self, **kwargs) -> Dict[str, Any]:
"""
return self._client._get("/v1/console/ledger-items", params=kwargs)

def list_landing_pages(self) -> List[LandingPage]:
"""List all landing pages."""
response = self._client._get("/v1/console/landing-pages")
pages = (
response
if isinstance(response, list)
else response.get("landing_pages", [])
)
return [LandingPage(self._client, lp) for lp in pages]

def create_landing_page(self, **kwargs) -> LandingPage:
"""
Create a new landing page.

Args:
name: Landing page name
kind: Landing page kind (e.g. 'universal')
additional_text: Optional text to display
bg_color: Background color hex string
allow_immediate_download: Whether to allow immediate download
password: Optional password protection
is_2fa_enabled: Whether 2FA is enabled
logo: Optional base64-encoded logo image

Returns:
LandingPage object
"""
response = self._client._post("/v1/console/landing-pages", kwargs)
return LandingPage(self._client, response)

def update_landing_page(self, landing_page_id: str, **kwargs) -> LandingPage:
"""
Update an existing landing page.

Args:
landing_page_id: The landing page ID
name: Updated name
additional_text: Updated text
bg_color: Updated background color
allow_immediate_download: Updated download setting
password: Updated password
is_2fa_enabled: Updated 2FA setting
logo: Updated base64-encoded logo image

Returns:
LandingPage object
"""
response = self._client._put(
f"/v1/console/landing-pages/{landing_page_id}", kwargs
)
return LandingPage(self._client, response)

def list_pass_template_pairs(self, **kwargs) -> Dict[str, Any]:
"""
List Pass Template Pairs with pagination support.
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

setup(
name="accessgrid",
version="0.2.1",
version="0.4.0",
author="Auston Bunsen",
author_email="ab@accessgrid.com",
description="Python SDK for the AccessGrid API",
Expand Down
Loading
Loading