193 lines
5.5 KiB
JavaScript
193 lines
5.5 KiB
JavaScript
|
|
/**
|
|||
|
|
* /api/industry — 行业代表制注册与管理路由
|
|||
|
|
*
|
|||
|
|
* 行业代表制架构:铸渊不是接入个人,而是接入行业。
|
|||
|
|
* 每个行业有一个代表人,代表人开自己的企业会员,
|
|||
|
|
* 铸渊管理代表人的仓库。
|
|||
|
|
*
|
|||
|
|
* 指令:ZY-AGEOS-TOWER-2026-0326-001
|
|||
|
|
* 版权:国作登字-2026-A-00037559
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
'use strict';
|
|||
|
|
|
|||
|
|
var express = require('express');
|
|||
|
|
var crypto = require('crypto');
|
|||
|
|
var router = express.Router();
|
|||
|
|
|
|||
|
|
var authModule = require('./auth');
|
|||
|
|
var requireSession = authModule.requireSession;
|
|||
|
|
var DEV_DATABASE = authModule.DEV_DATABASE;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Check if a dev ID is a registered developer
|
|||
|
|
* @param {string} devId
|
|||
|
|
* @returns {boolean}
|
|||
|
|
*/
|
|||
|
|
function isRegisteredDev(devId) {
|
|||
|
|
return !!(DEV_DATABASE[devId]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Generate a new industry ID
|
|||
|
|
* @returns {string}
|
|||
|
|
*/
|
|||
|
|
function generateIndustryId() {
|
|||
|
|
// Simple incremental ID; in production this would query existing IDs
|
|||
|
|
var timestamp = Date.now().toString(36).toUpperCase();
|
|||
|
|
return 'IND-' + timestamp.slice(-3).padStart(3, '0');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Hash a PAT for storage (never store raw PAT)
|
|||
|
|
* @param {string} pat
|
|||
|
|
* @returns {string}
|
|||
|
|
*/
|
|||
|
|
function hashPAT(pat) {
|
|||
|
|
return crypto.createHash('sha256').update(pat).digest('hex');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* POST /api/industry/register
|
|||
|
|
* Register a new industry with a representative developer
|
|||
|
|
* Requires authenticated session (DEV-XXX)
|
|||
|
|
*/
|
|||
|
|
router.post('/industry/register', requireSession, function(req, res) {
|
|||
|
|
var industry_name = (req.body.industry_name || '').trim();
|
|||
|
|
var rep_dev_id = (req.body.rep_dev_id || '').trim().toUpperCase();
|
|||
|
|
var github_username = (req.body.github_username || '').trim();
|
|||
|
|
var repo_name = (req.body.repo_name || '').trim();
|
|||
|
|
var pat = (req.body.pat || '').trim();
|
|||
|
|
|
|||
|
|
// Validate required fields
|
|||
|
|
if (!industry_name || !rep_dev_id || !github_username || !repo_name || !pat) {
|
|||
|
|
return res.status(400).json({
|
|||
|
|
error: true,
|
|||
|
|
code: 'MISSING_FIELDS',
|
|||
|
|
message: '缺少必填字段:industry_name, rep_dev_id, github_username, repo_name, pat'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Step 1: verify representative is a registered developer
|
|||
|
|
if (!isRegisteredDev(rep_dev_id)) {
|
|||
|
|
return res.status(400).json({
|
|||
|
|
error: true,
|
|||
|
|
code: 'INVALID_REPRESENTATIVE',
|
|||
|
|
message: '代表人必须是已注册开发者'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Step 2: only the representative themselves or admin can register
|
|||
|
|
var sessionDevId = req.sessionDevId;
|
|||
|
|
var sessionDev = req.sessionDev;
|
|||
|
|
if (sessionDevId !== rep_dev_id && (!sessionDev || sessionDev.level < 3)) {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
error: true,
|
|||
|
|
code: 'PERMISSION_DENIED',
|
|||
|
|
message: '只有代表人本人或管理者可以注册行业'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Step 3: validate PAT format (basic check — real validation against GitHub API
|
|||
|
|
// is done asynchronously after registration)
|
|||
|
|
if (pat.length < 10) {
|
|||
|
|
return res.status(400).json({
|
|||
|
|
error: true,
|
|||
|
|
code: 'INVALID_PAT',
|
|||
|
|
message: 'PAT 格式无效'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Step 4: create industry record
|
|||
|
|
var industryId = generateIndustryId();
|
|||
|
|
var patHash = hashPAT(pat);
|
|||
|
|
|
|||
|
|
var record = {
|
|||
|
|
industry_id: industryId,
|
|||
|
|
name: industry_name,
|
|||
|
|
representative: {
|
|||
|
|
dev_id: rep_dev_id,
|
|||
|
|
name: DEV_DATABASE[rep_dev_id] ? DEV_DATABASE[rep_dev_id].name : '',
|
|||
|
|
github_username: github_username,
|
|||
|
|
repo_url: 'https://github.com/' + github_username + '/' + repo_name,
|
|||
|
|
pat_hash: patHash,
|
|||
|
|
pat_status: 'pending_verification',
|
|||
|
|
membership: 'yearly_enterprise',
|
|||
|
|
membership_start: null
|
|||
|
|
},
|
|||
|
|
status: 'pending_init',
|
|||
|
|
created_at: new Date().toISOString(),
|
|||
|
|
created_by: sessionDevId
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// In production: store to database / encrypted file.
|
|||
|
|
// For now: return the record (minus PAT).
|
|||
|
|
console.log('[INDUSTRY] New industry registered: ' + industryId + ' ' + industry_name + ' by ' + rep_dev_id);
|
|||
|
|
|
|||
|
|
res.json({
|
|||
|
|
status: 'ok',
|
|||
|
|
industry_id: industryId,
|
|||
|
|
message: '行业「' + industry_name + '」已注册 · 铸渊正在初始化仓库',
|
|||
|
|
record: {
|
|||
|
|
industry_id: record.industry_id,
|
|||
|
|
name: record.name,
|
|||
|
|
representative: {
|
|||
|
|
dev_id: record.representative.dev_id,
|
|||
|
|
name: record.representative.name,
|
|||
|
|
github_username: record.representative.github_username,
|
|||
|
|
repo_url: record.representative.repo_url,
|
|||
|
|
pat_status: record.representative.pat_status
|
|||
|
|
},
|
|||
|
|
status: record.status,
|
|||
|
|
created_at: record.created_at
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* GET /api/industry/list
|
|||
|
|
* List all registered industries (admin only)
|
|||
|
|
*/
|
|||
|
|
router.get('/industry/list', requireSession, function(req, res) {
|
|||
|
|
var sessionDev = req.sessionDev;
|
|||
|
|
if (!sessionDev || sessionDev.level < 3) {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
error: true,
|
|||
|
|
code: 'PERMISSION_DENIED',
|
|||
|
|
message: '仅管理者可查看行业列表'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// In production: read from database.
|
|||
|
|
// For now: return placeholder.
|
|||
|
|
res.json({
|
|||
|
|
status: 'ok',
|
|||
|
|
industries: [
|
|||
|
|
{
|
|||
|
|
industry_id: 'IND-001',
|
|||
|
|
name: '网文行业',
|
|||
|
|
representative: { dev_id: 'DEV-002', name: '肥猫' },
|
|||
|
|
status: 'pending_setup'
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* GET /api/industry/status/:id
|
|||
|
|
* Get status of a specific industry
|
|||
|
|
*/
|
|||
|
|
router.get('/industry/status/:id', requireSession, function(req, res) {
|
|||
|
|
var industryId = req.params.id;
|
|||
|
|
|
|||
|
|
// In production: lookup from database
|
|||
|
|
res.json({
|
|||
|
|
status: 'ok',
|
|||
|
|
industry_id: industryId,
|
|||
|
|
message: '行业状态查询 · 功能开发中',
|
|||
|
|
note: '待铸渊初始化行业仓库后可查询完整状态'
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
module.exports = router;
|