Metadata-Version: 2.4
Name: vision-it-request-forms-backend
Version: 0.1.10
Summary: DRF API backend for Vision IT Request Forms — models, serializers, connectors
Project-URL: Homepage, https://git.mydatapath.com/datapath/vision-it-support-forms
Project-URL: Issues, https://git.mydatapath.com/datapath/vision-it-support-forms/issues
Author-email: Peter Annabel <pannabel@mydatapath.com>
License-Expression: LicenseRef-Proprietary
Keywords: django,drf,forms,it-requests,vision-dashboard
Classifier: Framework :: Django
Classifier: Framework :: Django :: 5.2
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Requires-Dist: asgiref>=3.8.1
Requires-Dist: django-admin-sortable2<3.0,>=2.2
Requires-Dist: django-groups-manager<2.0,>=1.0
Requires-Dist: django==5.2.11
Requires-Dist: djangorestframework<4.0,>=3.15
Requires-Dist: dnspython>=2.7.0
Requires-Dist: jsonfield<4.0,>=3.1
Requires-Dist: pyconnectwise<1.0,>=0.6
Requires-Dist: pytest-django<5.0,>=4.8
Requires-Dist: pytest<9.0,>=8.0
Requires-Dist: sendgrid<7.0,>=6.11
Requires-Dist: slack-sdk<4.0,>=3.27
Requires-Dist: sqlparse==0.5.5
Description-Content-Type: text/markdown

# Vision IT Request Forms

A self-service IT request form system for Django projects. Built for Datapath's Vision Dashboard but designed to run standalone. End users browse a form catalog, fill out structured multi-section forms, and submit requests that are routed through configurable approval workflows and outbound connectors (ConnectWise, email, Slack, webhooks).

## Packages

This repo produces two installable Django apps:

| Package | PyPI name | Django app label | Purpose |
|---|---|---|---|
| Frontend | `vision-it-request-forms-frontend` | `vision_it_request_forms` | HTMX views, templates, form catalog |
| Backend | `vision-it-request-forms-backend` | `vision_it_support_forms` | Models, DRF API, approvals, connectors |

Both packages are published to the Datapath Gitea PyPI registry.

## Requirements

- Python 3.11+
- Django 5.2+
- djangorestframework 3.15+
- django-groups-manager 1.x
- django-admin-sortable2 2.x

## Installation

### 1. Configure the private registry

Add the Datapath registry as an extra index in your `pip.conf` or `requirements.txt` header:

```
--extra-index-url https://git.mydatapath.com/api/packages/Datapath/pypi/simple
```

### 2. Install both packages

```bash
pip install vision-it-request-forms-backend vision-it-request-forms-frontend
```

### 3. Add apps to `INSTALLED_APPS`

The backend must come before the frontend. Both `rest_framework`, `adminsortable2`, and `groups_manager` are required dependencies:

```python
INSTALLED_APPS = [
    # ...
    "rest_framework",
    "adminsortable2",
    "groups_manager",
    "vision_it_support_forms",   # backend — models, API, connectors
    "vision_it_request_forms",   # frontend — views, templates
]
```

### 4. Configure Django REST Framework

```python
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "vision_it_support_forms.authentication.BearerTokenAuthentication",
        "rest_framework.authentication.SessionAuthentication",
    ],
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticated",
    ],
    "PAGE_SIZE": 25,
}
```

### 5. Add the context processor

The frontend views inject API connection details and user group information via a context processor:

```python
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
                "vision_it_request_forms.context_processors.it_requests_context",
            ],
        },
    }
]
```

### 6. Mount the URL patterns

```python
# urls.py
from django.urls import path, include

urlpatterns = [
    # Backend DRF API  →  /api/v1/it-requests/
    path("api/v1/", include("vision_it_support_forms.urls")),

    # Frontend views   →  /it-requests/
    path("it-requests/", include("vision_it_request_forms.urls")),
]
```

### 7. Set required environment variables

```bash
# Static bearer token used by the frontend to call the DRF API.
# In production with Vision Dashboard, the Wristband access token is used instead.
IT_REQUESTS_API_TOKEN=your-static-token-here

# Leave empty if frontend and API are on the same host (typical for standalone use).
IT_REQUESTS_API_BASE_URL=
```

Add the corresponding Django settings (or read them from the environment):

```python
IT_REQUESTS_API_TOKEN = os.getenv("IT_REQUESTS_API_TOKEN", "")
IT_REQUESTS_API_BASE_URL = os.getenv("IT_REQUESTS_API_BASE_URL", "")
```

### 8. Run migrations

```bash
python manage.py migrate
```

## Connector Configuration

Connectors are configured in the Django admin under **Vision IT Support Forms → Connector configs**. Each connector type expects specific fields in its `config` JSON object:

### ConnectWise

```json
{
  "company": "mycompany",
  "url": "https://na.myconnectwise.net",
  "client_id": "...",
  "public_key": "...",
  "private_key": "...",
  "board_id": 123,
  "board_name": "Service",
  "default_status_id": 1,
  "default_type_id": 2
}
```

Set environment variables and reference them, or store values directly in the admin.

### SendGrid (email)

```json
{
  "to_email": "helpdesk@example.com",
  "from_email": "noreply@example.com",
  "subject_template": "New IT Request: {form_name}"
}
```

Requires `SENDGRID_API_KEY` environment variable.

### Slack (webhook)

```json
{
  "webhook_url": "https://hooks.slack.com/services/..."
}
```

### Slack (bot)

```json
{
  "token": "xoxb-...",
  "channel": "#it-requests"
}
```

### Generic webhook / n8n

```json
{
  "url": "https://your-webhook-endpoint.example.com/it-requests",
  "headers": {
    "Authorization": "Bearer ..."
  }
}
```

## Running the Job Processor

Connector dispatches are queued in an outbox and processed by a management command. Run it on a schedule (cron, systemd timer, or a process manager):

```bash
python manage.py it_requests_process_jobs
```

Jobs are retried up to 5 times with exponential backoff (1 min, 5 min, 15 min, 60 min), then marked as permanently failed.

## Approval Workflows

Approval configuration is per-form and managed in the Django admin under **Approval configs** and **Approval rules**.

- **Require all**: all rules must produce an approved decision before the submission advances.
- **Require any**: one approved decision from any eligible approver is sufficient.

Approvers can be specified as:
- A specific Django user
- Any member of a group
- Any user holding a named role within a group (e.g. `it-forms-admin`)

Leadership users (those with an `it-forms-admin` role in their group) access pending submissions at `/it-requests/leadership/`.

## Form Structure

Forms are built in the admin as a hierarchy:

```
FormTemplate
└── SubForm  (ordered, with optional conditional display rules)
    └── Field (ordered, typed, with optional validation rules)
```

**Field types**: `text`, `textarea`, `integer`, `decimal`, `email`, `phone`, `date`, `datetime`, `boolean`, `select`, `multi_select`, `radio`, `user_picker`, `group_picker`

**SubForms** can be universal (shared across all tenants) or group-specific (overrides the universal version for a particular tenant group). The schema resolver picks the most specific variant at render and submission time.

**Form versioning**: the full resolved schema is snapshotted into a `FormVersion` record at the moment a user submits. Historical submissions always render against the version that was current when they were created, regardless of later edits.

## Vision Dashboard Integration

When mounted in Vision Dashboard, the host project supplies `wristband`, `user_feature_access`, and `company_feature_access` via its context processors. The templates guard all of these with `{% if %}` checks so the app runs without them in standalone mode.

Authentication in production uses the Wristband access token injected by Vision Dashboard into HTMX request headers via `token.js`.

## Development Setup

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
cd djangoappdev
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver     # http://localhost:8000/it-requests/
```

Run tests:

```bash
cd djangoappdev
python manage.py test
# or
pytest
```
