首页 > 技术文章 > Python实现ATM+购物商城

larry-luo 2019-05-13 15:48 原文

 

需求:

模拟实现一个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))
复制代码

 

推荐阅读