第六周的注释

pull/16/head
yyd 3 months ago
parent e8b9cc585b
commit 0e3fde2060

@ -0,0 +1,88 @@
# 导入WeRoBot框架的会话存储基类和工具函数
from werobot.session import SessionStorage
from werobot.utils import json_loads, json_dumps
# 导入Django项目的缓存工具
from djangoblog.utils import cache
class MemcacheStorage(SessionStorage):
"""
基于Memcached的WeRoBot会话存储实现
继承自WeRoBot的SessionStorage基类用于将会话数据存储到Memcached中
"""
def __init__(self, prefix='ws_'):
"""
初始化方法
Args:
prefix (str): 缓存键的前缀默认为'ws_'用于区分其他缓存数据
"""
self.prefix = prefix # 设置缓存键前缀
self.cache = cache # Django缓存实例通常是Memcached
@property
def is_available(self):
"""
检查缓存存储是否可用的属性
Returns:
bool: 如果缓存系统工作正常返回True否则返回False
"""
value = "1" # 测试值
# 尝试设置一个测试键值对
self.set('checkavaliable', value=value)
# 读取测试值并比较,验证缓存系统是否正常工作
return value == self.get('checkavaliable')
def key_name(self, s):
"""
生成完整的缓存键名
Args:
s (str): 原始会话ID
Returns:
str: 添加前缀后的完整缓存键名
"""
return '{prefix}{s}'.format(prefix=self.prefix, s=s)
def get(self, id):
"""
根据会话ID获取会话数据
Args:
id (str): 会话ID
Returns:
dict: 解析后的会话数据字典如果不存在返回空字典
"""
id = self.key_name(id) # 生成完整缓存键
# 从缓存获取数据如果不存在则返回空JSON对象
session_json = self.cache.get(id) or '{}'
# 将JSON字符串解析为Python字典
return json_loads(session_json)
def set(self, id, value):
"""
设置会话数据
Args:
id (str): 会话ID
value (dict): 要存储的会话数据字典
"""
id = self.key_name(id) # 生成完整缓存键
# 将会话数据序列化为JSON字符串并存储到缓存
self.cache.set(id, json_dumps(value))
def delete(self, id):
"""
删除指定会话ID的数据
Args:
id (str): 要删除的会话ID
"""
id = self.key_name(id) # 生成完整缓存键
# 从缓存中删除对应的数据
self.cache.delete(id)

@ -0,0 +1,63 @@
# 导入Django管理模块
from django.contrib import admin
# 导入自定义模型假设已在同一目录的models.py中定义
from .models import commands, EmailSendLog
# 注册Commands模型到Django管理后台
class CommandsAdmin(admin.ModelAdmin):
"""
命令模型的管理界面配置类
用于自定义commands模型在Django admin中的显示和行为
"""
# 设置在管理列表页面显示的字段
list_display = ('title', 'command', 'describe')
# 字段说明:
# - title: 命令标题
# - command: 具体命令内容
# - describe: 命令描述
# 注册EmailSendLog模型到Django管理后台
class EmailSendLogAdmin(admin.ModelAdmin):
"""
邮件发送日志模型的管理界面配置类
用于自定义EmailSendLog模型在Django admin中的显示和行为
"""
# 设置在管理列表页面显示的字段
list_display = ('title', 'emailto', 'send_result', 'creation_time')
# 字段说明:
# - title: 邮件标题
# - emailto: 收件人
# - send_result: 发送结果
# - creation_time: 创建时间
# 设置只读字段,这些字段在编辑页面不可修改
readonly_fields = (
'title', # 邮件标题(只读)
'emailto', # 收件人(只读)
'send_result', # 发送结果(只读)
'creation_time', # 创建时间(只读)
'content' # 邮件内容(只读)
)
def has_add_permission(self, request):
"""
重写添加权限方法禁止在管理后台手动添加邮件日志记录
Args:
request: HTTP请求对象
Returns:
bool: 总是返回False禁止添加操作
"""
return False
# 这样设计是因为邮件发送日志应该由系统自动创建
# 而不是手动添加,保证日志的真实性和完整性
# 将模型注册到Django管理后台
admin.site.register(commands, CommandsAdmin)
admin.site.register(EmailSendLog, EmailSendLogAdmin)

@ -0,0 +1,78 @@
# 导入Haystack搜索查询集
from haystack.query import SearchQuerySet
# 导入博客模型
from blog.models import Article, Category
class BlogApi:
"""
博客API类
提供博客文章的搜索分类获取和最近文章等功能
"""
def __init__(self):
"""
初始化方法
创建搜索查询集实例并设置最大返回数量
"""
# 创建搜索查询集实例
self.searchqueryset = SearchQuerySet()
# 初始化空查询,准备后续搜索
self.searchqueryset.auto_query('')
# 设置最大返回文章数量
self.__max_takecount__ = 8
def search_articles(self, query):
"""
搜索文章方法
Args:
query (str): 搜索关键词
Returns:
SearchQuerySet: 包含搜索结果的查询集最多返回__max_takecount__条结果
"""
# 使用Haystack进行自动搜索查询
sqs = self.searchqueryset.auto_query(query)
# 加载所有相关对象避免N+1查询问题
sqs = sqs.load_all()
# 返回前__max_takecount__条结果
return sqs[:self.__max_takecount__]
def get_category_lists(self):
"""
获取所有分类列表
Returns:
QuerySet: 包含所有分类的查询集
"""
return Category.objects.all()
def get_category_articles(self, categoryname):
"""
根据分类名称获取该分类下的文章
Args:
categoryname (str): 分类名称
Returns:
QuerySet or None: 包含该分类文章的查询集最多__max_takecount__条如果分类不存在返回None
"""
# 根据分类名称过滤文章
articles = Article.objects.filter(category__name=categoryname)
# 如果找到文章返回前__max_takecount__条
if articles:
return articles[:self.__max_takecount__]
# 没有找到文章返回None
return None
def get_recent_articles(self):
"""
获取最近的文章
Returns:
QuerySet: 包含最近文章的查询集最多返回__max_takecount__条
"""
# 获取所有文章并按时间排序假设Article模型的默认排序是按时间倒序
return Article.objects.all()[:self.__max_takecount__]

@ -0,0 +1,129 @@
# 导入必要的模块
import logging
import os
import openai # OpenAI API客户端
# 导入自定义的Django模型
from servermanager.models import commands
# 获取当前模块的日志记录器
logger = logging.getLogger(__name__)
# 配置OpenAI API密钥从环境变量中获取
openai.api_key = os.environ.get('OPENAI_API_KEY')
# 如果设置了HTTP代理配置OpenAI使用代理
if os.environ.get('HTTP_PROXY'):
openai.proxy = os.environ.get('HTTP_PROXY')
class ChatGPT:
"""
ChatGPT API封装类
提供与OpenAI GPT模型交互的静态方法
"""
@staticmethod
def chat(prompt):
"""
与ChatGPT进行对话的静态方法
Args:
prompt (str): 用户输入的提示词
Returns:
str: ChatGPT的回复内容如果出错返回错误信息
"""
try:
# 调用OpenAI ChatCompletion API创建对话完成
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo", # 指定使用gpt-3.5-turbo模型
messages=[{"role": "user", "content": prompt}] # 设置对话消息
)
# 返回第一个选择中的消息内容
return completion.choices[0].message.content
except Exception as e:
# 记录错误日志
logger.error(e)
# 返回用户友好的错误信息
return "服务器出错了"
class CommandHandler:
"""
命令处理器类
用于管理和执行预定义的系统命令
"""
def __init__(self):
"""
初始化方法
从数据库加载所有预定义命令
"""
# 从数据库获取所有命令对象
self.commands = commands.objects.all()
def run(self, title):
"""
运行指定标题的命令
Args:
title (str): 命令标题
Returns:
str: 命令执行结果或帮助信息
"""
# 使用filter和lambda函数查找标题匹配的命令不区分大小写
cmd = list(
filter(
lambda x: x.title.upper() == title.upper(), # 不区分大小写比较
self.commands))
# 如果找到匹配的命令
if cmd:
# 执行找到的第一个命令
return self.__run_command__(cmd[0].command)
else:
# 未找到命令时返回帮助提示
return "未找到相关命令请输入helpme获得帮助。"
def __run_command__(self, cmd):
"""
私有方法实际执行系统命令
Args:
cmd (str): 要执行的系统命令
Returns:
str: 命令执行结果或错误信息
"""
try:
# 使用os.popen执行系统命令并读取输出
res = os.popen(cmd).read()
return res
except BaseException:
# 捕获所有异常,返回错误信息
return '命令执行出错!'
def get_help(self):
"""
获取所有命令的帮助信息
Returns:
str: 格式化的命令帮助信息包含所有命令的标题和描述
"""
rsp = ''
# 遍历所有命令,格式化输出
for cmd in self.commands:
rsp += '{c}:{d}\n'.format(c=cmd.title, d=cmd.describe)
return rsp
# 主程序入口
if __name__ == '__main__':
# 创建ChatGPT实例
chatbot = ChatGPT()
# 测试提示词
prompt = "写一篇1000字关于AI的论文"
# 调用chat方法并打印结果
print(chatbot.chat(prompt))

@ -0,0 +1,31 @@
# 导入Django的应用配置基类
from django.apps import AppConfig
class ServermanagerConfig(AppConfig):
"""
Servermanager应用的配置类
继承自Django的AppConfig基类用于配置servermanager应用的相关设置
这个类主要用于
1. 定义应用的配置信息
2. 在Django启动时执行应用初始化代码
3. 配置应用的元数据
"""
# 指定应用的Python路径必需字段
# 这应该与settings.INSTALLED_APPS中使用的路径匹配
name = 'servermanager'
# 说明:
# - 'servermanager' 表示应用的Python导入路径
# - Django使用这个名称来识别和应用配置
# 可选配置字段示例(当前代码中未使用):
#
# verbose_name = '服务器管理器' # 应用的可读名称
# default_auto_field = 'django.db.models.BigAutoField' # 默认主键字段类型
#
# 可以在ready()方法中添加应用启动时的初始化代码:
# def ready(self):
# # 应用启动时执行的初始化代码
# import servermanager.signals # 例如:导入信号处理器

@ -0,0 +1,67 @@
# Generated by Django 4.1.7 on 2023-03-02 07:14
from django.db import migrations, models
class Migration(migrations.Migration):
"""
Django数据库迁移类
迁移用于创建数据库表结构这是初始迁移(initial=True)
"""
initial = True # 标记这是初始迁移
dependencies = [
# 依赖关系列表,此迁移不依赖其他迁移
]
operations = [
# 迁移操作列表
# 创建命令表
migrations.CreateModel(
name='commands', # 模型名称
fields=[
# 主键字段自增BigInteger类型
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
# 命令标题字段最大长度300字符
('title', models.CharField(max_length=300, verbose_name='命令标题')),
# 命令字段存储具体命令内容最大长度2000字符
('command', models.CharField(max_length=2000, verbose_name='命令')),
# 命令描述字段最大长度300字符
('describe', models.CharField(max_length=300, verbose_name='命令描述')),
# 创建时间字段,自动设置为记录创建时的时间
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
# 最后修改时间字段,每次保存时自动更新为当前时间
('last_mod_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')),
],
options={
'verbose_name': '命令', # 单数形式的可读名称
'verbose_name_plural': '命令', # 复数形式的可读名称
},
),
# 创建邮件发送日志表
migrations.CreateModel(
name='EmailSendLog', # 模型名称
fields=[
# 主键字段自增BigInteger类型
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
# 收件人字段存储收件人邮箱地址最大长度300字符
('emailto', models.CharField(max_length=300, verbose_name='收件人')),
# 邮件标题字段最大长度2000字符
('title', models.CharField(max_length=2000, verbose_name='邮件标题')),
# 邮件内容字段,文本类型,无长度限制
('content', models.TextField(verbose_name='邮件内容')),
# 发送结果字段布尔类型默认值为False(发送失败)
('send_result', models.BooleanField(default=False, verbose_name='结果')),
# 创建时间字段,自动设置为记录创建时的时间
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
],
options={
'verbose_name': '邮件发送log', # 单数形式的可读名称
'verbose_name_plural': '邮件发送log', # 复数形式的可读名称
'ordering': ['-created_time'], # 默认按创建时间降序排列
},
),
]

@ -0,0 +1,50 @@
# Generated by Django 4.2.5 on 2023-09-06 13:19
from django.db import migrations
class Migration(migrations.Migration):
"""
Django数据库迁移类
这是一个数据模型变更的迁移文件用于修改已有表结构
"""
dependencies = [
# 依赖关系此迁移依赖于servermanager应用的0001_initial初始迁移
('servermanager', '0001_initial'),
]
operations = [
# 迁移操作列表
# 修改EmailSendLog模型的元选项
migrations.AlterModelOptions(
name='emailsendlog', # 模型名称
options={
'ordering': ['-creation_time'], # 改为按creation_time字段降序排列
'verbose_name': '邮件发送log', # 单数形式的可读名称
'verbose_name_plural': '邮件发送log', # 复数形式的可读名称
},
),
# 重命名commands模型的created_time字段为creation_time
migrations.RenameField(
model_name='commands', # 模型名称
old_name='created_time', # 原字段名
new_name='creation_time', # 新字段名
),
# 重命名commands模型的last_mod_time字段为last_modify_time
migrations.RenameField(
model_name='commands', # 模型名称
old_name='last_mod_time', # 原字段名
new_name='last_modify_time', # 新字段名
),
# 重命名emailsendlog模型的created_time字段为creation_time
migrations.RenameField(
model_name='emailsendlog', # 模型名称
old_name='created_time', # 原字段名
new_name='creation_time', # 新字段名
),
]

@ -0,0 +1,82 @@
# 导入Django的模型模块
from django.db import models
# 创建命令模型(数据库表)
class commands(models.Model):
"""
命令模型类
用于存储系统命令的相关信息
"""
# 命令标题字段CharField类型最大长度300在admin中显示为'命令标题'
title = models.CharField('命令标题', max_length=300)
# 命令内容字段CharField类型最大长度2000在admin中显示为'命令'
command = models.CharField('命令', max_length=2000)
# 命令描述字段CharField类型最大长度300在admin中显示为'命令描述'
describe = models.CharField('命令描述', max_length=300)
# 创建时间字段DateTimeField类型自动设置为对象创建时的时间
creation_time = models.DateTimeField('创建时间', auto_now_add=True)
# 最后修改时间字段DateTimeField类型自动更新为对象最后修改的时间
last_modify_time = models.DateTimeField('修改时间', auto_now=True)
def __str__(self):
"""
定义对象的字符串表示形式
在Django admin和shell中显示时使用
Returns:
str: 命令标题
"""
return self.title
class Meta:
"""
模型的元数据配置类
用于定义模型的其他选项
"""
verbose_name = '命令' # 单数形式的可读名称
verbose_name_plural = verbose_name # 复数形式的可读名称(与单数相同)
class EmailSendLog(models.Model):
"""
邮件发送日志模型类
用于记录邮件发送的历史记录和结果
"""
# 收件人字段CharField类型最大长度300在admin中显示为'收件人'
emailto = models.CharField('收件人', max_length=300)
# 邮件标题字段CharField类型最大长度2000在admin中显示为'邮件标题'
title = models.CharField('邮件标题', max_length=2000)
# 邮件内容字段TextField类型无长度限制在admin中显示为'邮件内容'
content = models.TextField('邮件内容')
# 发送结果字段BooleanField类型默认值为False发送失败在admin中显示为'结果'
send_result = models.BooleanField('结果', default=False)
# 创建时间字段DateTimeField类型自动设置为对象创建时的时间
creation_time = models.DateTimeField('创建时间', auto_now_add=True)
def __str__(self):
"""
定义对象的字符串表示形式
Returns:
str: 邮件标题
"""
return self.title
class Meta:
"""
模型的元数据配置类
"""
verbose_name = '邮件发送log' # 单数形式的可读名称
verbose_name_plural = verbose_name # 复数形式的可读名称
ordering = ['-creation_time'] # 默认按创建时间降序排列(最新的在前)

@ -0,0 +1,255 @@
# 导入必要的模块
import logging
import os
import re
import jsonpickle # 用于对象序列化
from django.conf import settings
from werobot import WeRoBot # 微信机器人框架
from werobot.replies import ArticlesReply, Article # 微信图文回复
from werobot.session.filestorage import FileStorage # 文件会话存储
from djangoblog.utils import get_sha256 # 加密工具函数
from servermanager.api.blogapi import BlogApi # 博客API
from servermanager.api.commonapi import ChatGPT, CommandHandler # 聊天和命令处理
from .MemcacheStorage import MemcacheStorage # 自定义缓存存储
# 初始化微信机器人从环境变量获取token默认使用'lylinux'
robot = WeRoBot(token=os.environ.get('DJANGO_WEROBOT_TOKEN') or 'lylinux', enable_session=True)
# 初始化Memcached会话存储
memstorage = MemcacheStorage()
# 检查Memcached是否可用如果可用则使用否则使用文件存储
if memstorage.is_available:
robot.config['SESSION_STORAGE'] = memstorage
else:
# 如果存在旧的会话文件则删除
if os.path.exists(os.path.join(settings.BASE_DIR, 'werobot_session')):
os.remove(os.path.join(settings.BASE_DIR, 'werobot_session'))
robot.config['SESSION_STORAGE'] = FileStorage(filename='werobot_session')
# 初始化API处理器
blogapi = BlogApi()
cmd_handler = CommandHandler()
logger = logging.getLogger(__name__)
def convert_to_article_reply(articles, message):
"""
将文章列表转换为微信图文回复格式
Args:
articles: 文章对象列表
message: 微信消息对象
Returns:
ArticlesReply: 图文回复对象
"""
reply = ArticlesReply(message=message)
from blog.templatetags.blog_tags import truncatechars_content # 导入内容截断过滤器
for post in articles:
# 使用正则表达式从文章内容中提取第一张图片
imgs = re.findall(r'(?:http\:|https\:)?\/\/.*\.(?:png|jpg)', post.body)
imgurl = ''
if imgs:
imgurl = imgs[0] # 使用第一张图片作为封面
# 创建图文消息条目
article = Article(
title=post.title, # 文章标题
description=truncatechars_content(post.body), # 截断后的文章内容作为描述
img=imgurl, # 封面图片URL
url=post.get_full_url() # 文章完整URL
)
reply.add_article(article)
return reply
@robot.filter(re.compile(r"^\?.*"))
def search(message, session):
"""
文章搜索功能
触发方式: ?关键字
例如: ?python
"""
s = message.content
searchstr = str(s).replace('?', '') # 移除问号获取搜索关键词
result = blogapi.search_articles(searchstr) # 调用搜索API
if result:
# 将搜索结果转换为文章对象列表
articles = list(map(lambda x: x.object, result))
reply = convert_to_article_reply(articles, message)
return reply
else:
return '没有找到相关文章。'
@robot.filter(re.compile(r'^category\s*$', re.I))
def category(message, session):
"""
获取所有文章分类
触发方式: category
"""
categorys = blogapi.get_category_lists()
content = ','.join(map(lambda x: x.name, categorys))
return '所有文章分类目录:' + content
@robot.filter(re.compile(r'^recent\s*$', re.I))
def recents(message, session):
"""
获取最新文章
触发方式: recent
"""
articles = blogapi.get_recent_articles()
if articles:
reply = convert_to_article_reply(articles, message)
return reply
else:
return "暂时还没有文章"
@robot.filter(re.compile('^help$', re.I))
def help(message, session):
"""
获取帮助信息
触发方式: help
"""
return '''欢迎关注!
默认会与图灵机器人聊天~~
你可以通过下面这些命令来获得信息
?关键字搜索文章.
?python.
category获得文章分类目录及文章数.
category-***获得该分类目录文章
如category-python
recent获得最新文章
help获得帮助.
weather:获得天气
如weather:西安
idcard:获得身份证信息
如idcard:61048119xxxxxxxxxx
music:音乐搜索
如music:阴天快乐
PS:以上标点符号都不支持中文标点~~
'''
@robot.filter(re.compile(r'^weather\:.*$', re.I))
def weather(message, session):
"""天气查询功能(建设中)"""
return "建设中..."
@robot.filter(re.compile(r'^idcard\:.*$', re.I))
def idcard(message, session):
"""身份证查询功能(建设中)"""
return "建设中..."
@robot.handler
def echo(message, session):
"""
默认消息处理器
处理所有未匹配到其他过滤器的消息
"""
handler = MessageHandler(message, session)
return handler.handler()
class MessageHandler:
"""消息处理器类,负责处理用户会话和权限验证"""
def __init__(self, message, session):
userid = message.source
self.message = message
self.session = session
self.userid = userid
try:
# 从会话中获取用户信息
info = session[userid]
self.userinfo = jsonpickle.decode(info)
except Exception as e:
# 如果会话中没有用户信息,创建新的用户信息对象
userinfo = WxUserInfo()
self.userinfo = userinfo
@property
def is_admin(self):
"""检查用户是否为管理员"""
return self.userinfo.isAdmin
@property
def is_password_set(self):
"""检查管理员密码是否已设置"""
return self.userinfo.isPasswordSet
def save_session(self):
"""保存用户信息到会话"""
info = jsonpickle.encode(self.userinfo)
self.session[self.userid] = info
def handler(self):
"""主消息处理方法"""
info = self.message.content
# 管理员退出命令
if self.userinfo.isAdmin and info.upper() == 'EXIT':
self.userinfo = WxUserInfo()
self.save_session()
return "退出成功"
# 进入管理员模式
if info.upper() == 'ADMIN':
self.userinfo.isAdmin = True
self.save_session()
return "输入管理员密码"
# 管理员密码验证
if self.userinfo.isAdmin and not self.userinfo.isPasswordSet:
passwd = settings.WXADMIN # 从设置获取管理员密码
if settings.TESTING: # 测试环境下使用简单密码
passwd = '123'
# 验证密码双重SHA256加密
if passwd.upper() == get_sha256(get_sha256(info)).upper():
self.userinfo.isPasswordSet = True
self.save_session()
return "验证通过,请输入命令或者要执行的命令代码:输入helpme获得帮助"
else:
# 密码错误次数限制
if self.userinfo.Count >= 3:
self.userinfo = WxUserInfo()
self.save_session()
return "超过验证次数"
self.userinfo.Count += 1
self.save_session()
return "验证失败,请重新输入管理员密码:"
# 管理员命令执行
if self.userinfo.isAdmin and self.userinfo.isPasswordSet:
# 确认执行命令
if self.userinfo.Command != '' and info.upper() == 'Y':
return cmd_handler.run(self.userinfo.Command)
else:
# 获取命令帮助
if info.upper() == 'HELPME':
return cmd_handler.get_help()
# 保存命令等待确认
self.userinfo.Command = info
self.save_session()
return "确认执行: " + info + " 命令?"
# 默认使用ChatGPT回复
return ChatGPT.chat(info)
class WxUserInfo():
"""微信用户信息类,用于存储用户会话状态"""
def __init__(self):
self.isAdmin = False # 是否为管理员
self.isPasswordSet = False # 是否通过密码验证
self.Count = 0 # 密码尝试次数
self.Command = '' # 待确认的命令

@ -0,0 +1,121 @@
# 导入Django测试相关模块
from django.test import Client, RequestFactory, TestCase
from django.utils import timezone
# 导入WeRoBot文本消息类
from werobot.messages.messages import TextMessage
# 导入应用模型
from accounts.models import BlogUser
from blog.models import Category, Article
# 导入要测试的API类
from servermanager.api.commonapi import ChatGPT
from .models import commands
# 导入要测试的机器人处理类和方法
from .robot import MessageHandler, CommandHandler
from .robot import search, category, recents
# 创建服务器管理器测试类
class ServerManagerTest(TestCase):
"""
服务器管理器功能测试类
测试servermanager应用的各项功能
"""
def setUp(self):
"""
测试初始化方法
在每个测试方法执行前运行用于设置测试环境
"""
# 创建测试客户端用于模拟HTTP请求
self.client = Client()
# 创建请求工厂,用于构建请求对象
self.factory = RequestFactory()
def test_chat_gpt(self):
"""
测试ChatGPT功能
验证ChatGPT API是否能正常返回响应
"""
content = ChatGPT.chat("你好") # 发送测试消息
self.assertIsNotNone(content) # 断言响应内容不为空
def test_validate_comment(self):
"""
综合测试方法
测试博客系统和微信机器人的完整功能链
"""
# 创建超级用户
user = BlogUser.objects.create_superuser(
email="liangliangyy1@gmail.com",
username="liangliangyy1",
password="liangliangyy1")
# 使用创建的超级用户登录
self.client.login(username='liangliangyy1', password='liangliangyy1')
# 创建分类
c = Category()
c.name = "categoryccc"
c.save()
# 创建文章
article = Article()
article.title = "nicetitleccc"
article.body = "nicecontentccc"
article.author = user
article.category = c
article.type = 'a' # 文章类型
article.status = 'p' # 发布状态
article.save()
# 测试搜索功能
s = TextMessage([]) # 创建空的文本消息对象
s.content = "nice" # 设置消息内容
rsp = search(s, None) # 调用搜索函数
# 注意:这里没有对搜索结果进行断言,可能需要补充
# 测试分类功能
rsp = category(None, None) # 调用分类函数
self.assertIsNotNone(rsp) # 断言响应不为空
# 测试最近文章功能
rsp = recents(None, None) # 调用最近文章函数
self.assertTrue(rsp != '暂时还没有文章') # 断言有文章返回
# 测试命令功能
# 创建测试命令
cmd = commands()
cmd.title = "test"
cmd.command = "ls" # Linux列表命令
cmd.describe = "test"
cmd.save()
# 测试命令处理器
cmdhandler = CommandHandler()
rsp = cmdhandler.run('test') # 执行测试命令
self.assertIsNotNone(rsp) # 断言命令执行结果不为空
# 测试消息处理器
s.source = 'u' # 设置消息来源
s.content = 'test' # 设置消息内容
msghandler = MessageHandler(s, {}) # 创建消息处理器
# 注释掉的管理员权限设置
# msghandler.userinfo.isPasswordSet = True
# msghandler.userinfo.isAdmin = True
# 测试各种消息处理场景
msghandler.handler() # 处理'test'消息
s.content = 'y' # 确认执行命令
msghandler.handler()
s.content = 'idcard:12321233' # 身份证查询(建设中功能)
msghandler.handler()
s.content = 'weather:上海' # 天气查询(建设中功能)
msghandler.handler()
s.content = 'admin' # 进入管理员模式
msghandler.handler()
s.content = '123' # 输入管理员密码
msghandler.handler()
s.content = 'exit' # 退出管理员模式
msghandler.handler()

@ -0,0 +1,22 @@
# 导入Django的URL路由模块
from django.urls import path
# 导入WeRoBot的Django视图创建工具
from werobot.contrib.django import make_view
# 从当前目录的robot模块导入robot实例
from .robot import robot
# 定义应用的命名空间用于URL反向解析
app_name = "servermanager"
# 定义URL模式列表
urlpatterns = [
# 微信机器人消息接收接口
# 路径: /servermanager/robot
# 使用WeRoBot的make_view将robot实例转换为Django视图
path(r'robot', make_view(robot)),
# 说明:
# - r'robot': URL路径模式匹配"robot"路径
# - make_view(robot): 将WeRoBot机器人实例包装成Django视图函数
# - 这个端点用于接收微信服务器发送的消息和事件
]

@ -0,0 +1 @@
# Create your views here.
Loading…
Cancel
Save