rogerxavier commited on
Commit
ee37dcf
1 Parent(s): f7f23c0

Upload 20 files

Browse files
README.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: payHook
3
+ emoji: 🐨
4
+ colorFrom: pink
5
+ colorTo: pink
6
+ sdk: gradio
7
+ sdk_version: 4.36.1
8
+ app_file: main.py
9
+ pinned: false
10
+ license: mit
11
+ ---
12
+
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
main.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ import uvicorn
2
+
3
+ if __name__ == "__main__":
4
+ uvicorn.run("server.api:app", host="0.0.0.0", port=7860, reload=True)
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ requests==2.31.0
2
+ aiohttp==3.7.3
3
+ fastapi==0.112.0
4
+ urllib3==2.0.7
5
+ tablestore==6.0.1
6
+ pydantic==2.9.1 #用于自定义接口模型
7
+ uvicorn
8
+ mysql-connector-python
server/__pycache__/api.cpython-38.pyc ADDED
Binary file (860 Bytes). View file
 
server/__pycache__/dao_pool.cpython-38.pyc ADDED
Binary file (1.73 kB). View file
 
server/__pycache__/getPoints.cpython-38.pyc ADDED
Binary file (982 Bytes). View file
 
server/__pycache__/getPoolStatus.cpython-38.pyc ADDED
Binary file (474 Bytes). View file
 
server/__pycache__/invite_code_api.cpython-38.pyc ADDED
Binary file (1.26 kB). View file
 
server/__pycache__/utils.cpython-38.pyc ADDED
Binary file (919 Bytes). View file
 
server/__pycache__/verification.cpython-38.pyc ADDED
Binary file (2.33 kB). View file
 
server/account_manager.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+
3
+ from fastapi import HTTPException,APIRouter
4
+ from .pydanticModel import *
5
+ from .dao import tableStore
6
+
7
+ router = APIRouter()
8
+
9
+ # 定义路由和函数
10
+ @router.post("/login")
11
+ @router.get("/login")
12
+ async def login(login: signIn):
13
+ # ->"user info or throw error"
14
+ # 检查email和password是否匹配
15
+ table_store = tableStore(ots_client=router.ots_client,table_name=router.table_name)
16
+ try:
17
+ login_result = table_store.login(login.email, login.password)
18
+ if login_result['ec']==200:
19
+ return login_result
20
+ else:
21
+ raise HTTPException(status_code=400, detail="login failed in table store")
22
+ except Exception as e:
23
+ print(e)
24
+ raise HTTPException(status_code=400, detail="sign in failed")
25
+
26
+ @router.get("/signUp")
27
+ @router.post("/signUp")
28
+ async def sign_up(signUp: signUp):
29
+ # ->"user info or throw error"
30
+ table_store = tableStore(ots_client=router.ots_client,table_name=router.table_name)
31
+ try:
32
+ signUp_result = table_store.userSignUp(signUp.email,signUp.password)
33
+ if signUp_result['ec']==200:
34
+ return signUp_result
35
+ else:
36
+ raise HTTPException(status_code=400, detail="sign up failed in table store")
37
+ except Exception as e:
38
+ raise HTTPException(status_code=400, detail="sign up failed")
39
+
40
+
41
+
42
+
43
+
44
+ @router.get("/purchase")
45
+ @router.post("/purchase")
46
+ async def purchase(plan: userPlan):
47
+ #->bool or raise error
48
+ # 提取plan价格和时间
49
+ price = plan.price
50
+ time_to_add = plan.duration_seconds
51
+ email = plan.email
52
+ password = plan.password
53
+ table_store = tableStore(ots_client=router.ots_client, table_name=router.table_name)
54
+ # 读取存储数据,如果存的expiredAt>now,那么从expiredAt加时间
55
+ # 如果存的<now ,那么从now加时间 (总之是取两者较大+time_to_add)
56
+
57
+ table_store.getUserInfo(email=email)
58
+ cur_balance = table_store.balance
59
+ cur_expired_at = table_store.expired_at
60
+ cur_time = int(time.time())
61
+ user_password_stored = table_store.stored_password
62
+
63
+
64
+ if cur_balance -price <0:
65
+ raise HTTPException(status_code=400, detail="balance not enough")
66
+ elif password!=user_password_stored:
67
+ raise HTTPException(status_code=400, detail="auth not pass in purchase")
68
+ else:
69
+ expired_new = max(cur_expired_at, cur_time) + time_to_add
70
+ balance_new = cur_balance -price
71
+ # 更新余额和时间
72
+ update_balance_result = table_store.updateColumnByPrimaryKey(
73
+ key=router.key,
74
+ key_value=email,
75
+ update_column='balance',
76
+ update_column_value=balance_new
77
+ )
78
+ if not update_balance_result:
79
+ raise HTTPException(status_code=400, detail="updateBalance 结果失败")
80
+ update_expired_result = table_store.updateColumnByPrimaryKey(
81
+ key=router.key,
82
+ key_value=email,
83
+ update_column='expiredAt',
84
+ update_column_value=expired_new
85
+ )
86
+ if not update_expired_result:
87
+ raise HTTPException(status_code=400, detail="update_expired_result 结果失败")
88
+ return True
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
server/api.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from .notify import router as NotifyRouter
3
+ from .utils import config
4
+ from tablestore import OTSClient
5
+ from .account_manager import router as accountManagerRouter
6
+ access_key_id='LTAI5tNwpEHCMTupADmx6xA4'
7
+ access_key_secret="vX1q5Tvj3LSsIMUXN6SPbMUBCET3qG"
8
+ end_point='https://v2b-user-table.ap-southeast-1.ots.aliyuncs.com'
9
+ instance_name='v2b-user-table'
10
+ table_name = 'user'
11
+ primary_key = 'email'
12
+ ots_client = OTSClient(
13
+ end_point=end_point,
14
+ access_key_id=access_key_id,
15
+ access_key_secret=access_key_secret,
16
+ instance_name=instance_name
17
+ )
18
+
19
+ accountManagerRouter.key = primary_key
20
+ accountManagerRouter.ots_client = ots_client
21
+ accountManagerRouter.table_name = table_name
22
+
23
+ #和hook.pixiv.digital/uu兼容 故分开
24
+ NotifyRouter.key = primary_key
25
+ NotifyRouter.ots_client = ots_client
26
+ NotifyRouter.table_name = table_name
27
+
28
+
29
+
30
+ app = FastAPI()
31
+ @app.get("/config.json", tags=["Root"])
32
+ async def read_root() -> dict:
33
+ return config
34
+
35
+ # 全局路由
36
+ app.include_router(accountManagerRouter,prefix='/accountManager')
37
+ app.include_router(NotifyRouter, prefix=config['notify']) # https://hook.pixiv.digital/uu接受回调
38
+ if __name__ == '__main__':
39
+ print(config['notify'])
40
+
server/config.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+
2
+ {
3
+ "notify": "/uu",
4
+ "databaseName":"roger",
5
+ "databaseUser": "roger",
6
+ "password": "tWTcHxwKDtBGm6eJ",
7
+ "host": "146.190.67.151"
8
+ }
server/dao.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ from tablestore import *
3
+
4
+ # 定义一个自定义错误类
5
+ class customError(Exception):
6
+ def __init__(self, message,original_exception=None):
7
+ super().__init__(message)
8
+ self.message = message
9
+ self.original_expection = original_exception
10
+ print("original exception:",original_exception)
11
+
12
+ class tableStore:
13
+ def __init__(self,ots_client,table_name):
14
+ self.ots_client = ots_client
15
+ self.table_name = table_name
16
+ self.email = None
17
+ self.stored_password = None
18
+ self.is_vip = None
19
+ self.expired_at = None
20
+ self.balance = None
21
+
22
+ def getUserInfo(self,email)->"void or throw error":
23
+ #通过email主键查询用户信息
24
+ primary_key = [
25
+ ['email', email],
26
+ ]
27
+ columns_to_get = ['isVip', 'expiredAt', 'password','balance']
28
+ try:
29
+ consumed, return_row, next_token = self.ots_client.get_row(
30
+ table_name=self.table_name,
31
+ primary_key=primary_key,
32
+ columns_to_get=columns_to_get
33
+ )
34
+ if return_row is None:
35
+ raise customError('email not exist')
36
+ else:
37
+ # 创建一个字典来存储键值对
38
+ attributes = {}
39
+ for key, value, _ in return_row.attribute_columns:
40
+ attributes[key] = value
41
+
42
+ self.email = email
43
+ self.expired_at = attributes['expiredAt']
44
+ self.is_vip = attributes['isVip']
45
+ self.stored_password = attributes['password']
46
+ self.balance = attributes['balance']
47
+
48
+ except Exception as e:
49
+ raise customError("请求getUserInfo失败",e)
50
+ def checkInit(self)->"bool or throw error":
51
+ # 使用 all() 函数检查所有属性是否都存在且不为 None
52
+ return all([self.email is not None, self.stored_password is not None, self.is_vip is not None,
53
+ self.expired_at is not None])
54
+
55
+ def login(self, email, password)-> "user info or throw error":
56
+ self.getUserInfo(email) #检测登录前先获取用户信息
57
+ if self.checkInit():
58
+ #都存在说明正常初始化
59
+ if self.email==email and self.stored_password==password:
60
+ return {"ec":200,"expiredAt":self.expired_at
61
+ ,"balance":self.balance,"email":email,"password":password}
62
+ else:
63
+ raise customError("login验证失败-账户不匹配")
64
+ else:
65
+ raise customError("login调用时发现用户信息没有正常初始化")
66
+ def checkVipStatus(self)->"bool or throw error":
67
+ current_time = int(time.time())
68
+ if self.checkInit():
69
+ if self.expired_at > current_time:
70
+ #只看截止时间
71
+ return True
72
+ else:
73
+ return False
74
+ else:
75
+ raise customError("checkVipStatus调用时发现用户信息没有正常初始化")
76
+
77
+ def userSignUp(self,email,password)->"user info or throw error":
78
+ #如果收到参数不够,那么务必设置默认值 expiredAt->0 ,isVip->false
79
+ primary_key = [
80
+ ['email', email],
81
+ ]
82
+ attribute_columns = [
83
+ ['isVip', False], # 注册用户不为vip
84
+ ['password', password],
85
+ ['expiredAt', int(time.time())], # 第一次创建过期时间为当前时间
86
+ ['balance', int(0)], # 第一次创建balance为0
87
+ ]
88
+ try:
89
+ self.ots_client.put_row(
90
+ table_name=self.table_name,
91
+ row=Row(
92
+ primary_key=primary_key,
93
+ attribute_columns=attribute_columns
94
+ ),
95
+ condition=Condition(RowExistenceExpectation.EXPECT_NOT_EXIST) # 这种只要存在就不执行(多次注册只有第一次生效)
96
+ )
97
+ return {"ec":200,"expiredAt":0
98
+ ,"balance":0,"email":email,"password":password}
99
+ except Exception as e:
100
+ raise customError("userSignUp 失败",e)
101
+
102
+ def updateColumnByPrimaryKey(self,key:str,key_value:'dynamic',
103
+ update_column:str,update_column_value:'dynamic')\
104
+ -> "bool or throw error":
105
+ #比如支付回调的时候没有密码,故而只根据主键email更新时间
106
+ primary_key = [
107
+ (key, key_value),
108
+ ]
109
+ update_of_attribute_columns = {
110
+ 'PUT': [(update_column, update_column_value)]
111
+ }
112
+ updateRow = Row(
113
+ primary_key=primary_key,
114
+ attribute_columns=update_of_attribute_columns
115
+ )
116
+ try:
117
+ table_meta = self.ots_client.describe_table(table_name=self.table_name)
118
+ defined_columns = table_meta.table_meta.defined_columns # 定义的非主键列-不受意外列添加影响
119
+ isColumnExist = any(column_name == update_column for column_name, _ in defined_columns)
120
+ condition = Condition(RowExistenceExpectation.EXPECT_EXIST)
121
+
122
+ if isColumnExist:
123
+ # 执行UpdateRow操作
124
+ self.ots_client.update_row(
125
+ table_name=self.table_name,
126
+ row=updateRow,
127
+ condition=condition
128
+ )
129
+ return True
130
+ else:
131
+ raise customError("更新列名不存在")
132
+ except Exception as e:
133
+ raise customError('更新操作发生问题',e)
134
+
135
+
136
+
137
+
138
+ if __name__ == '__main__':
139
+ access_key_id = 'LTAI5tNwpEHCMTupADmx6xA4'
140
+ access_key_secret = "vX1q5Tvj3LSsIMUXN6SPbMUBCET3qG"
141
+ end_point = 'https://v2b-user-table.ap-southeast-1.ots.aliyuncs.com'
142
+ instance_name = 'v2b-user-table'
143
+ table_name = 'user'
144
+ ots_client = OTSClient(
145
+ end_point=end_point,
146
+ access_key_id=access_key_id,
147
+ access_key_secret=access_key_secret,
148
+ instance_name=instance_name
149
+ )
150
+ tablestore = tableStore(ots_client=ots_client,table_name=table_name)
151
+ tablestore.updateColumnByPrimaryKey(key='email',key_value='user@example.com',
152
+ update_column='balance',update_column_value=1728877808)
153
+
154
+
155
+
156
+
157
+
158
+
159
+
160
+
161
+
162
+
163
+
164
+
165
+
166
+
167
+
168
+
server/dao_pool.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import mysql.connector
2
+ from mysql.connector import pooling
3
+ from .utils import config
4
+ class Database:
5
+ __connection_pool = None
6
+ @classmethod
7
+ def init(cls):
8
+ try:
9
+ cls.__connection_pool = pooling.MySQLConnectionPool(
10
+ pool_name="v2boardPool",
11
+ pool_size=5,
12
+ host=config["host"],
13
+ database=config["databaseName"],
14
+ user=config["databaseUser"],
15
+ password=config["password"]
16
+ )
17
+ except mysql.connector.Error as e:
18
+ print("Error initializing connection pool: {}".format(str(e)))
19
+
20
+ @classmethod
21
+ def get_connection(cls):
22
+ if cls.__connection_pool is None:
23
+ cls.init()
24
+ conn = cls.__connection_pool.get_connection()
25
+ return conn
26
+
27
+ @classmethod
28
+ def release_connection(cls, connection):
29
+ connection.close()
30
+
31
+ @classmethod
32
+ def close_all_connections(cls):
33
+ cls.__connection_pool.close()
34
+
35
+ @classmethod
36
+ def status(cls):
37
+ # 获取使用了的连接状态
38
+ if cls.__connection_pool is None:
39
+ cls.init()
40
+ return cls.__connection_pool.get_pool_size()
41
+
42
+ if __name__ == '__main__':
43
+ email = 'hanryr.dios482992030@gmail.com'
44
+ with Database.get_connection() as conn:
45
+ with conn.cursor() as cur:
46
+ print("链接数据库成功")
47
+ query = "SELECT balance FROM `v2_user` WHERE email = %(email)s"
48
+ params = {'email': email}
49
+ cur.execute(query, params)
50
+ result = cur.fetchone()
51
+
52
+ if result is not None:
53
+ # 如果email已经存在于数据库中,那么从数据库中获取balance
54
+ balance = result[0]
55
+ print(balance)
56
+ else:
57
+ # 如果email不存在于数据库中,提示用户未注册(没必要,因为没法通知到app),所以不做处理
58
+ pass
59
+ print("数据库操作完成")
server/hook.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #notify通知到后自动写入数据库的hook操作,只添加余额就行,连月都不用管
2
+ from .dao_pool import Database
3
+ def updateBalance(email,amount):
4
+ ##通过传入用户email和回调中的金额修改balance
5
+ with Database.get_connection() as conn:
6
+ with conn.cursor() as cur:
7
+ print("链接数据库成功")
8
+ query = "SELECT balance FROM `v2_user` WHERE email = %(email)s"
9
+ params = {'email': email}
10
+ cur.execute(query, params)
11
+ result = cur.fetchone()
12
+
13
+ if result is not None:
14
+ # 如果email已经存在于数据库中,那么从数据库中获取balance,让balance加上新充值的金额就行
15
+ balance = result[0]
16
+ balance +=float(amount)*100
17
+ print(balance)
18
+ query = "UPDATE `v2_user` SET balance = %(balance)s WHERE email = %(email)s"
19
+ params = {'balance': str(balance), 'email': email}
20
+ cur.execute(query, params)
21
+ conn.commit()
22
+ else:
23
+ # 如果email不存在于数据库中,提示用户未注册(没必要,因为没法通知到app),所以不做处理
24
+ pass
25
+ print("数据库操作完成")
26
+
27
+
28
+
29
+
server/notify.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from fastapi import APIRouter, HTTPException
3
+ from fastapi.responses import JSONResponse
4
+ from .hook import *
5
+ from .pydanticModel import *
6
+ from .dao import tableStore
7
+
8
+ router = APIRouter()
9
+ #afdian的回调是post
10
+ @router.get('/',response_model=AfdianResp)
11
+ @router.post('/',response_model=AfdianResp)
12
+ async def update_balance(afdianHookjson: AfdianHookJson):
13
+
14
+ resp = {'ec': 200}
15
+ # 检查 ec 是否为 200
16
+ if afdianHookjson.ec != 200:
17
+ return {'ec': "afdian hook错误,ec 不是 200"}
18
+
19
+ # 提取订单详情和可选参数
20
+ order_details = afdianHookjson.data.order
21
+ custom_order_id = order_details.custom_order_id
22
+ total_amount = order_details.total_amount
23
+
24
+ table_store = tableStore(ots_client=router.ots_client, table_name=router.table_name)
25
+
26
+ if all([custom_order_id is not None, total_amount is not None]):
27
+
28
+ # 说明是余额类型
29
+ try:
30
+ # 先给mysql的数据库添加 - 这个毕竟久 稳定 但是不应该影响其他数据库添加(万一不用了)--------------------
31
+ updateBalance(email=custom_order_id, amount=total_amount)
32
+ # 先给mysql的数据库添加 - 这个毕竟久 稳定 但是不应该影响其他数据库添加(万一不用了)--------------------
33
+ except Exception as e:
34
+ print("updateBalance v2b digitalocean mysql failed",e)
35
+
36
+ try:
37
+ #应该改成从原来的余额基础上加total_amount的值
38
+ table_store.getUserInfo(email=custom_order_id)
39
+ cur_balance = table_store.balance
40
+ balance_new = cur_balance+ total_amount
41
+ # 更新余额列
42
+ update_balance_result = table_store.updateColumnByPrimaryKey(
43
+ key=router.key,
44
+ key_value=custom_order_id,
45
+ update_column='balance',
46
+ update_column_value=balance_new
47
+ )
48
+ if update_balance_result:
49
+ return resp #全部成功运行则返回爱发电要求的ec =200
50
+ else:
51
+ return {'ec': "updateBalance tablestore 结果失败"}
52
+ except Exception as e:
53
+ print(e)
54
+ return {'ec': "尝试 updateBalance tablestore 失败"}
55
+ else:
56
+ #这个直接返回200吧,反正测试接口的时候需要 ,平时也不用到
57
+ # return {'ec': "afdian hook custom_order_id 或者 total_amount 为 None"}
58
+ return resp
59
+
60
+ # test
61
+ # @router.get('/',response_model=AfdianResp)
62
+ # async def update_balance(afdianHookjson: AfdianHookJson):
63
+ # print("收到请求1")
64
+ # return {'ec':200}
server/pydanticModel.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel,field_validator,Field
2
+ from fastapi import Query
3
+ from typing import List, Optional, Any
4
+
5
+
6
+ # 定义fastapi请求参数模型
7
+
8
+ class signUp(BaseModel):
9
+ email: str
10
+ password: str
11
+ # 可选参数
12
+ expiredAt: int = Query(default=0, alias="expiredAt")
13
+ balance: int = Query(default=0, alias="balance")
14
+ ec: int = Query(default=200, alias="ec")
15
+
16
+
17
+ @field_validator('email')
18
+ #确保password不为''
19
+ def check_email(cls, v):
20
+ if v == '':
21
+ raise ValueError('email cannot be an empty string')
22
+ return v
23
+
24
+ @field_validator('password')
25
+ # 确保password不为''
26
+ def check_password(cls, v):
27
+ if v == '':
28
+ raise ValueError('password cannot be an empty string')
29
+ return v
30
+
31
+
32
+ class signIn(BaseModel):
33
+ email: str
34
+ password: str
35
+ # 可选参数
36
+ expiredAt: int = Query(default=0, alias="expiredAt")
37
+ balance: int = Query(default=0, alias="balance")
38
+ ec: int = Query(default=200, alias="ec")
39
+
40
+
41
+ @field_validator('email')
42
+ # 确保password不为''
43
+ def check_email(cls, v):
44
+ if v == '':
45
+ raise ValueError('email cannot be an empty string')
46
+ return v
47
+
48
+ @field_validator('password')
49
+ # 确保password不为''
50
+ def check_password(cls, v):
51
+ if v == '':
52
+ raise ValueError('password cannot be an empty string')
53
+ return v
54
+
55
+
56
+ class SKUDetail(BaseModel):
57
+ sku_id: str
58
+ price: str
59
+ count: int
60
+ name: str
61
+ album_id: Optional[str] = None
62
+ pic: Optional[str] = None
63
+ stock: Optional[str] = None
64
+ post_id: Optional[str] = None
65
+
66
+
67
+ class AfdianOrderDetail(BaseModel):
68
+ out_trade_no: str
69
+ user_id: str
70
+ plan_id: str
71
+ month: int
72
+ show_amount: str
73
+ status: int
74
+ remark: str
75
+ redeem_id: str
76
+ product_type: int
77
+ discount: str
78
+ sku_detail: List[SKUDetail] # 更新为 SKUDetail 列表
79
+ create_time: int
80
+ plan_title: str
81
+ user_private_id: str
82
+ address_person: str
83
+ address_phone: str
84
+ address_address: str
85
+ custom_order_id: Optional[str] = Field(default=None, alias="custom_order_id")
86
+ total_amount: Optional[int] = Field(default=None, alias="total_amount") #这里自动转int了
87
+
88
+ class AfdianOrderData(BaseModel):
89
+ type: str
90
+ order: AfdianOrderDetail
91
+
92
+
93
+ class AfdianHookJson(BaseModel):
94
+ ec: int
95
+ em: str
96
+ data: AfdianOrderData
97
+
98
+
99
+ class AfdianResp(BaseModel):
100
+ ec: Any
101
+
102
+
103
+
104
+ #根据plan中的价格和时间相应减少balance和增加expiredAt
105
+ class userPlan(BaseModel):
106
+ price: int
107
+ duration_seconds: int
108
+ email: str #订阅plan的用户
109
+ password: str #请求purchase接口用户的password,保证只有用户本身可以请求这个接口防止滥用
110
+
111
+ @field_validator('price')
112
+ # 确保password不为''
113
+ def check_price(cls, v):
114
+ if v < 0:
115
+ raise ValueError('price can not < 0')
116
+ return v
117
+
118
+ @field_validator('duration_seconds')
119
+ # 确保password不为''
120
+ def check_duration_seconds(cls, v):
121
+ if v < 0:
122
+ raise ValueError('duration_seconds can not < 0')
123
+ return v
124
+
125
+ @field_validator('email')
126
+ # 确保password不为''
127
+ def check_email(cls, v):
128
+ if v == '':
129
+ raise ValueError('email cannot be an empty string')
130
+ return v
131
+
132
+
133
+
134
+
135
+
server/utils.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ # 获取当前文件所在的目录
4
+ current_dir = os.path.dirname(os.path.realpath(__file__))
5
+ # 读取配置文件
6
+ with open(os.path.join(current_dir, 'config.json'), 'r') as f:
7
+ config = json.load(f)
8
+
9
+ if __name__ == '__main__':
10
+ print(config['notify'])
test.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ # port = 7860
3
+ port= 3000
4
+
5
+ # url = "http://localhost:{p}/accountManager/login".format(p=port)
6
+ url = "http://localhost:{p}/accountManager/signUp".format(p=port)
7
+ data = {
8
+ "email": '1234567891011@qq.com',
9
+ "password": '1234567891011@qq.com'
10
+ }
11
+ response = requests.get(url, json=data)
12
+ print(response.status_code)
13
+ print(response.json())
14
+
15
+
16
+ # #hook模拟
17
+ # # port = 7860
18
+ # # url = "http://localhost:{p}/uu".format(p=port)
19
+ # url = 'https://hook.pixiv.digital/uu'
20
+ # data = {
21
+ # "ec": 200,
22
+ # "em": "ok",
23
+ # "data": {
24
+ # "type": "order",
25
+ # "order": {
26
+ # "out_trade_no": "20241014133823102101567665",
27
+ # "user_id": "f05ca070734c11efa78052540025c377",
28
+ # "plan_id": "ef3c43c6daa411ee965e5254001e7c00",
29
+ # "month": 1,
30
+ # "total_amount": "10.00",
31
+ # "show_amount": "10.00",
32
+ # "status": 2,
33
+ # "remark": "",
34
+ # "redeem_id": "",
35
+ # "product_type": 1,
36
+ # "discount": "0.00",
37
+ # "sku_detail": [
38
+ # {
39
+ # "sku_id": "ef440afcdaa411ee9e165254001e7c00",
40
+ # "price": "1.00",
41
+ # "count": 10,
42
+ # "name": "\u4f59\u989d\u6570\u91cf",
43
+ # "album_id": "",
44
+ # "pic": "",
45
+ # "stock": "",
46
+ # "post_id": ""
47
+ # }
48
+ # ],
49
+ # "create_time": 1728884303,
50
+ # "plan_title": "\u4f59\u989d",
51
+ # "user_private_id": "f14e880d78ac9d5c623b677c6e0c7122f1158bf0",
52
+ # "address_person": "",
53
+ # "address_phone": "",
54
+ # "address_address": "",
55
+ # "custom_order_id": "12345678910@qq.com"
56
+ # }
57
+ # }
58
+ # }
59
+ # response = requests.get(url, json=data)
60
+ # print(response.status_code)
61
+ # print(response.text)
62
+
63
+
64
+
65
+ # # purchase 模拟
66
+ # url = "http://localhost:{p}/accountManager/purchase".format(p=port)
67
+ # data = {
68
+ # "price":10,
69
+ # "duration_seconds":2592000,
70
+ # "email":'1320890187@qq.com',
71
+ # "password":"1320890187@qq.com"
72
+ # }
73
+ #
74
+ # response = requests.get(url, json=data)
75
+ # print(response.status_code)
76
+ # print(response.json())