feat: add initial migration setup and configuration files
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="frontend/static/logo.svg" alt="DocuNova Logo" width="100" height="100" />
|
<img src="frontend/static/logo_writing.svg" alt="DocuNova Logo" width="280" />
|
||||||
<h1>DocuNova</h1>
|
|
||||||
<p>Intelligent Document Processing & Management</p>
|
<p>Intelligent Document Processing & Management</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
# DocuNova
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
DocuNova automates the handling, extraction, and processing of documents using a variety of services, including:
|
DocuNova automates the handling, extraction, and processing of documents using a variety of services, including:
|
||||||
@@ -19,6 +20,15 @@ It is designed for flexibility and configurability through environment variables
|
|||||||
|
|
||||||
The project includes a **UI** for uploading and managing files, and an API documentation page is available at `/docs` (powered by **FastAPI**).
|
The project includes a **UI** for uploading and managing files, and an API documentation page is available at `/docs` (powered by **FastAPI**).
|
||||||
|
|
||||||
|
## Documentation Index
|
||||||
|
|
||||||
|
- [User Guide](docs/UserGuide.md) - How to use DocuNova
|
||||||
|
- [API Documentation](docs/API.md) - API reference
|
||||||
|
- [Deployment Guide](docs/DeploymentGuide.md) - How to deploy DocuNova
|
||||||
|
- [Configuration Guide](docs/ConfigurationGuide.md) - Available configuration options
|
||||||
|
- [Development Guide](CONTRIBUTING.md) - How to contribute to DocuNova
|
||||||
|
- [Troubleshooting](docs/Troubleshooting.md) - Common issues and solutions
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
@@ -80,171 +90,32 @@ Users can choose to send documents to any combination of these destinations thro
|
|||||||
|
|
||||||
## Frameworks Used
|
## Frameworks Used
|
||||||
|
|
||||||
- **FastAPI**: A modern, fast (high-performance) web framework for building APIs with Python.
|
- **FastAPI**: High-performance web framework for APIs.
|
||||||
- **Celery**: A distributed task queue for asynchronous processing.
|
- **Celery**: Task queue for asynchronous processing.
|
||||||
- **SQLAlchemy**: A powerful ORM for database interactions.
|
- **Redis**: Message broker and result backend.
|
||||||
- **Jinja2**: A templating engine for rendering HTML pages.
|
- **SQLAlchemy**: ORM for database interactions.
|
||||||
- **Tailwind CSS**: A utility-first CSS framework for styling the UI.
|
- **Tailwind CSS**: Utility-first CSS framework.
|
||||||
|
- **Docker**: Containerization for easy deployment.
|
||||||
|
|
||||||
## Environment Variables
|
## Quick Start
|
||||||
|
|
||||||
The `.env` file drives all configuration. This table breaks down key variables—some are optional, depending on which services you actually use.
|
For detailed installation and deployment instructions, please refer to the [Deployment Guide](docs/DeploymentGuide.md).
|
||||||
|
|
||||||
### Core Settings
|
```bash
|
||||||
|
# Clone the repository
|
||||||
|
git clone <repository_url>
|
||||||
|
cd document-processor
|
||||||
|
|
||||||
| **Variable** | **Description** | **Example** |
|
# Configure environment variables
|
||||||
|------------------------|----------------------------------------------------------|--------------------------------|
|
cp .env.example .env
|
||||||
| `DATABASE_URL` | Path/URL to the SQLite database (or other SQL backend). | `sqlite:///./app/database.db` |
|
# Edit .env with your settings
|
||||||
| `REDIS_URL` | URL for Redis, used by Celery for broker & result store. | `redis://redis:6379/0` |
|
|
||||||
| `WORKDIR` | Working directory for the application. | `/workdir` |
|
|
||||||
| `GOTENBERG_URL` | Gotenberg PDF processing URL. | `http://gotenberg:3000` |
|
|
||||||
| `EXTERNAL_HOSTNAME` | The external hostname for the application. | `docunova.example.com` |
|
|
||||||
|
|
||||||
### IMAP Configuration (Multiple Mailboxes)
|
# Run with Docker Compose
|
||||||
|
docker-compose up -d
|
||||||
| **Variable** | **Description** | **Example** |
|
|
||||||
|-------------------------------|--------------------------------------------------------------|-------------------|
|
|
||||||
| `IMAP1_HOST` | Hostname for first IMAP server. | `mail.example.com`|
|
|
||||||
| `IMAP1_PORT` | Port number (usually `993`). | `993` |
|
|
||||||
| `IMAP1_USERNAME` | IMAP login (first mailbox). | `user@example.com`|
|
|
||||||
| `IMAP1_PASSWORD` | IMAP password (first mailbox). | `*******` |
|
|
||||||
| `IMAP1_SSL` | Use SSL (`true`/`false`). | `true` |
|
|
||||||
| `IMAP1_POLL_INTERVAL_MINUTES` | Frequency in minutes to poll for new mail. | `5` |
|
|
||||||
| `IMAP1_DELETE_AFTER_PROCESS` | Delete emails after processing (`true`/`false`). | `false` |
|
|
||||||
| `IMAP2_HOST` | Hostname for second IMAP server (optional). | `imap.gmail.com` |
|
|
||||||
| `IMAP2_PORT` | Port number for second mailbox. | `993` |
|
|
||||||
| `IMAP2_USERNAME` | IMAP login for second mailbox. | `you@gmail.com` |
|
|
||||||
| `IMAP2_PASSWORD` | IMAP password for second mailbox. | `*******` |
|
|
||||||
| `IMAP2_SSL` | Use SSL for second mailbox (`true`/`false`). | `true` |
|
|
||||||
| `IMAP2_POLL_INTERVAL_MINUTES` | Frequency in minutes to poll second mailbox. | `10` |
|
|
||||||
| `IMAP2_DELETE_AFTER_PROCESS` | Delete emails after processing (`true`/`false`) for mailbox.| `false` |
|
|
||||||
|
|
||||||
### OpenAI & Azure Document Intelligence
|
|
||||||
|
|
||||||
| **Variable** | **Description** | **How to Obtain** |
|
|
||||||
|-----------------------|--------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
|
|
||||||
| `OPENAI_API_KEY` | API key for OpenAI services (used for metadata extraction/refinement). | [OpenAI platform](https://platform.openai.com/account/api-keys) |
|
|
||||||
| `OPENAI_BASE_URL` | Base URL for OpenAI API (optional, defaults to OpenAI's endpoint). | `https://api.openai.com/v1` |
|
|
||||||
| `OPENAI_MODEL` | OpenAI model to use for tasks (e.g., GPT-4). | `gpt-4` |
|
|
||||||
| `AZURE_AI_KEY` | Azure Document Intelligence key (for OCR). | [Azure Portal](https://portal.azure.com/) |
|
|
||||||
| `AZURE_REGION` | Azure region of your Document Intelligence instance. | e.g. `eastus`, `westeurope` |
|
|
||||||
| `AZURE_ENDPOINT` | Endpoint URL for Document Intelligence. | e.g. `https://<yourendpoint>.cognitiveservices.azure.com/` |
|
|
||||||
|
|
||||||
### Authentik
|
|
||||||
|
|
||||||
| **Variable** | **Description** |
|
|
||||||
|-------------------------|---------------------------------------------------------------|
|
|
||||||
| `AUTH_ENABLED` | Enable or disable authentication (`true`/`false`). |
|
|
||||||
| `AUTHENTIK_CLIENT_ID` | Client ID for Authentik OAuth2. |
|
|
||||||
| `AUTHENTIK_CLIENT_SECRET` | Client secret for Authentik OAuth2. |
|
|
||||||
| `AUTHENTIK_CONFIG_URL` | Configuration URL for Authentik OpenID Connect. |
|
|
||||||
|
|
||||||
### Paperless NGX
|
|
||||||
|
|
||||||
| **Variable** | **Description** |
|
|
||||||
|-------------------------------|-----------------------------------------------------|
|
|
||||||
| `PAPERLESS_NGX_API_TOKEN` | API token for Paperless NGX. |
|
|
||||||
| `PAPERLESS_HOST` | Root URL for Paperless NGX (e.g. `https://paperless.example.com`). |
|
|
||||||
|
|
||||||
### Dropbox
|
|
||||||
|
|
||||||
| **Variable** | **Description** | **How to Obtain** |
|
|
||||||
|-------------------------|--------------------------------------------------|------------------------------------------------------------------------------------|
|
|
||||||
| `DROPBOX_APP_KEY` | Dropbox API app key. | [Dropbox Developer Console](https://www.dropbox.com/developers/apps/create) |
|
|
||||||
| `DROPBOX_APP_SECRET` | Dropbox API app secret. | [Dropbox Developer Console](https://www.dropbox.com/developers/apps/create) |
|
|
||||||
| `DROPBOX_REFRESH_TOKEN` | OAuth2 refresh token for Dropbox. | Follow Dropbox OAuth flow to retrieve |
|
|
||||||
| `DROPBOX_FOLDER` | Default folder path for Dropbox uploads. | e.g. `"/Documents/Uploads"` |
|
|
||||||
|
|
||||||
### Nextcloud
|
|
||||||
|
|
||||||
| **Variable** | **Description** |
|
|
||||||
|-------------------------|---------------------------------------------------------------|
|
|
||||||
| `NEXTCLOUD_UPLOAD_URL` | Nextcloud WebDAV URL (e.g. `https://nc.example.com/remote.php/dav/files/<USERNAME>`). |
|
|
||||||
| `NEXTCLOUD_USERNAME` | Nextcloud login username. |
|
|
||||||
| `NEXTCLOUD_PASSWORD` | Nextcloud login password. |
|
|
||||||
| `NEXTCLOUD_FOLDER` | Destination folder in Nextcloud (e.g. `"/Documents/Uploads"`). |
|
|
||||||
|
|
||||||
## Running as a Docker Container
|
|
||||||
|
|
||||||
This project uses Celery (with Redis) for asynchronous task management and Gotenberg for PDF conversion. The `docker-compose.yml` file defines these services:
|
|
||||||
|
|
||||||
- **API Service**: Runs the FastAPI application via `uvicorn`.
|
|
||||||
- **Worker Service**: Runs the Celery worker for processing tasks (PDF conversions, OCR, etc.).
|
|
||||||
- **Redis**: Provides the message broker & result backend for Celery.
|
|
||||||
- **Gotenberg**: Offers PDF conversion capabilities.
|
|
||||||
|
|
||||||
### Running the Application with Docker Compose
|
|
||||||
|
|
||||||
1. **Install Docker and Docker Compose** on your system.
|
|
||||||
2. **Clone the repository** and navigate into it:
|
|
||||||
```bash
|
|
||||||
git clone <repository_url>
|
|
||||||
cd <repository_name>
|
|
||||||
```
|
|
||||||
3. **Create and configure the `.env` file**:
|
|
||||||
- Fill in the variables from the tables above.
|
|
||||||
- (At minimum, you need `DATABASE_URL`, `REDIS_URL`, `WORKDIR`, plus whichever service creds you plan to use.)
|
|
||||||
4. **Launch the services**:
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
5. The API will be available at **`http://localhost:8000`**, and the API documentation is available at **`http://localhost:8000/docs`**.
|
|
||||||
|
|
||||||
### Services in `docker-compose.yml`
|
|
||||||
|
|
||||||
Below is the default structure:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
services:
|
|
||||||
api:
|
|
||||||
image: christianlouis/document-processor:latest
|
|
||||||
container_name: document_api
|
|
||||||
working_dir: /workdir
|
|
||||||
command: ["sh", "-c", "cd /app && uvicorn app.main:app --host 0.0.0.0 --port 8000 --proxy-headers"]
|
|
||||||
environment:
|
|
||||||
- PYTHONPATH=/app
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
ports:
|
|
||||||
- "8000:8000"
|
|
||||||
depends_on:
|
|
||||||
- redis
|
|
||||||
- worker
|
|
||||||
volumes:
|
|
||||||
- /var/docparse/workdir:/workdir
|
|
||||||
|
|
||||||
worker:
|
|
||||||
image: christianlouis/document-processor:latest
|
|
||||||
container_name: document_worker
|
|
||||||
working_dir: /workdir
|
|
||||||
command: ["celery", "-A", "app.celery_worker", "worker", "-B", "--loglevel=info", "-Q", "document_processor,default,celery"]
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
environment:
|
|
||||||
- PYTHONPATH=/app
|
|
||||||
depends_on:
|
|
||||||
- redis
|
|
||||||
- gotenberg
|
|
||||||
volumes:
|
|
||||||
- /var/docparse/workdir:/workdir
|
|
||||||
|
|
||||||
gotenberg:
|
|
||||||
image: gotenberg/gotenberg:latest
|
|
||||||
container_name: gotenberg
|
|
||||||
|
|
||||||
redis:
|
|
||||||
image: redis:alpine
|
|
||||||
container_name: document_redis
|
|
||||||
restart: always
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## To-Do List
|
The API will be available at **`http://localhost:8000`**, and the API documentation is available at **`http://localhost:8000/docs`**.
|
||||||
|
|
||||||
- **Make upload targets configurable** (e.g., easily choose only Dropbox, Nextcloud, or Paperless).
|
## License
|
||||||
|
|
||||||
---
|
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
|
||||||
|
|
||||||
**Questions or Issues?**
|
|
||||||
- Feel free to open an issue or pull request.
|
|
||||||
- For local testing or development, use `docker-compose up` and watch the logs via `docker-compose logs -f`.
|
|
||||||
- Ensure your `.env` aligns with the environment variables listed above. If you see unexpected errors, check for typos or missing values.
|
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
# Configuration Guide
|
||||||
|
|
||||||
|
DocuNova is designed to be highly configurable through environment variables. This guide explains all available configuration options and how to use them effectively.
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
Configuration is primarily done through environment variables specified in a `.env` file.
|
||||||
|
|
||||||
|
### Core Settings
|
||||||
|
|
||||||
|
| **Variable** | **Description** | **Example** |
|
||||||
|
|------------------------|----------------------------------------------------------|--------------------------------|
|
||||||
|
| `DATABASE_URL` | Path/URL to the SQLite database (or other SQL backend). | `sqlite:///./app/database.db` |
|
||||||
|
| `REDIS_URL` | URL for Redis, used by Celery for broker & result store. | `redis://redis:6379/0` |
|
||||||
|
| `WORKDIR` | Working directory for the application. | `/workdir` |
|
||||||
|
| `GOTENBERG_URL` | Gotenberg PDF processing URL. | `http://gotenberg:3000` |
|
||||||
|
| `EXTERNAL_HOSTNAME` | The external hostname for the application. | `docunova.example.com` |
|
||||||
|
|
||||||
|
### IMAP Configuration
|
||||||
|
|
||||||
|
DocuNova can monitor multiple IMAP mailboxes for document attachments. Each mailbox uses a numbered prefix (e.g., `IMAP1_`, `IMAP2_`).
|
||||||
|
|
||||||
|
| **Variable** | **Description** | **Example** |
|
||||||
|
|-------------------------------|--------------------------------------------------------------|-------------------|
|
||||||
|
| `IMAP1_HOST` | Hostname for first IMAP server. | `mail.example.com`|
|
||||||
|
| `IMAP1_PORT` | Port number (usually `993`). | `993` |
|
||||||
|
| `IMAP1_USERNAME` | IMAP login (first mailbox). | `user@example.com`|
|
||||||
|
| `IMAP1_PASSWORD` | IMAP password (first mailbox). | `*******` |
|
||||||
|
| `IMAP1_SSL` | Use SSL (`true`/`false`). | `true` |
|
||||||
|
| `IMAP1_POLL_INTERVAL_MINUTES` | Frequency in minutes to poll for new mail. | `5` |
|
||||||
|
| `IMAP1_DELETE_AFTER_PROCESS` | Delete emails after processing (`true`/`false`). | `false` |
|
||||||
|
|
||||||
|
To configure additional mailboxes, use `IMAP2_`, `IMAP3_`, etc.
|
||||||
|
|
||||||
|
### OpenAI & Azure Document Intelligence
|
||||||
|
|
||||||
|
| **Variable** | **Description** | **How to Obtain** |
|
||||||
|
|---------------------------------|------------------------------------------|--------------------------------------------------------------------------|
|
||||||
|
| `OPENAI_API_KEY` | OpenAI API key for GPT metadata extraction. | [OpenAI API keys](https://platform.openai.com/account/api-keys) |
|
||||||
|
| `AZURE_DOCUMENT_INTELLIGENCE_KEY` | Azure Document Intelligence API key for OCR. | [Azure Portal](https://portal.azure.com/) |
|
||||||
|
| `AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT` | Endpoint URL for Azure Doc Intelligence API. | [Azure Portal](https://portal.azure.com/) |
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
| **Variable** | **Description** |
|
||||||
|
|-------------------------|---------------------------------------------------------------|
|
||||||
|
| `AUTH_ENABLED` | Enable or disable authentication (`true`/`false`). |
|
||||||
|
| `AUTHENTIK_CLIENT_ID` | Client ID for Authentik OAuth2. |
|
||||||
|
| `AUTHENTIK_CLIENT_SECRET` | Client secret for Authentik OAuth2. |
|
||||||
|
| `AUTHENTIK_CONFIG_URL` | Configuration URL for Authentik OpenID Connect. |
|
||||||
|
|
||||||
|
### Paperless NGX
|
||||||
|
|
||||||
|
| **Variable** | **Description** |
|
||||||
|
|-------------------------------|-----------------------------------------------------|
|
||||||
|
| `PAPERLESS_NGX_API_TOKEN` | API token for Paperless NGX. |
|
||||||
|
| `PAPERLESS_HOST` | Root URL for Paperless NGX (e.g. `https://paperless.example.com`). |
|
||||||
|
|
||||||
|
### Dropbox
|
||||||
|
|
||||||
|
| **Variable** | **Description** | **How to Obtain** |
|
||||||
|
|-------------------------|--------------------------------------------------|------------------------------------------------------------------------------------|
|
||||||
|
| `DROPBOX_APP_KEY` | Dropbox API app key. | [Dropbox Developer Console](https://www.dropbox.com/developers/apps/create) |
|
||||||
|
| `DROPBOX_APP_SECRET` | Dropbox API app secret. | [Dropbox Developer Console](https://www.dropbox.com/developers/apps/create) |
|
||||||
|
| `DROPBOX_REFRESH_TOKEN` | OAuth2 refresh token for Dropbox. | Follow Dropbox OAuth flow to retrieve |
|
||||||
|
| `DROPBOX_FOLDER` | Default folder path for Dropbox uploads. | e.g. `"/Documents/Uploads"` |
|
||||||
|
|
||||||
|
### Nextcloud
|
||||||
|
|
||||||
|
| **Variable** | **Description** |
|
||||||
|
|-------------------------|---------------------------------------------------------------|
|
||||||
|
| `NEXTCLOUD_UPLOAD_URL` | Nextcloud WebDAV URL (e.g. `https://nc.example.com/remote.php/dav/files/<USERNAME>`). |
|
||||||
|
| `NEXTCLOUD_USERNAME` | Nextcloud login username. |
|
||||||
|
| `NEXTCLOUD_PASSWORD` | Nextcloud login password. |
|
||||||
|
| `NEXTCLOUD_FOLDER` | Destination folder in Nextcloud (e.g. `"/Documents/Uploads"`). |
|
||||||
|
|
||||||
|
## Configuration Examples
|
||||||
|
|
||||||
|
### Minimal Configuration
|
||||||
|
|
||||||
|
This is the minimal configuration needed to run DocuNova with local storage only:
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
DATABASE_URL=sqlite:///./app/database.db
|
||||||
|
REDIS_URL=redis://redis:6379/0
|
||||||
|
WORKDIR=/workdir
|
||||||
|
GOTENBERG_URL=http://gotenberg:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full Configuration with All Services
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
# Core settings
|
||||||
|
DATABASE_URL=sqlite:///./app/database.db
|
||||||
|
REDIS_URL=redis://redis:6379/0
|
||||||
|
WORKDIR=/workdir
|
||||||
|
GOTENBERG_URL=http://gotenberg:3000
|
||||||
|
EXTERNAL_HOSTNAME=docunova.example.com
|
||||||
|
|
||||||
|
# IMAP settings
|
||||||
|
IMAP1_HOST=mail.example.com
|
||||||
|
IMAP1_PORT=993
|
||||||
|
IMAP1_USERNAME=user@example.com
|
||||||
|
IMAP1_PASSWORD=password
|
||||||
|
IMAP1_SSL=true
|
||||||
|
IMAP1_POLL_INTERVAL_MINUTES=5
|
||||||
|
IMAP1_DELETE_AFTER_PROCESS=false
|
||||||
|
|
||||||
|
# AI services
|
||||||
|
OPENAI_API_KEY=sk-...
|
||||||
|
AZURE_DOCUMENT_INTELLIGENCE_KEY=...
|
||||||
|
AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT=https://...
|
||||||
|
|
||||||
|
# Authentication
|
||||||
|
AUTH_ENABLED=true
|
||||||
|
AUTHENTIK_CLIENT_ID=...
|
||||||
|
AUTHENTIK_CLIENT_SECRET=...
|
||||||
|
AUTHENTIK_CONFIG_URL=https://auth.example.com/.well-known/openid-configuration
|
||||||
|
|
||||||
|
# Storage services
|
||||||
|
PAPERLESS_NGX_API_TOKEN=...
|
||||||
|
PAPERLESS_HOST=https://paperless.example.com
|
||||||
|
|
||||||
|
DROPBOX_APP_KEY=...
|
||||||
|
DROPBOX_APP_SECRET=...
|
||||||
|
DROPBOX_REFRESH_TOKEN=...
|
||||||
|
DROPBOX_FOLDER=/Documents/Uploads
|
||||||
|
|
||||||
|
NEXTCLOUD_UPLOAD_URL=https://nc.example.com/remote.php/dav/files/username
|
||||||
|
NEXTCLOUD_USERNAME=username
|
||||||
|
NEXTCLOUD_PASSWORD=password
|
||||||
|
NEXTCLOUD_FOLDER=/Documents/Uploads
|
||||||
|
```
|
||||||
|
|
||||||
|
## Selective Service Configuration
|
||||||
|
|
||||||
|
You can choose which document storage services to use by only including the relevant environment variables. For example, if you only want to use Dropbox, include only the Dropbox variables and omit the Paperless NGX and Nextcloud variables.
|
||||||
|
|
||||||
|
## Configuration File Location
|
||||||
|
|
||||||
|
The `.env` file should be placed at the root of the project directory. When using Docker Compose, you can reference it with the `env_file` directive in your `docker-compose.yml`.
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="600" viewBox="0 0 800 600">
|
||||||
|
<style>
|
||||||
|
.label-bg {
|
||||||
|
fill: none;
|
||||||
|
stroke: #ccc;
|
||||||
|
stroke-width: 2;
|
||||||
|
rx: 8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Background box (optional) -->
|
||||||
|
<rect x="40" y="40" width="720" height="520" class="label-bg" />
|
||||||
|
|
||||||
|
<!-- DocuNova Logo (Top Center) -->
|
||||||
|
<g transform="translate(300, 60) scale(1.2)">
|
||||||
|
<text x="60" y="20" font-family="Segoe UI" font-size="24" font-weight="bold" fill="#3B82F6">DocuNova</text>
|
||||||
|
<path fill="#3B82F6" transform="translate(0,0)" d="m17.212 20.404l-.108-.885q-.57-.125-.938-.33q-.368-.204-.7-.577l-.835.334l-.539-.815l.689-.577q-.165-.531-.165-1.035t.165-1.034l-.689-.577l.539-.816l.835.335q.332-.393.7-.588q.369-.195.938-.32l.108-.885h1l.107.885q.57.125.938.32t.7.588l.835-.335l.539.816l-.689.576q.166.531.166 1.035t-.166 1.035l.689.577l-.539.815l-.834-.335q-.333.373-.701.578q-.369.205-.938.33l-.107.885zm.5-1.731q.882 0 1.518-.635q.636-.636.636-1.519t-.636-1.518t-1.518-.636t-1.519.636t-.635 1.518t.635 1.519t1.518.635M4 18V6v4.435V10zm.616 1q-.691 0-1.153-.462T3 17.384V6.616q0-.691.463-1.153T4.615 5h4.981l2 2h7.789q.69 0 1.153.463T21 8.616v2.294q-.238-.152-.479-.265q-.24-.112-.521-.21v-1.82q0-.269-.173-.442T19.385 8h-8.19l-2-2h-4.58q-.269 0-.442.173T4 6.616v10.769q0 .269.173.442t.443.173h6.748q.055.275.131.515t.186.485z"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Tailwind CSS (middle left) -->
|
||||||
|
<g transform="translate(120, 180) scale(0.8)">
|
||||||
|
<g fill-rule="evenodd" clip-rule="evenodd">
|
||||||
|
<path fill="#38bdf8" d="M27 0c-7.2 0-11.7 3.6-13.5 10.8 2.7-3.6 5.85-4.95 9.45-4.05 2.054.513 3.522 2.004 5.147 3.653C30.744 13.09 33.808 16.2 40.5 16.2c7.2 0 11.7-3.6 13.5-10.8-2.7 3.6-5.85 4.95-9.45 4.05-2.054-.513-3.522-2.004-5.147-3.653C36.756 3.11 33.692 0 27 0zM13.5 16.2C6.3 16.2 1.8 19.8 0 27c2.7-3.6 5.85-4.95 9.45-4.05 2.054.514 3.522 2.004 5.147 3.653C17.244 29.29 20.308 32.4 27 32.4c7.2 0 11.7-3.6 13.5-10.8-2.7 3.6-5.85 4.95-9.45 4.05-2.054-.513-3.522-2.004-5.147-3.653C23.256 19.31 20.192 16.2 13.5 16.2z"/>
|
||||||
|
<path fill="#0f172a" d="M80.996 13.652h-4.712v9.12c0 2.432 1.596 2.394 4.712 2.242V28.7c-6.308.76-8.816-.988-8.816-5.928v-9.12h-3.496V9.7h3.496V4.596l4.104-1.216V9.7h4.712v3.952zM98.958 9.7h4.104v19h-4.104v-2.736c-1.444 2.014-3.686 3.23-6.65 3.23-5.168 0-9.462-4.37-9.462-9.994 0-5.662 4.294-9.994 9.462-9.994 2.964 0 5.206 1.216 6.65 3.192V9.7zm-6.004 15.58c3.42 0 6.004-2.546 6.004-6.08 0-3.534-2.584-6.08-6.004-6.08-3.42 0-6.004 2.546-6.004 6.08 0 3.534 2.584 6.08 6.004 6.08zm16.948-18.43c-1.444 0-2.622-1.216-2.622-2.622a2.627 2.627 0 012.622-2.622 2.627 2.627 0 012.622 2.622c0 1.406-1.178 2.622-2.622 2.622zM107.85 28.7v-19h4.104v19h-4.104zm8.854 0V.96h4.104V28.7h-4.104zm30.742-19h4.332l-5.966 19h-4.028l-3.952-12.806-3.99 12.806h-4.028l-5.966-19h4.332l3.686 13.11 3.99-13.11h3.914l3.952 13.11 3.724-13.11zm9.424-2.85c-1.444 0-2.622-1.216-2.622-2.622a2.627 2.627 0 012.622-2.622 2.627 2.627 0 012.622 2.622c0 1.406-1.178 2.622-2.622 2.622zm-2.052 21.85v-19h4.104v19h-4.104zm18.848-19.494c4.256 0 7.296 2.888 7.296 7.828V28.7h-4.104V17.452c0-2.888-1.672-4.408-4.256-4.408-2.698 0-4.826 1.596-4.826 5.472V28.7h-4.104v-19h4.104v2.432c1.254-1.976 3.306-2.926 5.89-2.926zM200.418 2.1h4.104v26.6h-4.104v-2.736c-1.444 2.014-3.686 3.23-6.65 3.23-5.168 0-9.462-4.37-9.462-9.994 0-5.662 4.294-9.994 9.462-9.994 2.964 0 5.206 1.216 6.65 3.192V2.1zm-6.004 23.18c3.42 0 6.004-2.546 6.004-6.08 0-3.534-2.584-6.08-6.004-6.08-3.42 0-6.004 2.546-6.004 6.08 0 3.534 2.584 6.08 6.004 6.08zm23.864 3.914c-5.738 0-10.032-4.37-10.032-9.994 0-5.662 4.294-9.994 10.032-9.994 3.724 0 6.954 1.938 8.474 4.902l-3.534 2.052c-.836-1.786-2.698-2.926-4.978-2.926-3.344 0-5.89 2.546-5.89 5.966 0 3.42 2.546 5.966 5.89 5.966 2.28 0 4.142-1.178 5.054-2.926l3.534 2.014c-1.596 3.002-4.826 4.94-8.55 4.94zm15.314-14.25c0 3.458 10.222 1.368 10.222 8.398 0 3.8-3.306 5.852-7.41 5.852-3.8 0-6.536-1.71-7.752-4.446l3.534-2.052c.608 1.71 2.128 2.736 4.218 2.736 1.824 0 3.23-.608 3.23-2.128 0-3.382-10.222-1.482-10.222-8.284 0-3.572 3.078-5.814 6.954-5.814 3.116 0 5.7 1.444 7.03 3.952l-3.458 1.938c-.684-1.482-2.014-2.166-3.572-2.166-1.482 0-2.774.646-2.774 2.014zm17.518 0c0 3.458 10.222 1.368 10.222 8.398 0 3.8-3.306 5.852-7.41 5.852-3.8 0-6.536-1.71-7.752-4.446l3.534-2.052c.608 1.71 2.128 2.736 4.218 2.736 1.824 0 3.23-.608 3.23-2.128 0-3.382-10.222-1.482-10.222-8.284 0-3.572 3.078-5.814 6.954-5.814 3.116 0 5.7 1.444 7.03 3.952l-3.458 1.938c-.684-1.482-2.014-2.166-3.572-2.166-1.482 0-2.774.646-2.774 2.014z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Jinja2 (middle right) -->
|
||||||
|
<g transform="translate(500, 180) scale(0.5)">
|
||||||
|
<!-- Include only paths and groups from the Jinja2 logo here -->
|
||||||
|
<!-- (REPLACED content will be inserted here) -->
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- SQLAlchemy (bottom left) -->
|
||||||
|
<g transform="translate(100, 400) scale(1)">
|
||||||
|
<path fill="#333" d="M15.676 69.912c-.671-.107-2.39-.537-3.813-.926L9.27 68.26l1.33-2.444 1.329-2.444-1.074-1.33c-1.518-1.88-3.478-6.002-3.491-7.33-.014-3.103 4.014-7.601 8.956-10.018 3.397-1.665 6.096-1.705 9.48-.12l2.551 1.194.739-1.06c.402-.578.738-1.343.738-1.679s.336-.631.739-.631.738.107.738.228c0 .296-2.967 7.788-3.155 7.976-.081.08-.887-.295-1.8-.832-2.578-1.518-5.814-2.525-8.325-2.592-5.841-.148-7.869 5.56-3.746 10.554l1.45 1.76 3.961-3.21c4.445-3.585 4.955-3.666 8.42-1.275 3.893 2.685 3.96 6.767.2 11.037-3.33 3.8-6.753 4.848-12.635 3.867zm9.964-4.095c1.933-1.517 1.799-4.324-.296-6.553-2.632-2.793-3.45-2.672-8.083 1.195-4.606 3.84-4.633 3.693.873 5.452 3.638 1.181 5.921 1.141 7.506-.094zM63.05 80.614c-1.317-.483-4.862-1.947-7.896-3.263-8.191-3.572-9.346-3.639-11.79-.671-.564.685-1.181 1.114-1.356.94-.524-.524 1.034-3.035 2.914-4.686 1.53-1.343 2.04-1.531 3.733-1.343 1.074.12 4.646 1.37 7.935 2.766 7.426 3.155 9.601 3.827 12.435 3.827 3.45 0 5.223-2.417 4.135-5.626-.268-.806-.188-1.075.35-1.075 1.006 0 1.517 3.76.792 5.922-.31.926-1.209 2.242-2.001 2.9-1.182.994-1.934 1.209-4.15 1.195-1.49-.013-3.786-.402-5.102-.886zm-19.135-11.48c-3.048-1.424-5.801-4.136-7.386-7.305-2.537-5.076-1.759-8.325 3.049-12.716 4.041-3.693 7.345-5.13 11.79-5.13 3.208 0 3.893.175 5.974 1.45 4.928 3.049 6.15 8.863 3.183 15.2-3.478 7.44-10.823 11.186-16.61 8.5zm10.205-3.532c2.282-1.128 3.854-6.338 3.209-10.662-.806-5.33-8.016-8.97-13.307-6.713-5.438 2.323-5.519 8.513-.174 14.085 3.732 3.908 6.942 4.928 10.272 3.29zM64.473 70.114c0-.229.845-.631 1.893-.887l1.893-.47.403-6.82c.443-7.547.12-14.973-.698-15.966-.296-.35-1.195-.78-2.014-.967-3.33-.739-1.115-1.249 5.344-1.249 6.459 0 8.513.47 5.438 1.249-2.645.658-2.659.698-2.659 11.467 0 5.975.215 10.474.524 11.051.43.806 1.074.98 3.545.98 5.102 0 6.861-1.208 8.245-5.68.416-1.342 1.49-1.1 1.114.256-.175.63-.456 2.55-.631 4.296l-.322 3.156H75.51c-6.07 0-11.037-.188-11.037-.416z"/>
|
||||||
|
<path fill="#ca2727" d="M89.542 69.791c0-.402.39-.805 1.034-1.114.86-.403 1.423-1.249 3.464-5.237 3.236-6.31 8.339-17.147 8.822-18.772.376-1.235.457-1.302 1.853-1.463.806-.094 1.477-.148 1.49-.121.014.027 1.129 2.47 2.485 5.438 1.343 2.967 4.042 8.607 6.002 12.528 3.277 6.593 3.64 7.184 4.74 7.72.672.323 1.195.82 1.195 1.115 0 .47-.577.524-5.545.524-4.982 0-5.546-.054-5.546-.537 0-.322.43-.671 1.114-.9.632-.201 1.115-.577 1.115-.859 0-.269-.658-2.041-1.464-3.934l-1.463-3.451H97.746l-1.06 2.336c-1.988 4.378-2.028 5.412-.175 5.908.927.255 1.182.457 1.074.873-.12.484-.604.55-4.095.55-3.747.028-3.948 0-3.948-.604zm18.181-10.863c.188-.335-3.988-9.453-4.377-9.547-.282-.08-4.606 8.836-4.606 9.507 0 .336 8.782.376 8.983.04z"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Celery (bottom center) -->
|
||||||
|
<g transform="translate(340, 400) scale(1)">
|
||||||
|
<defs>
|
||||||
|
<clipPath id="celery-clip">
|
||||||
|
<path d="M493.54,171.25c-35.63,0-64.52-28.89-64.52-64.52s28.89-64.52,64.52-64.52c3.85,0,7.62,0.36,11.29,1V5.45
|
||||||
|
H104.46v0.02C49.24,6.51,4.78,51.59,4.78,107.07c0,55.47,44.45,100.56,99.68,101.59v0.02h389.07l11.29-38.44
|
||||||
|
C501.16,170.89,497.39,171.25,493.54,171.25z"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<g transform="scale(0.17)">
|
||||||
|
<path fill="#B6DE64" d="M493.54,171.25c-35.63,0-64.52-28.89-64.52-64.52s28.89-64.52,64.52-64.52c3.85,0,7.62,0.36,11.29,1
|
||||||
|
L493.54,5.45H104.46v0.02C49.24,6.51,4.78,51.59,4.78,107.07c0,55.47,44.45,100.56,99.68,101.59v0.02h389.07l11.29-38.44
|
||||||
|
C501.16,170.89,497.39,171.25,493.54,171.25z"/>
|
||||||
|
<g clip-path="url(#celery-clip)">
|
||||||
|
<rect x="-23.16" y="55.58" fill="#A9CC54" width="451.66" height="51.1"/>
|
||||||
|
<rect x="-23.16" y="157.59" fill="#A9CC54" width="530.98" height="72.35"/>
|
||||||
|
</g>
|
||||||
|
<path fill="none" stroke="#DDF4A4" stroke-width="49" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M493.54,184.23c-43.94,0-79.56-33.62-79.56-77.56s35.62-76.56,79.56-76.56"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- FastAPI (bottom right) -->
|
||||||
|
<g transform="translate(580, 400) scale(1)">
|
||||||
|
<g transform="scale(0.3)">
|
||||||
|
<!-- FastAPI Logo Circle and Icon -->
|
||||||
|
<g transform="translate(-900, 190) scale(0.96)">
|
||||||
|
<circle style="fill:#009688;fill-opacity:0.98" cx="964.56165" cy="-169.22266" r="33.234192"/>
|
||||||
|
<path style="fill:#ffffff;fill-opacity:0.98" d="m 962.2685,-187.40837 -6.64403,14.80375 -3.03599,6.76393 -6.64456,14.80375 30.59142,-21.56768 h -14.35312 l 20.99715,-14.80375 z"/>
|
||||||
|
</g>
|
||||||
|
<!-- FastAPI Text -->
|
||||||
|
<path style="fill:#009688" d="M 89.523017,59.410606 V 4.1680399 H 122.84393 V 10.784393 H 97.255382 V 27.44485 h 22.718808 v 6.536638 H 97.255382 v 25.429118 z m 52.292963,-5.340912 q 2.6306,0 4.62348,-0.07972 2.07259,-0.15943 3.42774,-0.47829 V 41.155848 q -0.79715,-0.398576 -2.63059,-0.637721 -1.75374,-0.31886 -4.30462,-0.31886 -1.67402,0 -3.58718,0.239145 -1.83345,0.239145 -3.42775,1.036296 -1.51459,0.717436 -2.55088,2.072593 -1.0363,1.275442 -1.0363,3.427749 0,3.985755 2.55089,5.580058 2.55088,1.514586 6.93521,1.514586 z m -0.63772,-37.147238 q 4.46404,0 7.49322,1.195727 3.10889,1.116011 4.94233,3.268319 1.91317,2.072593 2.71032,5.022052 0.79715,2.869743 0.79715,6.377208 V 58.69317 q -0.95658,0.159431 -2.71031,0.478291 -1.67402,0.239145 -3.82633,0.478291 -2.15231,0.239145 -4.70319,0.398575 -2.47117,0.239146 -4.94234,0.239146 -3.50746,0 -6.45692,-0.717436 -2.94946,-0.717436 -5.10177,-2.232023 -2.1523,-1.594302 -3.34803,-4.145186 -1.19573,-2.550883 -1.19573,-6.138063 0,-3.427749 1.35516,-5.898917 1.43487,-2.471168 3.82632,-3.985755 2.39146,-1.514587 5.58006,-2.232023 3.18861,-0.717436 6.69607,-0.717436 1.11601,0 2.31174,0.15943 1.19572,0.07972 2.23202,0.31886 1.11601,0.159431 1.91316,0.318861 0.79715,0.15943 1.11601,0.239145 v -2.072593 q 0,-1.833447 -0.39857,-3.587179 -0.39858,-1.833448 -1.43487,-3.188604 -1.0363,-1.434872 -2.86975,-2.232023 -1.75373,-0.876866 -4.62347,-0.876866 -3.6669,0 -6.45693,0.558005 -2.71031,0.478291 -4.06547,1.036297 l -0.87686,-6.138063 q 1.43487,-0.637721 4.7829,-1.195727 3.34804,-0.637721 7.25408,-0.637721 z m 37.86462,37.147238 q 4.54377,0 6.69607,-1.195726 2.23203,-1.195727 2.23203,-3.826325 0,-2.710314 -2.15231,-4.304616 -2.15231,-1.594302 -7.09465,-3.587179 -2.39145,-0.956581 -4.62347,-1.913163 -2.15231,-1.036296 -3.74661,-2.391453 -1.5943,-1.355157 -2.55088,-3.268319 -0.95659,-1.913163 -0.95659,-4.703191 0,-5.500342 4.06547,-8.688946 4.06547,-3.26832 11.0804,-3.26832 1.75374,0 3.50747,0.239146 1.75373,0.15943 3.26832,0.47829 1.51458,0.239146 2.6306,0.558006 1.19572,0.31886 1.83344,0.558006 l -1.35515,6.377208 q -1.19573,-0.637721 -3.74661,-1.275442 -2.55089,-0.717436 -6.13807,-0.717436 -3.10889,0 -5.42062,1.275442 -2.31174,1.195727 -2.31174,3.826325 0,1.355157 0.47829,2.391453 0.55801,1.036296 1.5943,1.913163 1.11601,0.797151 2.71031,1.514587 1.59431,0.717436 3.82633,1.514587 2.94946,1.116011 5.2612,2.232022 2.31173,1.036297 3.90604,2.471169 1.67401,1.434871 2.55088,3.507464 0.87687,1.992878 0.87687,4.942337 0,5.739487 -4.30462,8.688946 -4.2249,2.949459 -12.1167,2.949459 -5.50034,0 -8.60923,-0.956582 -3.10889,-0.876866 -4.2249,-1.355156 l 1.35516,-6.377209 q 1.27544,0.478291 4.06547,1.434872 2.79003,0.956581 7.4135,0.956581 z m 32.84256,-36.110941 h 15.70387 v 6.217778 h -15.70387 v 19.131625 q 0,3.108889 0.47829,5.181481 0.47829,1.992878 1.43487,3.188604 0.95658,1.116012 2.39145,1.594302 1.43487,0.478291 3.34804,0.478291 3.34803,0 5.34091,-0.717436 2.07259,-0.797151 2.86974,-1.116011 l 1.43487,6.138063 q -1.11601,0.558005 -3.90604,1.355156 -2.79003,0.876867 -6.37721,0.876867 -4.2249,0 -7.01492,-1.036297 -2.71032,-1.116011 -4.38434,-3.268319 -1.67401,-2.152308 -2.39145,-5.261197 -0.63772,-3.188604 -0.63772,-7.333789 V 6.4000628 l 7.41351,-1.2754417 z m 62.49652,41.451853 q -1.35516,-3.587179 -2.55088,-7.014929 -1.19573,-3.507464 -2.47117,-7.094644 h -25.03054 l -5.02205,14.109573 h -8.05123 q 3.18861,-8.768661 5.97863,-16.182166 2.79003,-7.493219 5.42063,-14.189288 2.71031,-6.696069 5.34091,-12.754416 2.6306,-6.138063 5.50034,-12.1166961 h 7.09465 q 2.86974,5.9786331 5.50034,12.1166961 2.6306,6.058347 5.2612,12.754416 2.71031,6.696069 5.50034,14.189288 2.79003,7.413505 5.97863,16.182166 z m -7.25407,-20.486781 q -2.55089,-6.935214 -5.10177,-13.392137 -2.47117,-6.536639 -5.18148,-12.515272 -2.79003,5.978633 -5.34091,12.515272 -2.47117,6.456923 -4.94234,13.392137 z M 304.99242,3.6100342 q 11.6384,0 17.85618,4.4640458 6.29749,4.384331 6.29749,13.152992 0,4.782906 -1.75373,8.210656 -1.67402,3.348034 -4.94234,5.500342 -3.1886,2.072592 -7.81208,3.029174 -4.62347,0.956581 -10.44268,0.956581 h -6.13806 v 20.486781 h -7.73236 V 4.9651909 q 3.26832,-0.797151 7.25407,-1.0362963 4.06547,-0.3188604 7.41351,-0.3188604 z m 0.63772,6.7757838 q -4.94234,0 -7.57294,0.239145 v 21.682508 h 5.8192 q 3.98576,0 7.17436,-0.47829 3.18861,-0.558006 5.34092,-1.753733 2.23202,-1.275441 3.42774,-3.427749 1.19573,-2.152308 1.19573,-5.500342 0,-3.188604 -1.27544,-5.261197 -1.19573,-2.072593 -3.34803,-3.268319 -2.0726,-1.275442 -4.86263,-1.753732 -2.79002,-0.478291 -5.89891,-0.478291 z M 338.7916,4.1680399 h 7.73237 V 59.410606 h -7.73237 z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,21 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="140" height="24" viewBox="0 0 124 24">
|
||||||
|
<style>
|
||||||
|
.icon {
|
||||||
|
fill: #3B82F6;
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
font-family: "Segoe UI", "Helvetica Neue", sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
fill: #3B82F6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Folder+gear icon -->
|
||||||
|
<g class="icon" transform="translate(0, 0)">
|
||||||
|
<path d="m17.212 20.404l-.108-.885q-.57-.125-.938-.33q-.368-.204-.7-.577l-.835.334l-.539-.815l.689-.577q-.165-.531-.165-1.035t.165-1.034l-.689-.577l.539-.816l.835.335q.332-.393.7-.588q.369-.195.938-.32l.108-.885h1l.107.885q.57.125.938.32t.7.588l.835-.335l.539.816l-.689.576q.166.531.166 1.035t-.166 1.035l.689.577l-.539.815l-.834-.335q-.333.373-.701.578q-.369.205-.938.33l-.107.885zm.5-1.731q.882 0 1.518-.635q.636-.636.636-1.519t-.636-1.518t-1.518-.636t-1.519.636t-.635 1.518t.635 1.519t1.518.635M4 18V6v4.435V10zm.616 1q-.691 0-1.153-.462T3 17.384V6.616q0-.691.463-1.153T4.615 5h4.981l2 2h7.789q.69 0 1.153.463T21 8.616v2.294q-.238-.152-.479-.265q-.24-.112-.521-.21v-1.82q0-.269-.173-.442T19.385 8h-8.19l-2-2h-4.58q-.269 0-.442.173T4 6.616v10.769q0 .269.173.442t.443.173h6.748q.055.275.131.515t.186.485z"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Text -->
|
||||||
|
<text class="text" x="28" y="17">DocuNova</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
|||||||
|
Generic single-database configuration.
|
||||||
+2
-1
@@ -11,4 +11,5 @@ dropbox # Dropbox integration
|
|||||||
azure-ai-documentintelligence # Azure OCR service
|
azure-ai-documentintelligence # Azure OCR service
|
||||||
authlib # Authentication
|
authlib # Authentication
|
||||||
python-dotenv # Environment variables
|
python-dotenv # Environment variables
|
||||||
starlette # ASGI toolkit (used by FastAPI)
|
starlette # ASGI toolkit (used by FastAPI)
|
||||||
|
alembic # Database migrations
|
||||||
Reference in New Issue
Block a user