For admins¶
An admin can do everything the interface offers. The menu is called Admin rather than Manage.
Roles¶
sets each approved person’s role, alongside the lab and mentor a manager can already set.
Approved people are listed under their lab, most senior first within each one, with everybody in no lab at the end. Each person’s tier is printed beside their name as well as being the dropdown you change it with — the dropdown is the control, the label beside the name is what makes a column of them readable.
Moving somebody to another lab moves their card to that lab’s section, which is the confirmation the change gets. Taking a lab away again is not offered here; somebody in no lab shows — no lab — and can be put into one.
- User
Borrow and return. This is where everybody starts.
- Manager
Also curate the catalogue and see who holds what.
- Admin
Also set roles, block people, delete locations and answer other labs’ borrowing requests.
Giving somebody a mentor makes them a student. It changes no permissions: the mentor is told when they take equipment out, sees it beside their own, and may take equipment out on their behalf.
You cannot change your own role. Ask another admin, which is what stops the last admin quietly demoting themselves.
Superuser is Django’s own top level and is granted only in the Django admin. It is deliberately not a tier here: it edits records underneath every rule this app enforces.
Blocking¶
Block on the Users page revokes access without deleting anything the person has done. Their checkouts, history and equipment stay exactly as they were. Let back in reverses it.
Borrowing requests¶
is the queue of other labs asking for your lab’s equipment, with whatever they said they needed it for. Let them grants one loan; Decline refuses it. The person who asked is told either way.
The same page sets your lab’s policy under When another lab wants our equipment: hold the request for an answer, or grant it and be told. A lab whose equipment is delicate or heavily booked wants the first; a lab that would always say yes only wants to know where its equipment went.
A superuser sees every lab’s queue, so that a lab with no admin of its own never has requests nobody can answer.
Locations¶
Deleting a location is an admin’s job because it rewrites checkouts, people’s default rooms and future imports in one go. The confirmation page names how many records refer to it before you commit.
Site settings¶
In the Django admin, under Site settings:
- Weekly reminder
Whether it goes out at all, and on which day. Turning it off stops it for everybody, whatever they have chosen for themselves.
- Maintainer address
Where “the nightly job failed” is sent. Left empty, the superusers are told instead. It is an address rather than a person on purpose: whoever looks after the server need not have an account here, and a shared alias outlives whoever currently reads it.
Logs¶
Manage → Logs is the record of who did what: every action anybody performed through this app or its API, and every action it refused. It is admin-only.
This is not the same thing as an item’s own history, which stays on the item’s page and is kept forever. That one answers what happened to this equipment. This one answers who asked, from where, and what did the app say back — including the requests that were turned down, which leave no other trace anywhere.
One row per action, and the columns sort: click a heading to order by it, click it again to reverse. What is the thing acted on — a piece of equipment links straight to its page. Click the date to open one entry in full: where the request came from, which token if it was a script, the address, every argument the act was given and everything it produced. A refusal is marked down the left edge of its row.
The filters are the questions people usually arrive with. Outcome finds what was refused, which is a question the log answers and nothing else does — a request that was turned away leaves no other trace. Mentioning searches inside the recorded arguments, which finds things the What column does not: a location an item was moved to, or a person a loan was taken out on behalf of.
Printing a sheet of labels is recorded, although it changes nothing here. The paper is the change: somebody walks off with stickers and puts them on hardware, and who printed the labels that went on these has a physical answer. Opening an item’s page is not recorded, and neither is any other reading.
The token’s secret is never recorded — this app has never been able to read one. What appears is its public prefix, which is how one person holding several credentials tells which of them acted.
At the top is the retention period, in days. Three years by default. Entries older than that are deleted nightly; 0 keeps them forever. It sits on this page rather than in the site settings because nobody decides a retention period without looking at what it would remove.
Nothing lengthens the record retrospectively: shortening the period deletes what is already past it on the next nightly run, and there is no undo. The setting is also the only one of its kind an admin can change without a superuser.
What runs by itself¶
Every night, on the server: the spreadsheet import, a database backup, the trimming of the log above, and once a week the reminder email. If any of them fails, the maintainer address is emailed, at most once a day per job, until it succeeds again.
The backup runs at 03:30 and the last fourteen are kept, so a mistake noticed within a fortnight can still be undone. They are written on the same server as the database, which covers a bad upgrade or a bulk edit that went wrong, but not the loss of the machine itself; there are no off-site copies at present. The equipment catalogue could in any case be imported again from the spreadsheet. What only exists here is who holds what, the checkout history, locations, tags and accounts.
Restoring one is a server operation rather than something this interface offers.
The tested procedure, rehearsed against real backups, is in docs/deployment.md
in the repository, under Backups and restore. Its first half verifies a backup
without touching anything live, which is worth running from time to time: a
backup nobody has ever read is a hypothesis.