From 330d8749397b69f5088baa904dd7da220c944cd6 Mon Sep 17 00:00:00 2001 From: floraachy <1622042529@gitlink.com> Date: Thu, 20 Mar 2025 08:37:45 +0800 Subject: [PATCH] ADD file via upload --- views.py | 611 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 611 insertions(+) create mode 100644 views.py diff --git a/views.py b/views.py new file mode 100644 index 0000000..383ee7a --- /dev/null +++ b/views.py @@ -0,0 +1,611 @@ +import configparser +import math +import requests +import json +import os + +from django.http import JsonResponse +from django.views.decorators.http import require_http_methods + +from maturityAnalyse import settings + +config_file_path = os.path.join(settings.BASE_DIR, 'static', 'config.ini') + + +# 加载配置文件 +def load_config(file_path): + config = configparser.ConfigParser() + config.read(file_path) + return config['Limits'] + + +# 获取最大最小值 +def get_extreme_values(name): + limits = load_config(config_file_path) + + try: + max_value = int(limits[f"{name}_max"]) + min_value = int(limits[f"{name}_min"]) + except KeyError: + print(f"没有找到配置项: {name}") + max_value, min_value = None, None + + return max_value, min_value + + +# 获取成熟度计算所需的上下文(最大最小值) +def get_maturity_context(): + context = MaturityContext() + context.commits_number_max, context.commits_number_min = get_extreme_values("commits_number") + context.contributing_max, context.contributing_min = get_extreme_values("contributing") + context.critical_advisory_max, context.critical_advisory_min = get_extreme_values("critical_advisory") + context.forks_max, context.forks_min = get_extreme_values("forks") + context.high_advisory_max, context.high_advisory_min = get_extreme_values("high_advisory") + context.issue_closed_max, context.issue_closed_min = get_extreme_values("issue_closed") + context.issue_opened_max, context.issue_opened_min = get_extreme_values("issue_opened") + context.license_max, context.license_min = get_extreme_values("license_info") + context.low_advisory_max, context.low_advisory_min = get_extreme_values("low_advisory") + context.moderate_advisory_max, context.moderate_advisory_min = get_extreme_values("moderate_advisory") + context.stars_max, context.stars_min = get_extreme_values("stars") + context.release_number_max, context.release_number_min = get_extreme_values("release_number") + context.developer_number_max, context.developer_number_min = get_extreme_values("developer_number") + + return context + + +class MaturityContext: + def __init__(self): + self.stars_max = 0 + self.stars_min = 0 + self.watching_max = 0 + self.watching_min = 0 + self.forks_max = 0 + self.forks_min = 0 + self.commits_number_max = 0 + self.commits_number_min = 0 + self.license_max = 0 + self.license_min = 0 + self.issue_closed_max = 0 + self.issue_closed_min = 0 + self.issue_opened_max = 0 + self.issue_opened_min = 0 + self.low_advisory_max = 0 + self.low_advisory_min = 0 + self.moderate_advisory_max = 0 + self.moderate_advisory_min = 0 + self.high_advisory_max = 0 + self.high_advisory_min = 0 + self.critical_advisory_max = 0 + self.critical_advisory_min = 0 + self.contributing_max = 0 + self.contributing_min = 0 + self.developer_number_max = 0 + self.developer_number_min = 0 + self.release_number_max = 0 + self.release_number_min = 0 + + +class Software: + def __init__(self, license, issue_opened, issue_closed, low_advisory, moderate_advisory, high_advisory, + critical_advisory, stars, watching, forks, commits_number, average_day_interval, readme, + contributing, developer_number, release_number, user_number, sum_user_score): + self.license = license + self.issue_opened = issue_opened + self.issue_closed = issue_closed + self.low_advisory = low_advisory + self.moderate_advisory = moderate_advisory + self.high_advisory = high_advisory + self.critical_advisory = critical_advisory + self.stars = stars + self.watching = watching + self.forks = forks + self.commits_number = commits_number + self.contributing = contributing + self.developer_number = developer_number + self.release_number = release_number + + +class AllWeightSoftware: + def __init__(self, software): + self.s = software + self.m = 0 + + +def generate_score(value, max_value, min_value): + if max_value - min_value == 0: + return 100 if value > 0 else 0 + + if max_value > 2: + return log_generate_score(value, max_value, min_value) + else: + return normal_generate_score(value, max_value, min_value) + + +def normal_generate_score(value, max_value, min_value): + return int(100 * (value - min_value) / (max_value - min_value)) + + +def log_generate_score(value, max_value, min_value): + if max_value - min_value == 0 and max_value != 0: + return 50 + + fv = math.log10(value) if value > 0 else 0 + fmax = math.log10(max_value) if max_value != 0 else 0 + fmin = math.log10(min_value) if min_value != 0 else 0 + + return int(100 * (fv - fmin) / (fmax - fmin)) + + +def maturity(software, context): + ws = AllWeightSoftware(software) + + # 计算每个属性的分数 + ws.license_score = generate_score(software.license, context.license_max, context.license_min) + + ws.open_issue_score = generate_score(software.issue_opened, context.issue_opened_max, + context.issue_opened_min) + + ws.closed_issue_score = generate_score(software.issue_closed, context.issue_closed_max, context.issue_closed_min) + + ws.low_advisory_score = 100 - generate_score(software.low_advisory, context.low_advisory_max, + context.low_advisory_min) + + ws.moderate_advisory_score = 100 - generate_score(software.moderate_advisory, context.moderate_advisory_max, + context.moderate_advisory_min) + + ws.high_advisory_score = 100 - generate_score(software.high_advisory, context.high_advisory_max, + context.high_advisory_min) + + ws.critical_advisory_score = 100 - generate_score(software.critical_advisory, context.critical_advisory_max, + context.critical_advisory_min) + + ws.stars_score = generate_score(software.stars, context.stars_max, context.stars_min) + + ws.watching_score = generate_score(software.watching, context.watching_max, context.watching_min) + + ws.fork_score = generate_score(software.forks, context.forks_max, context.forks_min) + + ws.commits_number_score = generate_score(software.commits_number, context.commits_number_max, + context.commits_number_min) + + ws.developer_number_score = generate_score(software.developer_number, context.developer_number_max, + context.developer_number_min) + + ws.release_number_score = generate_score(software.release_number, context.release_number_max, + context.release_number_min) + + # 计算整体成熟度,去掉权重影响 + ws.m = (ws.license_score + ws.open_issue_score + ws.closed_issue_score + + # 降低了这部分内容的权重 + (ws.low_advisory_score + ws.moderate_advisory_score + ws.high_advisory_score + ws.critical_advisory_score) * 0.25 + + ws.stars_score + ws.watching_score + ws.fork_score + ws.commits_number_score + + ws.developer_number_score + ws.release_number_score) / 10 + + stage = 0 + if ws.m < 60: + stage = 2 + elif ws.m >= 60 and ws.m < 80: + stage = 1 + + yadd = stage * 3 - 1 + + scores_charts = [ + { + "name": "license_score", + "score": ws.license_score, + "description": "开源许可证评分", + "criteria": { + "100": "使用标准开源许可证(MIT/Apache/GPL等)", + "0": "无许可证" + }, + "suggestion": "建议使用标准的开源许可证以明确项目的使用条款和限制", + "itemStyle": { + "color": "#e9ff40" + }, + "value": [ + 3, + 1 + yadd, + ws.license_score + ] + }, + { + "name": "open_issue_score", + "score": ws.open_issue_score, + "description": "未解决issue评分", + "criteria": { + "80-100": "未解决issue较少", + "60-80": "未解决issue较多", + "0-60": "未解决issue很多" + }, + "suggestion": "保持适度的未解决issue数量,及时处理重要issue", + "itemStyle": { + "color": "#abd9e9" + }, + "value": [ + 7, + 2 + yadd, + ws.open_issue_score + ] + }, + { + "name": "closed_issue_score", + "score": ws.closed_issue_score, + "description": "已解决issue评分", + "criteria": { + "80-100": "已解决issue很多", + "60-80": "已解决issue较多", + "0-60": "已解决issue较少" + }, + "suggestion": "提高issue解决率,保持良好的问题跟踪和处理机制", + "itemStyle": { + "color": "#74add1" + }, + "value": [ + 8, + 2 + yadd, + ws.closed_issue_score + ] + }, + { + "name": "low_advisory_score", + "score": ws.low_advisory_score, + "description": "低风险安全警告评分", + "criteria": { + "100": "无低风险警告", + "0": "多个低风险警告" + }, + "suggestion": "定期检查并修复安全隐患,即使是低风险问题也应重视", + "itemStyle": { + "color": "#ffffbf" + }, + "value": [ + 0, + 1 + yadd, + ws.low_advisory_score + ] + }, + { + "name": "moderate_advisory_score", + "score": ws.moderate_advisory_score, + "description": "中等风险安全警告评分", + "criteria": { + "100": "无中等风险警告", + "0": "多个中风险警告" + }, + "suggestion": "优先处理中等风险安全问题,避免安全隐患扩大", + "itemStyle": { + "color": "#fee090" + }, + "value": [ + 0, + 2 + yadd, + ws.moderate_advisory_score + ] + }, + { + "name": "high_advisory_score", + "score": ws.high_advisory_score, + "description": "高风险安全警告评分", + "criteria": { + "100": "无高风险警告", + "0": "多个高风险警告" + }, + "suggestion": "高风险安全问题必须立即处理,可考虑发布安全补丁版本", + "itemStyle": { + "color": "#fdae61" + }, + "value": [ + 1, + 1 + yadd, + ws.high_advisory_score + ] + }, + { + "name": "critical_advisory_score", + "score": ws.critical_advisory_score, + "description": "严重风险安全警告评分", + "criteria": { + "100": "无严重风险警告", + "0": "多个严重风险警告" + }, + "suggestion": "严重安全问题需要紧急修复并及时通知用户更新", + "itemStyle": { + "color": "#f46d43" + }, + "value": [ + 1, + 2 + yadd, + ws.critical_advisory_score + ] + }, + { + "name": "stars_score", + "score": ws.stars_score, + "description": "项目Star数评分", + "criteria": { + "80-100": "Star很多", + "60-80": "Star较多", + "0-60": "Star较少" + }, + "suggestion": "提高项目影响力,完善文档和功能以吸引更多用户关注", + "itemStyle": { + "color": "#93AAFC" + }, + "value": [ + 3, + 2 + yadd, + ws.stars_score + ] + }, + { + "name": "watching_score", + "score": ws.watching_score, + "description": "项目关注者评分", + "criteria": { + "80-100": "关注者很多", + "60-80": "关注者较多", + "0-60": "关注者较少" + }, + "suggestion": "增加项目曝光度,保持更新以维持用户关注度", + "itemStyle": { + "color": "#40daff" + }, + "value": [ + 4, + 2 + yadd, + ws.watching_score + ] + }, + { + "name": "fork_score", + "score": ws.fork_score, + "description": "项目fork数评分", + "criteria": { + "80-100": "fork数很多", + "60-80": "fork数较多", + "0-60": "fork数较少" + }, + "suggestion": "鼓励社区贡献,完善协作指南以促进fork开发", + "itemStyle": { + "color": "#73d797" + }, + "value": [ + 5, + 1 + yadd, + ws.fork_score + ] + }, + { + "name": "commits_number_score", + "score": ws.commits_number_score, + "description": "提交次数评分", + "criteria": { + "80-100": "提交次数很多", + "60-80": "提交次数较多", + "0-60": "提交次数较少" + }, + "suggestion": "保持稳定的开发活跃度,定期提交代码更新", + "itemStyle": { + "color": "#ad73d7" + }, + "value": [ + 6, + 1 + yadd, + ws.commits_number_score + ] + }, + { + "name": "developer_number_score", + "score": ws.developer_number_score, + "description": "开发者数量评分", + "criteria": { + "80-100": "开发者数量很多", + "60-80": "开发者数量较多", + "0-60": "开发者数量较少" + }, + "suggestion": "扩大开发团队,培养核心贡献者", + "itemStyle": { + "color": "#ee6df5" + }, + "value": [ + 2, + 2 + yadd, + ws.developer_number_score + ] + }, + { + "name": "release_number_score", + "score": ws.release_number_score, + "description": "发布版本数评分", + "criteria": { + "80-100": "发布版本数很多", + "60-80": "发布版本数较多", + "0-60": "发布版本数较少" + }, + "suggestion": "建立规范的版本发布流程,保持稳定的迭代节奏", + "itemStyle": { + "color": "#c4b7e5" + }, + "value": [ + 2, + 1 + yadd, + ws.release_number_score + ] + }, + ] + + main_score = { + "name": "overall_maturity_score", + "score": ws.m, + "description": "总体成熟度评分", + "criteria": { + "80-100": "项目成熟,维护良好", + "60-80": "项目稳定,有待改进", + "40-60": "项目基本可用,需要加强维护", + "0-40": "项目初期或疏于维护" + }, + "x_axis": ["稳健性","稳健性","稳健性","扩展性","扩展性","扩展性","维护性","维护性","维护性"], + "y_axis": ["成熟型","成熟型","成熟型","稳定型","稳定型","稳定型","成长型","成长型","成长型"], + "suggestion": "根据各项分值改进薄弱环节,提高项目整体质量" + } + + return {'main_score': main_score, 'scores': scores_charts} + + +def fetch_data(url): + """从给定 URL 获取数据并以 JSON 格式返回。""" + response = requests.get(url) + response.raise_for_status() # 对于错误响应抛出异常 + return response.json() + + +@require_http_methods(['GET']) +def calculate(request): + owner = request.GET.get('owner') + repository = request.GET.get('repository') + env_url = "https://www.gitlink.org.cn" + if request.GET.get('env_url') == "testforgeplus": + env_url = "https://testforgeplus.trustie.net" + + # owner = "xuos" # 替换为实际的 owner + # repository = "xiuos" # 替换为实际的 repository + + # owner = "leslieder" + # repository = "nodom" + + # owner = "openEuler-Ecosystem" + # repository = "openEuler-EulerOS" + + # 从 API 获取数据 + link1_info = f"{env_url}/api/{owner}/{repository}/detail.json" + link2_contri = f"{env_url}/api/{owner}/{repository}/contributors.json" + link3_issue = f"{env_url}/api/{owner}/{repository}/issues.json" + link4_commits = f"{env_url}/api/{owner}/{repository}/commits.json" + link_release = f"{env_url}/api/{owner}/{repository}/releases.json" + + try: + software_detail = fetch_data(link1_info) + contributors = fetch_data(link2_contri) + issues = fetch_data(link3_issue) + commits = fetch_data(link4_commits) + releases = fetch_data(link_release) + + # 提取必要的信息 + license_info = 1 if software_detail.get("license_name") else 0 + issue_opened = issues.get("open_count", 0) + issue_closed = issues.get("close_count", 0) + low_advisory = software_detail.get("advisories", {}).get("low", 0) + moderate_advisory = software_detail.get("advisories", {}).get("moderate", 0) + high_advisory = software_detail.get("advisories", {}).get("high", 0) + critical_advisory = software_detail.get("advisories", {}).get("critical", 0) + stars = software_detail.get("praises_count", 0) + watching = software_detail.get("watchers_count", 0) + forks = software_detail.get("forked_count", 0) + commits_number = commits.get("total_count") + average_day_interval = software_detail.get("average_day_interval", 0) + readme = software_detail.get("readme", False) + contributing = software_detail.get("contributing", False) + developer_number = len(contributors.get("list")) + release_number = releases.get("total_count") + user_number = software_detail.get("user_number", 0) + sum_user_score = software_detail.get("sum_user_score", 0) + + except TypeError: + return JsonResponse({'data': {}}) + except: + return JsonResponse({'data': {}}) + # 输出每个信息 + # print("许可证:", license_info) + # print("打开的问题数量:", issue_opened) + # print("关闭的问题数量:", issue_closed) + # print("低风险通报数量:", low_advisory) + # print("中风险通报数量:", moderate_advisory) + # print("高风险通报数量:", high_advisory) + # print("严重风险通报数量:", critical_advisory) + # print("星级:", stars) + # print("关注者数量:", watching) + # print("分支数量:", forks) + # print("提交数量:", commits_number) + # print("平均天数间隔:", average_day_interval) + # print("是否包含 README:", readme) + # print("是否包含贡献指南:", contributing) + # print("开发者数量:", developer_number) + # print("发布版本数量:", release_number) + # print("用户数量:", user_number) + # print("用户总评分:", sum_user_score) + + # 创建 Software 实例 + software = Software( + license=license_info, + issue_opened=issue_opened, + issue_closed=issue_closed, + low_advisory=low_advisory, + moderate_advisory=moderate_advisory, + high_advisory=high_advisory, + critical_advisory=critical_advisory, + stars=stars, + watching=watching, + forks=forks, + commits_number=commits_number, + average_day_interval=average_day_interval, + readme=readme, + contributing=contributing, + developer_number=developer_number, + release_number=release_number, + user_number=user_number, + sum_user_score=sum_user_score + ) + + update_config(software) + + context = get_maturity_context() + maturity_score = maturity(software, context) + + return JsonResponse({'data': maturity_score}) + + +def update_config(software): + """根据软件数据更新 config.ini 文件""" + config = configparser.ConfigParser() + config.read(config_file_path) + + # 更新每个数据项 + update_config_value(config, 'license_info', software.license) + update_config_value(config, 'issue_opened', software.issue_opened) + update_config_value(config, 'issue_closed', software.issue_closed) + update_config_value(config, 'low_advisory', software.low_advisory) + update_config_value(config, 'moderate_advisory', software.moderate_advisory) + update_config_value(config, 'high_advisory', software.high_advisory) + update_config_value(config, 'critical_advisory', software.critical_advisory) + update_config_value(config, 'stars', software.stars) + update_config_value(config, 'watching', software.watching) + update_config_value(config, 'forks', software.forks) + update_config_value(config, 'commits_number', software.commits_number) + update_config_value(config, 'developer_number', software.developer_number) + update_config_value(config, 'release_number', software.release_number) + + # 保存更新后的配置 + with open(config_file_path, 'w') as configfile: + config.write(configfile) + + +def update_config_value(config, key, value): + """更新配置中的最大值和最小值""" + section = 'Limits' # 指定使用的节 + + # 获取当前最小值和最大值 + current_min = config.getint(section, key + '_min') + current_max = config.getint(section, key + '_max') + + # 更新最小值 + if value < current_min: + config.set(section, key + '_min', str(value)) + + # 更新最大值 + if value > current_max: + config.set(section, key + '_max', str(value)) + +# if __name__ == "__main__": +# owner = "xuos" # 替换为实际的 owner +# repository = "xiuos" # 替换为实际的 repository +# calculate(owner,repository) \ No newline at end of file