Metadata-Version: 2.4
Name: django-turnstile-htmx
Version: 0.1.0
Summary: A Django app for integrating Cloudflare Turnstile CAPTCHA protection with support for HTMX.
Author-email: Your Name <you@example.com>
License: MIT
Project-URL: Homepage, https://github.com/your-username/django-turnstile-htmx
Project-URL: Issues, https://github.com/your-username/django-turnstile-htmx/issues
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: django>=4.2
Requires-Dist: requests
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-django; extra == "test"
Dynamic: license-file

# Django Turnstile HTMX

A Django app for integrating Cloudflare Turnstile CAPTCHA protection with support for HTMX.

## Features

- Easy integration with Django views and templates
- Support for both regular forms and HTMX requests
- Server-side validation via decorator
- Simple template tag for adding Turnstile to forms

## Installation

1. Install the package from PyPI:
   ```bash
   pip install django-turnstile-htmx
   ```

2. Add the app to `INSTALLED_APPS` in your `settings.py`:
   ```python
   INSTALLED_APPS = [
       # ...
       'turnstile_htmx.apps.TurnstileHtmxConfig',
       # ...
   ]
   ```
3. Configure Cloudflare Turnstile keys:
   ```python
   CLOUDFLARE_TURNSTILE_SITE_KEY = 'your-site-key-here'
   CLOUDFLARE_TURNSTILE_SECRET_KEY = 'your-secret-key-here'
   ```

## Usage

1. Add script to base template:
   ```html
   {% load turnstile_tags %}
   <head>
     {% turnstile_script %}
   </head>
   ```

2. Add Turnstile field to forms:
   ```html
   {% load turnstile_tags %}

   <!-- Regular form -->
   <form method="post">
     {% csrf_token %}
     {{ form.as_p }}
     {% turnstile_field %}
     <button type="submit">Submit</button>
   </form>

   <!-- HTMX form -->
   <form hx-post="{% url 'your-view' %}" hx-target="#result">
     {% csrf_token %}
     <input type="email" name="email" required>
     {% turnstile_field %}
     <button type="submit">Subscribe</button>
   </form>
   ```

3. Protect views with decorator:
   ```python
   from turnstile_htmx.decorators import turnstile_protected

   @turnstile_protected
   def contact_form_view(request):
       # Process form - validation already happened!
       return render(request, 'contact.html')
   ```

## API Reference

### Template Tags

- `{% turnstile_field %}` - Renders the Turnstile widget
  - Parameters: `container_id` (optional), `site_key` (optional)

- `{% turnstile_script %}` - Renders the Turnstile script tag

### Decorators

- `@turnstile_protected` - Validates Turnstile token on POST requests
  - Parameters: `error_template` (optional)

## Examples

### Contact Form

```html
<!-- Template -->
{% extends 'base.html' %}
{% load turnstile_tags %}

{% block content %}
  <form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    {% turnstile_field %}
    <button type="submit">Send</button>
  </form>
{% endblock %}
```

```python
# View
from turnstile_htmx.decorators import turnstile_protected

@turnstile_protected
def contact_view(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('success')
    else:
        form = ContactForm()
    return render(request, 'contact.html', {'form': form})
```

### Customization

```python
# Custom error template
@turnstile_protected(error_template='<div class="alert">Verification failed!</div>')
def my_view(request):
    # ...

# Custom container ID
{% turnstile_field container_id="my-turnstile" %}
```

## Troubleshooting

- **Widget not appearing**: Check that `{% turnstile_script %}` is included and site key is correct
- **Validation failing**: Verify secret key and check browser console for errors
- **HTMX issues**: Ensure HTMX is loaded before Turnstile script

## License

MIT
