origin commit
This commit is contained in:
commit
ac437a0f6a
|
@ -0,0 +1,6 @@
|
||||||
|
__pycache__/**
|
||||||
|
build
|
||||||
|
dump
|
||||||
|
config.toml
|
||||||
|
|
||||||
|
venv
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
// 使用 IntelliSense 了解相关属性。
|
||||||
|
// 悬停以查看现有属性的描述。
|
||||||
|
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Python 调试: dump",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "dump.py",
|
||||||
|
"console": "integratedTerminal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Python 调试: build",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "render.py",
|
||||||
|
"console": "integratedTerminal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Python 调试: http server",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "test.py",
|
||||||
|
"console": "integratedTerminal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"python.REPL.enableREPLSmartSend": false
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
[dump]
|
||||||
|
server = "127.0.0.1" # 服务器 IP,推荐本地数据库或者直接在服务器上运行脚本
|
||||||
|
port = 3306 # 端口,一般不用改
|
||||||
|
user = "root" # 用户名
|
||||||
|
passwd = "your_passwd" # 密码,必填
|
||||||
|
charset = "utf8mb4" # 字符集,出问题可以试试 `utf8`
|
||||||
|
db = "smf" # 数据库名,根据自己情况
|
||||||
|
table = "phpbb2" # 表前缀,一般不用改
|
||||||
|
clean = true # 是否清理先前生成,推荐打开
|
||||||
|
|
||||||
|
[render]
|
||||||
|
show_st = false # 显示详细信息,打开会降低生成速度
|
||||||
|
clean = true # 是否清理先前生成,推荐打开
|
||||||
|
page_split = 20 # 多少内容为一页,推荐 20,25,50
|
|
@ -0,0 +1,164 @@
|
||||||
|
import tomllib
|
||||||
|
import pymysql
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from t_parser import parser
|
||||||
|
|
||||||
|
|
||||||
|
print("Load config")
|
||||||
|
|
||||||
|
with open("config.toml", 'rb') as file:
|
||||||
|
cfg = tomllib.load(file)["dump"]
|
||||||
|
server = cfg["server"]
|
||||||
|
port = cfg["port"]
|
||||||
|
user = cfg["user"]
|
||||||
|
passwd = cfg["passwd"]
|
||||||
|
charset = cfg["charset"]
|
||||||
|
db = cfg["db"]
|
||||||
|
table = cfg["table"]
|
||||||
|
needclean = cfg["clean"]
|
||||||
|
|
||||||
|
print(f"Connect {server}:{port} as {user}")
|
||||||
|
|
||||||
|
conn = pymysql.connect(
|
||||||
|
host=server,
|
||||||
|
port=port,
|
||||||
|
user=user,
|
||||||
|
password=passwd,
|
||||||
|
charset=charset
|
||||||
|
)
|
||||||
|
|
||||||
|
print("Server version:"+conn.get_server_info())
|
||||||
|
|
||||||
|
cursor = conn.cursor()
|
||||||
|
conn.select_db(db)
|
||||||
|
|
||||||
|
if (needclean):
|
||||||
|
print("Init dump")
|
||||||
|
if os.path.exists("dump"):
|
||||||
|
shutil.rmtree("dump")
|
||||||
|
os.mkdir("dump")
|
||||||
|
|
||||||
|
if not (os.path.exists("dump/forums.json")):
|
||||||
|
print("Load forums")
|
||||||
|
cursor.execute(f'SELECT * FROM {table}forums')
|
||||||
|
result = cursor.fetchall()
|
||||||
|
forums_struct = [{"name": "杂项", "description": "无法归类的帖子", "id": -1}]
|
||||||
|
count = 0
|
||||||
|
forum_id_list = []
|
||||||
|
for t in result:
|
||||||
|
count += 1
|
||||||
|
forums_struct.append({"name": t[1], "description": t[2], "id": t[0]})
|
||||||
|
forum_id_list.append(t[0])
|
||||||
|
print(f"Forums count:{count}")
|
||||||
|
with open("dump/forums.json", 'w') as file:
|
||||||
|
json.dump(forums_struct, file, ensure_ascii=False, indent=4)
|
||||||
|
with open("dump/forums_tmp.json", 'w') as file:
|
||||||
|
json.dump(forum_id_list, file, ensure_ascii=False)
|
||||||
|
|
||||||
|
if not (os.path.exists("dump/forums")):
|
||||||
|
print(f"Load topics")
|
||||||
|
os.mkdir("dump/forums")
|
||||||
|
print("Load forums from json")
|
||||||
|
with open("dump/forums_tmp.json", 'r') as file:
|
||||||
|
forum_id_list = json.load(file)
|
||||||
|
cursor.execute(f'SELECT COUNT(*) FROM {table}topics')
|
||||||
|
counts = cursor.fetchall()[0][0]
|
||||||
|
print(f"Topics count:{counts}")
|
||||||
|
cursor.execute(f'SELECT * FROM {table}topics')
|
||||||
|
result = cursor.fetchall()
|
||||||
|
print(f"Get topics")
|
||||||
|
count = 0
|
||||||
|
for i in result:
|
||||||
|
count += 1
|
||||||
|
forums_ids = i[7]
|
||||||
|
if (forums_ids not in forum_id_list):
|
||||||
|
forums_ids = -1
|
||||||
|
fpath = f"dump/forums/{forums_ids}.manifest"
|
||||||
|
if not (os.path.exists(fpath)):
|
||||||
|
with open(fpath, "w") as file:
|
||||||
|
file.write("")
|
||||||
|
with open(fpath, 'a') as file:
|
||||||
|
file.write(json.dumps(
|
||||||
|
{"name": i[1], "time": i[3], "id": i[0]}, ensure_ascii=False)+'\n')
|
||||||
|
if (count % 100 == 0):
|
||||||
|
print(f" load {count}", end="\r")
|
||||||
|
print(f" load {count}")
|
||||||
|
|
||||||
|
if not (os.path.exists("dump/users.json")):
|
||||||
|
print("Load users")
|
||||||
|
cursor.execute(f'SELECT * FROM {table}users')
|
||||||
|
result = cursor.fetchall()
|
||||||
|
user_json = {
|
||||||
|
str(i[0]): {
|
||||||
|
"name": i[1],
|
||||||
|
"time": i[2],
|
||||||
|
"email": (i[4]) if (i[4] is not None) else "",
|
||||||
|
"description": parser.format(
|
||||||
|
("签名(sig): "+i[10]+"\n") if (i[10] is not None) else "" +
|
||||||
|
("邮箱(Email): "+i[4]+"\n") if (i[4] is not None and i[11] == 1) else "" +
|
||||||
|
("网站(website): [url="+i[6]+"]"+i[6]+"[/url]\n") if (i[6] is not None) else "" +
|
||||||
|
("状态(status): "+i[7]+"\n") if (i[7] is not None) else "" +
|
||||||
|
("属地(from): "+i[8]+"\n") if (i[8] is not None) else "" +
|
||||||
|
("爱好(interests): "+i[9] +
|
||||||
|
"\n") if (i[9] is not None) else ""
|
||||||
|
)
|
||||||
|
} for i in result
|
||||||
|
}
|
||||||
|
with open("dump/users.json", 'w') as file:
|
||||||
|
json.dump(user_json, file, ensure_ascii=False)
|
||||||
|
|
||||||
|
if not (os.path.exists("dump/topics")):
|
||||||
|
print("Load posts")
|
||||||
|
os.mkdir("dump/topics")
|
||||||
|
print("Load users from json")
|
||||||
|
with open("dump/users.json", 'r') as file:
|
||||||
|
user_json = json.load(file)
|
||||||
|
cursor.execute(f'SELECT COUNT(*) FROM {table}posts')
|
||||||
|
counts = cursor.fetchall()[0][0]
|
||||||
|
print(f"Posts count:{counts}")
|
||||||
|
page_size = 100
|
||||||
|
oppsize = 0
|
||||||
|
last_id = -1
|
||||||
|
while 1:
|
||||||
|
if (oppsize >= counts):
|
||||||
|
break
|
||||||
|
cursor.execute(
|
||||||
|
f'SELECT * FROM {table}posts WHERE `post_id` > {last_id} ORDER BY post_id LIMIT {page_size}')
|
||||||
|
result = cursor.fetchall()
|
||||||
|
last_id = result[-1][0]
|
||||||
|
oppsize += page_size
|
||||||
|
for i in result:
|
||||||
|
s_retcode = cursor.execute(
|
||||||
|
f'SELECT * FROM {table}posts_text WHERE `post_id`={i[0]}')
|
||||||
|
if (s_retcode == 0):
|
||||||
|
continue
|
||||||
|
s_res = cursor.fetchall()[0]
|
||||||
|
if (s_res[1] is None):
|
||||||
|
continue
|
||||||
|
|
||||||
|
def rend(str, en_bbcode):
|
||||||
|
if (en_bbcode == 1):
|
||||||
|
return parser.format(str)
|
||||||
|
return str
|
||||||
|
s_text = rend((
|
||||||
|
(("主题:"+s_res[4]+"\n\n") if s_res[4] is not None else "") + s_res[1]).replace(":"+str(s_res[3]), ""), i[10])
|
||||||
|
sender_id = i[3]
|
||||||
|
send_name = (i[9] if (i[9] is not None) else "")
|
||||||
|
if (send_name == "" and sender_id != -1 and str(sender_id) in user_json):
|
||||||
|
send_name = user_json[str(sender_id)]["name"]
|
||||||
|
if (sender_id == -1):
|
||||||
|
send_name = "[未注册]"+send_name
|
||||||
|
topic_id = i[1]
|
||||||
|
fpath = f"dump/topics/{topic_id}.manifest"
|
||||||
|
with open(fpath, 'a') as file:
|
||||||
|
file.write(json.dumps(
|
||||||
|
{"text": s_text, "poster_id": sender_id, "poster_name": send_name}, ensure_ascii=False)+"\n")
|
||||||
|
print(f" load {oppsize}", end="\r")
|
||||||
|
print(f" load {counts}")
|
||||||
|
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
|
@ -0,0 +1,35 @@
|
||||||
|
# BBcovert
|
||||||
|
|
||||||
|
> 本项目可以将phpbb论坛中的帖子和评论内容转换成纯静态页面
|
||||||
|
|
||||||
|
## 运行
|
||||||
|
|
||||||
|
> 请在字符集设置为utf-8的linux下运行!
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 请先配置config.toml!
|
||||||
|
# 从sample复制:
|
||||||
|
cp config.sample.toml config.toml
|
||||||
|
|
||||||
|
# 初始化虚拟环境,推荐先换源
|
||||||
|
python -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# 下载数据库
|
||||||
|
python dump.py
|
||||||
|
|
||||||
|
# 生成静态页面
|
||||||
|
python render.py
|
||||||
|
|
||||||
|
# 测试生成
|
||||||
|
python test.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 结构
|
||||||
|
|
||||||
|
`theme` 文件夹内是主题文件
|
||||||
|
|
||||||
|
数据库会被下载到 `dump` 文件夹
|
||||||
|
|
||||||
|
生成产物在 `build` 文件夹
|
|
@ -0,0 +1,170 @@
|
||||||
|
import jinja2
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import tomllib
|
||||||
|
import math
|
||||||
|
|
||||||
|
print("Load config")
|
||||||
|
with open("config.toml", 'rb') as file:
|
||||||
|
cfg = tomllib.load(file)["render"]
|
||||||
|
show_st = cfg["show_st"]
|
||||||
|
clean = cfg["clean"]
|
||||||
|
page_split = cfg["page_split"]
|
||||||
|
|
||||||
|
print("Init build")
|
||||||
|
|
||||||
|
if (clean):
|
||||||
|
if os.path.exists("build"):
|
||||||
|
shutil.rmtree("build")
|
||||||
|
os.mkdir("build")
|
||||||
|
|
||||||
|
if not os.path.exists("theme"):
|
||||||
|
print("Connot find any themes")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def render_func(filepath, extpath, **kwargs):
|
||||||
|
if (show_st):
|
||||||
|
print(f' render "{extpath}"')
|
||||||
|
with open(filepath, 'r') as file:
|
||||||
|
result = jinja2.Template(file.read()).render(**kwargs)
|
||||||
|
with open(extpath, 'w') as file:
|
||||||
|
file.write(result)
|
||||||
|
|
||||||
|
|
||||||
|
if not (os.path.exists("build/home.html")):
|
||||||
|
print("Render home page")
|
||||||
|
with open("dump/forums.json", 'r') as file:
|
||||||
|
json_res = json.load(file)
|
||||||
|
render_args = {
|
||||||
|
"forums": [
|
||||||
|
{
|
||||||
|
"url": "/topics/"+str(i["id"])+"/1.html",
|
||||||
|
"name": i["name"],
|
||||||
|
"description": i["description"]
|
||||||
|
} for i in json_res
|
||||||
|
]
|
||||||
|
}
|
||||||
|
render_func("theme/home.html", "build/index.html", **render_args)
|
||||||
|
|
||||||
|
if not (os.path.exists("build/users")):
|
||||||
|
print("Render users")
|
||||||
|
os.mkdir("build/users")
|
||||||
|
with open("dump/users.json", 'r') as file:
|
||||||
|
user_json_res = json.load(file)
|
||||||
|
count = 0
|
||||||
|
print(f"Users count: {len(user_json_res)}")
|
||||||
|
for ids, context in user_json_res.items():
|
||||||
|
count += 1
|
||||||
|
render_func("theme/user.html", "build/users/"+str(ids)+".html", user={
|
||||||
|
"name": context["name"],
|
||||||
|
"description": context["description"],
|
||||||
|
"reg_time": time.strftime("%Y-%m-%d", time.localtime(context["time"]))
|
||||||
|
})
|
||||||
|
if not (show_st):
|
||||||
|
if (count % 50 == 0):
|
||||||
|
print(f" render {count}", end='\r')
|
||||||
|
print(f" render {count}")
|
||||||
|
|
||||||
|
if not (os.path.exists("build/topics")):
|
||||||
|
print("Render topics")
|
||||||
|
os.mkdir("build/topics")
|
||||||
|
with open("dump/forums.json", 'r') as file:
|
||||||
|
json_res = json.load(file)
|
||||||
|
count = 0
|
||||||
|
for r in os.listdir("dump/forums"):
|
||||||
|
count += 1
|
||||||
|
u_cfg = []
|
||||||
|
with open("dump/forums/"+r, 'r') as file:
|
||||||
|
strs = file.readlines()
|
||||||
|
n_count = 0
|
||||||
|
for i in strs:
|
||||||
|
n_count += 1
|
||||||
|
line_st = i.rstrip("\r\n").lstrip("\r\n")
|
||||||
|
if (line_st == ""):
|
||||||
|
continue
|
||||||
|
line_json = json.loads(line_st)
|
||||||
|
u_cfg.append(
|
||||||
|
{
|
||||||
|
"id": n_count,
|
||||||
|
"name": line_json["name"],
|
||||||
|
"time": time.strftime("%Y-%m-%d", time.localtime(line_json["time"])),
|
||||||
|
"url": "/posts/"+str(line_json["id"])+"/1.html"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ids = int(r.split(".")[0])
|
||||||
|
os.mkdir("build/topics/" + str(ids))
|
||||||
|
for page_counts in range(1, math.ceil(len(strs)/page_split)+1):
|
||||||
|
render_func("theme/topics.html", "build/topics/" +
|
||||||
|
str(ids)+"/"+str(page_counts)+".html", topics={
|
||||||
|
"topics": u_cfg[page_split*(page_counts-1):page_split*page_counts],
|
||||||
|
"from_forum": list(filter(lambda d: d.get('id') == ids, json_res))[0]["name"],
|
||||||
|
"from_url": "/home.html"
|
||||||
|
}, page={
|
||||||
|
"now": page_counts,
|
||||||
|
"count": math.ceil(len(strs)/page_split),
|
||||||
|
"first_url": "/topics/"+str(ids)+"/"+str(1)+".html",
|
||||||
|
"prev_url": ("/topics/"+str(ids)+"/"+str(page_counts-1)+".html") if (page_counts > 1) else "",
|
||||||
|
"next_url": ("/topics/"+str(ids)+"/"+str(page_counts+1)+".html") if ((page_counts) < math.ceil(len(strs)/page_split)) else "",
|
||||||
|
"end_url": "/topics/"+str(ids)+"/"+str(math.ceil(len(strs)/page_split))+".html"
|
||||||
|
})
|
||||||
|
if not (show_st):
|
||||||
|
print(f" render {count}", end='\r')
|
||||||
|
print(f" render {count}")
|
||||||
|
|
||||||
|
if not (os.path.exists("build/posts")):
|
||||||
|
print("Render posts")
|
||||||
|
os.mkdir("build/posts")
|
||||||
|
n_count = 0
|
||||||
|
for r in os.listdir("dump/forums"):
|
||||||
|
with open("dump/forums/"+r, 'r') as file:
|
||||||
|
strs = file.readlines()
|
||||||
|
page_ncount = 0
|
||||||
|
for i in strs:
|
||||||
|
page_ncount += 1
|
||||||
|
line_st = i.rstrip("\r\n").lstrip("\r\n")
|
||||||
|
if (line_st == ""):
|
||||||
|
continue
|
||||||
|
n_json = json.loads(line_st)
|
||||||
|
n_id = n_json["id"]
|
||||||
|
if not (os.path.exists("dump/topics/"+str(n_id)+".manifest")):
|
||||||
|
continue
|
||||||
|
with open("dump/topics/"+str(n_id)+".manifest", 'r') as file:
|
||||||
|
strs_m = file.readlines()
|
||||||
|
u_cfg = []
|
||||||
|
t_count = 0
|
||||||
|
for j in strs_m:
|
||||||
|
n_count += 1
|
||||||
|
t_count += 1
|
||||||
|
m_st = j.rstrip("\r\n").lstrip("\r\n")
|
||||||
|
if (m_st == ""):
|
||||||
|
continue
|
||||||
|
m_json = json.loads(m_st)
|
||||||
|
ids = n_id
|
||||||
|
u_cfg.append({
|
||||||
|
"id": t_count,
|
||||||
|
"text": m_json["text"],
|
||||||
|
"postername": m_json["poster_name"],
|
||||||
|
"posterurl": "/users/"+str(m_json["poster_id"])+".html"
|
||||||
|
})
|
||||||
|
if (n_count % 10 == 0):
|
||||||
|
print(f" render {n_count}", end='\r')
|
||||||
|
os.mkdir("build/posts/" + str(ids))
|
||||||
|
for page_counts in range(1, math.ceil(len(u_cfg)/page_split)+1):
|
||||||
|
render_func("theme/posts.html", "build/posts/" +
|
||||||
|
str(ids)+"/"+str(page_counts)+".html", posts={
|
||||||
|
"posts": u_cfg[page_split*(page_counts-1):page_split*page_counts],
|
||||||
|
"from_topic": n_json["name"],
|
||||||
|
"from_url": "/topics/"+str(r.split(".")[0])+"/"+str((page_ncount-1)//page_split+1)+".html"
|
||||||
|
}, page={
|
||||||
|
"now": page_counts,
|
||||||
|
"count": math.ceil(len(u_cfg)/page_split),
|
||||||
|
"first_url": "/posts/"+str(ids)+"/"+str(1)+".html",
|
||||||
|
"prev_url": ("/posts/"+str(ids)+"/"+str(page_counts-1)+".html") if (page_counts > 1) else "",
|
||||||
|
"next_url": ("/posts/"+str(ids)+"/"+str(page_counts+1)+".html") if ((page_counts) < math.ceil(len(u_cfg)/page_split)) else "",
|
||||||
|
"end_url": "/posts/"+str(ids)+"/"+str(math.ceil(len(u_cfg)/page_split))+".html"
|
||||||
|
})
|
||||||
|
print(f" render {n_count}")
|
|
@ -0,0 +1,4 @@
|
||||||
|
bbcode==1.1.0
|
||||||
|
Jinja2==3.1.4
|
||||||
|
MarkupSafe==2.1.5
|
||||||
|
PyMySQL==1.1.1
|
|
@ -0,0 +1,39 @@
|
||||||
|
import bbcode
|
||||||
|
|
||||||
|
# init parser
|
||||||
|
parser = bbcode.Parser()
|
||||||
|
parser.add_simple_formatter('hr', '<hr />', standalone=True)
|
||||||
|
parser.add_simple_formatter('hl', '<mark>%(value)s</mark>')
|
||||||
|
parser.add_simple_formatter('sub', '<sub>%(value)s</sub>')
|
||||||
|
parser.add_simple_formatter('sup', '<sup>%(value)s</sup>')
|
||||||
|
parser.add_simple_formatter(
|
||||||
|
'iframe', '<iframe src="%(value)s">IFrame tag</iframe>')
|
||||||
|
parser.add_simple_formatter(
|
||||||
|
'showhide', '--- 隐藏内容 ---<br />%(value)s<br /> ----------------')
|
||||||
|
|
||||||
|
|
||||||
|
def render_color(tag_name, value, options, parent, context):
|
||||||
|
colors = "#0099ff"
|
||||||
|
if 'color' in options:
|
||||||
|
colors = options['color']
|
||||||
|
return f'<span style="color:{colors};">{value}</span>'
|
||||||
|
|
||||||
|
|
||||||
|
def render_bgcolor(tag_name, value, options, parent, context):
|
||||||
|
colors = "#0099ff"
|
||||||
|
if 'bgcolor' in options:
|
||||||
|
colors = options['bgcolor']
|
||||||
|
return f'<span style="background-color:{colors};">{value}</span>'
|
||||||
|
|
||||||
|
|
||||||
|
def render_size(tag_name, value, options, parent, context):
|
||||||
|
if 'size' in options:
|
||||||
|
sizes = options['size']
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
return f'<span style="font-size:{sizes};">{value}</span>'
|
||||||
|
|
||||||
|
|
||||||
|
parser.add_formatter("color", render_color)
|
||||||
|
parser.add_formatter("bgcolor", render_bgcolor)
|
||||||
|
parser.add_formatter("size", render_size)
|
|
@ -0,0 +1,7 @@
|
||||||
|
from http.server import test, SimpleHTTPRequestHandler as RH
|
||||||
|
from functools import partial
|
||||||
|
RH.extensions_map = {k: v+';charset=UTF-8' for k,
|
||||||
|
v in RH.extensions_map.items()}
|
||||||
|
RH.extensions_map['.html'] = 'text/html; charset=utf-8'
|
||||||
|
test(HandlerClass=partial(RH,
|
||||||
|
directory="build"), port=8000)
|
|
@ -0,0 +1,25 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Home</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Home Page</h1>
|
||||||
|
<ol>
|
||||||
|
{% for forum in forums %}
|
||||||
|
<li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<h3><a href="{{ forum.url }}">{{ forum.name }}</a></h3>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ forum.description | safe }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,41 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Posts -- from {{ posts.from_topic }}</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Posts</h1>
|
||||||
|
<a href="{{ posts.from_url }}">from {{ posts.from_topic }}</a>
|
||||||
|
<ol>
|
||||||
|
{% for posts in posts.posts %}
|
||||||
|
<li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<h3>{{ posts.id }}</h3>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<h3>{{ posts.text | safe }}</h3>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Poster: {{ posts.postername }}
|
||||||
|
{% if posts.posterurl != "" %}
|
||||||
|
<a href="{{ posts.posterurl }}">主页</a>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{{ page.now }}/{{ page.count }} 页
|
||||||
|
<a href="{{ page.first_url }}">第一页</a>
|
||||||
|
{% if page.prev_url != "" %}
|
||||||
|
<a href="{{ page.prev_url }}">上一页</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if page.next_url != "" %}
|
||||||
|
<a href="{{ page.next_url }}">下一页</a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="{{ page.end_url }}">最后一页</a>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,35 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Topics -- from {{ topics.from_forum }}</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Topics</h1>
|
||||||
|
<a href="{{ topics.from_url }}">from {{ topics.from_forum }}</a>
|
||||||
|
<ol>
|
||||||
|
{% for topic in topics.topics %}
|
||||||
|
<li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<h3>{{ topic.id }}<a href="{{ topic.url }}">{{ topic.name }}</a></h3>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Time: {{ topic.time }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{{ page.now }}/{{ page.count }} 页
|
||||||
|
<a href="{{ page.first_url }}">第一页</a>
|
||||||
|
{% if page.prev_url != "" %}
|
||||||
|
<a href="{{ page.prev_url }}">上一页</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if page.next_url != "" %}
|
||||||
|
<a href="{{ page.next_url }}">下一页</a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="{{ page.end_url }}">最后一页</a>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>User - {{ user.name }}</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>User Page</h1>
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
<h3>{{ user.name }}</h3>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ user.description | safe }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Register time: {{ user.reg_time }}
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Home</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Home Page</h1>
|
||||||
|
<ol>
|
||||||
|
{% for forum in forums %}
|
||||||
|
<li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<h3><a href="{{ forum.url }}">{{ forum.name }}</a></h3>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ forum.description | safe }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,41 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Posts -- from {{ posts.from_topic }}</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Posts</h1>
|
||||||
|
<a href="{{ posts.from_url }}">from {{ posts.from_topic }}</a>
|
||||||
|
<ol>
|
||||||
|
{% for posts in posts.posts %}
|
||||||
|
<li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<h3>{{ posts.id }}</h3>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<h3>{{ posts.text | safe }}</h3>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Poster: {{ posts.postername }}
|
||||||
|
{% if posts.posterurl != "" %}
|
||||||
|
<a href="{{ posts.posterurl }}">主页</a>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{{ page.now }}/{{ page.count }} 页
|
||||||
|
<a href="{{ page.first_url }}">第一页</a>
|
||||||
|
{% if page.prev_url != "" %}
|
||||||
|
<a href="{{ page.prev_url }}">上一页</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if page.next_url != "" %}
|
||||||
|
<a href="{{ page.next_url }}">下一页</a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="{{ page.end_url }}">最后一页</a>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,35 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Topics -- from {{ topics.from_forum }}</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Topics</h1>
|
||||||
|
<a href="{{ topics.from_url }}">from {{ topics.from_forum }}</a>
|
||||||
|
<ol>
|
||||||
|
{% for topic in topics.topics %}
|
||||||
|
<li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<h3>{{ topic.id }}<a href="{{ topic.url }}">{{ topic.name }}</a></h3>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Time: {{ topic.time }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{{ page.now }}/{{ page.count }} 页
|
||||||
|
<a href="{{ page.first_url }}">第一页</a>
|
||||||
|
{% if page.prev_url != "" %}
|
||||||
|
<a href="{{ page.prev_url }}">上一页</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if page.next_url != "" %}
|
||||||
|
<a href="{{ page.next_url }}">下一页</a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="{{ page.end_url }}">最后一页</a>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>User - {{ user.name }}</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>User Page</h1>
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
<h3>{{ user.name }}</h3>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ user.description | safe }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Register time: {{ user.reg_time }}
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Loading…
Reference in New Issue