zhizhi/backend/api-server/routes/industry.js

193 lines
5.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* /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;