From ed50c28e02f4be810b2a492717904ec8cd5a4970 Mon Sep 17 00:00:00 2001 From: Mitchell Pomery Date: Sun, 8 Mar 2015 22:54:43 +0800 Subject: [PATCH] DispenseInterface and OpenDispense Implimentation created and tested. Not curruntly used by VendServer --- VendServer/DispenseInterface.py | 70 +++++++++++++++ VendServer/OpenDispense.py | 126 +++++++++++++++++++++++++++ VendServer/OpenDispenseMappings.conf | 76 ++++++++++++++++ 3 files changed, 272 insertions(+) create mode 100644 VendServer/DispenseInterface.py create mode 100644 VendServer/OpenDispense.py create mode 100644 VendServer/OpenDispenseMappings.conf diff --git a/VendServer/DispenseInterface.py b/VendServer/DispenseInterface.py new file mode 100644 index 0000000..81a3f06 --- /dev/null +++ b/VendServer/DispenseInterface.py @@ -0,0 +1,70 @@ +""" +Author: Mitchell Pomery (bobgeorge33) + +Dispense is an abstract class that allows easy configuration between different systems. Anything that is +intended to talk to OpenDispense or similar should comply with this class. Using this class in particular +will cause you a lot of problems. +""" + +class DispenseInterface(object): + + """ + Create a new dispense object. + """ + def __init__(self, username=None, loggedIn=False, disabled=False): + pass + + """ + Create a new dispense interface as the supplied user. + """ + @staticmethod + def authUsernamePin(username, pin): + pass + + """ + Create a new dispense interface as the supplied user. + """ + @staticmethod + def authMifare(cardId): + pass + + """ + Check if creating the user worked correctly. + """ + def isLoggedIn(self): + pass + + """ + Get the users username. + """ + def getUsername(self, user): + pass + + """ + Get the users current balance. + """ + def getBalance(self, user): + pass + + """ + Get the name and price of an item. + itemId is the number entered into the vending machine + """ + @staticmethod + def getItemInfo(itemId): + pass + + """ + Check if the user is disabled. + """ + def isDisabled(self): + pass + + """ + Dispense an item for the current user. + itemId is the number entered into the vending machine + """ + def dispenseItem(self, itemId): + pass + + diff --git a/VendServer/OpenDispense.py b/VendServer/OpenDispense.py new file mode 100644 index 0000000..f8cee0d --- /dev/null +++ b/VendServer/OpenDispense.py @@ -0,0 +1,126 @@ +from DispenseInterface import DispenseInterface +import os +import re +import pwd +from subprocess import Popen, PIPE +from LDAPConnector import get_uid,get_uname, set_card_id + +""" +Author: Mitchell Pomery (bobgeorge33) + +System to connect to OpenDispense2. +Most of this code has been copied out of VendServer.py, then had variables updated so that it runs. +This is so VendServer can easily operate regardless of the current accounting backend. +Documentation for this code can be found inder Dispence.DispenceInterface +""" +class OpenDispense(DispenseInterface): + _username = None + _disabled = True + _loggedIn = False + _userId = None + + def __init__(self, userId=None, username=None, loggedIn=False): + self._username = username + self._loggedIn = loggedIn + self._userId = userId + + acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate() + # this is fucking appalling + flags = acct[acct.find("(")+1:acct.find(")")].strip() + if 'disabled' in flags: + self._disabled = True + if 'internal' in flags: + self._disabled = True + self._disabled = False + + @staticmethod + def authUserIdPin(userId, pin): + try: + # Get info from + info = pwd.getpwuid(userId) + except KeyError: + logging.info('getting pin for uid %d: user not in password file'%uid) + return None + + if info.pw_dir == None: return False + pinfile = os.path.join(info.pw_dir, '.pin') + try: + s = os.stat(pinfile) + except OSError: + logging.info('getting pin for uid %d: .pin not found in home directory'%uid) + return None + if s.st_mode & 077: + logging.info('getting pin for uid %d: .pin has wrong permissions. Fixing.'%uid) + os.chmod(pinfile, 0600) + try: + f = file(pinfile) + except IOError: + logging.info('getting pin for uid %d: I cannot read pin file'%uid) + return None + pinstr = f.readline().strip() + f.close() + if not re.search('^[0-9]{4}$', pinstr): + logging.info('getting pin for uid %d: %s not a good pin'%(uid,repr(pinstr))) + return None + return OpenDispense(userId, info.pw_name, (int(pin)==int(pinstr))) + + @staticmethod + def authMifareCard(cardId): + return OpenDispense(get_uid(cardId), get_uname(get_uid(cardId)), True) + + def addCard(self, cardId): + set_card_id(self._userId, cardId) + + def isLoggedIn(self): + return self._loggedIn + + def getUsername(self): + return self._username + + def getBalance(self): + # Balance checking + acct, unused = Popen(['dispense', 'acct', self._username], close_fds=True, stdout=PIPE).communicate() + # this is fucking appalling + balance = acct[acct.find("$")+1:acct.find("(")].strip() + return balance + + def getItemInfo(itemId): + itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId) + args = ('dispense', 'iteminfo', itemId) + info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate() + m = re.match("\s*[a-z]+:\d+\s+(\d+)\.(\d\d)\s+([^\n]+)", info) + cents = int(m.group(1))*100 + int(m.group(2)) + # return (name, price in cents) + return (m.group(3), cents) + + def isDisabled(self): + return False + + def dispenseItem(self, itemId): + itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId) + if itemId == "": + return False + else: + print('dispense -u "%s" %s'%(self._username, itemId)) + os.system('dispense -u "%s" %s'%(self._username, itemId)) + return True + +""" +This class abstracts the idea of item numbers. +It removes the need for VendServer to know the mappings between inputted numbers +and the equivalent itemId in OpenDispense. +""" +class OpenDispenseMapping(): + + @staticmethod + def vendingMachineToOpenDispense(itemId): + _mappingFile = "OpenDispenseMappings.conf" + fh = open(_mappingFile) + map = "" + for line in fh: + #line = line.strip() + if line.startswith(str(itemId) + " "): + map = line[len(str(itemId)) + 1:].strip() + print(map) + return map + diff --git a/VendServer/OpenDispenseMappings.conf b/VendServer/OpenDispenseMappings.conf new file mode 100644 index 0000000..61485ca --- /dev/null +++ b/VendServer/OpenDispenseMappings.conf @@ -0,0 +1,76 @@ +# This file is used to map things from vending machine inputs into OpenDispense items +# Lines that start with a # are comments +# Lines that contain only white space are ignored + +# The top three rows only contain 5 slots for items + +11 snack:11 +31 snack:31 +51 snack:51 +71 snack:71 +91 snack:91 + +12 snack:12 +32 snack:32 +52 snack:52 +72 snack:72 +92 snack:92 + +13 snack:13 +33 snack:33 +53 snack:53 +73 snack:73 +93 snack:93 + +# This row has 10 + +04 snack:04 +14 snack:14 +24 snack:24 +34 snack:34 +44 snack:44 +54 snack:54 +64 snack:64 +74 snack:74 +84 snack:84 +94 snack:94 + +# Row 5 is used only for door + +55 door + +# The next two rows have 10 items each + +06 snack:06 +16 snack:16 +26 snack:26 +36 snack:36 +46 snack:46 +56 snack:56 +66 snack:66 +76 snack:76 +86 snack:86 +96 snack:96 + +07 snack:07 +17 snack:17 +27 snack:27 +37 snack:37 +47 snack:47 +57 snack:57 +67 snack:67 +77 snack:77 +87 snack:87 +97 snack:97 + +# This last lot is for coke + +08 coke:0 +18 coke:1 +28 coke:2 +38 coke:3 +48 coke:4 +58 coke:5 +68 coke:6 + +# There is no row 9 -- 2.20.1