blob: 2ffffbc378322fab64367055661ab93314291ce1 [file] [log] [blame]
TRM-coding882dc442025-06-18 20:13:21 +08001from models.user import User as users
2from models.post import Post as post
3import secrets
4import hashlib
5from datetime import datetime, timedelta
6from sqlalchemy.orm import Session
7from models.logs import Log
8from models.syscost import PerformanceData
TRM-codingf55d2372025-06-20 16:22:37 +08009import os
10import requests
11from werkzeug.utils import secure_filename
12import uuid
13
TRM-coding882dc442025-06-18 20:13:21 +080014class Fpost:
15 def __init__(self,session:Session):
16 self.session=session
TRM-codingf55d2372025-06-20 16:22:37 +080017 # 配置文件存储节点(docker容器的实际路径)
18 self.storage_nodes = [
19 '/home/tianruiming/docker02/static',
20 '/home/tianruiming/docker03/static',
21 '/home/tianruiming/docker04/static'
22 ]
23 # 默认访问节点(LVS负载均衡器)
trm36915ed2025-06-20 09:48:51 +000024 self.access_node = '192.168.5.200:8080'
TRM-coding882dc442025-06-18 20:13:21 +080025 return
26
27
28 def getlist(self):
29 results = self.session.query(post.id, post.title,post.status)
30 return results
31
32 def getuserlist(self):
33 results= self.session.query(users.id, users.username, users.role)
34 return results
35
36 def giveadmin(self,userid):
37 res=self.session.query(users).filter(users.id==userid).first()
38 if not res:
39 return False
40 res.role='admin'
41 self.session.commit()
42 return True
43
44 def giveuser(self,userid):
45 res=self.session.query(users).filter(users.id==userid).first()
46 if not res:
47 return False
48 res.role='user'
49 self.session.commit()
50 return True
51
52 def givesuperadmin(self,userid):
53 res=self.session.query(users).filter(users.id==userid).first()
54 if not res:
55 return False
56 res.role='superadmin'
57 self.session.commit()
58 return True
59
60
61 def getpost(self,postid):
62 res=self.session.query(post).filter(post.id==postid).first()
63 return res
64 def checkid(self,userid,status=''):
65 res=self.session.query(users).filter(users.id==userid).first()
66 if(not res):
67 return False
68 if res.role !=status:
69 return False
70 return True
71
72 def review(self,postid,status):
73 print(status)
74 res=self.session.query(post).filter(post.id==postid).first()
75 if not res:
76 return False
77 res.status=status
78 self.session.commit()
79 return True
80
81 def createtoken(self, userid):
82 """
83 根据userid创建token并插入到数据库
84 :param userid: 用户ID
85 :return: 生成的token字符串
86 """
87 # 生成随机盐值
88 salt = secrets.token_hex(16)
89
90 # 创建哈希值:userid + 当前时间戳 + 随机盐值
91 current_time = str(datetime.now().timestamp())
92 hash_input = f"{userid}_{current_time}_{salt}"
93
94 # 生成SHA256哈希值作为token
95 token = hashlib.sha256(hash_input.encode()).hexdigest()
96
97 # 设置时间
98 created_time = datetime.now()
99 expires_time = created_time + timedelta(days=1) # 一天后过期
100
101 try:
102 # 创建新的token记录
103 new_token = Token(
104 token=token,
105 expires_at=expires_time,
106 created_at=created_time
107 )
108
109 # 假设self.session是数据库会话对象
110 self.session.add(new_token)
111 self.session.commit()
112
113 return token
114
115 except Exception as e:
116 self.session.rollback()
117 raise Exception(f"创建token失败: {str(e)}")
118
119 def recordlog(self,user_id,log_type,content,ip):
120 """
121 记录日志
122 :param user_id: 用户ID
123 :param log_type: 日志类型,'access','error','behavior','system'
124 :param content: 日志内容
125 :param ip: IP地址
126 """
127 try:
128 new_log = Log(
129 user_id=user_id,
130 type=log_type,
131 content=content,
132 ip=ip
133 )
134 self.session.add(new_log)
135 self.session.commit()
136 except Exception as e:
137 self.session.rollback()
138 raise Exception(f"记录日志失败: {str(e)}")
139
140 def getrecordlog(self):
141 res= self.session.query(Log).all()
142 return res
143
144 def recordsyscost(self, endpoint: str, elapsed_time: float, cpu_user: float, cpu_system: float, memory_rss: int):
145 """
146 记录系统性能消耗到 performance_data 表
147 :param endpoint: 请求接口路径
148 :param elapsed_time: 总耗时(秒)
149 :param cpu_user: 用户态 CPU 时间差(秒)
150 :param cpu_system: 系统态 CPU 时间差(秒)
151 :param memory_rss: RSS 内存增量(字节)
152 """
153 try:
154 new_record = PerformanceData(
155 endpoint=endpoint,
156 elapsed_time=elapsed_time,
157 cpu_user=cpu_user,
158 cpu_system=cpu_system,
159 memory_rss=memory_rss
160 )
161 self.session.add(new_record)
162 self.session.commit()
163 except Exception as e:
164 self.session.rollback()
165 raise Exception(f"记录系统性能消耗失败: {e}")
166
167 def getsyscost(self):
168 res= self.session.query(PerformanceData).all()
TRM-codingf55d2372025-06-20 16:22:37 +0800169 return res
170
171 def save_files_to_storage(self, files, post_id):
172 """
173 将文件保存到所有存储节点
174 :param files: 文件列表
175 :param post_id: 帖子ID
176 :return: 媒体URL列表
177 """
178 media_urls = []
179
180 for file in files:
181 if file and file.filename:
182 # 生成安全的文件名
183 original_filename = secure_filename(file.filename)
184 # 生成唯一文件名避免冲突
185 unique_id = str(uuid.uuid4())
186 file_extension = os.path.splitext(original_filename)[1]
187 unique_filename = f"{unique_id}{file_extension}"
188
189 # 读取文件内容
190 file_content = file.read()
191 file.seek(0) # 重置文件指针
192
193 # 保存到所有存储节点
194 success_count = 0
195 for node_path in self.storage_nodes:
196 try:
197 # 创建目录路径:/home/tianruiming/docker0X/static/{post_id}/
198 node_dir = os.path.join(node_path, str(post_id))
199 os.makedirs(node_dir, exist_ok=True)
200
201 # 完整文件路径
202 full_file_path = os.path.join(node_dir, unique_filename)
203
204 # 写入文件到存储节点
205 with open(full_file_path, 'wb') as f:
206 f.write(file_content)
207
208 success_count += 1
209 print(f"Successfully saved file to {full_file_path}")
210
211 except Exception as e:
212 print(f"Failed to save file to node {node_path}: {str(e)}")
213
214 if success_count > 0:
215 # 生成访问URL,格式:http://192.168.5.231:8080/static/{post_id}/{filename}
216 media_url = f"http://{self.access_node}/static/{post_id}/{unique_filename}"
217 media_urls.append(media_url)
218 else:
219 raise Exception(f"Failed to save file {original_filename} to any storage node")
220
221 return media_urls
222
223 def create_post_with_files(self, user_id, title, content, topic_id, status, files):
224 """
225 创建带文件的帖子
226 :param user_id: 用户ID
227 :param title: 标题
228 :param content: 内容
229 :param topic_id: 话题ID
230 :param status: 状态
231 :param files: 文件列表
232 :return: 帖子对象
233 """
234 # 先创建帖子获取ID
235 new_post = post(
236 user_id=user_id,
237 title=title,
238 content=content,
239 topic_id=topic_id if topic_id else None,
240 status=status,
241 created_at=datetime.now(),
242 updated_at=datetime.now()
243 )
244
245 self.session.add(new_post)
246 self.session.flush() # 获取ID但不提交
247
248 # 保存文件
249 if files:
250 media_urls = self.save_files_to_storage(files, new_post.id)
251 new_post.media_urls = media_urls
252 else:
253 new_post.media_urls = []
254
255 self.session.commit()
256 return new_post
257
258 def update_post_with_files(self, post_id, title=None, content=None, topic_id=None, status=None, files=None, existing_media_urls=None):
259 """
260 更新带文件的帖子
261 :param post_id: 帖子ID
262 :param title: 标题
263 :param content: 内容
264 :param topic_id: 话题ID
265 :param status: 状态
266 :param files: 新文件列表
267 :param existing_media_urls: 现有媒体URL
268 :return: 更新后的帖子对象
269 """
270 post_obj = self.session.query(post).filter(post.id == post_id).first()
271 if not post_obj:
272 return None
273
274 # 更新基本信息
275 if title is not None:
276 post_obj.title = title
277 if content is not None:
278 post_obj.content = content
279 if topic_id is not None:
280 post_obj.topic_id = topic_id
281 if status is not None:
282 post_obj.status = status
283
284 post_obj.updated_at = datetime.now()
285
286 # 处理文件
287 if files:
288 # 有新文件,保存新文件
289 media_urls = self.save_files_to_storage(files, post_id)
290 post_obj.media_urls = media_urls
291 elif existing_media_urls is not None:
292 # 保留现有媒体URL
293 post_obj.media_urls = existing_media_urls
294
295 self.session.commit()
296 return post_obj