| from models.user import User as users |
| from models.post import Post as post |
| import secrets |
| import hashlib |
| from datetime import datetime, timedelta |
| from sqlalchemy.orm import Session |
| from models.logs import Log |
| from models.syscost import PerformanceData |
| import os |
| import requests |
| from werkzeug.utils import secure_filename |
| import uuid |
| |
| class Fpost: |
| def __init__(self,session:Session): |
| self.session=session |
| # 配置文件存储节点(docker容器的实际路径) |
| self.storage_nodes = [ |
| '/home/tianruiming/docker02/static', |
| '/home/tianruiming/docker03/static', |
| '/home/tianruiming/docker04/static' |
| ] |
| # 默认访问节点(LVS负载均衡器) |
| self.access_node = '192.168.5.200:8080' |
| return |
| |
| |
| def getlist(self): |
| results = self.session.query(post.id, post.title,post.status) |
| return results |
| |
| def getuserlist(self): |
| results= self.session.query(users.id, users.username, users.role) |
| return results |
| |
| def giveadmin(self,userid): |
| res=self.session.query(users).filter(users.id==userid).first() |
| if not res: |
| return False |
| res.role='admin' |
| self.session.commit() |
| return True |
| |
| def giveuser(self,userid): |
| res=self.session.query(users).filter(users.id==userid).first() |
| if not res: |
| return False |
| res.role='user' |
| self.session.commit() |
| return True |
| |
| def givesuperadmin(self,userid): |
| res=self.session.query(users).filter(users.id==userid).first() |
| if not res: |
| return False |
| res.role='superadmin' |
| self.session.commit() |
| return True |
| |
| |
| def getpost(self,postid): |
| res=self.session.query(post).filter(post.id==postid).first() |
| return res |
| def checkid(self,userid,status=''): |
| res=self.session.query(users).filter(users.id==userid).first() |
| if(not res): |
| return False |
| if res.role !=status: |
| return False |
| return True |
| |
| def review(self,postid,status): |
| print(status) |
| res=self.session.query(post).filter(post.id==postid).first() |
| if not res: |
| return False |
| res.status=status |
| self.session.commit() |
| return True |
| |
| def createtoken(self, userid): |
| """ |
| 根据userid创建token并插入到数据库 |
| :param userid: 用户ID |
| :return: 生成的token字符串 |
| """ |
| # 生成随机盐值 |
| salt = secrets.token_hex(16) |
| |
| # 创建哈希值:userid + 当前时间戳 + 随机盐值 |
| current_time = str(datetime.now().timestamp()) |
| hash_input = f"{userid}_{current_time}_{salt}" |
| |
| # 生成SHA256哈希值作为token |
| token = hashlib.sha256(hash_input.encode()).hexdigest() |
| |
| # 设置时间 |
| created_time = datetime.now() |
| expires_time = created_time + timedelta(days=1) # 一天后过期 |
| |
| try: |
| # 创建新的token记录 |
| new_token = Token( |
| token=token, |
| expires_at=expires_time, |
| created_at=created_time |
| ) |
| |
| # 假设self.session是数据库会话对象 |
| self.session.add(new_token) |
| self.session.commit() |
| |
| return token |
| |
| except Exception as e: |
| self.session.rollback() |
| raise Exception(f"创建token失败: {str(e)}") |
| |
| def recordlog(self,user_id,log_type,content,ip): |
| """ |
| 记录日志 |
| :param user_id: 用户ID |
| :param log_type: 日志类型,'access','error','behavior','system' |
| :param content: 日志内容 |
| :param ip: IP地址 |
| """ |
| try: |
| new_log = Log( |
| user_id=user_id, |
| type=log_type, |
| content=content, |
| ip=ip |
| ) |
| self.session.add(new_log) |
| self.session.commit() |
| except Exception as e: |
| self.session.rollback() |
| raise Exception(f"记录日志失败: {str(e)}") |
| |
| def getrecordlog(self): |
| res= self.session.query(Log).all() |
| return res |
| |
| def recordsyscost(self, endpoint: str, elapsed_time: float, cpu_user: float, cpu_system: float, memory_rss: int): |
| """ |
| 记录系统性能消耗到 performance_data 表 |
| :param endpoint: 请求接口路径 |
| :param elapsed_time: 总耗时(秒) |
| :param cpu_user: 用户态 CPU 时间差(秒) |
| :param cpu_system: 系统态 CPU 时间差(秒) |
| :param memory_rss: RSS 内存增量(字节) |
| """ |
| try: |
| new_record = PerformanceData( |
| endpoint=endpoint, |
| elapsed_time=elapsed_time, |
| cpu_user=cpu_user, |
| cpu_system=cpu_system, |
| memory_rss=memory_rss |
| ) |
| self.session.add(new_record) |
| self.session.commit() |
| except Exception as e: |
| self.session.rollback() |
| raise Exception(f"记录系统性能消耗失败: {e}") |
| |
| def getsyscost(self): |
| res= self.session.query(PerformanceData).all() |
| return res |
| |
| def save_files_to_storage(self, files, post_id): |
| """ |
| 将文件保存到所有存储节点 |
| :param files: 文件列表 |
| :param post_id: 帖子ID |
| :return: 媒体URL列表 |
| """ |
| media_urls = [] |
| |
| for file in files: |
| if file and file.filename: |
| # 生成安全的文件名 |
| original_filename = secure_filename(file.filename) |
| # 生成唯一文件名避免冲突 |
| unique_id = str(uuid.uuid4()) |
| file_extension = os.path.splitext(original_filename)[1] |
| unique_filename = f"{unique_id}{file_extension}" |
| |
| # 读取文件内容 |
| file_content = file.read() |
| file.seek(0) # 重置文件指针 |
| |
| # 保存到所有存储节点 |
| success_count = 0 |
| for node_path in self.storage_nodes: |
| try: |
| # 创建目录路径:/home/tianruiming/docker0X/static/{post_id}/ |
| node_dir = os.path.join(node_path, str(post_id)) |
| os.makedirs(node_dir, exist_ok=True) |
| |
| # 完整文件路径 |
| full_file_path = os.path.join(node_dir, unique_filename) |
| |
| # 写入文件到存储节点 |
| with open(full_file_path, 'wb') as f: |
| f.write(file_content) |
| |
| success_count += 1 |
| print(f"Successfully saved file to {full_file_path}") |
| |
| except Exception as e: |
| print(f"Failed to save file to node {node_path}: {str(e)}") |
| |
| if success_count > 0: |
| # 生成访问URL,格式:http://192.168.5.231:8080/static/{post_id}/{filename} |
| media_url = f"http://{self.access_node}/static/{post_id}/{unique_filename}" |
| media_urls.append(media_url) |
| else: |
| raise Exception(f"Failed to save file {original_filename} to any storage node") |
| |
| return media_urls |
| |
| def create_post_with_files(self, user_id, title, content, topic_id, status, files): |
| """ |
| 创建带文件的帖子 |
| :param user_id: 用户ID |
| :param title: 标题 |
| :param content: 内容 |
| :param topic_id: 话题ID |
| :param status: 状态 |
| :param files: 文件列表 |
| :return: 帖子对象 |
| """ |
| # 先创建帖子获取ID |
| new_post = post( |
| user_id=user_id, |
| title=title, |
| content=content, |
| topic_id=topic_id if topic_id else None, |
| status=status, |
| created_at=datetime.now(), |
| updated_at=datetime.now() |
| ) |
| |
| self.session.add(new_post) |
| self.session.flush() # 获取ID但不提交 |
| |
| # 保存文件 |
| if files: |
| media_urls = self.save_files_to_storage(files, new_post.id) |
| new_post.media_urls = media_urls |
| else: |
| new_post.media_urls = [] |
| |
| self.session.commit() |
| return new_post |
| |
| def update_post_with_files(self, post_id, title=None, content=None, topic_id=None, status=None, files=None, existing_media_urls=None): |
| """ |
| 更新带文件的帖子 |
| :param post_id: 帖子ID |
| :param title: 标题 |
| :param content: 内容 |
| :param topic_id: 话题ID |
| :param status: 状态 |
| :param files: 新文件列表 |
| :param existing_media_urls: 现有媒体URL |
| :return: 更新后的帖子对象 |
| """ |
| post_obj = self.session.query(post).filter(post.id == post_id).first() |
| if not post_obj: |
| return None |
| |
| # 更新基本信息 |
| if title is not None: |
| post_obj.title = title |
| if content is not None: |
| post_obj.content = content |
| if topic_id is not None: |
| post_obj.topic_id = topic_id |
| if status is not None: |
| post_obj.status = status |
| |
| post_obj.updated_at = datetime.now() |
| |
| # 处理文件 |
| if files: |
| # 有新文件,保存新文件 |
| media_urls = self.save_files_to_storage(files, post_id) |
| post_obj.media_urls = media_urls |
| elif existing_media_urls is not None: |
| # 保留现有媒体URL |
| post_obj.media_urls = existing_media_urls |
| |
| self.session.commit() |
| return post_obj |