174 lines
7.2 KiB
Python
174 lines
7.2 KiB
Python
# myapp/views/vscode.py
|
||
import re
|
||
import os, uuid, json
|
||
from flask import Blueprint, current_app, session, redirect, url_for, render_template, request, jsonify
|
||
from ..services.backboard_service import realtime_response
|
||
from ..extension_ase.ase_client.manager import ChatManager
|
||
import subprocess
|
||
from ..auth.decorators import require_role
|
||
from ..services.course_service import load_learning_progress
|
||
|
||
bp = Blueprint("vscode", __name__)
|
||
|
||
@bp.route("/desktop/<user_uuid>/<course_id>/<chapter_name>/<lesson_name>")
|
||
@require_role
|
||
def desktop(user_uuid, course_id, chapter_name, lesson_name):
|
||
username2uuid = current_app.extensions["username2uuid"]
|
||
uuid2username = current_app.extensions["uuid2username"]
|
||
userid_recorder = current_app.extensions["userid_recorder"]
|
||
if "user_uuid" not in session:
|
||
return redirect(url_for("auth.login"))
|
||
|
||
# 检查是否有 load_history 参数
|
||
load_history_str = request.args.get('load_history')
|
||
if load_history_str is None:
|
||
# 如果没有参数,跳转到确认页面
|
||
return redirect(url_for("vscode.desktop_nouser", course_id=course_id, chapter_name=chapter_name, lesson_name=lesson_name))
|
||
|
||
# 将字符串转换为布尔值
|
||
load_history = load_history_str.lower() == 'true'
|
||
|
||
# 全局映射
|
||
user_id = uuid2username[user_uuid]
|
||
userid_recorder[f"{user_id}&{course_id}"] = session["user_uuid"]
|
||
|
||
user_home = os.path.join("/home", user_id)
|
||
try:
|
||
subprocess.run(["sudo", "useradd", "-m", "-d", user_home, user_id]) # 创建用户
|
||
subprocess.run(["sudo", "chown", "-R", user_id, user_home]) # 设置目录权限为新用户
|
||
except subprocess.CalledProcessError as e:
|
||
print(f"Error creating user {user_id}: {e}")
|
||
path_dir = os.path.join("/home", user_id, course_id, chapter_name, lesson_name)
|
||
try:
|
||
# 使用 sudo 执行 mkdir 命令来创建目录
|
||
subprocess.run(["sudo", "-u", user_id, "mkdir", "-p", path_dir], check=True)
|
||
print(f"Directory {path_dir} created successfully for user {user_id}")
|
||
except subprocess.CalledProcessError as e:
|
||
print(f"Error creating directory {path_dir} details {str(e)}")
|
||
|
||
try:#使用sudo创建shared_group
|
||
subprocess.run(["sudo", "groupadd", f"shared_group_{user_id}"], check=True)
|
||
except subprocess.CalledProcessError as e:
|
||
print(f"Error creating shared_group: {e}")
|
||
|
||
try:#使用sudo将user_id加入shared_group
|
||
subprocess.run(["sudo", "usermod", "-a", "-G", f"shared_group_{user_id}", user_id], check=True)
|
||
# 自己也加入
|
||
subprocess.run(["sudo", "usermod", "-a", "-G", f"shared_group_{user_id}", 'flask'], check=True)
|
||
except subprocess.CalledProcessError as e:
|
||
print(f"Error adding user {user_id} to shared_group: {e}")
|
||
try:#将文件
|
||
subprocess.run(["sudo", "chown", "-R", f"flask:shared_group_{user_id}", user_home], check=True)
|
||
subprocess.run(["sudo", "chmod", "-R", "770", path_dir], check=True)
|
||
except subprocess.CalledProcessError as e:
|
||
print(f"Error changing directory {path_dir} to shared_group_{user_id}: {e}")
|
||
try:#继承目录
|
||
subprocess.run(["sudo", "chmod", "g+s", path_dir], check=True)
|
||
except subprocess.CalledProcessError as e:
|
||
print(f"Error changing directory {path_dir} to shared_group_{user_id}: {e}")
|
||
|
||
|
||
|
||
restart = not load_history
|
||
chatmanager = ChatManager(restart=restart)
|
||
current_app.extensions["user_uuid2chatmanager"][user_uuid] = chatmanager
|
||
|
||
# 如果restart为True,删除mongo中的学习进度
|
||
if restart:
|
||
try:
|
||
mongo = current_app.extensions["mongo"]
|
||
mongo.db.learning_progress.delete_one({
|
||
"user_id": user_id,
|
||
"material_id": course_id,
|
||
"chapter_name": chapter_name,
|
||
"lesson_name": lesson_name
|
||
})
|
||
current_app.logger.info(f"删除学习进度成功: user_id={user_id}, course_id={course_id}, chapter={chapter_name}, lesson={lesson_name}")
|
||
except Exception as e:
|
||
current_app.logger.error(f"删除学习进度失败: {str(e)}")
|
||
code_server_port = 10000 + int(uuid.uuid4().int % 10000)
|
||
# chatmanager.start_code_server(user_uuid, user_id, path_dir, code_server_port)
|
||
|
||
|
||
|
||
|
||
cfg = current_app.config["VSCODE_WEB_PATH"]
|
||
path_for_vscode = path_dir
|
||
|
||
config_path = os.path.join(path_dir, ".config")
|
||
tmpd = {
|
||
"user_uuid": session["user_uuid"],
|
||
"user_id": user_id,
|
||
"course_id": course_id,
|
||
"chapter_name": chapter_name,
|
||
"lesson_name": lesson_name,
|
||
"path": path_for_vscode
|
||
}
|
||
config_json = json.dumps(tmpd, ensure_ascii=False)
|
||
|
||
# 使用 sudo 和 tee 命令将 JSON 数据写入文件
|
||
subprocess.run(
|
||
["sudo", "-u", user_id, "bash", "-c", f"echo '{config_json}' | tee {config_path} > /dev/null"],
|
||
check=True
|
||
)
|
||
# 确保文件的所有权归 user_id
|
||
subprocess.run(
|
||
["sudo", "chown","-R", f"flask:shared_group_{user_id}", config_path],
|
||
check=True
|
||
)
|
||
subprocess.run(
|
||
["sudo", "chmod", "-R", "770", config_path],
|
||
check=True
|
||
)
|
||
return render_template(
|
||
"code-like-desktop.html",
|
||
# vscode_web_url=current_app.config["VSCODE_WEB_URL"]+f"/vsc{user_id}",
|
||
vscode_web_url=current_app.config["CODE_LIKE_URL"],
|
||
user_uuid=session["user_uuid"], course_id=course_id, chapter_name=chapter_name, lesson_name=lesson_name,user_id=user_id,
|
||
workspace_path=path_for_vscode,
|
||
)
|
||
|
||
@bp.route("/desktop_nouser/<course_id>/<chapter_name>/<lesson_name>")
|
||
@require_role
|
||
def desktop_nouser(course_id, chapter_name, lesson_name):
|
||
if "user_uuid" not in session:
|
||
return redirect(url_for("auth.login")) # 如果你有 auth 蓝图
|
||
|
||
user_uuid = session["user_uuid"]
|
||
uuid2username = current_app.extensions["uuid2username"]
|
||
user_id = uuid2username[user_uuid]
|
||
|
||
# 检查是否有学习记录
|
||
progress_result = load_learning_progress(user_id, course_id, chapter_name, lesson_name)
|
||
|
||
if not progress_result["exists"]:
|
||
# 没有学习记录,直接跳转到学习页面,不显示确认加载历史的页面
|
||
return redirect(url_for("vscode.desktop", user_uuid=user_uuid, course_id=course_id, chapter_name=chapter_name, lesson_name=lesson_name, load_history="false"))
|
||
|
||
# 获取学习记录数据
|
||
progress_data = progress_result["data"]
|
||
chapter_chain_now = progress_data.get("chapter_chain_now", -1)
|
||
chapter_chain_length = progress_data.get("chapter_chain_length", 0)
|
||
|
||
# 检查是否已经学完所有章节
|
||
is_course_finished = chapter_chain_now >= chapter_chain_length - 1
|
||
|
||
return render_template(
|
||
"confirm_load_history.html",
|
||
user_uuid=user_uuid,
|
||
course_id=course_id,
|
||
chapter_name=chapter_name,
|
||
lesson_name=lesson_name,
|
||
is_course_finished=is_course_finished
|
||
)
|
||
|
||
@bp.route("/vscode_data", methods=["POST"])
|
||
def vscode_data():
|
||
# data = request.get_json(force=True)
|
||
# config = data.get("config") or {}
|
||
|
||
# realtime_response(config, data) # 调用服务层逻辑
|
||
# return jsonify({"status": "success", "received": data})
|
||
|
||
return jsonify({"status": "success", "received": "success"})
|