合并JWL,WZY,TRM代码

Change-Id: Ifb4fcad3c06733e1e005e7d8d9403e3561010fb4
diff --git a/Merge/back_trm/app/__init__.py b/Merge/back_trm/app/__init__.py
new file mode 100644
index 0000000..5587d2a
--- /dev/null
+++ b/Merge/back_trm/app/__init__.py
@@ -0,0 +1,15 @@
+from flask import Flask
+
+def create_app():
+    app = Flask(__name__)
+    
+    # Load configuration
+    app.config.from_object('config.Config')
+
+    # Register blueprints or routes
+    from .routes import main as main_blueprint
+    app.register_blueprint(main_blueprint)
+
+    return app
+
+app = create_app()
\ No newline at end of file
diff --git a/Merge/back_trm/app/__pycache__/__init__.cpython-310.pyc b/Merge/back_trm/app/__pycache__/__init__.cpython-310.pyc
new file mode 100644
index 0000000..f713fad
--- /dev/null
+++ b/Merge/back_trm/app/__pycache__/__init__.cpython-310.pyc
Binary files differ
diff --git a/Merge/back_trm/app/__pycache__/__init__.cpython-312.pyc b/Merge/back_trm/app/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000..ec28c7e
--- /dev/null
+++ b/Merge/back_trm/app/__pycache__/__init__.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_trm/app/__pycache__/routes.cpython-310.pyc b/Merge/back_trm/app/__pycache__/routes.cpython-310.pyc
new file mode 100644
index 0000000..5166bf4
--- /dev/null
+++ b/Merge/back_trm/app/__pycache__/routes.cpython-310.pyc
Binary files differ
diff --git a/Merge/back_trm/app/functions/Fpost.py b/Merge/back_trm/app/functions/Fpost.py
new file mode 100644
index 0000000..7d6ccd2
--- /dev/null
+++ b/Merge/back_trm/app/functions/Fpost.py
@@ -0,0 +1,102 @@
+from ..models.users 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
+class Fpost:
+    def __init__(self,session:Session):
+        self.session=session
+        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)}")
\ No newline at end of file
diff --git a/Merge/back_trm/app/functions/__pycache__/Fpost.cpython-310.pyc b/Merge/back_trm/app/functions/__pycache__/Fpost.cpython-310.pyc
new file mode 100644
index 0000000..f9b1bc6
--- /dev/null
+++ b/Merge/back_trm/app/functions/__pycache__/Fpost.cpython-310.pyc
Binary files differ
diff --git a/Merge/back_trm/app/models/__init__.py b/Merge/back_trm/app/models/__init__.py
new file mode 100644
index 0000000..f726a19
--- /dev/null
+++ b/Merge/back_trm/app/models/__init__.py
@@ -0,0 +1,8 @@
+from sqlalchemy.ext.declarative import declarative_base
+
+Base = declarative_base()
+
+# 先定义好 Base,再把所有 model import 进来,让 SQLAlchemy 一次性注册它们
+from .users import User
+from .topics import Topic
+from .post   import Post
\ No newline at end of file
diff --git a/Merge/back_trm/app/models/__pycache__/__init__.cpython-310.pyc b/Merge/back_trm/app/models/__pycache__/__init__.cpython-310.pyc
new file mode 100644
index 0000000..015de51
--- /dev/null
+++ b/Merge/back_trm/app/models/__pycache__/__init__.cpython-310.pyc
Binary files differ
diff --git a/Merge/back_trm/app/models/__pycache__/post.cpython-310.pyc b/Merge/back_trm/app/models/__pycache__/post.cpython-310.pyc
new file mode 100644
index 0000000..8d33351
--- /dev/null
+++ b/Merge/back_trm/app/models/__pycache__/post.cpython-310.pyc
Binary files differ
diff --git a/Merge/back_trm/app/models/__pycache__/topics.cpython-310.pyc b/Merge/back_trm/app/models/__pycache__/topics.cpython-310.pyc
new file mode 100644
index 0000000..fba569b
--- /dev/null
+++ b/Merge/back_trm/app/models/__pycache__/topics.cpython-310.pyc
Binary files differ
diff --git a/Merge/back_trm/app/models/__pycache__/users.cpython-310.pyc b/Merge/back_trm/app/models/__pycache__/users.cpython-310.pyc
new file mode 100644
index 0000000..155a86c
--- /dev/null
+++ b/Merge/back_trm/app/models/__pycache__/users.cpython-310.pyc
Binary files differ
diff --git a/Merge/back_trm/app/models/post.py b/Merge/back_trm/app/models/post.py
new file mode 100644
index 0000000..041e263
--- /dev/null
+++ b/Merge/back_trm/app/models/post.py
@@ -0,0 +1,111 @@
+from .users import User
+from . import Base
+
+from sqlalchemy import (
+    Column, Integer, String, Text, JSON, Enum,
+    TIMESTAMP, ForeignKey, Index, func, text
+)
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy.orm import relationship
+
+
+class Post(Base):
+    __tablename__ = 'posts'
+    __table_args__ = (
+        # 索引
+        Index('idx_posts_heat', 'heat'),
+        # MySQL 引擎、字符集、校对规则、表注释
+        {
+            'mysql_engine': 'InnoDB',
+            'mysql_charset': 'utf8mb4',
+            'mysql_collate': 'utf8mb4_general_ci',
+            'comment': '内容帖子表'
+        }
+    )
+
+    def to_dict(self):
+        return {
+            'id': self.id if self.id else None,
+            'user_id': self.user_id if self.user_id else None,
+            'topic_id': self.topic_id if self.topic_id else None,
+            'type': self.type if self.type else None,
+            'title': self.title if self.title else None,
+            'content': self.content if self.content else None,
+            'media_urls': self.media_urls if self.media_urls else None,
+            'status': self.status if self.status else None,
+            'heat': self.heat if self.heat else None,
+            'created_at': self.created_at.isoformat() if self.created_at else None,
+            'updated_at': self.updated_at.isoformat() if self.updated_at else None
+        }
+
+
+    id = Column(
+        Integer,
+        primary_key=True,
+        autoincrement=True,
+        comment='帖子ID'
+    )
+    user_id = Column(
+        Integer,
+        ForeignKey('users.id', ondelete='CASCADE'),
+        nullable=False,
+        index=True,
+        comment='作者ID'
+    )
+    topic_id = Column(
+        Integer,
+        ForeignKey('topics.id', ondelete='SET NULL'),
+        nullable=True,
+        index=True,
+        comment='所属话题ID'
+    )
+    type = Column(
+        Enum('text', 'image', 'video', 'document', name='post_type'),
+        nullable=False,
+        server_default=text("'text'"),
+        comment='内容类型'
+    )
+    title = Column(
+        String(255),
+        nullable=False,
+        comment='标题'
+    )
+    content = Column(
+        Text,
+        nullable=False,
+        comment='正文内容'
+    )
+    media_urls = Column(
+        JSON,
+        nullable=True,
+        comment='媒体资源URL数组'
+    )
+    status = Column(
+        Enum('draft', 'pending', 'published', 'deleted', 'rejected', name='post_status'),
+        nullable=False,
+        server_default=text("'draft'"),
+        comment='状态'
+    )
+    heat = Column(
+        Integer,
+        nullable=False,
+        server_default=text('0'),
+        comment='热度值'
+    )
+    created_at = Column(
+        TIMESTAMP,
+        nullable=True,
+        server_default=func.current_timestamp(),
+        comment='创建时间'
+    )
+    updated_at = Column(
+        TIMESTAMP,
+        nullable=True,
+        server_default=func.current_timestamp(),
+        onupdate=func.current_timestamp(),
+        comment='更新时间'
+    )
+
+    # 可选:与 User/Topic 模型的关系(需要在 User、Topic 中也定义 back_populates)
+    # user = relationship('User', back_populates='posts')
+    # topic = relationship('Topic', back_populates='posts')
diff --git a/Merge/back_trm/app/models/token.py b/Merge/back_trm/app/models/token.py
new file mode 100644
index 0000000..cbe864b
--- /dev/null
+++ b/Merge/back_trm/app/models/token.py
@@ -0,0 +1,27 @@
+from sqlalchemy import Column, Integer, String, DateTime, TIMESTAMP, Index
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy.sql import func
+from datetime import datetime
+
+Base = declarative_base()
+
+class Token(Base):
+    __tablename__ = 'tokens'
+    
+    id = Column(Integer, primary_key=True, autoincrement=True)
+    token = Column(String(255), nullable=False, unique=True)
+    expires_at = Column(DateTime, nullable=False)
+    created_at = Column(TIMESTAMP, default=func.current_timestamp())
+    updated_at = Column(TIMESTAMP, default=func.current_timestamp(), onupdate=func.current_timestamp())
+    
+    __table_args__ = (
+        Index('idx_token', 'token'),
+        Index('idx_expires_at', 'expires_at'),
+    )
+    
+    def __repr__(self):
+        return f"<Token(id={self.id}, token='{self.token[:10]}...', expires_at={self.expires_at})>"
+    
+    def is_expired(self):
+        """检查token是否已过期"""
+        return datetime.now() > self.expires_at
\ No newline at end of file
diff --git a/Merge/back_trm/app/models/topics.py b/Merge/back_trm/app/models/topics.py
new file mode 100644
index 0000000..1a35a38
--- /dev/null
+++ b/Merge/back_trm/app/models/topics.py
@@ -0,0 +1,26 @@
+from . import Base
+from sqlalchemy import Column, Integer, String, Text, Enum, TIMESTAMP
+from sqlalchemy.sql import func
+
+class Topic(Base):
+    __tablename__ = 'topics'
+    __table_args__ = {
+        'mysql_engine': 'InnoDB',
+        'mysql_charset': 'utf8mb4',
+        'mysql_collate': 'utf8mb4_general_ci',
+        'comment': '话题/超话表'
+    }
+
+    id = Column(Integer, primary_key=True, autoincrement=True, comment='话题ID')
+    name = Column(String(100, collation='utf8mb4_general_ci'), nullable=False, unique=True, comment='话题名称')
+    description = Column(Text(collation='utf8mb4_general_ci'), comment='话题描述')
+    status = Column(
+        Enum('active', 'archived', name='topic_status', collation='utf8mb4_general_ci'),
+        default='active',
+        comment='状态'
+    )
+    created_at = Column(
+        TIMESTAMP,
+        server_default=func.current_timestamp(),
+        comment='创建时间'
+    )
\ No newline at end of file
diff --git a/Merge/back_trm/app/models/users.py b/Merge/back_trm/app/models/users.py
new file mode 100644
index 0000000..0505e86
--- /dev/null
+++ b/Merge/back_trm/app/models/users.py
@@ -0,0 +1,51 @@
+from . import Base
+from sqlalchemy import (
+    Column, Integer, String, Enum, TIMESTAMP, text
+)
+from sqlalchemy.ext.declarative import declarative_base
+
+
+class User(Base):
+    __tablename__ = 'users'
+
+    def to_dict(self):
+        return {
+            'id': self.id,
+            'username': self.username if self.username else None,
+            'email': self.email if self.email else None,
+            'avatar': self.avatar if self.avatar else None,
+            'role': self.role if self.role else None,
+            'bio': self.bio if self.bio else None,
+            'status': self.status if self.status else None,
+            'created_at': self.created_at.isoformat() if self.created_at else None,
+            'updated_at': self.updated_at.isoformat() if self.updated_at else None
+        }
+
+
+
+    id = Column(Integer, primary_key=True, autoincrement=True, comment='用户ID')
+    username = Column(String(50), nullable=False, unique=True, comment='用户名')
+    password = Column(String(255), nullable=False, comment='加密密码')
+    email = Column(String(100), nullable=False, unique=True, comment='邮箱')
+    avatar = Column(String(255), comment='头像URL')
+    role = Column(Enum('user', 'admin', 'superadmin', name='user_role'), comment='角色')
+    bio = Column(String(255), comment='个人简介')
+    status = Column(
+        Enum('active','banned','muted', name='user_status'),
+        nullable=False,
+        server_default=text("'active'"),
+        comment='账号状态'
+    )
+    created_at = Column(
+        TIMESTAMP,
+        nullable=True,
+        server_default=text('CURRENT_TIMESTAMP'),
+        comment='创建时间'
+    )
+    updated_at = Column(
+        TIMESTAMP,
+        nullable=True,
+        server_default=text('CURRENT_TIMESTAMP'),
+        onupdate=text('CURRENT_TIMESTAMP'),
+        comment='更新时间'
+    )
\ No newline at end of file
diff --git a/Merge/back_trm/app/routes.py b/Merge/back_trm/app/routes.py
new file mode 100644
index 0000000..41b022b
--- /dev/null
+++ b/Merge/back_trm/app/routes.py
@@ -0,0 +1,155 @@
+from flask import Blueprint, render_template
+from .functions.Fpost import Fpost;
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker
+from config import Config
+from flask import jsonify,request
+
+main = Blueprint('main', __name__)
+
+@main.route('/sgiveadmin',methods=['POST','GET'])
+def giveadmin():
+    data=request.get_json()
+    print(data)
+    engine=create_engine(Config.SQLURL)
+    SessionLocal = sessionmaker(bind=engine)
+    session = SessionLocal()
+    f=Fpost(session)
+    checres=f.checkid(data['userid'],'superadmin')
+    if(not checres):
+        return jsonify({'status': 'error', 'message': 'Unauthorized'})
+    
+    res=f.giveadmin(data['targetid'])
+    if not res:
+        return jsonify({'status': 'error', 'message': 'User not found'})
+    
+    return jsonify({'status': 'success', 'message': 'User role updated to admin'})
+
+@main.route('/sgiveuser',methods=['POST','GET'])
+def giveuser():
+    data=request.get_json()
+    print(data)
+    engine=create_engine(Config.SQLURL)
+    SessionLocal = sessionmaker(bind=engine)
+    session = SessionLocal()
+    f=Fpost(session)
+    checres=f.checkid(data['userid'],'superadmin')
+    if(not checres):
+        return jsonify({'status': 'error', 'message': 'Unauthorized'})
+    
+    res=f.giveuser(data['targetid'])
+    if not res:
+        return jsonify({'status': 'error', 'message': 'User not found'})
+    
+    return jsonify({'status': 'success', 'message': 'User role updated to user'})
+
+
+@main.route('/sgivesuperadmin',methods=['POST','GET'])
+def givesuperadmin():
+    data=request.get_json()
+    print(data)
+    engine=create_engine(Config.SQLURL)
+    SessionLocal = sessionmaker(bind=engine)
+    session = SessionLocal()
+    f=Fpost(session)
+    checres=f.checkid(data['userid'],'superadmin')
+    if(not checres):
+        return jsonify({'status': 'error', 'message': 'Unauthorized'})
+    
+    res=f.givesuperadmin(data['targetid'])
+    if not res:
+        return jsonify({'status': 'error', 'message': 'User not found'})
+    
+    return jsonify({'status': 'success', 'message': 'User role updated to superadmin'})
+
+@main.route('/sgetuserlist',methods=['POST','GET'])
+def userlist():
+    data=request.get_json()
+    print(data)
+    engine=create_engine(Config.SQLURL)
+    SessionLocal = sessionmaker(bind=engine)
+    session = SessionLocal()
+    f=Fpost(session)
+    checres=f.checkid(data['userid'],'superadmin')
+    if(not checres):
+        return jsonify({'status': 'error', 'message': 'Unauthorized'})
+    res=f.getuserlist()
+    respons=[]
+    for datai in res:
+        respons.append({
+            'id': datai[0],
+            'username': datai[1],
+            'role': datai[2]
+        })
+    return jsonify(respons)
+
+@main.route('/apostlist',methods=['POST','GET'])
+def postlist():
+    data=request.get_json()
+    print(data)
+    engine=create_engine(Config.SQLURL)
+    SessionLocal = sessionmaker(bind=engine)
+    session = SessionLocal()
+    f=Fpost(session)
+    checres=f.checkid(data['userid'],'admin')
+    if(not checres):
+        return jsonify({'status': 'error', 'message': 'Unauthorized'})
+    res=f.getlist()
+    respons=[]
+    for datai in res:
+        respons.append({
+            'id': datai[0],
+            'title': datai[1],
+            'status': datai[2]
+        })
+    return jsonify(respons)
+
+@main.route('/agetpost',methods=['POST','GET'])
+def post():
+    data=request.get_json()
+    engine=create_engine(Config.SQLURL)
+    SessionLocal = sessionmaker(bind=engine)
+    session = SessionLocal()
+    f=Fpost(session)
+    checres=f.checkid(data['userid'],'admin')
+    if(not checres):
+        return jsonify({'status': 'error', 'message': 'Unauthorized'})
+    res=f.getpost(data['postid'])
+
+    return jsonify(res.to_dict() if res else {})
+
+@main.route('/areview',methods=['POST','GET'])
+def review():
+    data=request.get_json()
+    engine=create_engine(Config.SQLURL)
+    SessionLocal = sessionmaker(bind=engine)
+    session = SessionLocal()
+    f=Fpost(session)
+    checres=f.checkid(data['userid'],'admin')
+    if(not checres):
+        return jsonify({'status': 'error', 'message': 'Unauthorized'})
+    
+    res=f.review(data['postid'],data['status'])
+    if not res:
+        return jsonify({'status': 'error', 'message': 'Post not found'})
+    
+    return jsonify({'status': 'success', 'message': 'Post reviewed successfully'})
+
+
+
+@main.route('/nginxauth',methods=['POST','GET'])
+def nginxauth():
+    data=request.get_json()
+    engine=create_engine(Config.SQLURL)
+    SessionLocal = sessionmaker(bind=engine)
+    session = SessionLocal()
+    f=Fpost(session)
+    checres=f.checkid(data['userid'],'admin')
+    if(not checres):
+        return jsonify({'status': 'error', 'message': 'Unauthorized'})
+    
+    res=f.nginxauth(data['postid'],data['status'])
+    if not res:
+        return jsonify({'status': 'error', 'message': 'Post not found'})
+    
+    return jsonify({'status': 'success', 'message': 'Nginx auth updated successfully'})
\ No newline at end of file
diff --git a/Merge/back_trm/app/templates/base.html b/Merge/back_trm/app/templates/base.html
new file mode 100644
index 0000000..3c6f3cb
--- /dev/null
+++ b/Merge/back_trm/app/templates/base.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>{% block title %}My Flask App{% endblock %}</title>
+    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
+</head>
+<body>
+    <header>
+        <h1>Welcome to My Flask App</h1>
+        <nav>
+            <ul>
+                <li><a href="{{ url_for('index') }}">Home</a></li>
+                <!-- Add more navigation links here -->
+            </ul>
+        </nav>
+    </header>
+    
+    <main>
+        {% block content %}
+        {% endblock %}
+    </main>
+    
+    <footer>
+        <p>&copy; 2023 My Flask App</p>
+    </footer>
+</body>
+</html>
\ No newline at end of file
diff --git a/Merge/back_trm/app/templates/index.html b/Merge/back_trm/app/templates/index.html
new file mode 100644
index 0000000..6631bea
--- /dev/null
+++ b/Merge/back_trm/app/templates/index.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Index Page</title>
+    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
+</head>
+<body>
+    {% extends 'base.html' %}
+
+    {% block content %}
+    <h1>Welcome to the Index Page</h1>
+    <p>This is the main page of the application.</p>
+    {% endblock %}
+</body>
+</html>
\ No newline at end of file