checkscanner 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checkscanner-0.1.2/LICENSE +21 -0
- checkscanner-0.1.2/MANIFEST.in +5 -0
- checkscanner-0.1.2/PKG-INFO +212 -0
- checkscanner-0.1.2/README.md +178 -0
- checkscanner-0.1.2/pyproject.toml +3 -0
- checkscanner-0.1.2/setup.cfg +54 -0
- checkscanner-0.1.2/setup.py +2 -0
- checkscanner-0.1.2/src/checkscanner/__init__.py +5 -0
- checkscanner-0.1.2/src/checkscanner/active_scanners.py +53 -0
- checkscanner-0.1.2/src/checkscanner/admin_console.py +583 -0
- checkscanner-0.1.2/src/checkscanner/app.py +228 -0
- checkscanner-0.1.2/src/checkscanner/auth.py +51 -0
- checkscanner-0.1.2/src/checkscanner/bottle/__init__.py +0 -0
- checkscanner-0.1.2/src/checkscanner/bottle/bottle.py +4403 -0
- checkscanner-0.1.2/src/checkscanner/bottle/bottle_cors.py +18 -0
- checkscanner-0.1.2/src/checkscanner/bottle/bottle_jwt.py +116 -0
- checkscanner-0.1.2/src/checkscanner/bottle/bottle_rest.py +76 -0
- checkscanner-0.1.2/src/checkscanner/bottle/bottle_sqlite.py +161 -0
- checkscanner-0.1.2/src/checkscanner/check_scanner_handlers/__init__.py +3 -0
- checkscanner-0.1.2/src/checkscanner/check_scanner_handlers/check_scanner_handler.py +126 -0
- checkscanner-0.1.2/src/checkscanner/check_scanner_handlers/magtek_scanner_handler.py +185 -0
- checkscanner-0.1.2/src/checkscanner/check_scanner_handlers/rdm_scanner_handler.py +191 -0
- checkscanner-0.1.2/src/checkscanner/cli.py +221 -0
- checkscanner-0.1.2/src/checkscanner/data/__init__.py +0 -0
- checkscanner-0.1.2/src/checkscanner/data/api.json +715 -0
- checkscanner-0.1.2/src/checkscanner/data/arial.ttf +0 -0
- checkscanner-0.1.2/src/checkscanner/data/server.db.sql +37 -0
- checkscanner-0.1.2/src/checkscanner/debugger.py +40 -0
- checkscanner-0.1.2/src/checkscanner/ftp_server.py +74 -0
- checkscanner-0.1.2/src/checkscanner/resources/__init__.py +7 -0
- checkscanner-0.1.2/src/checkscanner/resources/check.py +41 -0
- checkscanner-0.1.2/src/checkscanner/resources/config.py +47 -0
- checkscanner-0.1.2/src/checkscanner/resources/connections.py +158 -0
- checkscanner-0.1.2/src/checkscanner/resources/profiles.py +73 -0
- checkscanner-0.1.2/src/checkscanner/resources/restart.py +20 -0
- checkscanner-0.1.2/src/checkscanner/resources/token.py +20 -0
- checkscanner-0.1.2/src/checkscanner/resources/users.py +72 -0
- checkscanner-0.1.2/src/checkscanner/static/200.html +16 -0
- checkscanner-0.1.2/src/checkscanner/static/404.html +16 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/-WfchzD6.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/BKuAqpd3.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/Bf__CQGB.js +34 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/CPYLmeXC.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/CZQnppu7.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/CpQhjTOX.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/CvytG1-F.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/CzsOtQj8.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/DMCEdG9B.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/DMCkEJxe.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/DRSp4aqm.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/DhGZ3OhD.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/LsS5jRfi.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/RRYXIiA5.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/builds/latest.json +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/builds/meta/1228cefd-1a9f-4246-a783-69aa576c153c.json +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/default.CKljHALx.css +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/entry.B9nQ-h33.css +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/error-404.MksMKVWr.css +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/error-500.DOWD7OuR.css +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/lZ82j3id.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/login.CepLjysV.css +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/odLcdTJR.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/settings.CZt2o3Ma.css +1 -0
- checkscanner-0.1.2/src/checkscanner/static/_nuxt/zO-zkS4P.js +1 -0
- checkscanner-0.1.2/src/checkscanner/static/active_scanners/index.html +16 -0
- checkscanner-0.1.2/src/checkscanner/static/index.html +16 -0
- checkscanner-0.1.2/src/checkscanner/static/login/index.html +16 -0
- checkscanner-0.1.2/src/checkscanner/static/scanner_profiles/index.html +16 -0
- checkscanner-0.1.2/src/checkscanner/static/scanner_test/index.html +16 -0
- checkscanner-0.1.2/src/checkscanner/static/settings/index.html +16 -0
- checkscanner-0.1.2/src/checkscanner/static/token/index.html +16 -0
- checkscanner-0.1.2/src/checkscanner/static/users/index.html +16 -0
- checkscanner-0.1.2/src/checkscanner/swagger/favicon-16x16.png +0 -0
- checkscanner-0.1.2/src/checkscanner/swagger/favicon-32x32.png +0 -0
- checkscanner-0.1.2/src/checkscanner/swagger/index.html +61 -0
- checkscanner-0.1.2/src/checkscanner/swagger/oauth2-redirect.html +75 -0
- checkscanner-0.1.2/src/checkscanner/swagger/swagger-ui-bundle.js +3 -0
- checkscanner-0.1.2/src/checkscanner/swagger/swagger-ui-bundle.js.map +1 -0
- checkscanner-0.1.2/src/checkscanner/swagger/swagger-ui-es-bundle-core.js +3 -0
- checkscanner-0.1.2/src/checkscanner/swagger/swagger-ui-es-bundle-core.js.map +1 -0
- checkscanner-0.1.2/src/checkscanner/swagger/swagger-ui-es-bundle.js +3 -0
- checkscanner-0.1.2/src/checkscanner/swagger/swagger-ui-es-bundle.js.map +1 -0
- checkscanner-0.1.2/src/checkscanner/swagger/swagger-ui-standalone-preset.js +3 -0
- checkscanner-0.1.2/src/checkscanner/swagger/swagger-ui-standalone-preset.js.map +1 -0
- checkscanner-0.1.2/src/checkscanner/swagger/swagger-ui.css +4 -0
- checkscanner-0.1.2/src/checkscanner/swagger/swagger-ui.css.map +1 -0
- checkscanner-0.1.2/src/checkscanner/swagger/swagger-ui.js +3 -0
- checkscanner-0.1.2/src/checkscanner/swagger/swagger-ui.js.map +1 -0
- checkscanner-0.1.2/src/checkscanner.egg-info/PKG-INFO +212 -0
- checkscanner-0.1.2/src/checkscanner.egg-info/SOURCES.txt +93 -0
- checkscanner-0.1.2/src/checkscanner.egg-info/dependency_links.txt +1 -0
- checkscanner-0.1.2/src/checkscanner.egg-info/entry_points.txt +3 -0
- checkscanner-0.1.2/src/checkscanner.egg-info/requires.txt +25 -0
- checkscanner-0.1.2/src/checkscanner.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DiscipleMakers
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: checkscanner
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Check scanner API server and admin console
|
|
5
|
+
Home-page: https://bitbucket.org/disciplemakers/check-reader
|
|
6
|
+
Author: DiscipleMakers
|
|
7
|
+
License: MIT
|
|
8
|
+
Keywords: check scanner,micr,magtek,rdm
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Framework :: Bottle
|
|
12
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
13
|
+
Requires-Python: <3.13,>=3.6
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: gevent<22.0.0,>=1.5.0; python_version < "3.7"
|
|
17
|
+
Requires-Dist: gevent>=23.0.0; python_version >= "3.7"
|
|
18
|
+
Requires-Dist: Pillow<9.0.0,>=5.0.0; python_version < "3.7"
|
|
19
|
+
Requires-Dist: Pillow>=10.0.0; python_version >= "3.7"
|
|
20
|
+
Requires-Dist: pyftpdlib<2.0.0,>=1.5.0; python_version < "3.7"
|
|
21
|
+
Requires-Dist: pyftpdlib>=1.5.7; python_version >= "3.7"
|
|
22
|
+
Requires-Dist: PyJWT<2.5.0,>=2.0.0; python_version < "3.7"
|
|
23
|
+
Requires-Dist: PyJWT>=2.8.0; python_version >= "3.7"
|
|
24
|
+
Requires-Dist: requests<2.28.0,>=2.20.0; python_version < "3.7"
|
|
25
|
+
Requires-Dist: requests>=2.31.0; python_version >= "3.7"
|
|
26
|
+
Requires-Dist: toml>=0.10.0
|
|
27
|
+
Requires-Dist: click<8.1,>=7.1; python_version < "3.7"
|
|
28
|
+
Requires-Dist: click>=8.1; python_version >= "3.7"
|
|
29
|
+
Requires-Dist: rich<13.0,>=12.0; python_version < "3.7"
|
|
30
|
+
Requires-Dist: rich>=13.0; python_version >= "3.7"
|
|
31
|
+
Requires-Dist: questionary<2.0,>=1.10.0; python_version < "3.8"
|
|
32
|
+
Requires-Dist: questionary>=2.0; python_version >= "3.8"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# checkscanner
|
|
36
|
+
|
|
37
|
+
Python package for the check scanner backend. Manages connections to Magtek and RDM check scanning devices, extracts MICR data and check images, and serves them through a JWT-authenticated REST API.
|
|
38
|
+
|
|
39
|
+
## Requirements
|
|
40
|
+
|
|
41
|
+
- Python 3.6+
|
|
42
|
+
- SQLite3
|
|
43
|
+
- pip 21.3.1+ (required on Python 3.6 to resolve pre-built wheels)
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
Ensure pip is up to date before installing:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install --upgrade pip
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Then install the package from PyPI:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install checkscanner
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Or from the source tree:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
cd server
|
|
63
|
+
pip install .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
For development (changes take effect without reinstalling):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install -e .
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Building the Frontend
|
|
73
|
+
|
|
74
|
+
The frontend must be built and bundled into the package before installing. Run this once from the source tree (requires Node.js):
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
checkscanner build
|
|
78
|
+
pip install . # reinstall to pick up the bundled frontend
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
In development with an editable install, `checkscanner build` copies the output directly into `src/checkscanner/static/` so it takes effect immediately without reinstalling.
|
|
82
|
+
|
|
83
|
+
## Usage
|
|
84
|
+
|
|
85
|
+
The package installs two commands. Run them from your project directory — config files and the database are created there.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Start the API server (serves UI at http://localhost:8000/).
|
|
89
|
+
# Runs first-time setup automatically if needed.
|
|
90
|
+
checkscanner
|
|
91
|
+
|
|
92
|
+
# Open the interactive admin console
|
|
93
|
+
checkscanner-cli
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`checkscanner` also accepts subcommands (run `checkscanner --help` or `checkscanner <command> --help` for details):
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
checkscanner server [options] # Same as no arguments; see `checkscanner server --help`
|
|
100
|
+
checkscanner setup [-i] # Create anything missing: config/, server.db, admin user (-i: edit config first)
|
|
101
|
+
checkscanner status # Show config, database and connection status
|
|
102
|
+
checkscanner admin # Same as checkscanner-cli
|
|
103
|
+
checkscanner build # Build the frontend and bundle it into the package (source tree only)
|
|
104
|
+
|
|
105
|
+
checkscanner user list|add|passwd|delete
|
|
106
|
+
checkscanner profile list|add|delete
|
|
107
|
+
checkscanner config show|edit|rotate-keys
|
|
108
|
+
checkscanner token <username>[:<password>] # or -u <username> [-p <password>]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Server options can also be passed directly, e.g. `checkscanner --port 9000`.
|
|
112
|
+
|
|
113
|
+
## First-Time Setup
|
|
114
|
+
|
|
115
|
+
`checkscanner setup` (also runs automatically before the server and admin console start) creates:
|
|
116
|
+
|
|
117
|
+
| File | Description |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `config/config.toml` | Server host, port, debug mode |
|
|
120
|
+
| `config/auth.toml` | JWT signing key, FTP credentials |
|
|
121
|
+
| `server.db` | SQLite database |
|
|
122
|
+
| `admin_credentials.txt` | Generated admin username and password — delete after noting |
|
|
123
|
+
|
|
124
|
+
## Admin Console
|
|
125
|
+
|
|
126
|
+
`checkscanner-cli` opens an arrow-key menu for managing the server:
|
|
127
|
+
|
|
128
|
+
- View server status
|
|
129
|
+
- List, add and delete users; reset passwords
|
|
130
|
+
- List, add and delete check scanner profiles
|
|
131
|
+
- Edit config and regenerate auth keys
|
|
132
|
+
- Get a bearer token for API testing
|
|
133
|
+
- Start the server, optionally restarting it automatically when it stops
|
|
134
|
+
|
|
135
|
+
Every menu action is also available as a `checkscanner` subcommand for scripting.
|
|
136
|
+
|
|
137
|
+
## API
|
|
138
|
+
|
|
139
|
+
Swagger UI is available at `http://localhost:8000/docs` when the server is running.
|
|
140
|
+
|
|
141
|
+
| Method | Endpoint | Description |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| POST | `/token` | Authenticate, receive JWT |
|
|
144
|
+
| GET/POST | `/connections` | List or create reader connections |
|
|
145
|
+
| DELETE | `/connections/<id>` | Disconnect from reader |
|
|
146
|
+
| GET/PUT | `/connections/<id>/check` | Get check data or return check to queue |
|
|
147
|
+
| GET/POST/PATCH/DELETE | `/profiles` | Manage reader device profiles |
|
|
148
|
+
| GET/POST/PATCH/DELETE | `/users` | Manage users (admin only) |
|
|
149
|
+
|
|
150
|
+
## Supported Devices
|
|
151
|
+
|
|
152
|
+
| Type | Protocol |
|
|
153
|
+
|---|---|
|
|
154
|
+
| Magtek | Telnet + FTP |
|
|
155
|
+
| RDM | HTTPS (XML) |
|
|
156
|
+
|
|
157
|
+
## Project Structure
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
src/
|
|
161
|
+
└── checkscanner/
|
|
162
|
+
├── app.py # Bottle API server
|
|
163
|
+
├── admin_console.py # Interactive admin CLI
|
|
164
|
+
├── active_scanners.py # In-memory scanner connection registry
|
|
165
|
+
├── auth.py # Password hashing and JWT verification
|
|
166
|
+
├── ftp_server.py # FTP server for Magtek image uploads
|
|
167
|
+
├── debugger.py # Colored terminal logging
|
|
168
|
+
├── bottle/ # Vendored Bottle framework + plugins
|
|
169
|
+
├── resources/ # REST resource handlers
|
|
170
|
+
├── check_scanner_handlers/ # Device-specific connection handlers
|
|
171
|
+
├── static/ # Bundled frontend (populated by `checkscanner build`)
|
|
172
|
+
├── swagger/ # Bundled Swagger UI
|
|
173
|
+
└── data/ # Bundled assets (schema, font, API spec)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Releasing to PyPI
|
|
177
|
+
|
|
178
|
+
Releases are published by the Bitbucket pipeline (`bitbucket-pipelines.yml`) when a `v*` tag is pushed. The pipeline builds the frontend, bundles it into the package, builds the sdist and wheel, uploads them to PyPI, and uploads the wheel to Bitbucket Downloads.
|
|
179
|
+
|
|
180
|
+
1. Bump `version` in `setup.cfg` (PyPI rejects re-uploads of an existing version).
|
|
181
|
+
2. Commit, then tag with the matching version and push the tag:
|
|
182
|
+
```bash
|
|
183
|
+
git tag v0.1.0
|
|
184
|
+
git push origin v0.1.0
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The pipeline fails if the tag does not match `setup.cfg`. It needs these secured repository variables:
|
|
188
|
+
|
|
189
|
+
| Variable | Purpose |
|
|
190
|
+
|---|---|
|
|
191
|
+
| `PYPI_TOKEN` | PyPI API token (`pypi-...`) used by twine |
|
|
192
|
+
| `BB_TOKEN` | Bitbucket token for the Downloads upload |
|
|
193
|
+
|
|
194
|
+
To build locally instead:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
checkscanner build # bundle the frontend first
|
|
198
|
+
python -m build # creates dist/*.tar.gz and dist/*.whl
|
|
199
|
+
twine check dist/*
|
|
200
|
+
twine upload dist/*
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Dependencies
|
|
204
|
+
|
|
205
|
+
| Package | Purpose |
|
|
206
|
+
|---|---|
|
|
207
|
+
| `gevent` | Async concurrency for the server |
|
|
208
|
+
| `Pillow` | Check image processing |
|
|
209
|
+
| `pyftpdlib` | FTP server for Magtek readers |
|
|
210
|
+
| `PyJWT` | JWT signing and verification |
|
|
211
|
+
| `requests` | HTTP client for RDM readers |
|
|
212
|
+
| `toml` | Config file parsing |
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# checkscanner
|
|
2
|
+
|
|
3
|
+
Python package for the check scanner backend. Manages connections to Magtek and RDM check scanning devices, extracts MICR data and check images, and serves them through a JWT-authenticated REST API.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Python 3.6+
|
|
8
|
+
- SQLite3
|
|
9
|
+
- pip 21.3.1+ (required on Python 3.6 to resolve pre-built wheels)
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
Ensure pip is up to date before installing:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install --upgrade pip
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Then install the package from PyPI:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install checkscanner
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or from the source tree:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cd server
|
|
29
|
+
pip install .
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
For development (changes take effect without reinstalling):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install -e .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Building the Frontend
|
|
39
|
+
|
|
40
|
+
The frontend must be built and bundled into the package before installing. Run this once from the source tree (requires Node.js):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
checkscanner build
|
|
44
|
+
pip install . # reinstall to pick up the bundled frontend
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
In development with an editable install, `checkscanner build` copies the output directly into `src/checkscanner/static/` so it takes effect immediately without reinstalling.
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
The package installs two commands. Run them from your project directory — config files and the database are created there.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Start the API server (serves UI at http://localhost:8000/).
|
|
55
|
+
# Runs first-time setup automatically if needed.
|
|
56
|
+
checkscanner
|
|
57
|
+
|
|
58
|
+
# Open the interactive admin console
|
|
59
|
+
checkscanner-cli
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`checkscanner` also accepts subcommands (run `checkscanner --help` or `checkscanner <command> --help` for details):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
checkscanner server [options] # Same as no arguments; see `checkscanner server --help`
|
|
66
|
+
checkscanner setup [-i] # Create anything missing: config/, server.db, admin user (-i: edit config first)
|
|
67
|
+
checkscanner status # Show config, database and connection status
|
|
68
|
+
checkscanner admin # Same as checkscanner-cli
|
|
69
|
+
checkscanner build # Build the frontend and bundle it into the package (source tree only)
|
|
70
|
+
|
|
71
|
+
checkscanner user list|add|passwd|delete
|
|
72
|
+
checkscanner profile list|add|delete
|
|
73
|
+
checkscanner config show|edit|rotate-keys
|
|
74
|
+
checkscanner token <username>[:<password>] # or -u <username> [-p <password>]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Server options can also be passed directly, e.g. `checkscanner --port 9000`.
|
|
78
|
+
|
|
79
|
+
## First-Time Setup
|
|
80
|
+
|
|
81
|
+
`checkscanner setup` (also runs automatically before the server and admin console start) creates:
|
|
82
|
+
|
|
83
|
+
| File | Description |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `config/config.toml` | Server host, port, debug mode |
|
|
86
|
+
| `config/auth.toml` | JWT signing key, FTP credentials |
|
|
87
|
+
| `server.db` | SQLite database |
|
|
88
|
+
| `admin_credentials.txt` | Generated admin username and password — delete after noting |
|
|
89
|
+
|
|
90
|
+
## Admin Console
|
|
91
|
+
|
|
92
|
+
`checkscanner-cli` opens an arrow-key menu for managing the server:
|
|
93
|
+
|
|
94
|
+
- View server status
|
|
95
|
+
- List, add and delete users; reset passwords
|
|
96
|
+
- List, add and delete check scanner profiles
|
|
97
|
+
- Edit config and regenerate auth keys
|
|
98
|
+
- Get a bearer token for API testing
|
|
99
|
+
- Start the server, optionally restarting it automatically when it stops
|
|
100
|
+
|
|
101
|
+
Every menu action is also available as a `checkscanner` subcommand for scripting.
|
|
102
|
+
|
|
103
|
+
## API
|
|
104
|
+
|
|
105
|
+
Swagger UI is available at `http://localhost:8000/docs` when the server is running.
|
|
106
|
+
|
|
107
|
+
| Method | Endpoint | Description |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| POST | `/token` | Authenticate, receive JWT |
|
|
110
|
+
| GET/POST | `/connections` | List or create reader connections |
|
|
111
|
+
| DELETE | `/connections/<id>` | Disconnect from reader |
|
|
112
|
+
| GET/PUT | `/connections/<id>/check` | Get check data or return check to queue |
|
|
113
|
+
| GET/POST/PATCH/DELETE | `/profiles` | Manage reader device profiles |
|
|
114
|
+
| GET/POST/PATCH/DELETE | `/users` | Manage users (admin only) |
|
|
115
|
+
|
|
116
|
+
## Supported Devices
|
|
117
|
+
|
|
118
|
+
| Type | Protocol |
|
|
119
|
+
|---|---|
|
|
120
|
+
| Magtek | Telnet + FTP |
|
|
121
|
+
| RDM | HTTPS (XML) |
|
|
122
|
+
|
|
123
|
+
## Project Structure
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
src/
|
|
127
|
+
└── checkscanner/
|
|
128
|
+
├── app.py # Bottle API server
|
|
129
|
+
├── admin_console.py # Interactive admin CLI
|
|
130
|
+
├── active_scanners.py # In-memory scanner connection registry
|
|
131
|
+
├── auth.py # Password hashing and JWT verification
|
|
132
|
+
├── ftp_server.py # FTP server for Magtek image uploads
|
|
133
|
+
├── debugger.py # Colored terminal logging
|
|
134
|
+
├── bottle/ # Vendored Bottle framework + plugins
|
|
135
|
+
├── resources/ # REST resource handlers
|
|
136
|
+
├── check_scanner_handlers/ # Device-specific connection handlers
|
|
137
|
+
├── static/ # Bundled frontend (populated by `checkscanner build`)
|
|
138
|
+
├── swagger/ # Bundled Swagger UI
|
|
139
|
+
└── data/ # Bundled assets (schema, font, API spec)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Releasing to PyPI
|
|
143
|
+
|
|
144
|
+
Releases are published by the Bitbucket pipeline (`bitbucket-pipelines.yml`) when a `v*` tag is pushed. The pipeline builds the frontend, bundles it into the package, builds the sdist and wheel, uploads them to PyPI, and uploads the wheel to Bitbucket Downloads.
|
|
145
|
+
|
|
146
|
+
1. Bump `version` in `setup.cfg` (PyPI rejects re-uploads of an existing version).
|
|
147
|
+
2. Commit, then tag with the matching version and push the tag:
|
|
148
|
+
```bash
|
|
149
|
+
git tag v0.1.0
|
|
150
|
+
git push origin v0.1.0
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The pipeline fails if the tag does not match `setup.cfg`. It needs these secured repository variables:
|
|
154
|
+
|
|
155
|
+
| Variable | Purpose |
|
|
156
|
+
|---|---|
|
|
157
|
+
| `PYPI_TOKEN` | PyPI API token (`pypi-...`) used by twine |
|
|
158
|
+
| `BB_TOKEN` | Bitbucket token for the Downloads upload |
|
|
159
|
+
|
|
160
|
+
To build locally instead:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
checkscanner build # bundle the frontend first
|
|
164
|
+
python -m build # creates dist/*.tar.gz and dist/*.whl
|
|
165
|
+
twine check dist/*
|
|
166
|
+
twine upload dist/*
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Dependencies
|
|
170
|
+
|
|
171
|
+
| Package | Purpose |
|
|
172
|
+
|---|---|
|
|
173
|
+
| `gevent` | Async concurrency for the server |
|
|
174
|
+
| `Pillow` | Check image processing |
|
|
175
|
+
| `pyftpdlib` | FTP server for Magtek readers |
|
|
176
|
+
| `PyJWT` | JWT signing and verification |
|
|
177
|
+
| `requests` | HTTP client for RDM readers |
|
|
178
|
+
| `toml` | Config file parsing |
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
[metadata]
|
|
2
|
+
name = checkscanner
|
|
3
|
+
version = 0.1.2
|
|
4
|
+
description = Check scanner API server and admin console
|
|
5
|
+
long_description = file: README.md
|
|
6
|
+
long_description_content_type = text/markdown
|
|
7
|
+
author = DiscipleMakers
|
|
8
|
+
url = https://bitbucket.org/disciplemakers/check-reader
|
|
9
|
+
license = MIT
|
|
10
|
+
license_files = LICENSE
|
|
11
|
+
keywords = check scanner, micr, magtek, rdm
|
|
12
|
+
classifiers =
|
|
13
|
+
Programming Language :: Python :: 3
|
|
14
|
+
Operating System :: OS Independent
|
|
15
|
+
Framework :: Bottle
|
|
16
|
+
Topic :: Office/Business :: Financial
|
|
17
|
+
|
|
18
|
+
[options]
|
|
19
|
+
package_dir =
|
|
20
|
+
= src
|
|
21
|
+
packages = find_namespace:
|
|
22
|
+
python_requires = >=3.6, <3.13
|
|
23
|
+
include_package_data = True
|
|
24
|
+
install_requires =
|
|
25
|
+
gevent>=1.5.0,<22.0.0; python_version < "3.7"
|
|
26
|
+
gevent>=23.0.0; python_version >= "3.7"
|
|
27
|
+
Pillow>=5.0.0,<9.0.0; python_version < "3.7"
|
|
28
|
+
Pillow>=10.0.0; python_version >= "3.7"
|
|
29
|
+
pyftpdlib>=1.5.0,<2.0.0; python_version < "3.7"
|
|
30
|
+
pyftpdlib>=1.5.7; python_version >= "3.7"
|
|
31
|
+
PyJWT>=2.0.0,<2.5.0; python_version < "3.7"
|
|
32
|
+
PyJWT>=2.8.0; python_version >= "3.7"
|
|
33
|
+
requests>=2.20.0,<2.28.0; python_version < "3.7"
|
|
34
|
+
requests>=2.31.0; python_version >= "3.7"
|
|
35
|
+
toml>=0.10.0
|
|
36
|
+
click>=7.1,<8.1; python_version < "3.7"
|
|
37
|
+
click>=8.1; python_version >= "3.7"
|
|
38
|
+
rich>=12.0,<13.0; python_version < "3.7"
|
|
39
|
+
rich>=13.0; python_version >= "3.7"
|
|
40
|
+
questionary>=1.10.0,<2.0; python_version < "3.8"
|
|
41
|
+
questionary>=2.0; python_version >= "3.8"
|
|
42
|
+
|
|
43
|
+
[options.packages.find]
|
|
44
|
+
where = src
|
|
45
|
+
|
|
46
|
+
[options.entry_points]
|
|
47
|
+
console_scripts =
|
|
48
|
+
checkscanner = checkscanner.cli:main
|
|
49
|
+
checkscanner-cli = checkscanner.cli:admin_main
|
|
50
|
+
|
|
51
|
+
[egg_info]
|
|
52
|
+
tag_build =
|
|
53
|
+
tag_date = 0
|
|
54
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from threading import Thread
|
|
2
|
+
from . import debugger
|
|
3
|
+
from .check_scanner_handlers import MagtekScannerHandler, RDMScannerHandler, CheckScannerHandler
|
|
4
|
+
from .ftp_server import DummyFTP
|
|
5
|
+
|
|
6
|
+
class Singleton (type):
|
|
7
|
+
_instances = {}
|
|
8
|
+
def __call__(cls, *args, **kwargs):
|
|
9
|
+
if cls not in cls._instances:
|
|
10
|
+
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
|
|
11
|
+
return cls._instances[cls]
|
|
12
|
+
|
|
13
|
+
class ActiveScanners(dict, metaclass=Singleton):
|
|
14
|
+
|
|
15
|
+
handlers = {
|
|
16
|
+
"magtek": MagtekScannerHandler,
|
|
17
|
+
"rdm": RDMScannerHandler
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
def __init__(self, sleep_time = 5, handlers: dict = None) -> None:
|
|
21
|
+
debugger.print("Initializing active scanners handler")
|
|
22
|
+
self.sleep_time = sleep_time
|
|
23
|
+
self.ftp = None
|
|
24
|
+
if handlers:
|
|
25
|
+
self.handlers = handlers
|
|
26
|
+
self.started = False
|
|
27
|
+
|
|
28
|
+
def newReaderHandler(self, reader_type) -> CheckScannerHandler:
|
|
29
|
+
handler = self.handlers[reader_type](self)
|
|
30
|
+
if reader_type == "magtek":
|
|
31
|
+
if not self.ftp:
|
|
32
|
+
self.ftp = DummyFTP()
|
|
33
|
+
self.ftp_thread = Thread(target=self.ftp.start, daemon=True).start()
|
|
34
|
+
handler.ftp = self.ftp
|
|
35
|
+
return handler
|
|
36
|
+
|
|
37
|
+
def isReaderActive(self, reader_host):
|
|
38
|
+
for crh in self.values():
|
|
39
|
+
if reader_host == crh.host:
|
|
40
|
+
return True
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
def jsonSerialize(self):
|
|
44
|
+
return {
|
|
45
|
+
"active_scanners": [{"conn_id": conn_id, **conn} for conn_id, conn in self.items()]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
def start(self):
|
|
49
|
+
if not self.started:
|
|
50
|
+
self.started = True
|
|
51
|
+
|
|
52
|
+
def stop(self):
|
|
53
|
+
self.started = False
|