Python实现ATM+购物商城
需求:
模拟实现一个ATM + 购物商城程序
额度 15000或自定义
实现购物商城,买东西加入 购物车,调用信用卡接口结账
可以提现,手续费5%
每月22号出账单,每月10号为还款日,过期未还,按欠款总额 万分之5 每日计息
支持多账户登录
支持账户间转账
记录每月日常消费流水
提供还款接口
ATM记录操作日志
提供管理接口,包括添加账户、用户额度,冻结账户等。。。
用户认证用装饰器
实现功能:
额度 15000或自定义
实现购物商城,买东西加入 购物车,调用信用卡接口结账
可以提现,手续费5%
支持多账户登录
记录每月日常消费流水
提供还款接口
ATM记录操作日志
提供管理接口,包括添加账户、用户额度,冻结账户等。。。
用户认证用装饰器
程序结构:
atm/
├── README
└── atm #ATM主程目录
├── __init__.py
├── bin #ATM 执行文件 目录
│ ├── __init__.py
│ ├── atm.py #ATM 执行程序
│ └── manage.py #ATM 管理端,未实现
├── conf #配置文件
│ ├── __init__.py
│ └── settings.py
├── core #主要程序逻辑都 在这个目录 里
│ ├── __init__.py
│ ├── accounts.py #用于从文件里加载和存储账户数据
│ ├── auth.py #用户认证模块
│ ├── db_handler.py #数据库连接引擎
│ ├── logger.py #日志记录模块
│ ├── main.py #主逻辑交互程序
│ └── transaction.py #记账\还钱\取钱等所有的与账户金额相关的操作都 在这
├── db #用户数据存储的地方
│ ├── __init__.py
│ ├── account_sample.py #生成一个初始的账户数据 ,把这个数据 存成一个 以这个账户id为文件名的文件,放在accounts目录 就行了,程序自己去会这里找
│ └── accounts #存各个用户的账户数据 ,一个用户一个文件
│ └── 1234.json #一个用户账户示例文件
└── log #日志目录
├── __init__.py
├── access.log #用户访问和操作的相关日志
└── transactions.log #所有的交易日志
二、流程图
三、代码
bin/atm.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print(base_dir)
sys.path.append(base_dir)
from core import main
if __name__ == '__main__':
main.run()
conf/settings.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import logging
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATABASE = {
'engine': 'file_storage', #support mysql,postgresql in the future
'name':'accounts',
'path': "%s/db" % BASE_DIR
}
LOG_LEVEL = logging.INFO
LOG_TYPES = {
'transaction': 'transactions.log',
'access': 'access.log',
}
TRANSACTION_TYPE = {
'repay':{'action':'plus', 'interest':0.03},
'withdraw':{'action':'minus', 'interest':0.05},
'transfer':{'action':'minus', 'interest':0.05},
'consume':{'action':'minus', 'interest':0},
}
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 import os 4 import sys 5 import logging 6 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 7 8 9 DATABASE = { 10 'engine': 'file_storage', #support mysql,postgresql in the future 11 'name':'accounts', 12 'path': "%s/db" % BASE_DIR 13 } 14 15 16 LOG_LEVEL = logging.INFO 17 LOG_TYPES = { 18 'transaction': 'transactions.log', 19 'access': 'access.log', 20 } 21 22 TRANSACTION_TYPE = { 23 'repay':{'action':'plus', 'interest':0.03}, 24 'withdraw':{'action':'minus', 'interest':0.05}, 25 'transfer':{'action':'minus', 'interest':0.05}, 26 'consume':{'action':'minus', 'interest':0}, 27 28 }
core/main.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
main program handle module , handle all the user interaction stuff
'''
from core import auth
from core import accounts
from core import logger
from core import accounts
from core import transaction
from core.auth import login_required
import time
#transaction logger
trans_logger = logger.logger('transaction')
#access logger
access_logger = logger.logger('access')
#temp account data ,only saves the data in memory
user_data = {
'account_id':None,
'is_authenticated':False,
'account_data':None
}
def account_info(acc_data):
account_data = accounts.load_current_balance(acc_data['account_id'])
data_info = u'''
\033[34;1m 账号ID:%s
余额: %s
信用度:%s
账号注册时间:%s
账号过期时间:%s
工资天数:%s
\033[0m'''%(acc_data['account_id'],
account_data['balance'],
account_data['credit'],
account_data['enroll_date'],
account_data['expire_date'],
account_data['pay_day'],)
print(data_info)
@login_required
def repay(acc_data):
'''
print current balance and let user repay the bill
:return:
'''
account_data = accounts.load_current_balance(acc_data['account_id'])
#再从硬盘加载一次数据, 为了确保数据是最新的
#for k,v in account_data.items():
# print(k,v )
current_balance= ''' --------- BALANCE INFO --------
Credit : %s
Balance: %s''' %(account_data['credit'],account_data['balance'])
print(current_balance)
back_flag = False
while not back_flag:
repay_amount = input("\033[33;1mInput repay amount:\033[0m").strip()
if len(repay_amount) >0 and repay_amount.isdigit():
#print('ddd 00')
new_balance = transaction.make_transaction(trans_logger,account_data,'repay', repay_amount)
if new_balance:
print('''\033[42;1mNew Balance:%s\033[0m''' %(new_balance['balance']))
else:
print('\033[31;1m[%s] is not a valid amount, only accept integer!\033[0m' % repay_amount)
if repay_amount == 'b':
back_flag = True
def withdraw(acc_data):
'''
print current balance and let user do the withdraw action
:param acc_data:
:return:
'''
account_data = accounts.load_current_balance(acc_data['account_id'])
current_balance= ''' --------- BALANCE INFO --------
Credit : %s
Balance: %s''' %(account_data['credit'],account_data['balance'])
print(current_balance)
back_flag = False
while not back_flag:
withdraw_amount = input("\033[33;1mInput withdraw amount:\033[0m").strip()
if len(withdraw_amount) >0 and withdraw_amount.isdigit():
new_balance = transaction.make_transaction(trans_logger,account_data,'withdraw', withdraw_amount)
if new_balance:
print('''\033[42;1mNew Balance:%s\033[0m''' %(new_balance['balance']))
else:
print('\033[31;1m[%s] is not a valid amount, only accept integer!\033[0m' % withdraw_amount)
if withdraw_amount == 'b':
back_flag = True
def transfer(acc_data):
pass
def pay_check(acc_data):
pass
def logout(acc_data):
exit()
def shopping(acc_data):
'''
:param acc_data:
:return:
'''
product_list = [
['Iphone7 Plus', 6500],
['Iphone8 ', 8200],
['MacBook Pro', 12000],
['Python Book', 99],
['Coffee', 33],
['Bike', 666],
['pen', 2]
]
shopping_cart = []
count = 0
salary = acc_data['account_data']['balance']
while True:
account_data = accounts.load_current_balance(acc_data['account_id'])
print(">> 欢迎来到电子商城 您的余额是 %s 元<<" % (salary))
for index, i in enumerate(product_list): # 循环商品列表,商品列表索引
print("%s.\t%s\t%s" % (index, i[0], i[1])) # 打印商品列表,显示商品列表索引
choice = input(">>请输入商品序号或输入 exit 退出商城>>: ").strip()
if len(choice) == 0: # 判断输入字符串是否为空和字符串长度
print('-->您没有选择商品<--')
continue
if choice.isdigit(): # 判断输入的choice是不是一个数字
choice = int(choice) # 把输入的字符串转成整型
if choice < len(product_list) and choice >= 0: # 输入的整数必须小于商品列表的数量
product_item = product_list[choice] # 获取商品
if salary >= product_item[1]: # 拿现有金额跟商品对比,是否买得起
salary -= product_item[1] # 扣完商品的价格
shopping_cart.append(product_item) # 把选着的商品加入购物车
print("添加 \033[32;1m%s\033[0m 到购物车,您目前的金额是 \
\033[31;1m%s\033[0m" % (product_item[0], salary))
else:
print("对不起,您的金额不足,还差 \033[31;1m%s\033[0m" % (product_item[1] - salary,))
else:
print("-->没有此商品<--")
elif choice == "exit":
total_cost = 0
print("您的购物车列表:")
for i in shopping_cart:
print(i)
total_cost += i[1]
print("您的购物车总价是: \033[31;1m%s\033[0m" % (total_cost,))
print("您目前的余额是: \033[31;1m%s\033[0m" % (salary,))
new_balance = transaction.make_transaction(trans_logger, account_data, 'withdraw', total_cost)
if new_balance:
print('''\033[42;1mNew Balance:%s\033[0m''' % (new_balance['balance']))
break
def interactive(acc_data):
'''
interact with user
:return:
'''
menu = u'''
------- hehe Bank ---------
\033[32;1m
1. 账户信息(实现)
2. 还款(实现)
3. 取款(实现)
4. 转账
5. 账单
6. 商城(实现)
7. 退出(实现)
\033[0m'''
menu_dic = {
'1': account_info,
'2': repay,
'3': withdraw,
'4': transfer,
'5': pay_check,
'6': shopping,
'7': logout,
}
exit_flag = False
while not exit_flag:
print(menu)
user_option = input(">>:").strip()
if user_option in menu_dic:
#print('accdata',acc_data)
#acc_data['is_authenticated'] =False
menu_dic[user_option](acc_data)
else:
print("\033[31;1mOption does not exist!\033[0m")
def run():
'''
this function will be called right a way when the program started, here handles the user interaction stuff
:return:
'''
acc_data = auth.acc_login(user_data,access_logger)
if user_data['is_authenticated']:
user_data['account_data'] = acc_data
interactive(user_data)
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 ''' 5 main program handle module , handle all the user interaction stuff 6 7 ''' 8 9 from core import auth 10 from core import accounts 11 from core import logger 12 from core import accounts 13 from core import transaction 14 from core.auth import login_required 15 import time 16 17 #transaction logger 18 trans_logger = logger.logger('transaction') 19 #access logger 20 access_logger = logger.logger('access') 21 22 23 #temp account data ,only saves the data in memory 24 user_data = { 25 'account_id':None, 26 'is_authenticated':False, 27 'account_data':None 28 29 } 30 31 def account_info(acc_data): 32 account_data = accounts.load_current_balance(acc_data['account_id']) 33 data_info = u''' 34 \033[34;1m 账号ID:%s 35 余额: %s 36 信用度:%s 37 账号注册时间:%s 38 账号过期时间:%s 39 工资天数:%s 40 \033[0m'''%(acc_data['account_id'], 41 account_data['balance'], 42 account_data['credit'], 43 account_data['enroll_date'], 44 account_data['expire_date'], 45 account_data['pay_day'],) 46 print(data_info) 47 48 49 @login_required 50 def repay(acc_data): 51 ''' 52 print current balance and let user repay the bill 53 :return: 54 ''' 55 account_data = accounts.load_current_balance(acc_data['account_id']) 56 #再从硬盘加载一次数据, 为了确保数据是最新的 57 #for k,v in account_data.items(): 58 # print(k,v ) 59 current_balance= ''' --------- BALANCE INFO -------- 60 Credit : %s 61 Balance: %s''' %(account_data['credit'],account_data['balance']) 62 print(current_balance) 63 back_flag = False 64 while not back_flag: 65 repay_amount = input("\033[33;1mInput repay amount:\033[0m").strip() 66 if len(repay_amount) >0 and repay_amount.isdigit(): 67 #print('ddd 00') 68 new_balance = transaction.make_transaction(trans_logger,account_data,'repay', repay_amount) 69 if new_balance: 70 print('''\033[42;1mNew Balance:%s\033[0m''' %(new_balance['balance'])) 71 72 else: 73 print('\033[31;1m[%s] is not a valid amount, only accept integer!\033[0m' % repay_amount) 74 75 if repay_amount == 'b': 76 back_flag = True 77 def withdraw(acc_data): 78 ''' 79 print current balance and let user do the withdraw action 80 :param acc_data: 81 :return: 82 ''' 83 account_data = accounts.load_current_balance(acc_data['account_id']) 84 current_balance= ''' --------- BALANCE INFO -------- 85 Credit : %s 86 Balance: %s''' %(account_data['credit'],account_data['balance']) 87 print(current_balance) 88 back_flag = False 89 while not back_flag: 90 withdraw_amount = input("\033[33;1mInput withdraw amount:\033[0m").strip() 91 if len(withdraw_amount) >0 and withdraw_amount.isdigit(): 92 new_balance = transaction.make_transaction(trans_logger,account_data,'withdraw', withdraw_amount) 93 if new_balance: 94 print('''\033[42;1mNew Balance:%s\033[0m''' %(new_balance['balance'])) 95 96 else: 97 print('\033[31;1m[%s] is not a valid amount, only accept integer!\033[0m' % withdraw_amount) 98 99 if withdraw_amount == 'b': 100 back_flag = True 101 102 def transfer(acc_data): 103 pass 104 def pay_check(acc_data): 105 pass 106 def logout(acc_data): 107 exit() 108 109 110 def shopping(acc_data): 111 ''' 112 113 :param acc_data: 114 :return: 115 ''' 116 product_list = [ 117 ['Iphone7 Plus', 6500], 118 ['Iphone8 ', 8200], 119 ['MacBook Pro', 12000], 120 ['Python Book', 99], 121 ['Coffee', 33], 122 ['Bike', 666], 123 ['pen', 2] 124 ] 125 shopping_cart = [] 126 count = 0 127 salary = acc_data['account_data']['balance'] 128 while True: 129 account_data = accounts.load_current_balance(acc_data['account_id']) 130 print(">> 欢迎来到电子商城 您的余额是 %s 元<<" % (salary)) 131 for index, i in enumerate(product_list): # 循环商品列表,商品列表索引 132 print("%s.\t%s\t%s" % (index, i[0], i[1])) # 打印商品列表,显示商品列表索引 133 choice = input(">>请输入商品序号或输入 exit 退出商城>>: ").strip() 134 if len(choice) == 0: # 判断输入字符串是否为空和字符串长度 135 print('-->您没有选择商品<--') 136 continue 137 if choice.isdigit(): # 判断输入的choice是不是一个数字 138 choice = int(choice) # 把输入的字符串转成整型 139 if choice < len(product_list) and choice >= 0: # 输入的整数必须小于商品列表的数量 140 product_item = product_list[choice] # 获取商品 141 if salary >= product_item[1]: # 拿现有金额跟商品对比,是否买得起 142 salary -= product_item[1] # 扣完商品的价格 143 shopping_cart.append(product_item) # 把选着的商品加入购物车 144 print("添加 \033[32;1m%s\033[0m 到购物车,您目前的金额是 \ 145 \033[31;1m%s\033[0m" % (product_item[0], salary)) 146 else: 147 print("对不起,您的金额不足,还差 \033[31;1m%s\033[0m" % (product_item[1] - salary,)) 148 else: 149 print("-->没有此商品<--") 150 elif choice == "exit": 151 total_cost = 0 152 print("您的购物车列表:") 153 for i in shopping_cart: 154 print(i) 155 total_cost += i[1] 156 print("您的购物车总价是: \033[31;1m%s\033[0m" % (total_cost,)) 157 print("您目前的余额是: \033[31;1m%s\033[0m" % (salary,)) 158 new_balance = transaction.make_transaction(trans_logger, account_data, 'withdraw', total_cost) 159 if new_balance: 160 print('''\033[42;1mNew Balance:%s\033[0m''' % (new_balance['balance'])) 161 break 162 163 164 def interactive(acc_data): 165 ''' 166 interact with user 167 :return: 168 ''' 169 menu = u''' 170 ------- hehe Bank --------- 171 \033[32;1m 172 1. 账户信息(实现) 173 2. 还款(实现) 174 3. 取款(实现) 175 4. 转账 176 5. 账单 177 6. 商城(实现) 178 7. 退出(实现) 179 \033[0m''' 180 menu_dic = { 181 '1': account_info, 182 '2': repay, 183 '3': withdraw, 184 '4': transfer, 185 '5': pay_check, 186 '6': shopping, 187 '7': logout, 188 } 189 exit_flag = False 190 while not exit_flag: 191 print(menu) 192 user_option = input(">>:").strip() 193 if user_option in menu_dic: 194 #print('accdata',acc_data) 195 #acc_data['is_authenticated'] =False 196 menu_dic[user_option](acc_data) 197 198 else: 199 print("\033[31;1mOption does not exist!\033[0m") 200 def run(): 201 ''' 202 this function will be called right a way when the program started, here handles the user interaction stuff 203 :return: 204 ''' 205 acc_data = auth.acc_login(user_data,access_logger) 206 if user_data['is_authenticated']: 207 user_data['account_data'] = acc_data 208 interactive(user_data)
core/transaction.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from conf import settings
from core import accounts
from core import logger
#transaction logger
def make_transaction(log_obj,account_data,tran_type,amount,**others):
'''
deal all the user transactions
:param account_data: user account data
:param tran_type: transaction type
:param amount: transaction amount
:param others: mainly for logging usage
:return:
'''
amount = float(amount)
if tran_type in settings.TRANSACTION_TYPE:
interest = amount * settings.TRANSACTION_TYPE[tran_type]['interest']
old_balance = account_data['balance']
if settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus':
new_balance = old_balance + amount + interest
elif settings.TRANSACTION_TYPE[tran_type]['action'] == 'minus':
new_balance = old_balance - amount - interest
#check credit
if new_balance <0:
print('''\033[31;1mYour credit [%s] is not enough for this transaction [-%s], your current balance is
[%s]''' %(account_data['credit'],(amount + interest), old_balance ))
return
account_data['balance'] = new_balance
accounts.dump_account(account_data) #save the new balance back to file
log_obj.info("account:%s action:%s amount:%s interest:%s" %
(account_data['id'], tran_type, amount,interest) )
return account_data
else:
print("\033[31;1mTransaction type [%s] is not exist!\033[0m" % tran_type)
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 from conf import settings 5 from core import accounts 6 from core import logger 7 #transaction logger 8 9 10 11 def make_transaction(log_obj,account_data,tran_type,amount,**others): 12 ''' 13 deal all the user transactions 14 :param account_data: user account data 15 :param tran_type: transaction type 16 :param amount: transaction amount 17 :param others: mainly for logging usage 18 :return: 19 ''' 20 amount = float(amount) 21 if tran_type in settings.TRANSACTION_TYPE: 22 23 interest = amount * settings.TRANSACTION_TYPE[tran_type]['interest'] 24 old_balance = account_data['balance'] 25 if settings.TRANSACTION_TYPE[tran_type]['action'] == 'plus': 26 new_balance = old_balance + amount + interest 27 elif settings.TRANSACTION_TYPE[tran_type]['action'] == 'minus': 28 new_balance = old_balance - amount - interest 29 #check credit 30 if new_balance <0: 31 print('''\033[31;1mYour credit [%s] is not enough for this transaction [-%s], your current balance is 32 [%s]''' %(account_data['credit'],(amount + interest), old_balance )) 33 return 34 account_data['balance'] = new_balance 35 accounts.dump_account(account_data) #save the new balance back to file 36 log_obj.info("account:%s action:%s amount:%s interest:%s" % 37 (account_data['id'], tran_type, amount,interest) ) 38 return account_data 39 else: 40 print("\033[31;1mTransaction type [%s] is not exist!\033[0m" % tran_type)
core/accounts.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import time
from core import db_handler
from conf import settings
def load_current_balance(account_id):
'''
return account balance and other basic info
:param account_id:
:return:
'''
# db_path = db_handler.db_handler(settings.DATABASE)
# account_file = "%s/%s.json" %(db_path,account_id)
#
db_api = db_handler.db_handler()
data = db_api("select * from accounts where account=%s" % account_id)
return data
# with open(account_file) as f:
# acc_data = json.load(f)
# return acc_data
def dump_account(account_data):
'''
after updated transaction or account data , dump it back to file db
:param account_data:
:return:
'''
db_api = db_handler.db_handler()
data = db_api("update accounts where account=%s" % account_data['id'],account_data=account_data)
# db_path = db_handler.db_handler(settings.DATABASE)
# account_file = "%s/%s.json" %(db_path,account_data['id'])
# with open(account_file, 'w') as f:
# acc_data = json.dump(account_data,f)
return True
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 import json 5 import time 6 from core import db_handler 7 from conf import settings 8 9 10 def load_current_balance(account_id): 11 ''' 12 return account balance and other basic info 13 :param account_id: 14 :return: 15 ''' 16 # db_path = db_handler.db_handler(settings.DATABASE) 17 # account_file = "%s/%s.json" %(db_path,account_id) 18 # 19 db_api = db_handler.db_handler() 20 data = db_api("select * from accounts where account=%s" % account_id) 21 22 return data 23 24 # with open(account_file) as f: 25 # acc_data = json.load(f) 26 # return acc_data 27 def dump_account(account_data): 28 ''' 29 after updated transaction or account data , dump it back to file db 30 :param account_data: 31 :return: 32 ''' 33 db_api = db_handler.db_handler() 34 data = db_api("update accounts where account=%s" % account_data['id'],account_data=account_data) 35 36 # db_path = db_handler.db_handler(settings.DATABASE) 37 # account_file = "%s/%s.json" %(db_path,account_data['id']) 38 # with open(account_file, 'w') as f: 39 # acc_data = json.dump(account_data,f) 40 41 return True
core/auth.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from core import db_handler
from conf import settings
from core import logger
import json
import time
def login_required(func):
"验证用户是否登录"
def wrapper(*args,**kwargs):
#print('--wrapper--->',args,kwargs)
if args[0].get('is_authenticated'):
return func(*args,**kwargs)
else:
exit("User is not authenticated.")
return wrapper
def acc_auth(account,password):
'''
account auth func
:param account: credit account number
:param password: credit card password
:return: if passed the authentication , retun the account object, otherwise ,return None
'''
db_path = db_handler.db_handler(settings.DATABASE)
account_file = "%s/%s.json" %(db_path,account)
print(account_file)
if os.path.isfile(account_file):
with open(account_file,'r') as f:
account_data = json.load(f)
if account_data['password'] == password:
exp_time_stamp = time.mktime(time.strptime(account_data['expire_date'], "%Y-%m-%d"))
if time.time() >exp_time_stamp:
print("\033[31;1mAccount [%s] has expired,please contact the back to get a new card!\033[0m" % account)
else: #passed the authentication
return account_data
else:
print("\033[31;1mAccount ID or password is incorrect!\033[0m")
else:
print("\033[31;1mAccount [%s] does not exist!\033[0m" % account)
def acc_auth2(account,password):
'''
优化版认证接口
:param account: credit account number
:param password: credit card password
:return: if passed the authentication , retun the account object, otherwise ,return None
'''
db_api = db_handler.db_handler() #连接数据库 file_execute内存地址
data = db_api("select * from accounts where account=%s" % account) #执行sql
if data['password'] == password:
exp_time_stamp = time.mktime(time.strptime(data['expire_date'], "%Y-%m-%d"))
if time.time() > exp_time_stamp:
print("\033[31;1mAccount [%s] has expired,please contact the back to get a new card!\033[0m" % account)
else: # passed the authentication
return data
else:
print("\033[31;1mAccount ID or password is incorrect!\033[0m")
def acc_login(user_data,log_obj):
'''
account login func
:user_data: user info data , only saves in memory
:return:
'''
retry_count = 0
while user_data['is_authenticated'] is not True and retry_count < 3 :
account = input("\033[32;1maccount:\033[0m").strip()
password = input("\033[32;1mpassword:\033[0m").strip()
auth = acc_auth2(account, password)
if auth: #not None means passed the authentication
user_data['is_authenticated'] = True
user_data['account_id'] = account
#print("welcome")
return auth
retry_count +=1
else:
log_obj.error("account [%s] too many login attempts" % account)
exit()
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 import os 4 from core import db_handler 5 from conf import settings 6 from core import logger 7 import json 8 import time 9 10 11 12 def login_required(func): 13 "验证用户是否登录" 14 15 def wrapper(*args,**kwargs): 16 #print('--wrapper--->',args,kwargs) 17 if args[0].get('is_authenticated'): 18 return func(*args,**kwargs) 19 else: 20 exit("User is not authenticated.") 21 return wrapper 22 23 24 def acc_auth(account,password): 25 ''' 26 account auth func 27 :param account: credit account number 28 :param password: credit card password 29 :return: if passed the authentication , retun the account object, otherwise ,return None 30 ''' 31 db_path = db_handler.db_handler(settings.DATABASE) 32 account_file = "%s/%s.json" %(db_path,account) 33 print(account_file) 34 if os.path.isfile(account_file): 35 with open(account_file,'r') as f: 36 account_data = json.load(f) 37 if account_data['password'] == password: 38 exp_time_stamp = time.mktime(time.strptime(account_data['expire_date'], "%Y-%m-%d")) 39 if time.time() >exp_time_stamp: 40 print("\033[31;1mAccount [%s] has expired,please contact the back to get a new card!\033[0m" % account) 41 else: #passed the authentication 42 return account_data 43 else: 44 print("\033[31;1mAccount ID or password is incorrect!\033[0m") 45 else: 46 print("\033[31;1mAccount [%s] does not exist!\033[0m" % account) 47 48 49 def acc_auth2(account,password): 50 ''' 51 优化版认证接口 52 :param account: credit account number 53 :param password: credit card password 54 :return: if passed the authentication , retun the account object, otherwise ,return None 55 56 ''' 57 db_api = db_handler.db_handler() #连接数据库 file_execute内存地址 58 data = db_api("select * from accounts where account=%s" % account) #执行sql 59 if data['password'] == password: 60 exp_time_stamp = time.mktime(time.strptime(data['expire_date'], "%Y-%m-%d")) 61 if time.time() > exp_time_stamp: 62 print("\033[31;1mAccount [%s] has expired,please contact the back to get a new card!\033[0m" % account) 63 else: # passed the authentication 64 return data 65 else: 66 print("\033[31;1mAccount ID or password is incorrect!\033[0m") 67 68 def acc_login(user_data,log_obj): 69 ''' 70 account login func 71 :user_data: user info data , only saves in memory 72 :return: 73 ''' 74 retry_count = 0 75 while user_data['is_authenticated'] is not True and retry_count < 3 : 76 account = input("\033[32;1maccount:\033[0m").strip() 77 password = input("\033[32;1mpassword:\033[0m").strip() 78 auth = acc_auth2(account, password) 79 if auth: #not None means passed the authentication 80 user_data['is_authenticated'] = True 81 user_data['account_id'] = account 82 #print("welcome") 83 return auth 84 retry_count +=1 85 else: 86 log_obj.error("account [%s] too many login attempts" % account) 87 exit()
core/db_handler.py
#!_*_coding:utf-8_*_
#__author__:"Alex Li"
'''
handle all the database interactions
'''
import json,time ,os
from conf import settings
def file_db_handle(conn_params):
'''
parse the db file path
:param conn_params: the db connection params set in settings
:return:
'''
# print('file db:',conn_params)
#db_path ='%s/%s' %(conn_params['path'],conn_params['name'])
return file_execute
def db_handler():
'''
connect to db
:param conn_parms: the db connection params set in settings
:return:a
'''
conn_params = settings.DATABASE
if conn_params['engine'] == 'file_storage':
return file_db_handle(conn_params)
elif conn_params['engine'] == 'mysql':
pass #todo
def file_execute(sql,**kwargs):
conn_params = settings.DATABASE
db_path = '%s/%s' % (conn_params['path'], conn_params['name'])
# print(sql,db_path)
sql_list = sql.split("where")
# print(sql_list)
if sql_list[0].startswith("select") and len(sql_list)> 1:#has where clause
column,val = sql_list[1].strip().split("=")
if column == 'account':
account_file = "%s/%s.json" % (db_path, val)
print(account_file)
if os.path.isfile(account_file):
with open(account_file, 'r') as f:
account_data = json.load(f)
return account_data
else:
exit("\033[31;1mAccount [%s] does not exist!\033[0m" % val )
elif sql_list[0].startswith("update") and len(sql_list)> 1:#has where clause
column, val = sql_list[1].strip().split("=")
if column == 'account':
account_file = "%s/%s.json" % (db_path, val)
#print(account_file)
if os.path.isfile(account_file):
account_data = kwargs.get("account_data")
with open(account_file, 'w') as f:
acc_data = json.dump(account_data, f)
return True
1 #!_*_coding:utf-8_*_ 2 #__author__:"Alex Li" 3 4 ''' 5 handle all the database interactions 6 ''' 7 import json,time ,os 8 from conf import settings 9 def file_db_handle(conn_params): 10 ''' 11 parse the db file path 12 :param conn_params: the db connection params set in settings 13 :return: 14 ''' 15 # print('file db:',conn_params) 16 #db_path ='%s/%s' %(conn_params['path'],conn_params['name']) 17 return file_execute 18 def db_handler(): 19 ''' 20 connect to db 21 :param conn_parms: the db connection params set in settings 22 :return:a 23 ''' 24 conn_params = settings.DATABASE 25 if conn_params['engine'] == 'file_storage': 26 return file_db_handle(conn_params) 27 elif conn_params['engine'] == 'mysql': 28 pass #todo 29 30 31 32 def file_execute(sql,**kwargs): 33 conn_params = settings.DATABASE 34 db_path = '%s/%s' % (conn_params['path'], conn_params['name']) 35 36 # print(sql,db_path) 37 sql_list = sql.split("where") 38 # print(sql_list) 39 if sql_list[0].startswith("select") and len(sql_list)> 1:#has where clause 40 column,val = sql_list[1].strip().split("=") 41 42 if column == 'account': 43 account_file = "%s/%s.json" % (db_path, val) 44 print(account_file) 45 if os.path.isfile(account_file): 46 with open(account_file, 'r') as f: 47 account_data = json.load(f) 48 return account_data 49 else: 50 exit("\033[31;1mAccount [%s] does not exist!\033[0m" % val ) 51 52 elif sql_list[0].startswith("update") and len(sql_list)> 1:#has where clause 53 column, val = sql_list[1].strip().split("=") 54 if column == 'account': 55 account_file = "%s/%s.json" % (db_path, val) 56 #print(account_file) 57 if os.path.isfile(account_file): 58 account_data = kwargs.get("account_data") 59 with open(account_file, 'w') as f: 60 acc_data = json.dump(account_data, f) 61 return True
core/logger.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
handle all the logging works
'''
import logging
from conf import settings
def logger(log_type):
#create logger
logger = logging.getLogger(log_type)
logger.setLevel(settings.LOG_LEVEL)
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(settings.LOG_LEVEL)
# create file handler and set level to warning
log_file = "%s/log/%s" %(settings.BASE_DIR, settings.LOG_TYPES[log_type])
fh = logging.FileHandler(log_file)
fh.setLevel(settings.LOG_LEVEL)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# add formatter to ch and fh
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# add ch and fh to logger
logger.addHandler(ch)
logger.addHandler(fh)
return logger
# 'application' code
'''logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')'''
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 ''' 5 handle all the logging works 6 ''' 7 8 import logging 9 from conf import settings 10 11 def logger(log_type): 12 13 #create logger 14 logger = logging.getLogger(log_type) 15 logger.setLevel(settings.LOG_LEVEL) 16 17 18 # create console handler and set level to debug 19 ch = logging.StreamHandler() 20 ch.setLevel(settings.LOG_LEVEL) 21 22 # create file handler and set level to warning 23 log_file = "%s/log/%s" %(settings.BASE_DIR, settings.LOG_TYPES[log_type]) 24 fh = logging.FileHandler(log_file) 25 fh.setLevel(settings.LOG_LEVEL) 26 # create formatter 27 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 28 29 # add formatter to ch and fh 30 ch.setFormatter(formatter) 31 fh.setFormatter(formatter) 32 33 # add ch and fh to logger 34 logger.addHandler(ch) 35 logger.addHandler(fh) 36 37 return logger 38 # 'application' code 39 '''logger.debug('debug message') 40 logger.info('info message') 41 logger.warn('warn message') 42 logger.error('error message') 43 logger.critical('critical message')'''
db/account_sample.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
acc_dic = {
'id': 1234,
'password': 'abc',
'credit': 15000,
'balance': 15000,
'enroll_date': '2016-01-02',
'expire_date': '2021-01-01',
'pay_day': 22,
'status': 0 # 0 = normal, 1 = locked, 2 = disabled
}
print(json.dumps(acc_dic))
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 5 import json 6 acc_dic = { 7 'id': 1234, 8 'password': 'abc', 9 'credit': 15000, 10 'balance': 15000, 11 'enroll_date': '2016-01-02', 12 'expire_date': '2021-01-01', 13 'pay_day': 22, 14 'status': 0 # 0 = normal, 1 = locked, 2 = disabled 15 } 16 17 print(json.dumps(acc_dic))