首先要了解下discuzX3.4和nodebb的数据库结构,discuzX用的是mysql,nodebb用的是mongodb。
最重要的当然是用户相关的数据表和帖子数据表。discuzX能查到数据表字典,nodebb只能自己用mongodb的admin工具看了。
一、用户数据
1、nodebb和discuz数据表的对照
Nodebb用户表须用的数据(字段):
db.objects.findOne({username:"admin"}) -->
{
"_id" : ObjectId("65cb8801e09f69ff71141520"),
"_key" : "user:1",
"joindate" : 1707837441083,
"lastonline" : 1708000177292,
//"status" : "online",
"uid" : 1,
"username" : "admin",
//"userslug" : "admin",
"password" : "$2a$12$VIKLGFC3AS1B4sDuVNivIOQO1HVpxjdOJXyUDBnDZqbu5nK",
//"password:shaWrapped" : 1,
"email" : "32342@yeah.net",
//"email:confirmed" : 1,
//"groupTitle" : "[\"\"]",
//"gdpr_consent" : 1,
"profileviews" : 0, // 空间点击数 views
"reputation" : 0, // 声誉,积分 credits
"topiccount" : 1, // 主题 threads
"lastposttime" : 1707837441933,
"postcount" : 1, // 帖子 posts (包含了主题)
//"rss_token" : "17305070-9558-4f2a-bef1-aba7902e0990",
"picture" : "/assets/uploads/profile/1-profileavatar-1707989852545.jpeg",
"uploadedpicture" : "/assets/uploads/profile/1-profileavatar-1707989852545.jpeg",
"fullname" : "全名guojin",
"aboutme" : "关于我是一个管理员",
"birthday" : "2024-02-15",
"location" : "广州",
"signature" : "签名:我是一个管理员",
"website" : "https://weibo.com/我的网"
}
discuzX 的表分得比较散,有好几个表:
pre_common_member 用户主表
字段名 | 数据类型 | 默认值 | 允许非空 | 备注 |
---|---|---|---|---|
uid | mediumint(8) unsigned | NO | 会员id | |
char(40) | NO | 邮箱 | ||
username | char(15) | NO | 用户名 | |
password | char(32) | NO | 密码 | |
status | tinyint(1) | 0 | NO | 判断用户是否已经删除 需要discuz程序加判断,并增加整体清理的功能。原home字段为flag |
emailstatus | tinyint(1) | 0 | NO | email是否经过验证 home字段为emailcheck |
avatarstatus | tinyint(1) | 0 | NO | 是否有头像 home字段为avatar |
videophotostatus | tinyint(1) | 0 | NO | 视频认证状态 home |
adminid | tinyint(1) | 0 | NO | 管理员id |
groupid | smallint(6) unsigned | 0 | NO | 会员组id |
groupexpiry | int(10) unsigned | 0 | NO | 用户组有效期 |
extgroupids | char(20) | NO | 扩展用户组 | |
regdate | int(10) unsigned | 0 | NO | 注册时间 |
credits | int(10) | 0 | NO | 总积分 |
notifysound | tinyint(1) | 0 | NO | 短信声音 |
timeoffset | char(4) | NO | 时区校正 | |
newpm | smallint(6) unsigned | 0 | NO | 新短消息数量 |
newprompt | smallint(6) unsigned | 0 | NO | 新提醒数目 |
accessmasks | tinyint(1) | 0 | NO | 标志 |
allowadmincp | tinyint(1) | 0 | NO | 标志 |
onlyacceptfriendpm | tinyint(1) | 0 | NO | 是否只接收好友短消息 |
conisbind | tinyint(1) unsigned | 0 | NO | 用户是否绑定QC |
uc_members 用户表
字段名 | 数据类型 | 默认值 | 允许非空 | 备注 |
---|---|---|---|---|
uid | mediumint(8) unsigned | NO | 用户ID | |
username | char(15) | NO | 用户名 | |
password | char(32) | NO | 密码 | |
char(32) | NO | 用户Email | ||
myid | char(30) | NO | 漫游id | |
myidkey | char(16) | NO | 漫游id | |
regip | char(15) | NO | 注册IP | |
regdate | int(10) unsigned | 0 | NO | 注册时间 |
lastloginip | int(10) | 0 | NO | 上次登陆的IP(程序转换成数值类型) |
lastlogintime | int(10) unsigned | 0 | NO | 上次登录的时间 |
salt | char(6) | NO | 密码干扰串,用来和密码进行配合验证,防止被暴力破解 | |
secques | char(8) | NO | 用户的安全提问 |
pre_common_member_field_forum 用户论坛字段表
字段名 | 数据类型 | 默认值 | 允许非空 | 备注 |
---|---|---|---|---|
uid | mediumint(8) unsigned | NO | 会员id | |
publishfeed | tinyint(3) | 0 | NO | 用户自定义发送哪些类型的feed(原字段为customaddfeed) |
customshow | tinyint(1) unsigned | 26 | NO | 自定义帖子显示模式 |
customstatus | varchar(30) | NO | 自定义头衔 | |
medals | text | NO | 勋章信息 | |
sightml | text | NO | 签名 | |
groupterms | text | NO | 公共用户组 | |
authstr | varchar(20) | NO | 找回密码验证串 | |
groups | mediumtext | NO | 用户所有群组 | |
attentiongroup | varchar(255) | NO | 用户偏好 |
pre_common_member_profile 用户栏目表
字段名 | 数据类型 | 默认值 | 允许非空 | 备注 |
---|---|---|---|---|
uid | mediumint(8) unsigned | NO | 会员id | |
realname | varchar(255) | NO | 实名 | |
gender | tinyint(1) | 0 | NO | 性别 (0:保密 1:男 2:女) |
birthyear | smallint(6) unsigned | 0 | NO | |
birthmonth | tinyint(3) unsigned | 0 | NO | |
birthday | tinyint(3) unsigned | 0 | NO | |
constellation | varchar(255) | NO | 星座(根据生日自动计算) | |
zodiac | varchar(255) | NO | 生肖(根据生日自动计算) | |
telephone | varchar(255) | NO | 固定电话 | |
mobile | varchar(255) | NO | 手机 | |
idcardtype | varchar(255) | NO | 证件类型:身份证 护照 军官证等 | |
idcard | varchar(255) | NO | 证件号码 | |
address | varchar(255) | NO | 邮寄地址 | |
zipcode | varchar(255) | NO | 邮编 | |
nationality | varchar(255) | NO | 国籍 | |
birthprovince | varchar(255) | NO | 出生省份 | |
birthcity | varchar(255) | NO | 出生城市 | |
birthdist | varchar(20) | NO | 出生行政区/县 | |
birthcommunity | varchar(255) | NO | 出生小区 | |
resideprovince | varchar(255) | NO | 居住省份 | |
residecity | varchar(255) | NO | 居住城市 | |
residedist | varchar(20) | NO | 居住行政区/县 | |
residecommunity | varchar(255) | NO | 居住小区 | |
residesuite | varchar(255) | NO | 小区、写字楼门牌号 | |
graduateschool | varchar(255) | NO | 毕业学校 | |
company | varchar(255) | NO | 公司 | |
education | varchar(255) | NO | 学历 | |
occupation | varchar(255) | NO | 职业 | |
position | varchar(255) | NO | 职位 | |
revenue | varchar(255) | NO | 年收入 | |
affectivestatus | varchar(255) | NO | 情感状态 | |
lookingfor | varchar(255) | NO | 交友目的(交友类型) | |
bloodtype | varchar(255) | NO | 血型 | |
height | varchar(255) | NO | 身高 | |
weight | varchar(255) | NO | 体重 | |
alipay | varchar(255) | NO | 支付宝帐号 | |
icq | varchar(255) | NO | ICQ | |
varchar(255) | NO | |||
yahoo | varchar(255) | NO | YAHOO | |
msn | varchar(255) | NO | MSN | |
taobao | varchar(255) | NO | 阿里旺旺 | |
site | varchar(255) | NO | 主页 | |
bio | text | NO | 自我介绍 来自论坛bio字段 | |
interest | text | NO | 兴趣爱好 | |
field1 | text | NO | 自定义字段1 | |
field2 | text | NO | 自定义字段2 | |
field3 | text | NO | 自定义字段3 | |
field4 | text | NO | 自定义字段4 | |
field5 | text | NO | 自定义字段5 | |
field6 | text | NO | 自定义字段6 | |
field7 | text | NO | 自定义字段7 | |
field8 | text | NO | 自定义字段8 |
pre_common_member_count 用户统计表
字段名 | 数据类型 | 默认值 | 允许非空 | 备注 |
---|---|---|---|---|
uid | mediumint(8) unsigned | NO | 会员id | |
extcredits1 | int(10) | 0 | NO | 声望 |
extcredits2 | int(10) | 0 | NO | 金钱 |
extcredits3 | int(10) | 0 | NO | 扩展 |
extcredits4 | int(10) | 0 | NO | 扩展 |
extcredits5 | int(10) | 0 | NO | 扩展 |
extcredits6 | int(10) | 0 | NO | 扩展 |
extcredits7 | int(10) | 0 | NO | 扩展 |
extcredits8 | int(10) | 0 | NO | 扩展 |
friends | smallint(6) unsigned | 0 | NO | 好友个数 home |
posts | mediumint(8) unsigned | 0 | NO | 帖子数 |
threads | mediumint(8) unsigned | 0 | NO | 主题数 |
digestposts | smallint(6) unsigned | 0 | NO | 精华数 |
doings | smallint(6) unsigned | 0 | NO | 记录数 |
blogs | smallint(6) unsigned | 0 | NO | 日志数 |
albums | smallint(6) unsigned | 0 | NO | 相册数 |
sharings | smallint(6) unsigned | 0 | NO | 分享数 |
attachsize | int(10) unsigned | 0 | NO | 上传附件占用的空间 home |
views | mediumint(8) unsigned | 0 | NO | 空间查看数 |
oltime | smallint(6) unsigned | 0 | NO | 在线时间 |
todayattachs | smallint(6) unsigned | 0 | NO | 当天上传附件数 |
todayattachsize | int(10) unsigned | 0 | NO | 当天上传附件容量 |
feeds | mediumint(8) unsigned | 0 | NO | 广播数 |
follower | mediumint(8) unsigned | 0 | NO | 听众数量 |
following | mediumint(8) unsigned | 0 | NO | 收听数量 |
newfollower | mediumint(8) unsigned | 0 | NO | 新增听众数量 |
blacklist | mediumint(8) unsigned | 0 | NO | 拉黑用户数 |
pre_common_member_status 用户状态表
字段名 | 数据类型 | 默认值 | 允许非空 | 备注 |
---|---|---|---|---|
uid | mediumint(8) unsigned | NO | 会员id | |
regip | char(15) | NO | 注册IP | |
lastip | char(15) | NO | 最后登录IP | |
lastvisit | int(10) unsigned | 0 | NO | 最后访问 |
lastactivity | int(10) unsigned | 0 | NO | 最后活动 |
lastpost | int(10) unsigned | 0 | NO | 最后发表 |
lastsendmail | int(10) unsigned | 0 | NO | 上次发送email时间 home原字段为lastsend |
invisible | tinyint(1) | 0 | NO | 是否隐身登录 |
buyercredit | smallint(6) | 0 | NO | 买家信用等级及积分 |
sellercredit | smallint(6) | 0 | NO | 卖家信用等级及积分 |
favtimes | mediumint(8) unsigned | 0 | NO | 个人空间收藏次数 |
sharetimes | mediumint(8) unsigned | 0 | NO | 个人空间分享次数 |
profileprogress | tinyint(2) unsigned | 0 | NO | 个人资料完成度 |
2、处理头像
discuz 默认自定义头像目录:data/attachment/forum/pw/upload/33370.jpg
discuzX的默认自定议头像目录:
/uc_server/data/avatar/000/xx/xx/xx_avatar_middle.jpg
其中 xx/xx/xx_ 正好是 uid,位数不够的系统会自动补零
因此写了个程序,把xx_avatar_middle.jpg文件拷贝到一个目录里(一会儿复制到服务端去),并把文字名改为 xxxxxx_avatar_middle.jpg,最后还把{uid: “xxxxxx”, path: "/assets/uploads/profile/000/dz_avatar/62011_avatar_middle.jpg”} 存成json文件,以备后面使用。
服务端我复制到目录:~/nodebb/public/uploads/profile/dz_avatar
import os,shutil,json
# file_list 为文件名称列表
def find_files_path(str_list, path=r"./"):
# 组合绝对路径,当前路径+目录
whole_path = os.getcwd() + path
# 遍历目录下的文件
files_path = os.walk(whole_path)
# 路径空列表,用来存储查找文件路径
path_data = []
try:
# 遍历要寻找的文件
for str in str_list:
# 查找目录下对应的文件
for root, dirs, files in files_path:
# 遍历所有文件名称,添加符合文件名称的文件路径进列表
for f in files:
if str in f:
real_path = (root + "\\" + f).replace("./", "\\")
#print(real_path)
uid_file = real_path[-26:].replace("\\", "").lstrip("0") #去0,得到文件名:uid + _avatar_middle.jpg
path_data.append({"uid": real_path[-26:-18].replace("\\", "").lstrip("0"),
"path": '/assets/uploads/profile/dz_avatar/'+uid_file})
shutil.copyfile(real_path, "./" + uid_file) # 拷贝文件
except Exception as e:
print("遍历出现错误:" + e)
finally:
return path_data
uid_file_list = find_files_path(["big"], "./")
print(uid_file_list)
#data = {'name': 'John', 'age': 30, 'city': 'New York'}
with open('avatar_data.json', 'w') as f:
json.dump(uid_file_list, f)