fix(xhs): 管理员账号使用 customerId=0,取消客户账号限制

小红书各服务统一走 ResolveXhsCustomerIdAsync,管理员无需客户上下文即可操作 Agent、拟人设置等接口。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zzh 2026-07-01 09:02:18 +08:00
parent ffaf325563
commit 607e09433b
10 changed files with 37 additions and 125 deletions

View File

@ -22,7 +22,7 @@ public class XhsAgentService : ApplicationService
[HttpPost("/xhs/agent/register")]
public async Task<XhsAgentRegisterOutput> RegisterAsync(XhsAgentRegisterInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var deviceId = input.DeviceId.Trim();
if (string.IsNullOrWhiteSpace(deviceId))
{
@ -72,7 +72,7 @@ public class XhsAgentService : ApplicationService
[HttpPost("/xhs/agent/heartbeat")]
public async Task<XhsAgentHeartbeatOutput> HeartbeatAsync(XhsAgentHeartbeatInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var agent = await GetOwnedAgentByDeviceAsync(input.DeviceId.Trim(), customerId);
agent.EngineRunning = input.EngineRunning;
agent.ExtensionConnected = input.ExtensionConnected;
@ -119,24 +119,12 @@ public class XhsAgentService : ApplicationService
[HttpPost("/xhs/agent/control")]
public async Task<XhsAgentControlOutput> ControlAsync(XhsAgentControlInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var agent = await GetOwnedAgentByIdAsync(input.AgentId, customerId);
var task = XhsTaskFactory.CreateControlTask(customerId, agent.Id, input.Action.Trim());
await TaskRepository.InsertAsync(task);
return new XhsAgentControlOutput { TaskId = task.Id };
}
private async Task<int> RequireCustomerIdAsync()
{
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(CustomerRepository, CurrentUser, null);
if (!customerId.HasValue)
{
throw new BusinessException("请使用客户账号操作,或指定客户上下文");
}
return customerId.Value;
}
private async Task<XhsAgent> GetOwnedAgentByDeviceAsync(string deviceId, int customerId)
{
if (string.IsNullOrWhiteSpace(deviceId))

View File

@ -20,7 +20,7 @@ public class XhsAiService : ApplicationService
[HttpPost("/xhs/ai/provider/list")]
public async Task<OmsItemsResult<XhsAiProviderOutput>> ListProvidersAsync()
{
var customerId = await ResolveAiCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var items = await AiProviderRepository.GetListAsync(x => x.CustomerId == customerId || x.CustomerId == 0);
return new OmsItemsResult<XhsAiProviderOutput>
{
@ -31,7 +31,7 @@ public class XhsAiService : ApplicationService
[HttpPost("/xhs/ai/provider/save")]
public async Task<XhsAiProviderOutput> SaveProviderAsync(XhsAiProviderSaveInput input)
{
var customerId = await ResolveAiCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var providerKey = input.ProviderKey.Trim();
var entity = await AiProviderRepository.GetByProviderKeyAsync(customerId, providerKey);
if (entity == null)
@ -81,7 +81,7 @@ public class XhsAiService : ApplicationService
[HttpPost("/xhs/ai/chat")]
public async Task<XhsAiChatOutput> ChatAsync(XhsAiChatInput input)
{
var customerId = await ResolveAiCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var provider = await ResolveProviderAsync(customerId, input.ProviderKey.Trim());
var llm = LazyServiceProvider.GetRequiredService<XhsLlmClient>();
var content = await llm.ChatCompletionAsync(
@ -107,12 +107,6 @@ public class XhsAiService : ApplicationService
return provider;
}
private async Task<int> ResolveAiCustomerIdAsync()
{
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(CustomerRepository, CurrentUser, null);
return customerId ?? 0;
}
private static XhsAiProviderOutput MapProvider(XhsAiProvider entity, bool maskSecret) => new()
{
Id = entity.Id,

View File

@ -23,7 +23,7 @@ public class XhsAnalysisService : ApplicationService
[HttpPost("/xhs/analysis/start")]
public async Task<XhsAnalysisStartOutput> StartAsync(XhsAnalysisStartInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
return await StartSessionAsync(customerId, input);
}
@ -85,7 +85,7 @@ public class XhsAnalysisService : ApplicationService
[HttpPost("/xhs/analysis/run-ai")]
public async Task<XhsAnalysisRunAiOutput> RunAiAsync(XhsAnalysisRunAiInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var session = await AnalysisSessionRepository.FirstOrDefaultAsync(x => x.Id == input.SessionId);
if (session == null || session.CustomerId != customerId)
{
@ -132,7 +132,7 @@ public class XhsAnalysisService : ApplicationService
[HttpPost("/xhs/analysis/interact")]
public async Task<XhsAnalysisInteractOutput> InteractAsync(XhsAnalysisInteractInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var (toolName, args) = BuildInteractTask(input);
var task = new XhsTask
@ -278,18 +278,6 @@ public class XhsAnalysisService : ApplicationService
XhsAnalysisTypeCodes.FeedDetail => $"笔记详情:{keyword}",
_ => analysisType
};
private async Task<int> RequireCustomerIdAsync()
{
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(CustomerRepository, CurrentUser, null);
if (!customerId.HasValue)
{
throw new BusinessException("请使用客户账号操作");
}
return customerId.Value;
}
private static XhsAnalysisSessionOutput MapSession(XhsAnalysisSession session) => new()
{
Id = session.Id,

View File

@ -18,7 +18,7 @@ public class XhsCreationService : ApplicationService
[HttpPost("/xhs/creation/publish")]
public async Task<XhsCreationPublishOutput> PublishAsync(XhsCreationPublishInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var toolName = string.IsNullOrWhiteSpace(input.ToolName) ? "publish_content" : input.ToolName.Trim();
var scheduled = input.ScheduledTime.HasValue && input.ScheduledTime.Value > DateTime.Now;
@ -59,7 +59,7 @@ public class XhsCreationService : ApplicationService
[HttpPost("/xhs/creation/generate")]
public async Task<XhsCreationGenerateOutput> GenerateAsync(XhsCreationGenerateInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var aiService = LazyServiceProvider.GetRequiredService<XhsAiService>();
var provider = await aiService.ResolveProviderAsync(customerId, input.ProviderKey.Trim());
var llm = LazyServiceProvider.GetRequiredService<XhsLlmClient>();
@ -116,15 +116,4 @@ public class XhsCreationService : ApplicationService
return text;
}
private async Task<int> RequireCustomerIdAsync()
{
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(CustomerRepository, CurrentUser, null);
if (!customerId.HasValue)
{
throw new BusinessException("请使用客户账号操作");
}
return customerId.Value;
}
}

View File

@ -18,7 +18,7 @@ public class XhsHumanConfigService : ApplicationService
[HttpPost("/xhs/human-config/get")]
public async Task<XhsHumanConfigOutput> GetAsync()
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var config = await GetOrCreateConfigAsync(customerId);
return MapOutput(config);
}
@ -26,7 +26,7 @@ public class XhsHumanConfigService : ApplicationService
[HttpPost("/xhs/human-config/save")]
public async Task<XhsHumanConfigOutput> SaveAsync(XhsHumanConfigSaveInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var config = await GetOrCreateConfigAsync(customerId);
config.BehaviorJson = OmsDocHelper.SerializeJson(input.Behavior) ?? XhsHumanDefaults.BehaviorJson;
config.GuardJson = OmsDocHelper.SerializeJson(input.Guard) ?? XhsHumanDefaults.GuardJson;
@ -38,7 +38,7 @@ public class XhsHumanConfigService : ApplicationService
[HttpPost("/xhs/human-config/pull")]
public async Task<XhsHumanConfigPullOutput> PullAsync(XhsHumanConfigPullInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
_ = await GetOwnedAgentByDeviceAsync(input.DeviceId.Trim(), customerId);
var config = await GetOrCreateConfigAsync(customerId);
if (config.Version == input.KnownVersion)
@ -74,17 +74,6 @@ public class XhsHumanConfigService : ApplicationService
return config;
}
private async Task<int> RequireCustomerIdAsync()
{
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(CustomerRepository, CurrentUser, null);
if (!customerId.HasValue)
{
throw new BusinessException("请使用客户账号操作");
}
return customerId.Value;
}
private async Task<XhsAgent> GetOwnedAgentByDeviceAsync(string deviceId, int customerId)
{
var agent = await AgentRepository.GetByDeviceIdAsync(deviceId);

View File

@ -25,7 +25,7 @@ public class XhsMediaService : ApplicationService
throw new BusinessException("请选择文件");
}
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var uploadsRoot = Path.Combine(WebHostEnvironment.WebRootPath ?? "wwwroot", "uploads", "xhs", customerId.ToString());
Directory.CreateDirectory(uploadsRoot);
@ -57,15 +57,4 @@ public class XhsMediaService : ApplicationService
PublicUrl = publicUrl
};
}
private async Task<int> RequireCustomerIdAsync()
{
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(CustomerRepository, CurrentUser, null);
if (!customerId.HasValue)
{
throw new BusinessException("请使用客户账号操作");
}
return customerId.Value;
}
}

View File

@ -40,7 +40,7 @@ public class XhsPublishService : ApplicationService
[HttpPost("/xhs/publish/cancel")]
public async Task CancelAsync(XhsPublishCancelInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var record = await GetOwnedRecordAsync(input.PublishRecordId, customerId);
if (record.Status != XhsPublishStatusCodes.Scheduled)
{
@ -65,7 +65,7 @@ public class XhsPublishService : ApplicationService
[HttpPost("/xhs/publish/retry")]
public async Task<XhsCreationPublishOutput> RetryAsync(XhsPublishRetryInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var record = await GetOwnedRecordAsync(input.PublishRecordId, customerId);
if (record.Status != XhsPublishStatusCodes.Failed)
{
@ -115,18 +115,6 @@ public class XhsPublishService : ApplicationService
await TaskRepository.InsertAsync(task);
return task;
}
private async Task<int> RequireCustomerIdAsync()
{
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(CustomerRepository, CurrentUser, null);
if (!customerId.HasValue)
{
throw new BusinessException("请使用客户账号操作");
}
return customerId.Value;
}
private async Task<XhsPublishRecord> GetOwnedRecordAsync(int id, int customerId)
{
var record = await PublishRecordRepository.FirstOrDefaultAsync(x => x.Id == id);

View File

@ -19,11 +19,10 @@ public class XhsSkillService : ApplicationService
[HttpPost("/xhs/skill/list")]
public async Task<OmsItemsResult<XhsSkillOutput>> ListAsync(XhsSkillListInput input)
{
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(CustomerRepository, CurrentUser, input.CustomerId);
var listCustomerId = customerId ?? 0;
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser, input.CustomerId);
var items = await SkillRepository.GetListAsync(x =>
x.CustomerId == listCustomerId || x.CustomerId == 0);
x.CustomerId == customerId || x.CustomerId == 0);
items = items.OrderBy(x => x.SortOrder).ThenBy(x => x.Id).ToList();
return new OmsItemsResult<XhsSkillOutput>
@ -35,7 +34,7 @@ public class XhsSkillService : ApplicationService
[HttpPost("/xhs/skill/save")]
public async Task<XhsSkillOutput> SaveAsync(XhsSkillSaveInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
XhsSkill entity;
if (input.Id is > 0)
{
@ -75,7 +74,7 @@ public class XhsSkillService : ApplicationService
[HttpPost("/xhs/skill/delete")]
public async Task DeleteAsync(IdInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var entity = await SkillRepository.FirstOrDefaultAsync(x => x.Id == input.Id);
if (entity == null || entity.CustomerId != customerId)
{
@ -88,7 +87,7 @@ public class XhsSkillService : ApplicationService
[HttpPost("/xhs/skill/run")]
public async Task<XhsSkillRunOutput> RunAsync(XhsSkillRunInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var entity = await SkillRepository.FirstOrDefaultAsync(x => x.Id == input.SkillId);
if (entity == null || (entity.CustomerId != customerId && entity.CustomerId != 0))
{
@ -174,18 +173,6 @@ public class XhsSkillService : ApplicationService
throw new BusinessException($"未知 runMode: {runMode}");
}
private async Task<int> RequireCustomerIdAsync()
{
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(CustomerRepository, CurrentUser, null);
if (!customerId.HasValue)
{
throw new BusinessException("请使用客户账号操作");
}
return customerId.Value;
}
private static XhsSkillOutput MapSkill(XhsSkill skill) => new()
{
Id = skill.Id,

View File

@ -23,7 +23,7 @@ public class XhsTaskService : ApplicationService
[HttpPost("/xhs/task/claim")]
public async Task<XhsTaskClaimOutput> ClaimAsync(XhsTaskClaimInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var agent = await GetOwnedAgentByDeviceAsync(input.DeviceId.Trim(), customerId);
var limit = input.Limit <= 0 ? 1 : Math.Min(input.Limit, 5);
var tasks = await TaskRepository.ClaimPendingAsync(customerId, agent.Id, limit);
@ -45,7 +45,7 @@ public class XhsTaskService : ApplicationService
[HttpPost("/xhs/task/report")]
public async Task ReportAsync(XhsTaskReportInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var task = await TaskRepository.FirstOrDefaultAsync(x => x.Id == input.TaskId);
if (task == null || task.CustomerId != customerId)
{
@ -106,7 +106,7 @@ public class XhsTaskService : ApplicationService
[HttpPost("/xhs/task/cancel")]
public async Task CancelAsync(XhsTaskCancelInput input)
{
var customerId = await RequireCustomerIdAsync();
var customerId = await OmsSessionHelper.ResolveXhsCustomerIdAsync(CustomerRepository, CurrentUser);
var task = await TaskRepository.FirstOrDefaultAsync(x => x.Id == input.TaskId);
if (task == null || task.CustomerId != customerId)
{
@ -218,18 +218,6 @@ public class XhsTaskService : ApplicationService
return json;
}
private async Task<int> RequireCustomerIdAsync()
{
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(CustomerRepository, CurrentUser, null);
if (!customerId.HasValue)
{
throw new BusinessException("请使用客户账号操作");
}
return customerId.Value;
}
private async Task<XhsAgent> GetOwnedAgentByDeviceAsync(string deviceId, int customerId)
{
var agent = await AgentRepository.GetByDeviceIdAsync(deviceId);

View File

@ -108,4 +108,16 @@ public static class OmsSessionHelper
return customer.Id;
}
/// <summary>
/// 小红书模块客户上下文:客户登录返回 t_customer.Id;管理员无客户上下文时返回 0(系统级)。
/// </summary>
public static async Task<int> ResolveXhsCustomerIdAsync(
ICustomerRepository customerRepository,
ICurrentUser currentUser,
int? requestedCustomerId = null)
{
var customerId = await ResolveListCustomerIdAsync(customerRepository, currentUser, requestedCustomerId);
return customerId ?? 0;
}
}