diff --git a/.env.example b/.env.example index 83b2d8d..297c1a7 100644 --- a/.env.example +++ b/.env.example @@ -38,6 +38,7 @@ mysqlpassword= mysqldatabase= mysqlssl = DATABASE_URL= +#DATABASE_URL="mysql://root:mysql_Rxd3Ph@10.192.136.23:3306/zerocat" = = # S3存储 生产环境,给俺小心点 diff --git a/app.js b/app.js index 15b0226..f0c2c01 100644 --- a/app.js +++ b/app.js @@ -126,34 +126,29 @@ app.all("*", function (req, res, next) { display_name: "", avatar: "", is_admin: 0, + usertoken: "", }; console.log("JWT验证失败: " + err.message); } else { // 如果验证成功,将用户信息存储在res.locals和session中 let userInfo = decodedToken; - res.locals.userid = userInfo.userid; - res.locals.email = userInfo.email; - res.locals.username = userInfo.username; - - res.locals.display_name = userInfo.display_name; - res.locals.avatar = userInfo.avatar; - - res.locals["is_admin"] = 0; - if (userInfo.email == global.config.security.adminuser) { - res.locals["is_admin"] = 1; - } - //console.log("JWT验证成功: " + userInfo.email); - //console.log( "调试用户信息(session):" + res.locals.userid + "," + res.locals.email + "," + res.locals.username + "," + res.locals.display_name + "," + res.locals.is_admin ); - res.locals = { login: true, - userid: res.locals.userid, - email: res.locals.email, - username: res.locals.username, - display_name: res.locals.display_name, - avatar: res.locals.avatar, - is_admin: res.locals["is_admin"], + userid: userInfo.userid, + email: userInfo.email, + username: userInfo.username, + display_name: userInfo.display_name, + avatar: userInfo.avatar, + is_admin: 0, + usertoken: token, }; + //res.locals["is_admin"] = 0; + //if (userInfo.email == global.config.security.adminuser) { + // res.locals["is_admin"] = 1; + //} + //console.log("JWT验证成功: " + userInfo.email); + //console.log( "调试用户信息(session):" + res.locals.userid + "," + res.locals.email + "," + res.locals.username + "," + res.locals.display_name + "," + res.locals.is_admin ); + //console.log( "调试用户信息(locals ):" + res.locals.userid + "," + res.locals.email + "," + res.locals.username + "," + res.locals.display_name + "," + res.locals.is_admin ); } @@ -170,6 +165,7 @@ app.all("*", function (req, res, next) { display_name: "未登录", avatar: "", is_admin: 0, + usertoken: "", }; //console.log("未找到JWT Token"); next(); diff --git a/data/material/asset/d08d9631057826d5e83c0ef13c844f2c.png b/data/material/asset/d08d9631057826d5e83c0ef13c844f2c.png new file mode 100644 index 0000000..ae8a8bf Binary files /dev/null and b/data/material/asset/d08d9631057826d5e83c0ef13c844f2c.png differ diff --git a/prisma/schema.prisma b/prisma/schema.prisma index a49472a..5edefcf 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -219,3 +219,109 @@ model scratch { description String? @default("OurWorld上的Scratch项目") @db.VarChar(1000) src String? @db.MediumText } + +model ow_projects_file { + sha256 String @id @db.VarChar(64) + source String? @db.Text + create_time DateTime? @default(now()) @db.DateTime(0) +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model scratch_favo { + id Int @default(autoincrement()) @db.UnsignedInt + userid Int @db.UnsignedInt + projectid Int @db.UnsignedInt + time DateTime? @default(now()) @db.Timestamp(0) + + @@id([id, userid, projectid]) +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model scratch_like { + id Int @default(autoincrement()) @db.UnsignedInt + userid Int @db.UnsignedInt + projectid Int @db.UnsignedInt + time DateTime? @default(now()) @db.Timestamp(0) + + @@id([id, userid, projectid]) +} + +model sys_ini { + id Int @id @default(autoincrement()) @db.UnsignedInt + iniKey String? @db.Char(16) + iniValue String? @db.Char(64) +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model user { + id String @unique(map: "id_UNIQUE") @db.VarChar(32) + username String @unique(map: "user_UNIQUE") @db.Char(100) + pwd String @db.Char(100) + display_name String @default("OurWorld创作者") @db.Char(20) + state Int @default(0) @db.TinyInt + loginTime DateTime? @db.Timestamp(0) + regTime DateTime? @default(now()) @db.Timestamp(0) + sex Int? @default(0) @db.TinyInt + birthday DateTime? @default(dbgenerated("'2000-04-01 00:00:00'")) @db.Timestamp(0) + motto String? @default("OurWorld创作者") @db.VarChar(1000) + images String? @default("头像") @db.VarChar(255) + + @@id([id, username]) +} + +model wl_comment { + id Int @id @default(autoincrement()) @db.UnsignedInt + user_id Int? + comment String? @db.Text + insertedAt DateTime? @default(now()) @db.Timestamp(0) + ip String? @default("") @db.VarChar(100) + link String? @db.VarChar(255) + mail String? @db.VarChar(255) + nick String? @db.VarChar(255) + pid Int? + rid Int? + sticky Boolean? + status String @default("") @db.VarChar(50) + like Int? + ua String? @db.Text + url String? @db.VarChar(255) + createdAt DateTime? @default(now()) @db.Timestamp(0) + updatedAt DateTime? @default(now()) @db.Timestamp(0) +} + +model wl_counter { + id Int @id @default(autoincrement()) @db.UnsignedInt + time Int? + reaction0 Int? + reaction1 Int? + reaction2 Int? + reaction3 Int? + reaction4 Int? + reaction5 Int? + reaction6 Int? + reaction7 Int? + reaction8 Int? + url String @default("") @db.VarChar(255) + createdAt DateTime? @default(now()) @db.Timestamp(0) + updatedAt DateTime? @default(now()) @db.Timestamp(0) +} + +model wl_users { + id Int @id @default(autoincrement()) @db.UnsignedInt + display_name String @default("") @db.VarChar(255) + email String @default("") @db.VarChar(255) + password String @default("") @db.VarChar(255) + type String @default("") @db.VarChar(50) + label String? @db.VarChar(255) + url String? @db.VarChar(255) + avatar String? @db.VarChar(255) + github String? @db.VarChar(255) + twitter String? @db.VarChar(255) + facebook String? @db.VarChar(255) + google String? @db.VarChar(255) + weibo String? @db.VarChar(255) + qq String? @db.VarChar(255) + fa String? @map("2fa") @db.VarChar(32) + createdAt DateTime? @default(now()) @db.Timestamp(0) + updatedAt DateTime? @default(now()) @db.Timestamp(0) +} diff --git a/server/lib/default_project.js b/server/lib/default_project.js index 0ac1f39..f976c33 100644 --- a/server/lib/default_project.js +++ b/server/lib/default_project.js @@ -1,7 +1,6 @@ project = { - scratch: - '{"targets":[{"isStage":true,"name":"Stage","variables":{"`jEk@4|i[#Fk?(8x)AV.-my variable":["变量",0]},"lists":{},"broadcasts":{},"blocks":{},"comments":{},"currentCostume":0,"costumes":[{"name":"ZeroCat","bitmapResolution":1,"dataFormat":"svg","assetId":"7cb4e1f10e1b712eed814f04b40c7882","md5ext":"7cb4e1f10e1b712eed814f04b40c7882.svg","rotationCenterX":240,"rotationCenterY":180}],"sounds":[{"name":"啵","assetId":"83a9787d4cb6f3b7632b4ddfebf74367","dataFormat":"wav","format":"","rate":48000,"sampleCount":1123,"md5ext":"83a9787d4cb6f3b7632b4ddfebf74367.wav"}],"volume":100,"layerOrder":0,"tempo":60,"videoTransparency":50,"videoState":"on","textToSpeechLanguage":null},{"isStage":false,"name":"zero","variables":{},"lists":{},"broadcasts":{},"blocks":{"e":{"opcode":"event_whenflagclicked","next":"a","parent":null,"inputs":{},"fields":{},"shadow":false,"topLevel":true,"x":48,"y":64},"a":{"opcode":"motion_gotoxy","next":"b","parent":"e","inputs":{"X":[1,[4,"-240"]],"Y":[1,[4,"0"]]},"fields":{},"shadow":false,"topLevel":false},"b":{"opcode":"control_repeat","next":null,"parent":"a","inputs":{"TIMES":[1,[6,"10"]],"SUBSTACK":[2,"f"]},"fields":{},"shadow":false,"topLevel":false},"f":{"opcode":"motion_movesteps","next":null,"parent":"b","inputs":{"STEPS":[1,[4,"24"]]},"fields":{},"shadow":false,"topLevel":false}},"comments":{},"currentCostume":0,"costumes":[{"name":"造型1","bitmapResolution":1,"dataFormat":"svg","assetId":"365a43dce18a8020c6e2ba44f4507836","md5ext":"365a43dce18a8020c6e2ba44f4507836.svg","rotationCenterX":50,"rotationCenterY":50}],"sounds":[],"volume":100,"layerOrder":1,"visible":true,"x":0,"y":0,"size":100,"direction":90,"draggable":false,"rotationStyle":"all around"},{"isStage":false,"name":"cat","variables":{},"lists":{},"broadcasts":{},"blocks":{"g":{"opcode":"event_whenflagclicked","next":"c","parent":null,"inputs":{},"fields":{},"shadow":false,"topLevel":true,"x":417,"y":142},"c":{"opcode":"motion_gotoxy","next":"d","parent":"g","inputs":{"X":[1,[4,"240"]],"Y":[1,[4,"0"]]},"fields":{},"shadow":false,"topLevel":false},"d":{"opcode":"control_repeat","next":null,"parent":"c","inputs":{"TIMES":[1,[6,"10"]],"SUBSTACK":[3,"h",null]},"fields":{},"shadow":false,"topLevel":false},"h":{"opcode":"motion_movesteps","next":null,"parent":"d","inputs":{"STEPS":[1,[4,"-24"]]},"fields":{},"shadow":false,"topLevel":false}},"comments":{},"currentCostume":0,"costumes":[{"name":"造型1","bitmapResolution":1,"dataFormat":"svg","assetId":"f4f02527595957f021eca4b4bcdc5b45","md5ext":"f4f02527595957f021eca4b4bcdc5b45.svg","rotationCenterX":50,"rotationCenterY":0}],"sounds":[],"volume":100,"layerOrder":2,"visible":true,"x":0,"y":0,"size":100,"direction":90,"draggable":false,"rotationStyle":"all around"}],"monitors":[],"extensions":[],"meta":{"semver":"3.0.0","vm":"0.2.0","agent":"","platform":{"name":"ZeroCat","url":"https://zerocat.wuyuan.dev/"}}}', - python: - 'import turtle\n\nt = turtle.Turtle()\nt.forward(100)\n\nprint ("Welcome to ZeroCat!")', + scratch: "ddd5546735d2af86721d037443e4bb917040ae78f1778df6afb985957426dab7", + python: "da7548a7a8cffc35d1ed73b39cf8b095b9be7bff30e74896b2288aebca20d10a", + text: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", }; module.exports = project; diff --git a/server/lib/global.js b/server/lib/global.js index fd6315f..9a18dcb 100644 --- a/server/lib/global.js +++ b/server/lib/global.js @@ -13,19 +13,18 @@ exports.prisma =prisma; const { S3Client, PutObjectCommand } =require('@aws-sdk/client-s3'); - // Create an S3 client const s3 = new S3Client({ endpoint: global.config.s3.endpoint, region: global.config.s3.region, credentials: { - accessKeyId: global.config.s3.accessKeyId, - secretAccessKey: global.config.s3.secretAccessKey, + accessKeyId: global.config.s3.AWS_ACCESS_KEY_ID, + secretAccessKey: global.config.s3.AWS_SECRET_ACCESS_KEY, } }); -exports.S3update = function ow(name, file,email) { +exports.S3update = function ow(name, file) { console.log(name); try { s3.send(new PutObjectCommand({ @@ -36,7 +35,7 @@ try { console.log(err); }).then((data) => { console.log(data); - console.log(`用户 ${email} 成功上传了文件 ${global.config.s3.bucket}/${name}`); + console.log(`用户 ${res.locals.email} 成功上传了文件 ${global.config.s3.bucket}/${name}`); }) diff --git a/server/router_my.js b/server/router_my.js index 79e81f9..d06f244 100644 --- a/server/router_my.js +++ b/server/router_my.js @@ -320,7 +320,7 @@ router.post("/set/avatar", geetest,function (req, res) { chunks.on("end", () => { const hashValue = hash.digest("hex"); // 上传到七牛云 - I.S3update(`user/${hashValue}`, newpath, res.locals.email); + I.S3update(`user/${hashValue}`, newpath); var UPDATE = `UPDATE ow_users SET ? WHERE id=${res.locals.userid} LIMIT 1`; var SET = { images: hashValue, diff --git a/server/router_scratch.js b/server/router_scratch.js index 72e7a0e..a000534 100644 --- a/server/router_scratch.js +++ b/server/router_scratch.js @@ -217,7 +217,7 @@ router.get("/projectinfo2", function (req, res) { parent: null, root: null, }, - project_token: "", + project_token: res.locals.usertoken||'', }; ////console.log(SCRATCH[0]); res.json(jsontw); @@ -456,8 +456,7 @@ router.post("/thumbnail/:projectid", function (req, res) { } else { I.S3update( "scratch_slt/" + req.params.projectid, - strFileName, - res.locals.email + strFileName ); ////console.log('保存缩略图成功:'+strFileName); @@ -540,8 +539,7 @@ router.post("/assets/:filename", function (req, res) { } else { I.S3update( "material/asset/" + req.params.filename, - strFileName, - res.locals.email + strFileName ); console.log("素材保存成功:" + strFileName); diff --git a/test2.js b/test2.js index 9b8747a..443d41a 100644 --- a/test2.js +++ b/test2.js @@ -1,55 +1,110 @@ const { PrismaClient } = require("@prisma/client"); -const prisma = new PrismaClient(); const crypto = require("crypto"); -prisma.ow_projects - .findMany({}) - .then((projects) => { - //console.log(projects); - projects.forEach((project) => { - const hash = crypto - .createHash("sha256") - .update(String(project.source)) - .digest("hex"); - //console.log(project.source); - prisma.ow_projects_file - .upsert({ - where: { - sha256: hash, - }, - update: { - sha256: hash, - source: project.source, - } - - }) - .catch((error) => { - prisma.ow_projects.update({ - where: { - id: project.id, - }, - data: { - source: hash, - }, - }).catch((error) => { - console.log(error); - }) - //console.log(error); - }).then(() => { - prisma.ow_projects.update({ - where: { - id: project.id, - }, - data: { - source: hash, - }, - }).catch((error) => { - console.log(error); - }) - console.log("done"); - }) - }); - }) - .catch((error) => { - console.log(error); +const prisma = new PrismaClient(); + +(async () => { + try { + // 获取所有项目 + const projects = await prisma.ow_projects.findMany({}); + + // 遍历项目,计算哈希并更新数据库 + for (const project of projects) { + var source = processSource(project.source); + const hash = calculateHash(source); + + var devsource = processSource(project.devsource); + const devhash = calculateHash(devsource); + + console.log(`Hash for project ${project.id} source: ${hash}`); + console.log(`Hash for project ${project.id} devsource: ${devhash}`); + + // 插入或更新 `ow_projects_file` 表 + await upsertProjectFile(hash, source); + // 插入或更新 `ow_projects_file` 表 + await upsertProjectFile(devhash, devsource); + + // 更新 `ow_projects` 表 + await updateProjectSource(project.id, hash); + // 更新 `ow_projects` 表 + await updateProjectDevsource(project.id, devhash); + console.log(`Project ${project.id} processed successfully.`); + } + + console.log("All projects processed."); + } catch (error) { + console.error("Error processing projects:", error); + } finally { + // 关闭数据库连接 + await prisma.$disconnect(); + } +})(); + +// 计算 SHA-256 哈希值 +function calculateHash(source) { + return crypto.createHash("sha256").update(source).digest("hex"); +} + +// 插入或更新 `ow_projects_file` 表 +async function upsertProjectFile(hash, source) { + try { + await prisma.ow_projects_file.upsert({ + where: { sha256: hash }, + update: { sha256: hash, source: String(source) }, + create: { sha256: hash, source: String(source) }, + }); + } catch (error) { + console.error(`Error in upserting project file for hash ${hash}:`, error); + } +} + +// 更新 `ow_projects` 表中的 `source` 字段 +async function updateProjectSource(projectId, hash) { + try { + await prisma.ow_projects.update({ + where: { id: projectId }, + data: { source: hash }, + }); + } catch (error) { + console.error(`Error in updating project ${projectId}:`, error); + } +} +// 更新 `ow_projects` 表中的 `devsource` 字段 +async function updateProjectDevsource(projectId, hash) { + try { + await prisma.ow_projects.update({ + where: { id: projectId }, + data: { devsource: hash }, }); + } catch (error) { + console.error(`Error in updating project ${projectId}:`, error); + } +} + +// 检查是否为哈希值 +function isHash(str, length) { + const hexRegex = /^[a-fA-F0-9]+$/; + return str.length === length && hexRegex.test(str); +} +function processSource(source) { + // 判断是否为 JSON 格式 + if (isJson(source)) { + console.log("Source is valid JSON, processing as JSON..."); + // 对 JSON 字符串进行处理,例如将其转换为字符串 + return JSON.stringify(JSON.parse(source)); + } else { + console.log("Source is not JSON, processing as a regular string..."); + // 直接处理非 JSON 字符串 + return String(source); + } +} + +// 判断是否为有效 JSON +function isJson(str) { + try { + JSON.parse(str); // 如果能成功解析,说明是合法的 JSON + return true; + } catch (error) { + return false; // 如果解析失败,说明不是 JSON + } +}