Compare commits
1 Commits
libdibific
...
master
Author | SHA1 | Date | |
---|---|---|---|
f5557a1d99
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,9 +1,8 @@
|
||||
result
|
||||
result-*
|
||||
**/__pycache__
|
||||
dibbler.egg-info
|
||||
|
||||
dist
|
||||
|
||||
test.db
|
||||
|
||||
.ruff_cache
|
||||
.ruff_cache
|
@ -76,8 +76,12 @@ class Database:
|
||||
personDatoVerdi = defaultdict(list) # dict->array
|
||||
personUkedagVerdi = defaultdict(list)
|
||||
# for global
|
||||
personPosTransactions = {} # personPosTransactions[trygvrad] == 100 #trygvrad har lagt 100kr i boksen
|
||||
personNegTransactions = {} # personNegTransactions[trygvrad» == 70 #trygvrad har tatt 70kr fra boksen
|
||||
personPosTransactions = (
|
||||
{}
|
||||
) # personPosTransactions[trygvrad] == 100 #trygvrad har lagt 100kr i boksen
|
||||
personNegTransactions = (
|
||||
{}
|
||||
) # personNegTransactions[trygvrad» == 70 #trygvrad har tatt 70kr fra boksen
|
||||
globalVareAntall = {} # globalVareAntall[Oreo] == 3
|
||||
globalVareVerdi = {} # globalVareVerdi[Oreo] == 30 #[kr]
|
||||
globalPersonAntall = {} # globalPersonAntall[trygvrad] == 3
|
||||
|
@ -1,8 +1,4 @@
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from dibbler.conf import config
|
||||
|
||||
@ -24,65 +20,26 @@ subparsers = parser.add_subparsers(
|
||||
subparsers.add_parser("loop", help="Run the dibbler loop")
|
||||
subparsers.add_parser("create-db", help="Create the database")
|
||||
subparsers.add_parser("slabbedasker", help="Find out who is slabbedasker")
|
||||
subparsers.add_parser("seed-data", help="Fill with mock data")
|
||||
|
||||
|
||||
def _get_database_url_from_config() -> str:
|
||||
"""Get the database URL from the configuration."""
|
||||
url = config.get("database", "url")
|
||||
if url is not None:
|
||||
return url
|
||||
|
||||
url_file = config.get("database", "url_file")
|
||||
if url_file is not None:
|
||||
with Path(url_file).open() as file:
|
||||
return file.read().strip()
|
||||
|
||||
raise ValueError("No database URL found in configuration.")
|
||||
|
||||
|
||||
def _connect_to_database(url: str, **engine_args) -> Session:
|
||||
try:
|
||||
engine = create_engine(url, **engine_args)
|
||||
sql_session = Session(engine)
|
||||
except Exception as err:
|
||||
print("Error: could not connect to database.")
|
||||
print(err)
|
||||
exit(1)
|
||||
|
||||
print(f"Debug: Connected to database at '{url}'")
|
||||
return sql_session
|
||||
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
config.read(args.config)
|
||||
|
||||
database_url = _get_database_url_from_config()
|
||||
sql_session = _connect_to_database(
|
||||
database_url,
|
||||
echo=config.getboolean("database", "echo_sql", fallback=False),
|
||||
)
|
||||
|
||||
if args.subcommand == "loop":
|
||||
import dibbler.subcommands.loop as loop
|
||||
|
||||
loop.main(sql_session)
|
||||
loop.main()
|
||||
|
||||
elif args.subcommand == "create-db":
|
||||
import dibbler.subcommands.makedb as makedb
|
||||
|
||||
makedb.main(sql_session)
|
||||
makedb.main()
|
||||
|
||||
elif args.subcommand == "slabbedasker":
|
||||
import dibbler.subcommands.slabbedasker as slabbedasker
|
||||
|
||||
slabbedasker.main(sql_session)
|
||||
|
||||
elif args.subcommand == "seed-data":
|
||||
import dibbler.subcommands.seed_test_data as seed_test_data
|
||||
|
||||
seed_test_data.main(sql_session)
|
||||
slabbedasker.main()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -180,7 +180,7 @@ When finished, write an empty line to confirm the purchase.\n"""
|
||||
print(f"User {t.user.name}'s credit is now {t.user.credit:d} kr")
|
||||
if t.user.credit < config.getint("limits", "low_credit_warning_limit"):
|
||||
print(
|
||||
f"USER {t.user.name} HAS LOWER CREDIT THAN {config.getint('limits', 'low_credit_warning_limit'):d},",
|
||||
f'USER {t.user.name} HAS LOWER CREDIT THAN {config.getint("limits", "low_credit_warning_limit"):d},',
|
||||
"AND SHOULD CONSIDER PUTTING SOME MONEY IN THE BOX.",
|
||||
)
|
||||
|
||||
|
@ -1,176 +0,0 @@
|
||||
import sys
|
||||
import signal
|
||||
import traceback
|
||||
|
||||
from sqlalchemy import (
|
||||
event,
|
||||
)
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from libdib.repl import (
|
||||
NumberedCmd,
|
||||
InteractiveItemSelector,
|
||||
prompt_yes_no,
|
||||
)
|
||||
|
||||
from dibbler.conf import config
|
||||
|
||||
class DibblerCli(NumberedCmd):
|
||||
def __init__(self, sql_session: Session):
|
||||
super().__init__()
|
||||
self.sql_session = sql_session
|
||||
self.sql_session_dirty = False
|
||||
|
||||
@event.listens_for(self.sql_session, "after_flush")
|
||||
def mark_session_as_dirty(*_):
|
||||
self.sql_session_dirty = True
|
||||
self.prompt_header = "(unsaved changes)"
|
||||
|
||||
@event.listens_for(self.sql_session, "after_commit")
|
||||
@event.listens_for(self.sql_session, "after_rollback")
|
||||
def mark_session_as_clean(*_):
|
||||
self.sql_session_dirty = False
|
||||
self.prompt_header = None
|
||||
|
||||
# TODO: move to libdib.repl
|
||||
@classmethod
|
||||
def run_with_safe_exit_wrapper(cls, sql_session: Session):
|
||||
tool = cls(sql_session)
|
||||
|
||||
if not config.getboolean("general", "stop_allowed"):
|
||||
signal.signal(signal.SIGQUIT, signal.SIG_IGN)
|
||||
|
||||
if not config.getboolean("general", "stop_allowed"):
|
||||
signal.signal(signal.SIGTSTP, signal.SIG_IGN)
|
||||
|
||||
while True:
|
||||
try:
|
||||
tool.cmdloop()
|
||||
except KeyboardInterrupt:
|
||||
if not tool.sql_session_dirty:
|
||||
exit(0)
|
||||
try:
|
||||
print()
|
||||
if prompt_yes_no(
|
||||
"Are you sure you want to exit without saving?", default=False
|
||||
):
|
||||
raise KeyboardInterrupt
|
||||
except KeyboardInterrupt:
|
||||
if tool.sql_session is not None:
|
||||
tool.sql_session.rollback()
|
||||
exit(0)
|
||||
except Exception:
|
||||
print("Something went wrong.")
|
||||
print(f"{sys.exc_info()[0]}: {sys.exc_info()[1]}")
|
||||
if config.getboolean("general", "show_tracebacks"):
|
||||
traceback.print_tb(sys.exc_info()[2])
|
||||
|
||||
def default(self, maybe_barcode: str):
|
||||
raise NotImplementedError(
|
||||
"This command is not implemented yet. Please use the numbered commands instead."
|
||||
)
|
||||
|
||||
def do_buy(self, arg: str):
|
||||
...
|
||||
|
||||
def do_product_list(self, arg: str):
|
||||
...
|
||||
|
||||
def do_show_user(self, arg: str):
|
||||
...
|
||||
|
||||
def do_user_list(self, arg: str):
|
||||
...
|
||||
|
||||
def do_adjust_credit(self, arg: str):
|
||||
...
|
||||
|
||||
def do_transfer(self, arg: str):
|
||||
...
|
||||
|
||||
def do_add_stock(self, arg: str):
|
||||
...
|
||||
|
||||
def do_add_edit(self, arg: str):
|
||||
...
|
||||
# AddEditMenu(self.sql_session).cmdloop()
|
||||
|
||||
def do_product_search(self, arg: str):
|
||||
...
|
||||
|
||||
def do_statistics(self, arg: str):
|
||||
...
|
||||
|
||||
def do_faq(self, arg: str):
|
||||
...
|
||||
|
||||
def do_print_label(self, arg: str):
|
||||
...
|
||||
|
||||
|
||||
def do_exit(self, _: str):
|
||||
if self.sql_session_dirty:
|
||||
if prompt_yes_no("Would you like to save your changes?"):
|
||||
self.sql_session.commit()
|
||||
else:
|
||||
self.sql_session.rollback()
|
||||
exit(0)
|
||||
|
||||
funcs = {
|
||||
0: {
|
||||
"f": default,
|
||||
"doc": "Choose / Add item with its ISBN",
|
||||
},
|
||||
1: {
|
||||
"f": do_buy,
|
||||
"doc": "Buy",
|
||||
},
|
||||
2: {
|
||||
"f": do_product_list,
|
||||
"doc": "Product List",
|
||||
},
|
||||
3: {
|
||||
"f": do_show_user,
|
||||
"doc": "Show User",
|
||||
},
|
||||
4: {
|
||||
"f": do_user_list,
|
||||
"doc": "User List",
|
||||
},
|
||||
5: {
|
||||
"f": do_adjust_credit,
|
||||
"doc": "Adjust Credit",
|
||||
},
|
||||
6: {
|
||||
"f": do_transfer,
|
||||
"doc": "Transfer",
|
||||
},
|
||||
7: {
|
||||
"f": do_add_stock,
|
||||
"doc": "Add Stock",
|
||||
},
|
||||
8: {
|
||||
"f": do_add_edit,
|
||||
"doc": "Add/Edit",
|
||||
},
|
||||
9: {
|
||||
"f": do_product_search,
|
||||
"doc": "Product Search",
|
||||
},
|
||||
10: {
|
||||
"f": do_statistics,
|
||||
"doc": "Statistics",
|
||||
},
|
||||
11: {
|
||||
"f": do_faq,
|
||||
"doc": "FAQ",
|
||||
},
|
||||
12: {
|
||||
"f": do_print_label,
|
||||
"doc": "Print Label",
|
||||
},
|
||||
13: {
|
||||
"f": do_exit,
|
||||
"doc": "Exit",
|
||||
},
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
__all__ = [
|
||||
"Base",
|
||||
"Product",
|
||||
"Purchase",
|
||||
"PurchaseEntry",
|
||||
"Transaction",
|
||||
"User",
|
||||
"UserProducts",
|
||||
'Base',
|
||||
'Product',
|
||||
'Purchase',
|
||||
'PurchaseEntry',
|
||||
'Transaction',
|
||||
'User',
|
||||
'UserProducts',
|
||||
]
|
||||
|
||||
from .Base import Base
|
||||
|
@ -1,12 +1,79 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import random
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from ..conf import config
|
||||
from ..lib.helpers import *
|
||||
from ..menus import *
|
||||
|
||||
from ..menus.main import DibblerCli
|
||||
random.seed()
|
||||
|
||||
def main(sql_session: Session):
|
||||
random.seed()
|
||||
|
||||
DibblerCli.run_with_safe_exit_wrapper(sql_session)
|
||||
def main():
|
||||
if not config.getboolean("general", "stop_allowed"):
|
||||
signal.signal(signal.SIGQUIT, signal.SIG_IGN)
|
||||
|
||||
exit(0)
|
||||
if not config.getboolean("general", "stop_allowed"):
|
||||
signal.signal(signal.SIGTSTP, signal.SIG_IGN)
|
||||
|
||||
main = MainMenu(
|
||||
"Dibbler main menu",
|
||||
items=[
|
||||
BuyMenu(),
|
||||
ProductListMenu(),
|
||||
ShowUserMenu(),
|
||||
UserListMenu(),
|
||||
AdjustCreditMenu(),
|
||||
TransferMenu(),
|
||||
AddStockMenu(),
|
||||
Menu(
|
||||
"Add/edit",
|
||||
items=[
|
||||
AddUserMenu(),
|
||||
EditUserMenu(),
|
||||
AddProductMenu(),
|
||||
EditProductMenu(),
|
||||
AdjustStockMenu(),
|
||||
CleanupStockMenu(),
|
||||
],
|
||||
),
|
||||
ProductSearchMenu(),
|
||||
Menu(
|
||||
"Statistics",
|
||||
items=[
|
||||
ProductPopularityMenu(),
|
||||
ProductRevenueMenu(),
|
||||
BalanceMenu(),
|
||||
LoggedStatisticsMenu(),
|
||||
],
|
||||
),
|
||||
FAQMenu(),
|
||||
PrintLabelMenu(),
|
||||
],
|
||||
exit_msg="happy happy joy joy",
|
||||
exit_confirm_msg="Really quit Dibbler?",
|
||||
)
|
||||
if not config.getboolean("general", "quit_allowed"):
|
||||
main.exit_disallowed_msg = "You can check out any time you like, but you can never leave."
|
||||
while True:
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
main.execute()
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
print("Interrupted.")
|
||||
except:
|
||||
print("Something went wrong.")
|
||||
print(f"{sys.exc_info()[0]}: {sys.exc_info()[1]}")
|
||||
if config.getboolean("general", "show_tracebacks"):
|
||||
traceback.print_tb(sys.exc_info()[2])
|
||||
else:
|
||||
break
|
||||
print("Restarting main menu.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -1,8 +1,11 @@
|
||||
from sqlalchemy.orm import Session
|
||||
#!/usr/bin/python
|
||||
from dibbler.models import Base
|
||||
from dibbler.db import engine
|
||||
|
||||
|
||||
def main(sql_session: Session):
|
||||
if not sql_session.bind:
|
||||
raise RuntimeError("SQLAlchemy session is not bound to a database engine.")
|
||||
Base.metadata.create_all(sql_session.bind)
|
||||
def main():
|
||||
Base.metadata.create_all(engine)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -1,45 +0,0 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from dibbler.models import Product, User
|
||||
|
||||
JSON_FILE = Path(__file__).parent.parent.parent / "mock_data.json"
|
||||
|
||||
|
||||
def clear_db(sql_session: Session):
|
||||
sql_session.query(Product).delete()
|
||||
sql_session.query(User).delete()
|
||||
sql_session.commit()
|
||||
|
||||
|
||||
def main(sql_session: Session):
|
||||
clear_db(sql_session)
|
||||
product_items = []
|
||||
user_items = []
|
||||
|
||||
with open(JSON_FILE) as f:
|
||||
json_obj = json.load(f)
|
||||
|
||||
for product in json_obj["products"]:
|
||||
product_item = Product(
|
||||
bar_code=product["bar_code"],
|
||||
name=product["name"],
|
||||
price=product["price"],
|
||||
stock=product["stock"],
|
||||
)
|
||||
product_items.append(product_item)
|
||||
|
||||
for user in json_obj["users"]:
|
||||
user_item = User(
|
||||
name=user["name"],
|
||||
card=user["card"],
|
||||
rfid=user["rfid"],
|
||||
credit=user["credit"],
|
||||
)
|
||||
user_items.append(user_item)
|
||||
|
||||
sql_session.add_all(product_items)
|
||||
sql_session.add_all(user_items)
|
||||
sql_session.commit()
|
@ -1,12 +1,18 @@
|
||||
from sqlalchemy.orm import Session
|
||||
#!/usr/bin/python
|
||||
|
||||
# from dibbler.db import Session
|
||||
from dibbler.db import Session
|
||||
from dibbler.models import User
|
||||
|
||||
|
||||
def main(sql_session: Session):
|
||||
# Let's find all users with a negative credit
|
||||
slabbedasker = sql_session.query(User).filter(User.credit < 0).all()
|
||||
def main():
|
||||
# Start an SQL session
|
||||
session = Session()
|
||||
# Let's find all users with a negative credit
|
||||
slabbedasker = session.query(User).filter(User.credit < 0).all()
|
||||
|
||||
for slubbert in slabbedasker:
|
||||
print(f"{slubbert.name}, {slubbert.credit}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -5,7 +5,7 @@ show_tracebacks = true
|
||||
input_encoding = 'utf8'
|
||||
|
||||
[database]
|
||||
# url = "postgresql://robertem@127.0.0.1/pvvvv"
|
||||
; url = postgresql://robertem@127.0.0.1/pvvvv
|
||||
url = sqlite:///test.db
|
||||
|
||||
[limits]
|
||||
|
76
flake.lock
generated
76
flake.lock
generated
@ -17,65 +17,13 @@
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "flake-utils",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"libdib": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749301134,
|
||||
"narHash": "sha256-JHLVV4ug8AgG71xhXEdmXozQfesXut6NUdXbBZNkD3c=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "ca26131c22bb2833c81254dbabab6d785b9f37f0",
|
||||
"revCount": 8,
|
||||
"type": "git",
|
||||
"url": "https://git.pvv.ntnu.no/Projects/libdib.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.pvv.ntnu.no/Projects/libdib.git"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1749143949,
|
||||
"narHash": "sha256-QuUtALJpVrPnPeozlUG/y+oIMSLdptHxb3GK6cpSVhA=",
|
||||
"lastModified": 1742288794,
|
||||
"narHash": "sha256-Txwa5uO+qpQXrNG4eumPSD+hHzzYi/CdaM80M9XRLCo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d3d2d80a2191a73d1e86456a751b83aa13085d7d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1749143949,
|
||||
"narHash": "sha256-QuUtALJpVrPnPeozlUG/y+oIMSLdptHxb3GK6cpSVhA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d3d2d80a2191a73d1e86456a751b83aa13085d7d",
|
||||
"rev": "b6eaf97c6960d97350c584de1b6dcff03c9daf42",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -88,8 +36,7 @@
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"libdib": "libdib",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
@ -106,21 +53,6 @@
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
21
flake.nix
21
flake.nix
@ -1,29 +1,20 @@
|
||||
{
|
||||
description = "Dibbler samspleisebod";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
|
||||
libdib.url = "git+https://git.pvv.ntnu.no/Projects/libdib.git";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, libdib }: let
|
||||
outputs = { self, nixpkgs, flake-utils }: let
|
||||
inherit (nixpkgs) lib;
|
||||
|
||||
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
|
||||
|
||||
forAllSystems = f: lib.genAttrs systems (system: let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
libdib.overlays.default
|
||||
];
|
||||
};
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in f system pkgs);
|
||||
in {
|
||||
packages = forAllSystems (system: pkgs: {
|
||||
@ -54,7 +45,7 @@
|
||||
python = pkgs.python312;
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
# Note: using the module requires that you have applied the overlay first
|
||||
nixosModules.default = import ./nix/module.nix;
|
||||
|
||||
|
@ -1,76 +0,0 @@
|
||||
{
|
||||
"products": [
|
||||
{
|
||||
"product_id": 1,
|
||||
"bar_code": "1234567890123",
|
||||
"name": "Wireless Mouse",
|
||||
"price": 2999,
|
||||
"stock": 150,
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"product_id": 2,
|
||||
"bar_code": "9876543210987",
|
||||
"name": "Mechanical Keyboard",
|
||||
"price": 5999,
|
||||
"stock": 75,
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"product_id": 3,
|
||||
"bar_code": "1112223334445",
|
||||
"name": "Gaming Monitor",
|
||||
"price": 19999,
|
||||
"stock": 20,
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"product_id": 4,
|
||||
"bar_code": "5556667778889",
|
||||
"name": "USB-C Docking Station",
|
||||
"price": 8999,
|
||||
"stock": 50,
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"product_id": 5,
|
||||
"bar_code": "4445556667771",
|
||||
"name": "Noise Cancelling Headphones",
|
||||
"price": 12999,
|
||||
"stock": 30,
|
||||
"hidden": true
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"name": "Albert",
|
||||
"credit": 42069,
|
||||
"card": "NTU12345678",
|
||||
"rfid": "a1b2c3d4e5"
|
||||
},
|
||||
{
|
||||
"name": "lorem",
|
||||
"credit": 2000,
|
||||
"card": "9876543210",
|
||||
"rfid": "f6e7d8c9b0"
|
||||
},
|
||||
{
|
||||
"name": "ibsum",
|
||||
"credit": 1000,
|
||||
"card": "11122233",
|
||||
"rfid": ""
|
||||
},
|
||||
{
|
||||
"name": "dave",
|
||||
"credit": 7500,
|
||||
"card": "NTU56789012",
|
||||
"rfid": "1234abcd5678"
|
||||
},
|
||||
{
|
||||
"name": "eve",
|
||||
"credit": 3000,
|
||||
"card": null,
|
||||
"rfid": "deadbeef1234"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
{ lib
|
||||
, python3Packages
|
||||
, fetchFromGitHub
|
||||
}:
|
||||
python3Packages.buildPythonApplication {
|
||||
pname = "dibbler";
|
||||
@ -15,7 +16,6 @@ python3Packages.buildPythonApplication {
|
||||
nativeBuildInputs = with python3Packages; [ setuptools ];
|
||||
propagatedBuildInputs = with python3Packages; [
|
||||
brother-ql
|
||||
libdib
|
||||
matplotlib
|
||||
psycopg2
|
||||
python-barcode
|
||||
|
@ -1,31 +1,21 @@
|
||||
{ config, pkgs, lib, ... }: let
|
||||
cfg = config.services.dibbler;
|
||||
|
||||
format = pkgs.formats.ini { };
|
||||
in {
|
||||
options.services.dibbler = {
|
||||
enable = lib.mkEnableOption "dibbler, the little kiosk computer";
|
||||
|
||||
|
||||
package = lib.mkPackageOption pkgs "dibbler" { };
|
||||
|
||||
settings = lib.mkOption {
|
||||
description = "Configuration for dibbler";
|
||||
default = { };
|
||||
type = lib.types.submodule {
|
||||
freeformType = format.type;
|
||||
};
|
||||
|
||||
config = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = "Path to the configuration file.";
|
||||
default = ../example-config.ini;
|
||||
};
|
||||
};
|
||||
|
||||
config = let
|
||||
screen = "${pkgs.screen}/bin/screen";
|
||||
in lib.mkIf cfg.enable {
|
||||
services.dibbler.settings = lib.pipe ../example-config.ini [
|
||||
builtins.readFile
|
||||
builtins.fromTOML
|
||||
(lib.mapAttrsRecursive (_: lib.mkDefault))
|
||||
];
|
||||
|
||||
boot = {
|
||||
consoleLogLevel = 0;
|
||||
enableContainers = false;
|
||||
@ -38,7 +28,7 @@ in {
|
||||
group = "dibbler";
|
||||
extraGroups = [ "lp" ];
|
||||
isNormalUser = true;
|
||||
shell = (pkgs.writeShellScriptBin "login-shell" "${screen} -x dibbler") // {shellPath = "/bin/login-shell";};
|
||||
shell = ((pkgs.writeShellScriptBin "login-shell" "${screen} -x dibbler") // {shellPath = "/bin/login-shell";});
|
||||
};
|
||||
};
|
||||
|
||||
@ -47,9 +37,7 @@ in {
|
||||
wantedBy = [ "default.target" ];
|
||||
serviceConfig = {
|
||||
ExecStartPre = "-${screen} -X -S dibbler kill";
|
||||
ExecStart = let
|
||||
config = format.generate "dibbler-config.ini" cfg.settings;
|
||||
in "${screen} -dmS dibbler -O -l ${cfg.package}/bin/dibbler --config ${config} loop";
|
||||
ExecStart = "${screen} -dmS dibbler -O -l ${cfg.package}/bin/dibbler --config ${cfg.config} loop";
|
||||
ExecStartPost = "${screen} -X -S dibbler width 42 80";
|
||||
User = "dibbler";
|
||||
Group = "dibbler";
|
||||
@ -72,6 +60,30 @@ in {
|
||||
serviceConfig.Restart = "always"; # restart when session is closed
|
||||
};
|
||||
|
||||
services.getty.autologinUser = lib.mkForce "dibbler";
|
||||
services = {
|
||||
openssh = {
|
||||
enable = true;
|
||||
permitRootLogin = "yes";
|
||||
};
|
||||
|
||||
getty.autologinUser = lib.mkForce "dibbler";
|
||||
udisks2.enable = false;
|
||||
};
|
||||
|
||||
networking.firewall.logRefusedConnections = false;
|
||||
console.keyMap = "no";
|
||||
programs.command-not-found.enable = false;
|
||||
i18n.supportedLocales = [ "en_US.UTF-8/UTF-8" ];
|
||||
# environment.noXlibs = true;
|
||||
|
||||
documentation = {
|
||||
info.enable = false;
|
||||
man.enable = false;
|
||||
};
|
||||
|
||||
security = {
|
||||
polkit.enable = lib.mkForce false;
|
||||
audit.enable = false;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -2,17 +2,14 @@
|
||||
mkShell,
|
||||
python,
|
||||
ruff,
|
||||
uv,
|
||||
}:
|
||||
|
||||
mkShell {
|
||||
packages = [
|
||||
ruff
|
||||
uv
|
||||
(python.withPackages (ps: with ps; [
|
||||
brother-ql
|
||||
matplotlib
|
||||
libdib
|
||||
psycopg2
|
||||
python-barcode
|
||||
sqlalchemy
|
||||
|
@ -15,15 +15,11 @@ dependencies = [
|
||||
"SQLAlchemy >= 2.0, <2.1",
|
||||
"brother-ql",
|
||||
"matplotlib",
|
||||
"libdib",
|
||||
"psycopg2 >= 2.8, <2.10",
|
||||
"python-barcode",
|
||||
]
|
||||
dynamic = ["version"]
|
||||
|
||||
[tool.uv.sources]
|
||||
libdib = { git = "https://git.pvv.ntnu.no/Projects/libdib.git" }
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
include = ["dibbler*"]
|
||||
|
||||
|
Reference in New Issue
Block a user