Skip to content

Commit

Permalink
Merge pull request #92 from kuafuai/feat/tenant
Browse files Browse the repository at this point in the history
Feat/tenant
  • Loading branch information
yakeJiang authored Aug 31, 2023
2 parents 92543b7 + eaf75fd commit 1ebf752
Show file tree
Hide file tree
Showing 41 changed files with 1,978 additions and 296 deletions.
4 changes: 3 additions & 1 deletion backend/app/controllers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .step_api import bp as step_api_bp
from .step_requirement import bp as step_requirement_bp
from .setting import bp as setting_bp
from .tenant_pro import bp as tenant_bp

def register_controllers(app):
app.register_blueprint(user_bp)
Expand All @@ -19,4 +20,5 @@ def register_controllers(app):
app.register_blueprint(step_subtask_bp)
app.register_blueprint(step_code_bp)
app.register_blueprint(step_devops_bp)
app.register_blueprint(setting_bp)
app.register_blueprint(setting_bp)
app.register_blueprint(tenant_bp)
15 changes: 10 additions & 5 deletions backend/app/controllers/requirement.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from app.pkgs.tools.i18b import getI18n
from app.models.requirement import Requirement
from app.models.requirement_memory_pro import RequirementMemory
from app.models.tenant_pro import Tenant
from config import REQUIREMENT_STATUS_NotStarted, GRADE

bp = Blueprint('requirement', __name__, url_prefix='/requirement')
Expand All @@ -17,11 +18,12 @@ def clear_up():
print("clear_up failed:"+str(e))

session[session["username"]] = getEmptyTaskInfo()
# todo 1
session['tenant_id'] = 0
session.update()
tenant_name = "DevOpsGPT"
if GRADE != "base":
tenant = Tenant.get_tenant_baseinfo_by_id(session["tenant_id"])
tenant_name = tenant["name"]

return {"username": session["username"], "info": session[session["username"]]}
return {"username": session["username"], "tenant_name": tenant_name, "tenant_id": session["tenant_id"], "info": session[session["username"]]}


@bp.route('/setup_app', methods=['POST'])
Expand All @@ -35,7 +37,10 @@ def setup_app():
username = session['username']
tenantID = session['tenant_id']

requirement = Requirement.create_requirement(tenantID, "", "New", appID, 1, sourceBranch, featureBranch, REQUIREMENT_STATUS_NotStarted, 0, 0)
if GRADE != "base" and not Tenant.check_quota(tenantID):
raise Exception(_("You have exceeded your quota limit, please check your business bill."))

requirement = Requirement.create_requirement(tenantID, "New requirement", "New", appID, 1, sourceBranch, featureBranch, REQUIREMENT_STATUS_NotStarted, 0, 0)

session[username]['memory']['task_info'] = {
"app_id": appID,
Expand Down
3 changes: 3 additions & 0 deletions backend/app/controllers/step_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ def gen_interface_doc():
userPrompt = request.json.get('user_prompt')
username = session["username"]
requirementID = request.json.get('task_id')
tenant_id = session['tenant_id']

# todo Use llm to determine which interface documents to adjust
req = Requirement.get_requirement_by_id(requirementID)
apiDoc, success = getServiceSwagger(req["app_id"], 0)

Requirement.update_requirement(requirement_id=requirementID, original_requirement=userPrompt)

msg, success = clarifyAPI(requirementID, userPrompt, apiDoc)

session[username]['memory']['originalPrompt'] = userPrompt
Expand Down
13 changes: 11 additions & 2 deletions backend/app/controllers/step_requirement.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
from app.pkgs.prompt.prompt import clarifyRequirement
from app.pkgs.knowledge.app_info import getAppArchitecture
from app.models.requirement import Requirement
from app.models.tenant_pro import Tenant
from app.models.tenant_bill_pro import TenantBill
from config import GRADE
from config import REQUIREMENT_STATUS_InProgress

bp = Blueprint('step_requirement', __name__, url_prefix='/step_requirement')
Expand All @@ -17,14 +20,20 @@ def clarify():
globalContext = request.json.get('global_context')
userName = session["username"]
requirementID = request.json.get('task_id')
tenantID = session['tenant_id']

req = Requirement.get_requirement_by_id(requirementID)

if not req["app_id"] or req["app_id"] < 1 :
if not req or req["app_id"] < 1 :
raise Exception(_("Please select the application you want to develop."))

if len(globalContext) < 4 :
Requirement.update_requirement(requirement_id=requirementID, original_requirement=userPrompt, status=REQUIREMENT_STATUS_InProgress)
Requirement.update_requirement(requirement_id=requirementID, requirement_name=userPrompt, status=REQUIREMENT_STATUS_InProgress)

if GRADE != "base" and not Tenant.check_quota(tenantID):
raise Exception(_("You have exceeded your quota limit, please check your business bill."))
if GRADE != "base":
TenantBill.record_requirement(tenantID, userName, requirementID, userPrompt)

appArchitecture, _ = getAppArchitecture(req["app_id"])
msg, success = clarifyRequirement(requirementID, userPrompt, globalContext, appArchitecture)
Expand Down
20 changes: 20 additions & 0 deletions backend/app/controllers/tenant_pro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from flask import Blueprint
from app.controllers.common import json_response
from app.pkgs.tools.i18b import getI18n

bp = Blueprint('tenant', __name__, url_prefix='/tenant')

def test():
pass

@bp.route('/get_all', methods=['GET'])
@json_response
def get_all():
_ = getI18n("controllers")
raise Exception(_("The current version does not support this feature."))

@bp.route('/create', methods=['POST'])
@json_response
def create():
_ = getI18n("controllers")
raise Exception(_("The current version does not support this feature."))
10 changes: 8 additions & 2 deletions backend/app/controllers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from app.pkgs.tools.i18b import getFrontendText
from app.models.user import User
from app.models.user_pro import UserPro
from app.models.tenant_user_pro import TenantUser
from config import GRADE
from config import LANGUAGE

Expand All @@ -25,10 +26,16 @@ def register():
if GRADE == "base":
raise Exception("The current version does not support this feature")
else:
# todo 0
current_tenant = 0
tus = TenantUser.get_tenant_user_by_invite_email(email)
for tu in tus:
current_tenant = tu["tenant_id"]

user = UserPro.create_user(username, password, phone_number, email, zone_language, current_tenant)

for tu in tus:
TenantUser.active_tenant_user(tu["tenant_user_id"], user.user_id)

return user.username

@bp.route('/login', methods=['POST'])
Expand All @@ -50,7 +57,6 @@ def login():
session['tenant_id'] = userinfo["current_tenant"]

if ok:
session['logged_in'] = True
session['username'] = username
return {'message': _('Login successful.')}
else:
Expand Down
34 changes: 18 additions & 16 deletions backend/app/models/requirement.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,22 +61,24 @@ def get_all_requirements(tenantID=None):
@staticmethod
def get_requirement_by_id(requirement_id):
req = Requirement.query.get(requirement_id)
req_dict = {
'requirement_id': req.requirement_id,
'requirement_name': req.requirement_name,
'original_requirement': req.original_requirement,
'app_id': req.app_id,
'user_id': req.user_id,
'default_source_branch': req.default_source_branch,
'default_target_branch': req.default_target_branch,
'status': req.status,
'satisfaction_rating': req.satisfaction_rating,
'completion_rating': req.completion_rating,
'created_at': req.created_at,
'updated_at': req.updated_at,
'app': Application.get_application_by_id(req.app_id)
}
return req_dict
if req:
req_dict = {
'requirement_id': req.requirement_id,
'requirement_name': req.requirement_name,
'original_requirement': req.original_requirement,
'app_id': req.app_id,
'user_id': req.user_id,
'default_source_branch': req.default_source_branch,
'default_target_branch': req.default_target_branch,
'status': req.status,
'satisfaction_rating': req.satisfaction_rating,
'completion_rating': req.completion_rating,
'created_at': req.created_at,
'updated_at': req.updated_at,
'app': Application.get_application_by_id(req.app_id)
}
return req_dict
return None

@staticmethod
def update_requirement(requirement_id, requirement_name=None, original_requirement=None, app_id=None, user_id=None, status=None, satisfaction_rating=None, completion_rating=None):
Expand Down
3 changes: 3 additions & 0 deletions backend/app/models/tenant_bill_pro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class TenantBill():
def test():
pass
3 changes: 3 additions & 0 deletions backend/app/models/tenant_pro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Tenant():
def test():
pass
3 changes: 3 additions & 0 deletions backend/app/models/tenant_user_pro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class TenantUser():
def test():
pass
29 changes: 28 additions & 1 deletion backend/app/pkgs/tools/i18b.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def getFrontendText():
"app_list": _("APP List"),
"setting": _("Setting"),
"create_new": _("Create new"),
"back_to_list": _("Back to list page"),
"app_name": _("APP name"),
"app_intro": _("APP introduction"),
"app_base_branch": _("Base branch"),
Expand Down Expand Up @@ -122,5 +123,31 @@ def getFrontendText():
"password": _("Password"),
"register": _("Register"),
"email": _("Email"),
"phone": _("Phone"),
"tenant_name": _("Company Name"),
"tenant_status": _("Company Status"),
"tenant_description": _("Company Description"),
"tenant_billing_type": _("Billing type"),
"tenant_billing_quota": _("Billing quota"),
"tenant_created_at": _("Created"),
"tenant_billing_end": _("Plus expiry"),
"employee_count": _("Employee count"),
"industry_type": _("Industry type"),
"change_tenant": _("Switch Tenant"),
"tenant_member_count": _("Member Count"),
"create_tenant_notice": _("Please ensure that the information is accurate and we will review it within 24 hours to activate your account."),
"create_user_notice": _("In order to protect your rights, please ensure that the information is accurate."),
"enter": _("Enter"),
"show_tenant": _("Details"),
"members": _("Members"),
"country": _("Country"),
"role": _("Role"),
"phone": _("Phone Number"),
"add_member": _("Add member"),
"invite": _("Invite"),
"billing": _("Billing"),
"bill_type": _("Bill type"),
"bill_user": _("Operating user"),
"bill_date": _("Billing date"),
"remarks": _("Remarks"),
"operate": _("Operate"),
}
100 changes: 100 additions & 0 deletions backend/app/pkgs/tools/utils_tool.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import json
import re
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
import ssl

from app.pkgs.tools.llm import chatCompletion
from config import EMAIL_PASSWORD, EMAIL_PORT, EMAIL_SENDER, EMAIL_SERVER, EMAIL_SSL


def detect_programming_language(file_path):
Expand Down Expand Up @@ -97,3 +103,97 @@ def get_code_from_str(input_string):
output_string = match

return output_string

def send_email(receiver_email, subject, html_content):
# 邮件服务器的信息
smtp_server = EMAIL_SERVER
smtp_port = EMAIL_PORT

# 发件人和收件人信息
sender_email = EMAIL_SENDER
password = EMAIL_PASSWORD

msg = MIMEMultipart()
msg['From'] = sender_email
msg['To'] = receiver_email
msg['Subject'] = subject

html = """
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}
.container {
max-width: 600px;
margin: 0 auto;
background-color: #ffffff;
padding: 20px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
.header {
text-align: center;
padding: 20px 0;
}
.header h1 {
color: #333;
margin: 0;
}
.content {
padding: 20px 0;
}
.footer {
text-align: center;
padding: 20px 0;
color: #888;
font-size: 12px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>"""+subject+"""</h1>
</div>
<div class="content">
"""+html_content+"""
</div>
<div class="footer">
<p>本邮件为系统邮件,请勿回复。This email is a system email, please do not reply.</p>
<p>如有疑问,请添加我们的公众号:KuafuAI</p>
</div>
</div>
</body>
</html>
"""

html_part = MIMEText(html, 'html')
msg.attach(html_part)

# 建立与邮件服务器的连接并发送邮件
try:
if EMAIL_SSL:
context = ssl.create_default_context()
server = smtplib.SMTP_SSL(smtp_server, smtp_port, context=context)
else:
server = smtplib.SMTP(smtp_server, smtp_port)
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, msg.as_string())
server.quit()
print("邮件发送成功")
return True
except Exception as e:
print(f"邮件发送失败: {e}")
return False
5 changes: 5 additions & 0 deletions backend/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ def read_config(key):
CD_TOOLS = read_config("CD_TOOLS")
CD_ACCESS_KEY = read_config("CD_ACCESS_KEY")
CD_SECRET_KEY = read_config("CD_SECRET_KEY")
EMAIL_SERVER = read_config("EMAIL_SERVER")
EMAIL_PORT = read_config("EMAIL_PORT")
EMAIL_SSL = read_config("EMAIL_SSL")
EMAIL_SENDER = read_config("EMAIL_SENDER")
EMAIL_PASSWORD = read_config("EMAIL_PASSWORD")
except Exception as e:
print(f"\033[91mError: Failed to read the configuration, please copy a new env.yaml from env.yaml.tpl and reconfigure it according to the documentation. Error in env.yaml: {str(e)}. 读取配置错误,请重新从 env.yaml.tpl 复制一个 env.yaml 进行配置后重启程序。 \033[0m")
input("Press Enter to exit...")
Expand Down
Loading

0 comments on commit 1ebf752

Please sign in to comment.