-
Notifications
You must be signed in to change notification settings - Fork 3
Modernise template: Django 6 / Python 3.14, security fixes, tests, docs & tooling #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
f74cd5b
cc1c0c2
fdbadf5
c4a9979
8175301
706e8fd
4877de7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| #!/usr/bin/env python | ||
| """ | ||
| Cookiecutter post-generation hook. | ||
|
|
||
| Runs in the generated project directory after rendering. It creates a ``.env`` | ||
| from ``.env.example`` with a freshly generated ``SECRET_KEY`` so the project is | ||
| runnable immediately (every ``manage.py`` command requires ``SECRET_KEY``). | ||
| """ | ||
| import secrets | ||
| from pathlib import Path | ||
|
|
||
| # Avoid characters that are awkward in .env values: quotes, '#', '$', whitespace. | ||
| SECRET_KEY_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@%^&*(-_=+)" | ||
|
|
||
|
|
||
| def generate_secret_key(length: int = 50) -> str: | ||
| return "".join(secrets.choice(SECRET_KEY_CHARS) for _ in range(length)) | ||
|
|
||
|
|
||
| def main() -> None: | ||
| example = Path(".env.example") | ||
| env = Path(".env") | ||
|
|
||
| if not example.exists() or env.exists(): | ||
| return | ||
|
|
||
| content = example.read_text() | ||
| # Replace the bare ``SECRET_KEY=`` line with a generated value. | ||
| content = content.replace("SECRET_KEY=\n", f"SECRET_KEY={generate_secret_key()}\n", 1) | ||
| env.write_text(content) | ||
|
|
||
| print("Created .env with a generated SECRET_KEY.") | ||
| print("Next: configure the PG* database variables in .env, then run `make migrations`.") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| --- | ||
| name: ip | ||
| description: Use when quickly capturing an intellectual property idea - searches for related proposals, extends existing or creates new | ||
| user-invocable: true | ||
| argument-hint: "[NNN] <idea description>" | ||
| --- | ||
|
|
||
| # ip — Quick proposal capture | ||
|
|
||
| Quickly save an Intellectual Property (IP) proposal to `docs/proposals/posts/` following the | ||
| project's proposal system (see `CLAUDE.md` for the full guidelines). | ||
|
|
||
| ## Argument Parsing | ||
|
|
||
| Args format: `[NNN] <description>` | ||
|
|
||
| - **`/ip 002 description...`** — NNN provided → go directly to that proposal number (extend if exists, create with that number if not) | ||
| - **`/ip description...`** — no number → search by keywords, then extend or create new | ||
|
|
||
| Parse logic: | ||
| 1. Split args on first space | ||
| 2. If first token matches `^\d{3}$` → `target_number = first token`, `description = rest` | ||
| 3. Otherwise → `target_number = nil`, `description = all args` | ||
|
|
||
| ## Paths | ||
|
|
||
| All paths are relative to the **current working directory** (the project root). Do not hardcode absolute paths. | ||
|
|
||
| - Proposals dir: `docs/proposals/posts/` | ||
| - Proposal file: `docs/proposals/posts/IP-{NNN}-{slug}.md` (one file per proposal) | ||
| - Template: `docs/proposals/.template.md` | ||
| - Index: `docs/proposals/index.md` | ||
|
|
||
| ## Author | ||
|
|
||
| Derive the author from git at runtime; do not hardcode a username. This value is used for | ||
| both the frontmatter `author:` field and the Changelog column: | ||
|
|
||
| ```sh | ||
| git config user.name || git config user.email || echo "author" | ||
| ``` | ||
|
|
||
| ## Workflow | ||
|
|
||
| ### Step 1: Resolve Target | ||
|
|
||
| **If `target_number` provided:** | ||
| - Run: `ls docs/proposals/posts/ | grep -iE "^IP-0*{target_number}-"` to find the matching file | ||
| - If found → go to **2A (Extend)** | ||
| - If not found → go to **2B (Create)** using `target_number` as the IP number | ||
|
|
||
| **If no `target_number`:** | ||
| - Check description for explicit "create new" / "new proposal" intent → skip search, go directly to **2B (Create)** | ||
| - Otherwise: run `ls docs/proposals/posts/` and grep filenames + file content for keywords from description | ||
| - If matches found → pick the best match and go to **2A (Extend)** automatically (no confirmation needed) | ||
| - If no matches → go to **2B (Create)** | ||
|
|
||
| ### 2A. Extend Existing Proposal | ||
|
|
||
| 1. Read the matched `IP-{NNN}-{slug}.md` file | ||
| 2. Locate and update relevant sections: | ||
| - Add to **Implementation Plan** (append new phase/steps as checkboxes) | ||
| - Add supporting details to **Problem Statement**, **Proposed Solution**, or other relevant sections | ||
| 3. Update **Changelog**: `| {today} | {author} | [brief change description] |` | ||
| 4. Update **Status** if appropriate | ||
| 5. Use the Edit tool to modify the file | ||
| 6. Update `docs/proposals/index.md` tracking table if status changed | ||
| 7. Confirm: `✓ Extended IP-{NNN}: [title]` | ||
|
|
||
| ### 2B. Create New Proposal | ||
|
|
||
| 1. Determine IP number: | ||
| - If `target_number` provided → use it | ||
| - Otherwise: `ls docs/proposals/posts/ | grep -oiE '^IP-[0-9]+' | grep -oE '[0-9]+' | sort -n | tail -1` → increment by 1 (start at 1 if none) | ||
| 2. Format as zero-padded 3-digit: e.g. `002` | ||
| 3. Derive slug from description (lowercase, hyphens, max 40 chars) | ||
| 4. Read template: `docs/proposals/.template.md` | ||
| 5. Create `docs/proposals/posts/IP-{NNN}-{slug}.md` with: | ||
| - Updated frontmatter (`date: {today}`, `author: {author}`, tags) | ||
| - Title: `# IP-{NNN}: [Full Title]` | ||
| - All template sections filled in | ||
| - **Review Questions section** (required for AI-created proposals) | ||
| - **Changelog**: `| {today} | {author} | Initial draft |` | ||
| 6. Update `docs/proposals/index.md` tracking table (add row: IP number linking to the file, title, status, last updated) | ||
| 7. Confirm: `✓ Created IP-{NNN}: [title]` | ||
|
|
||
| ## Key Rules | ||
|
|
||
| - No time estimates in proposals | ||
| - AI-created proposals MUST include a Review Questions section | ||
| - Always update the Changelog with `YYYY-MM-DD`, author, change description | ||
| - Always update `docs/proposals/index.md` | ||
| - Derive the author from git config (see **Author** above) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,18 +1,34 @@ | ||
| DATABASE_HOST=localhost | ||
| DATABASE_PORT=5432 | ||
| DATABASE_NAME={{cookiecutter.project_name}} | ||
| DATABASE_USER=postgres | ||
| DATABASE_PASSWORD=admin | ||
| PGHOST=localhost | ||
| PGPORT=5432 | ||
| PGDATABASE={{cookiecutter.project_name}} | ||
| PGUSER=postgres | ||
| PGPASSWORD=admin | ||
|
|
||
| REDIS_DB=0 | ||
|
|
||
| LOG_LEVEL=INFO | ||
|
|
||
| SENTRY_DSN='' | ||
|
|
||
| INSTANCE_NAME={{cookiecutter.project_name}} | ||
|
|
||
| # Comma-separated hostnames served in production, e.g. api.example.com,www.example.com | ||
| ALLOWED_HOSTS='' | ||
|
|
||
| # SECURITY WARNING: keep this secret and use a unique value per environment. | ||
| # Generate using: https://djecrety.ir/ | ||
| SECRET_KEY= | ||
|
|
||
| EMAIL_IMAP_HOST='' | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. za mna by bolo pre uplnost fajn tuto pridat comment, ze tie EMAIL_IMAP sa tykaju iba cisto toho naseho django imap backendu, a pridat sem example aj pre klasicky smtp backend (kedze tie tu uplne chybaju, mozno okrem EMAIL_SENDER_NAME, ak ten sa tam pouziva) |
||
| EMAIL_IMAP_USER='' | ||
| EMAIL_IMAP_PASSWORD='' | ||
| EMAIL_IMAP_MAILBOX='' | ||
| EMAIL_IMAP_SSL='true' | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. EMAIL_IMAP_SSL==true nastavit port na fixnu hodnotu (i.e. 993), a ak je false, tak na fixnu default hodnotu (143), alebo odkial je identifikovane, na akom porte ten imap pocuva, kedze ziadne EMAIL_IMAP_PORT tu nemame ? |
||
| EMAIL_SENDER_NAME='' | ||
|
|
||
| # SMTP (used by non-development environments) | ||
| EMAIL_HOST='' | ||
| EMAIL_PORT='' | ||
| EMAIL_HOST_USER='' | ||
| EMAIL_HOST_PASSWORD='' | ||
| EMAIL_USE_TLS='false' | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| [flake8] | ||
| max-line-length = 119 | ||
|
Serbel97 marked this conversation as resolved.
|
||
| # E203 / W503 conflict with Black's formatting. | ||
| extend-ignore = E203, W503 | ||
| # Re-export packages legitimately import names they don't use locally. | ||
| per-file-ignores = | ||
| __init__.py:F401 | ||
| exclude = | ||
| .git, | ||
| __pycache__, | ||
| migrations, | ||
| venv, | ||
| .venv, | ||
| static, | ||
| media, | ||
| private, | ||
| conf | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a toto nechces dat prec tiez ?