Docs audit fixes: kiosk code drift, PowerShell chains, broken links, leaks
From the Fable/Opus documentation audit (8 confirmed + verified lab-drift the run's session limit had cut short): - HIGH: the lab's kiosk _kiosk_find_item block showed the pre-stage-17 row-id resolver as current; replace with the shipped gagelabtag / numeric-tail resolver, fix the stale 'resolved by row id' prose and the 'stage-7 code is corrected' note. - MED: the badge _external_lookup block used dict-only row access that breaks on a tuple cursor; use the tuple-or-dict form shipped. Split '&&' command chains (fail in PowerShell 5.1) in the lab. - LOW/link: the Windows note's [DEVELOPMENT-SETUP] link dropped the .md and 404'd in four docs; fix. Correct the stage-6a->16a comment and the lab-stage tag range (..16 -> ..17). - Leaks: drop /home/camp path from ADR-006, the internal gitea host from PLUGINS.md. - Windows: add an mklink junction note for the external-plugin symlink dev loop. - CI: prime root to mysql_native_password so pymysql connects to the MySQL 8 service without the cryptography package (and its kit wheel).
This commit is contained in:
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -75,10 +75,16 @@ jobs:
|
||||
python-version: '3.12'
|
||||
cache: pip
|
||||
- run: pip install -r requirements.txt
|
||||
- name: Force utf8mb4 on the CI database
|
||||
- name: Prime the CI database (utf8mb4 + native auth for pymysql)
|
||||
# MySQL 8 defaults root to caching_sha2_password, which pymysql can
|
||||
# only speak with the 'cryptography' package. Rather than add that
|
||||
# dependency (and its offline wheel), switch root to native auth here
|
||||
# via the mysql CLI, so the app's pymysql connections work as-is.
|
||||
run: |
|
||||
mysql -h 127.0.0.1 -uroot -proot -e \
|
||||
"ALTER DATABASE shopdb_ci CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
||||
"ALTER DATABASE shopdb_ci CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; \
|
||||
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root'; \
|
||||
FLUSH PRIVILEGES;"
|
||||
- name: Fresh core upgrade from empty
|
||||
run: flask db upgrade
|
||||
- name: Install every bundled plugin (runs its chain)
|
||||
|
||||
@@ -10,7 +10,7 @@ is required for v1 (pip distribution is deferred to v2 per ADR-003).
|
||||
> **Windows / VS Code:** command examples use the Linux venv path
|
||||
> `venv/bin/python`; on Windows use `venv\Scripts\python` and
|
||||
> `$env:FLASK_APP="shopdb"` (not `export`). Full Windows onboarding:
|
||||
> [DEVELOPMENT-SETUP](DEVELOPMENT-SETUP).
|
||||
> [DEVELOPMENT-SETUP](DEVELOPMENT-SETUP.md).
|
||||
|
||||
|
||||
If you have not written a plugin before, start with
|
||||
@@ -77,6 +77,11 @@ git clone https://github.com/ge-aero/wjsf-shipping.git
|
||||
cd shopdb-flask
|
||||
ln -s ../../wjsf-shipping plugins/shipping
|
||||
# (use an absolute path if you prefer: ln -s "$(pwd)/../wjsf-shipping" plugins/shipping)
|
||||
#
|
||||
# Windows: use a directory junction instead of ln -s. In an ADMIN prompt
|
||||
# (or with Developer Mode on) from the shopdb-flask dir:
|
||||
# mklink /D plugins\shipping ..\..\wjsf-shipping
|
||||
# The plugin loader treats a junction the same as a real directory.
|
||||
|
||||
# 3. Set up the framework as usual.
|
||||
python3 -m venv venv
|
||||
|
||||
@@ -8,7 +8,7 @@ way it does by walking the shipped code of the exemplar plugin.
|
||||
> **Windows / VS Code:** command examples use the Linux venv path
|
||||
> `venv/bin/python`; on Windows use `venv\Scripts\python` and
|
||||
> `$env:FLASK_APP="shopdb"` (not `export`). Full Windows onboarding:
|
||||
> [DEVELOPMENT-SETUP](DEVELOPMENT-SETUP).
|
||||
> [DEVELOPMENT-SETUP](DEVELOPMENT-SETUP.md).
|
||||
|
||||
`measuringtools` was chosen as the exemplar on purpose. It is the first plugin
|
||||
built after the framework matured (ADR-005 scoped it; ADR-008 changed how plugin
|
||||
|
||||
@@ -17,7 +17,7 @@ decision records: `docs/proposals/printedparts-plugin.md`.
|
||||
> **Windows / VS Code:** command examples below use the Linux venv path
|
||||
> `venv/bin/python`; on Windows use `venv\Scripts\python` and
|
||||
> `$env:FLASK_APP="shopdb"` (not `export`). Full Windows onboarding:
|
||||
> [DEVELOPMENT-SETUP](DEVELOPMENT-SETUP).
|
||||
> [DEVELOPMENT-SETUP](DEVELOPMENT-SETUP.md).
|
||||
|
||||
|
||||
Know before you start
|
||||
@@ -262,7 +262,7 @@ def downgrade():
|
||||
See it work:
|
||||
|
||||
```
|
||||
flask plugin install printedparts && flask plugin enable printedparts
|
||||
flask plugin install printedparts; flask plugin enable printedparts
|
||||
mysql> SHOW TABLES LIKE 'printed%'; -- both tables
|
||||
mysql> SELECT * FROM alembic_version_printedparts; -- printedparts0001baseline
|
||||
flask plugin upgrade-all -- printedparts: ok
|
||||
@@ -299,7 +299,7 @@ printedparts_bp = Blueprint('printedparts', __name__)
|
||||
|
||||
|
||||
@printedparts_bp.route('/items', methods=['GET'])
|
||||
@jwt_required(optional=True) # stage 6a tightens this to view-gated
|
||||
@jwt_required(optional=True) # stage 16a tightens this to view-gated
|
||||
def list_items():
|
||||
"""List printed items, paginated; search + low-stock filter."""
|
||||
page, per_page = get_pagination_params(request)
|
||||
@@ -629,10 +629,11 @@ def _external_lookup(kind, digits):
|
||||
f'WHERE {column} = %s', (digits,))
|
||||
row = cursor.fetchone()
|
||||
if row:
|
||||
sso = str(row['SSO'])
|
||||
name = f"{(row['First_Name'] or '').strip()} " \
|
||||
f"{(row['Last_Name'] or '').strip()}".strip()
|
||||
return sso, name
|
||||
# pymysql may return a tuple or a dict cursor - handle both.
|
||||
sso = str(row[0] if not isinstance(row, dict) else row['SSO'])
|
||||
first = row[1] if not isinstance(row, dict) else row['First_Name']
|
||||
last = row[2] if not isinstance(row, dict) else row['Last_Name']
|
||||
return sso, f"{(first or '').strip()} {(last or '').strip()}".strip()
|
||||
except Exception:
|
||||
logger.exception('HR directory lookup failed for %s %s', kind, digits)
|
||||
finally:
|
||||
@@ -798,17 +799,25 @@ catch you (below).
|
||||
def _kiosk_find_item(itemcode):
|
||||
"""Resolve a scanned or typed code to an active item.
|
||||
|
||||
Accepts the full code (WJRP0042) or bare digits from the touch keypad -
|
||||
the digits in a minted code ARE the row id, so id lookup keeps working
|
||||
even for labels printed under an older prefix."""
|
||||
itemcode = (itemcode or '').strip()
|
||||
Matches the internal code OR the gage-lab tag exactly; bare keypad
|
||||
digits match the numeric tail of EITHER identifier, and only when
|
||||
exactly one active item matches (see stage 17)."""
|
||||
scanned = (itemcode or '').strip().upper()
|
||||
item = PrintedItem.query.filter(
|
||||
PrintedItem.itemcode == itemcode,
|
||||
or_(PrintedItem.itemcode == scanned,
|
||||
PrintedItem.gagelabtag == scanned),
|
||||
PrintedItem.isactive == True).first()
|
||||
if not item and itemcode.isdigit():
|
||||
candidate = db.session.get(PrintedItem, int(itemcode))
|
||||
if candidate and candidate.isactive:
|
||||
item = candidate
|
||||
if not item and scanned.isdigit():
|
||||
wanted = int(scanned)
|
||||
matches = []
|
||||
for candidate in PrintedItem.query.filter_by(isactive=True).all():
|
||||
for value in (candidate.itemcode, candidate.gagelabtag):
|
||||
tail = ''.join(ch for ch in (value or '') if ch.isdigit())
|
||||
if tail and int(tail) == wanted:
|
||||
matches.append(candidate)
|
||||
break
|
||||
if len(matches) == 1:
|
||||
item = matches[0]
|
||||
return item
|
||||
|
||||
|
||||
@@ -920,7 +929,8 @@ function onWedgeEnter() {
|
||||
```
|
||||
|
||||
Manual fallbacks use the TouchKeypad: badge entry is digits (an SSO), and
|
||||
item entry is bare digits resolved by row id server-side - no alphanumeric
|
||||
item entry is bare digits matched server-side against the numeric tail of
|
||||
either the internal code or the gage-lab tag (unique match only) - no alphanumeric
|
||||
on-screen keyboard needed. Success screen auto-resets after a few seconds.
|
||||
Full component (~250 lines) at the tag.
|
||||
|
||||
@@ -1093,7 +1103,7 @@ failure. Summaries here; complete diffs at the tags.
|
||||
hit the deny policy. Lesson: anything resolving PEOPLE must honor the
|
||||
site's directory mode (the stage-5 code above is the corrected version).
|
||||
- **16 - touchscreen findings** (`lab-stage-16`): the focus-steal guard and
|
||||
keypad-driven manual entry (the stage-7 code above is the corrected
|
||||
keypad-driven manual entry (the kiosk resolver above is the stage-17
|
||||
version).
|
||||
|
||||
- **17 - the gage-lab asset tag** (`lab-stage-17`): the field team assigns
|
||||
@@ -1134,11 +1144,12 @@ for a contributor:
|
||||
2. **Build in stage-sized commits** exactly as this lab does - each commit a
|
||||
working checkpoint with its tests. Subject line: short, plain English,
|
||||
present tense ("printedparts stage 5: the ledger"); body says WHY.
|
||||
3. **Before every push**, the same three gates CI runs:
|
||||
```bash
|
||||
bash scripts/check-naming-and-style.sh
|
||||
venv/bin/python -m pytest tests/ -q
|
||||
cd frontend && npx vitest run && npm run build
|
||||
3. **Before every push**, run the three gates CI runs (in VS Code: the
|
||||
**Check: naming + tests + build** task). By hand in PowerShell:
|
||||
```powershell
|
||||
venv\Scripts\python -m pytest tests/ -q
|
||||
cd frontend; npx vitest run; npm run build; cd ..
|
||||
bash scripts/check-naming-and-style.sh # naming - runs via Git Bash
|
||||
```
|
||||
4. **Push your branch and open a Pull Request** against `main`:
|
||||
```bash
|
||||
@@ -1179,4 +1190,4 @@ for a contributor:
|
||||
| List/Detail master templates | `PrintersList.vue`, `PrinterDetail.vue` |
|
||||
| Reports hook + CSV | `plugins/warranty/` + `shopdb/core/api/reports.py` |
|
||||
| Permissions declaration | `plugins/usb/plugin.py::get_permissions` |
|
||||
| The finished plugin itself | branch `feat/printedparts-plugin`, tags `lab-stage-01..16` |
|
||||
| The finished plugin itself | branch `feat/printedparts-plugin`, tags `lab-stage-01..17` |
|
||||
|
||||
@@ -7,7 +7,7 @@ For the full hook reference, see [PLUGIN-HOOKS.md](PLUGIN-HOOKS.md).
|
||||
> **Windows / VS Code:** command examples below use the Linux venv path
|
||||
> `venv/bin/python`; on Windows use `venv\Scripts\python` and
|
||||
> `$env:FLASK_APP="shopdb"` (not `export`). Full Windows onboarding:
|
||||
> [DEVELOPMENT-SETUP](DEVELOPMENT-SETUP).
|
||||
> [DEVELOPMENT-SETUP](DEVELOPMENT-SETUP.md).
|
||||
|
||||
For the architectural decisions behind the contract, see [docs/adr/](../docs/adr/).
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ which revisions each plugin has applied in `migrations_applied`.
|
||||
|
||||
For sister-site plugins (per [ADR-003](adr/ADR-003-plugin-distribution.md)):
|
||||
|
||||
- Plugin lives in its own git repo: `gitea.proudtech.net/<your-site>/<pluginname>`
|
||||
- Plugin lives in its own git repo: `<git-host>/<your-site>/<pluginname>`
|
||||
- Adopting site clones or symlinks into their `<repo>/plugins/<name>/`
|
||||
- Plugin manifest declares `core_version` range matching the framework version they target
|
||||
- Plugin readme explains: what it tracks, who maintains it, where to file issues
|
||||
|
||||
@@ -145,4 +145,4 @@ Migration path:
|
||||
- `shopdb/plugins/base.py` (`get_collector_schema` + `apply_collector_payload` hooks)
|
||||
- ADR-001 (asset model the collectors target)
|
||||
- ADR-002 (collector schema is part of plugin contract; changes to the hook signature are major bumps)
|
||||
- The PXE project (`/home/camp/projects/pxe/`) which feeds the computers collector
|
||||
- The PXE project (the PXE imaging project) which feeds the computers collector
|
||||
|
||||
Reference in New Issue
Block a user