update
This commit is contained in:
@@ -1,15 +1,173 @@
|
||||
import argon2 from 'argon2';
|
||||
import { PrismaClient, AccessMode, ToolStatus, ArtifactStatus, AdminUserStatus } from '@prisma/client';
|
||||
import {
|
||||
PrismaClient,
|
||||
AccessMode,
|
||||
ToolStatus,
|
||||
ArtifactStatus,
|
||||
DownloadRecordStatus,
|
||||
AdminUserStatus,
|
||||
} from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
function todayDateString(): string {
|
||||
return new Date().toISOString().slice(0, 10);
|
||||
type ArtifactSeed = {
|
||||
id: string;
|
||||
version: string;
|
||||
fileName: string;
|
||||
fileSizeBytes: number;
|
||||
sha256: string;
|
||||
mimeType: string;
|
||||
gitlabProjectId: number;
|
||||
gitlabPackageName: string;
|
||||
gitlabPackageVersion: string;
|
||||
gitlabFilePath: string;
|
||||
status: ArtifactStatus;
|
||||
releaseNotes: string;
|
||||
uploadedBy?: string;
|
||||
createdAt: Date;
|
||||
};
|
||||
|
||||
type ToolSeed = {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
categoryId: string;
|
||||
description: string;
|
||||
rating: number;
|
||||
downloadCount: number;
|
||||
openCount: number;
|
||||
accessMode: AccessMode;
|
||||
openUrl?: string;
|
||||
openInNewTab?: boolean;
|
||||
status: ToolStatus;
|
||||
createdAt: Date;
|
||||
updatedAt: string;
|
||||
features: Array<{
|
||||
id: string;
|
||||
featureText: string;
|
||||
sortOrder: number;
|
||||
}>;
|
||||
tagIds: string[];
|
||||
artifacts?: ArtifactSeed[];
|
||||
latestArtifactId?: string;
|
||||
};
|
||||
|
||||
const USER_AGENTS = [
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4)',
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
|
||||
'Mozilla/5.0 (X11; Linux x86_64)',
|
||||
'ToolsShowDesktop/1.1.0',
|
||||
'curl/8.7.1',
|
||||
];
|
||||
|
||||
function dateOnly(date: Date): string {
|
||||
return date.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
function daysAgo(days: number, hour = 10, minute = 0): Date {
|
||||
const date = new Date();
|
||||
date.setHours(hour, minute, 0, 0);
|
||||
date.setDate(date.getDate() - days);
|
||||
return date;
|
||||
}
|
||||
|
||||
function makeIp(seed: number): string {
|
||||
return `10.24.${Math.floor(seed / 200) + 10}.${(seed % 200) + 20}`;
|
||||
}
|
||||
|
||||
function buildOpenRecords(
|
||||
toolId: string,
|
||||
dailyCounts: number[],
|
||||
channel: string,
|
||||
referer: string,
|
||||
) {
|
||||
return dailyCounts.flatMap((count, index) => {
|
||||
const dayOffset = dailyCounts.length - index - 1;
|
||||
return Array.from({ length: count }, (_, slot) => ({
|
||||
toolId,
|
||||
openedAt: daysAgo(dayOffset, 9 + (slot % 8), (slot * 11) % 60),
|
||||
clientIp: makeIp(index * 40 + slot),
|
||||
userAgent: USER_AGENTS[(index + slot) % USER_AGENTS.length],
|
||||
channel,
|
||||
clientVersion: channel === 'desktop' ? '1.1.0' : 'web',
|
||||
referer,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function buildDownloadRecords(
|
||||
toolId: string,
|
||||
artifactId: string,
|
||||
dailyCounts: number[],
|
||||
channel: string,
|
||||
clientVersion: string,
|
||||
) {
|
||||
return dailyCounts.flatMap((count, index) => {
|
||||
const dayOffset = dailyCounts.length - index - 1;
|
||||
return Array.from({ length: count }, (_, slot) => ({
|
||||
toolId,
|
||||
artifactId,
|
||||
ticket: `ticket_${toolId}_${dayOffset}_${slot}`,
|
||||
downloadedAt: daysAgo(dayOffset, 8 + (slot % 10), (slot * 7) % 60),
|
||||
clientIp: makeIp(index * 60 + slot + 300),
|
||||
userAgent: USER_AGENTS[(index + slot + 1) % USER_AGENTS.length],
|
||||
channel,
|
||||
clientVersion,
|
||||
status: DownloadRecordStatus.success,
|
||||
errorMessage: null,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
async function createToolWithRelations(tool: ToolSeed) {
|
||||
await prisma.tool.create({
|
||||
data: {
|
||||
id: tool.id,
|
||||
name: tool.name,
|
||||
slug: tool.slug,
|
||||
categoryId: tool.categoryId,
|
||||
description: tool.description,
|
||||
rating: tool.rating,
|
||||
downloadCount: tool.downloadCount,
|
||||
openCount: tool.openCount,
|
||||
accessMode: tool.accessMode,
|
||||
openUrl: tool.openUrl,
|
||||
openInNewTab: tool.openInNewTab ?? true,
|
||||
status: tool.status,
|
||||
createdAt: tool.createdAt,
|
||||
updatedAt: tool.updatedAt,
|
||||
features: {
|
||||
createMany: {
|
||||
data: tool.features,
|
||||
},
|
||||
},
|
||||
tags: {
|
||||
create: tool.tagIds.map((tagId) => ({ tagId })),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (tool.artifacts?.length) {
|
||||
await prisma.toolArtifact.createMany({
|
||||
data: tool.artifacts.map((artifact) => ({
|
||||
...artifact,
|
||||
toolId: tool.id,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
if (tool.latestArtifactId) {
|
||||
await prisma.tool.update({
|
||||
where: { id: tool.id },
|
||||
data: {
|
||||
latestArtifactId: tool.latestArtifactId,
|
||||
updatedAt: tool.updatedAt,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const nowDate = todayDateString();
|
||||
|
||||
await prisma.$transaction([
|
||||
prisma.toolTag.deleteMany(),
|
||||
prisma.toolFeature.deleteMany(),
|
||||
@@ -30,6 +188,8 @@ async function main() {
|
||||
{ id: 'cat_ai', name: 'AI', sortOrder: 10 },
|
||||
{ id: 'cat_dev', name: 'Developer', sortOrder: 20 },
|
||||
{ id: 'cat_ops', name: 'Operations', sortOrder: 30 },
|
||||
{ id: 'cat_design', name: 'Design', sortOrder: 40 },
|
||||
{ id: 'cat_productivity', name: 'Productivity', sortOrder: 50 },
|
||||
],
|
||||
});
|
||||
|
||||
@@ -38,107 +198,744 @@ async function main() {
|
||||
{ id: 'tag_hot', name: 'Hot' },
|
||||
{ id: 'tag_free', name: 'Free' },
|
||||
{ id: 'tag_official', name: 'Official' },
|
||||
{ id: 'tag_new', name: 'New' },
|
||||
{ id: 'tag_team', name: 'Team' },
|
||||
{ id: 'tag_self_hosted', name: 'Self-hosted' },
|
||||
{ id: 'tag_enterprise', name: 'Enterprise' },
|
||||
{ id: 'tag_recommended', name: 'Recommended' },
|
||||
],
|
||||
});
|
||||
|
||||
const webToolId = 'tool_web_001';
|
||||
const downloadToolId = 'tool_dl_001';
|
||||
const artifactId = 'art_001';
|
||||
const passwordHash = await argon2.hash('admin123456', {
|
||||
type: argon2.argon2id,
|
||||
});
|
||||
await prisma.adminUser.createMany({
|
||||
data: [
|
||||
{
|
||||
id: 'u_admin_001',
|
||||
username: 'admin',
|
||||
passwordHash,
|
||||
displayName: 'System Admin',
|
||||
status: AdminUserStatus.active,
|
||||
lastLoginAt: daysAgo(0, 9, 25),
|
||||
},
|
||||
{
|
||||
id: 'u_admin_002',
|
||||
username: 'ops-admin',
|
||||
passwordHash,
|
||||
displayName: 'Operations Admin',
|
||||
status: AdminUserStatus.active,
|
||||
lastLoginAt: daysAgo(1, 18, 5),
|
||||
},
|
||||
{
|
||||
id: 'u_admin_003',
|
||||
username: 'auditor',
|
||||
passwordHash,
|
||||
displayName: 'Read Only Auditor',
|
||||
status: AdminUserStatus.disabled,
|
||||
lastLoginAt: daysAgo(11, 13, 10),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await prisma.tool.create({
|
||||
data: {
|
||||
id: webToolId,
|
||||
const tools: ToolSeed[] = [
|
||||
{
|
||||
id: 'tool_web_001',
|
||||
name: 'OpenAI Playground',
|
||||
slug: 'openai-playground',
|
||||
categoryId: 'cat_ai',
|
||||
description: 'OpenAI web playground for prompt testing.',
|
||||
rating: 4.8,
|
||||
description:
|
||||
'OpenAI web playground for prompt iteration, parameter tuning, and quick eval loops.',
|
||||
rating: 4.9,
|
||||
downloadCount: 0,
|
||||
openCount: 128,
|
||||
openCount: 642,
|
||||
accessMode: AccessMode.web,
|
||||
openUrl: 'https://platform.openai.com/playground',
|
||||
openInNewTab: true,
|
||||
status: ToolStatus.published,
|
||||
updatedAt: nowDate,
|
||||
features: {
|
||||
createMany: {
|
||||
data: [
|
||||
{ id: 'feat_web_001', featureText: 'Prompt debugging', sortOrder: 10 },
|
||||
{ id: 'feat_web_002', featureText: 'Model parameter tuning', sortOrder: 20 },
|
||||
],
|
||||
createdAt: daysAgo(45, 10, 0),
|
||||
updatedAt: dateOnly(daysAgo(0)),
|
||||
features: [
|
||||
{ id: 'feat_web_001', featureText: 'Prompt debugging', sortOrder: 10 },
|
||||
{
|
||||
id: 'feat_web_002',
|
||||
featureText: 'Model parameter tuning',
|
||||
sortOrder: 20,
|
||||
},
|
||||
},
|
||||
tags: {
|
||||
create: [{ tagId: 'tag_hot' }, { tagId: 'tag_official' }],
|
||||
},
|
||||
{
|
||||
id: 'feat_web_003',
|
||||
featureText: 'Quick compare workflow',
|
||||
sortOrder: 30,
|
||||
},
|
||||
],
|
||||
tagIds: ['tag_hot', 'tag_official', 'tag_recommended'],
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.tool.create({
|
||||
data: {
|
||||
id: downloadToolId,
|
||||
{
|
||||
id: 'tool_web_002',
|
||||
name: 'Claude Artifacts',
|
||||
slug: 'claude-artifacts',
|
||||
categoryId: 'cat_ai',
|
||||
description:
|
||||
'Web workspace for iterating on prompts, generated UI fragments, and artifact previews.',
|
||||
rating: 4.7,
|
||||
downloadCount: 0,
|
||||
openCount: 438,
|
||||
accessMode: AccessMode.web,
|
||||
openUrl: 'https://claude.ai',
|
||||
openInNewTab: true,
|
||||
status: ToolStatus.published,
|
||||
createdAt: daysAgo(31, 11, 0),
|
||||
updatedAt: dateOnly(daysAgo(1)),
|
||||
features: [
|
||||
{ id: 'feat_web_101', featureText: 'Artifact preview', sortOrder: 10 },
|
||||
{
|
||||
id: 'feat_web_102',
|
||||
featureText: 'Long context drafting',
|
||||
sortOrder: 20,
|
||||
},
|
||||
{
|
||||
id: 'feat_web_103',
|
||||
featureText: 'Fast iteration loop',
|
||||
sortOrder: 30,
|
||||
},
|
||||
],
|
||||
tagIds: ['tag_hot', 'tag_new'],
|
||||
},
|
||||
{
|
||||
id: 'tool_web_003',
|
||||
name: 'Figma AI Board',
|
||||
slug: 'figma-ai-board',
|
||||
categoryId: 'cat_design',
|
||||
description:
|
||||
'Design board for collecting references, generating layout ideas, and collaborating on concepts.',
|
||||
rating: 4.5,
|
||||
downloadCount: 0,
|
||||
openCount: 271,
|
||||
accessMode: AccessMode.web,
|
||||
openUrl: 'https://www.figma.com',
|
||||
openInNewTab: true,
|
||||
status: ToolStatus.published,
|
||||
createdAt: daysAgo(22, 14, 0),
|
||||
updatedAt: dateOnly(daysAgo(2)),
|
||||
features: [
|
||||
{ id: 'feat_web_201', featureText: 'Shared whiteboard', sortOrder: 10 },
|
||||
{
|
||||
id: 'feat_web_202',
|
||||
featureText: 'Prompt-based explorations',
|
||||
sortOrder: 20,
|
||||
},
|
||||
{
|
||||
id: 'feat_web_203',
|
||||
featureText: 'Reference clustering',
|
||||
sortOrder: 30,
|
||||
},
|
||||
],
|
||||
tagIds: ['tag_official', 'tag_team'],
|
||||
},
|
||||
{
|
||||
id: 'tool_web_004',
|
||||
name: 'Runbook Atlas',
|
||||
slug: 'runbook-atlas',
|
||||
categoryId: 'cat_ops',
|
||||
description:
|
||||
'Operational runbook viewer with incident links, deployment guides, and on-call context.',
|
||||
rating: 4.4,
|
||||
downloadCount: 0,
|
||||
openCount: 196,
|
||||
accessMode: AccessMode.web,
|
||||
openUrl: 'https://atlas.example.internal/runbooks',
|
||||
openInNewTab: false,
|
||||
status: ToolStatus.published,
|
||||
createdAt: daysAgo(19, 9, 0),
|
||||
updatedAt: dateOnly(daysAgo(3)),
|
||||
features: [
|
||||
{
|
||||
id: 'feat_web_301',
|
||||
featureText: 'Incident handoff docs',
|
||||
sortOrder: 10,
|
||||
},
|
||||
{
|
||||
id: 'feat_web_302',
|
||||
featureText: 'Change checklist templates',
|
||||
sortOrder: 20,
|
||||
},
|
||||
{
|
||||
id: 'feat_web_303',
|
||||
featureText: 'Service ownership map',
|
||||
sortOrder: 30,
|
||||
},
|
||||
],
|
||||
tagIds: ['tag_team', 'tag_self_hosted'],
|
||||
},
|
||||
{
|
||||
id: 'tool_web_005',
|
||||
name: 'Notion Workflow Hub',
|
||||
slug: 'notion-workflow-hub',
|
||||
categoryId: 'cat_productivity',
|
||||
description:
|
||||
'Documentation and request-tracking workspace for internal workflow handoffs.',
|
||||
rating: 4.2,
|
||||
downloadCount: 0,
|
||||
openCount: 153,
|
||||
accessMode: AccessMode.web,
|
||||
openUrl: 'https://www.notion.so',
|
||||
openInNewTab: true,
|
||||
status: ToolStatus.published,
|
||||
createdAt: daysAgo(12, 13, 30),
|
||||
updatedAt: dateOnly(daysAgo(1)),
|
||||
features: [
|
||||
{
|
||||
id: 'feat_web_401',
|
||||
featureText: 'Workflow templates',
|
||||
sortOrder: 10,
|
||||
},
|
||||
{
|
||||
id: 'feat_web_402',
|
||||
featureText: 'Knowledge base linking',
|
||||
sortOrder: 20,
|
||||
},
|
||||
{
|
||||
id: 'feat_web_403',
|
||||
featureText: 'Review queue boards',
|
||||
sortOrder: 30,
|
||||
},
|
||||
],
|
||||
tagIds: ['tag_team', 'tag_recommended'],
|
||||
},
|
||||
{
|
||||
id: 'tool_dl_001',
|
||||
name: 'ToolsShow Desktop',
|
||||
slug: 'toolsshow-desktop',
|
||||
categoryId: 'cat_dev',
|
||||
description: 'Desktop bundle for local workflows.',
|
||||
rating: 4.6,
|
||||
downloadCount: 52,
|
||||
description:
|
||||
'Desktop bundle for local workflows, offline browsing, and curated plugin execution.',
|
||||
rating: 4.8,
|
||||
downloadCount: 182,
|
||||
openCount: 0,
|
||||
accessMode: AccessMode.download,
|
||||
status: ToolStatus.published,
|
||||
updatedAt: nowDate,
|
||||
features: {
|
||||
createMany: {
|
||||
data: [
|
||||
{ id: 'feat_dl_001', featureText: 'Offline usage', sortOrder: 10 },
|
||||
{ id: 'feat_dl_002', featureText: 'Bundled plugins', sortOrder: 20 },
|
||||
],
|
||||
createdAt: daysAgo(40, 10, 15),
|
||||
updatedAt: dateOnly(daysAgo(0)),
|
||||
features: [
|
||||
{ id: 'feat_dl_001', featureText: 'Offline usage', sortOrder: 10 },
|
||||
{ id: 'feat_dl_002', featureText: 'Bundled plugins', sortOrder: 20 },
|
||||
{
|
||||
id: 'feat_dl_003',
|
||||
featureText: 'Local workspace sync',
|
||||
sortOrder: 30,
|
||||
},
|
||||
},
|
||||
tags: {
|
||||
create: [{ tagId: 'tag_free' }],
|
||||
},
|
||||
artifacts: {
|
||||
create: {
|
||||
id: artifactId,
|
||||
],
|
||||
tagIds: ['tag_hot', 'tag_free', 'tag_recommended'],
|
||||
artifacts: [
|
||||
{
|
||||
id: 'art_001',
|
||||
version: '1.0.0',
|
||||
fileName: 'toolsshow-desktop-1.0.0.zip',
|
||||
fileSizeBytes: 12_345_678,
|
||||
sha256: 'sample-sha256-not-real',
|
||||
fileSizeBytes: 12345678,
|
||||
sha256: 'sha256-toolsshow-100',
|
||||
mimeType: 'application/zip',
|
||||
gitlabProjectId: 0,
|
||||
gitlabProjectId: 1001,
|
||||
gitlabPackageName: 'toolsshow/toolsshow-desktop',
|
||||
gitlabPackageVersion: '1.0.0',
|
||||
gitlabFilePath: 'storage/toolsshow-desktop-1.0.0.zip',
|
||||
status: ArtifactStatus.active,
|
||||
releaseNotes: 'Initial release',
|
||||
status: ArtifactStatus.deprecated,
|
||||
releaseNotes: 'Initial public release with bundled runtime.',
|
||||
uploadedBy: 'u_admin_001',
|
||||
createdAt: daysAgo(35, 15, 30),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'art_002',
|
||||
version: '1.1.0',
|
||||
fileName: 'toolsshow-desktop-1.1.0.zip',
|
||||
fileSizeBytes: 14567890,
|
||||
sha256: 'sha256-toolsshow-110',
|
||||
mimeType: 'application/zip',
|
||||
gitlabProjectId: 1001,
|
||||
gitlabPackageName: 'toolsshow/toolsshow-desktop',
|
||||
gitlabPackageVersion: '1.1.0',
|
||||
gitlabFilePath: 'storage/toolsshow-desktop-1.1.0.zip',
|
||||
status: ArtifactStatus.active,
|
||||
releaseNotes: 'Adds plugin auto-update and workspace pinning.',
|
||||
uploadedBy: 'u_admin_002',
|
||||
createdAt: daysAgo(8, 16, 45),
|
||||
},
|
||||
],
|
||||
latestArtifactId: 'art_002',
|
||||
},
|
||||
});
|
||||
{
|
||||
id: 'tool_dl_002',
|
||||
name: 'MCP Inspector',
|
||||
slug: 'mcp-inspector',
|
||||
categoryId: 'cat_dev',
|
||||
description:
|
||||
'Desktop inspector for local MCP servers, request payloads, and connector metadata.',
|
||||
rating: 4.6,
|
||||
downloadCount: 134,
|
||||
openCount: 0,
|
||||
accessMode: AccessMode.download,
|
||||
openUrl: 'https://github.com/modelcontextprotocol/inspector/releases',
|
||||
status: ToolStatus.published,
|
||||
createdAt: daysAgo(28, 12, 0),
|
||||
updatedAt: dateOnly(daysAgo(2)),
|
||||
features: [
|
||||
{ id: 'feat_dl_101', featureText: 'Connection tracing', sortOrder: 10 },
|
||||
{ id: 'feat_dl_102', featureText: 'Schema inspection', sortOrder: 20 },
|
||||
{ id: 'feat_dl_103', featureText: 'Replay requests', sortOrder: 30 },
|
||||
],
|
||||
tagIds: ['tag_new', 'tag_recommended'],
|
||||
artifacts: [
|
||||
{
|
||||
id: 'art_101',
|
||||
version: '0.9.2',
|
||||
fileName: 'mcp-inspector-0.9.2.dmg',
|
||||
fileSizeBytes: 67452311,
|
||||
sha256: 'sha256-mcp-092',
|
||||
mimeType: 'application/x-apple-diskimage',
|
||||
gitlabProjectId: 1002,
|
||||
gitlabPackageName: 'toolsshow/mcp-inspector',
|
||||
gitlabPackageVersion: '0.9.2',
|
||||
gitlabFilePath: 'storage/mcp-inspector-0.9.2.dmg',
|
||||
status: ArtifactStatus.active,
|
||||
releaseNotes:
|
||||
'Adds server capability panel and request timeline export.',
|
||||
uploadedBy: 'u_admin_001',
|
||||
createdAt: daysAgo(9, 17, 20),
|
||||
},
|
||||
],
|
||||
latestArtifactId: 'art_101',
|
||||
},
|
||||
{
|
||||
id: 'tool_dl_003',
|
||||
name: 'LogScope Agent',
|
||||
slug: 'logscope-agent',
|
||||
categoryId: 'cat_ops',
|
||||
description:
|
||||
'Lightweight collector for shipping local logs, traces, and health snapshots to a central view.',
|
||||
rating: 4.3,
|
||||
downloadCount: 89,
|
||||
openCount: 0,
|
||||
accessMode: AccessMode.download,
|
||||
status: ToolStatus.published,
|
||||
createdAt: daysAgo(26, 9, 40),
|
||||
updatedAt: dateOnly(daysAgo(4)),
|
||||
features: [
|
||||
{ id: 'feat_dl_201', featureText: 'Log tail capture', sortOrder: 10 },
|
||||
{
|
||||
id: 'feat_dl_202',
|
||||
featureText: 'Service heartbeat sync',
|
||||
sortOrder: 20,
|
||||
},
|
||||
{
|
||||
id: 'feat_dl_203',
|
||||
featureText: 'Remote support bundle',
|
||||
sortOrder: 30,
|
||||
},
|
||||
],
|
||||
tagIds: ['tag_enterprise', 'tag_self_hosted'],
|
||||
artifacts: [
|
||||
{
|
||||
id: 'art_201',
|
||||
version: '2.0.0',
|
||||
fileName: 'logscope-agent-2.0.0.tar.gz',
|
||||
fileSizeBytes: 28765432,
|
||||
sha256: 'sha256-logscope-200',
|
||||
mimeType: 'application/gzip',
|
||||
gitlabProjectId: 1003,
|
||||
gitlabPackageName: 'toolsshow/logscope-agent',
|
||||
gitlabPackageVersion: '2.0.0',
|
||||
gitlabFilePath: 'storage/logscope-agent-2.0.0.tar.gz',
|
||||
status: ArtifactStatus.deleted,
|
||||
releaseNotes: 'Pulled due to startup regression on Linux hosts.',
|
||||
uploadedBy: 'u_admin_002',
|
||||
createdAt: daysAgo(21, 14, 0),
|
||||
},
|
||||
{
|
||||
id: 'art_202',
|
||||
version: '2.1.0',
|
||||
fileName: 'logscope-agent-2.1.0.tar.gz',
|
||||
fileSizeBytes: 29876543,
|
||||
sha256: 'sha256-logscope-210',
|
||||
mimeType: 'application/gzip',
|
||||
gitlabProjectId: 1003,
|
||||
gitlabPackageName: 'toolsshow/logscope-agent',
|
||||
gitlabPackageVersion: '2.1.0',
|
||||
gitlabFilePath: 'storage/logscope-agent-2.1.0.tar.gz',
|
||||
status: ArtifactStatus.active,
|
||||
releaseNotes:
|
||||
'Fixes Linux startup regression and improves compression.',
|
||||
uploadedBy: 'u_admin_002',
|
||||
createdAt: daysAgo(6, 11, 45),
|
||||
},
|
||||
],
|
||||
latestArtifactId: 'art_202',
|
||||
},
|
||||
{
|
||||
id: 'tool_draft_001',
|
||||
name: 'Local Agent Kit',
|
||||
slug: 'local-agent-kit',
|
||||
categoryId: 'cat_dev',
|
||||
description:
|
||||
'Work-in-progress desktop kit for packaging internal prompts, tools, and local runtime configs.',
|
||||
rating: 0,
|
||||
downloadCount: 0,
|
||||
openCount: 0,
|
||||
accessMode: AccessMode.download,
|
||||
status: ToolStatus.draft,
|
||||
createdAt: daysAgo(5, 10, 10),
|
||||
updatedAt: dateOnly(daysAgo(0)),
|
||||
features: [
|
||||
{
|
||||
id: 'feat_draft_001',
|
||||
featureText: 'Local prompt packs',
|
||||
sortOrder: 10,
|
||||
},
|
||||
{
|
||||
id: 'feat_draft_002',
|
||||
featureText: 'Workspace policies',
|
||||
sortOrder: 20,
|
||||
},
|
||||
],
|
||||
tagIds: ['tag_new'],
|
||||
},
|
||||
{
|
||||
id: 'tool_archived_001',
|
||||
name: 'Canvas Pilot',
|
||||
slug: 'canvas-pilot',
|
||||
categoryId: 'cat_design',
|
||||
description:
|
||||
'Legacy internal design helper kept for historical reference and migration support.',
|
||||
rating: 3.9,
|
||||
downloadCount: 14,
|
||||
openCount: 25,
|
||||
accessMode: AccessMode.web,
|
||||
openUrl: 'https://legacy.example.internal/canvas-pilot',
|
||||
openInNewTab: false,
|
||||
status: ToolStatus.archived,
|
||||
createdAt: daysAgo(90, 9, 0),
|
||||
updatedAt: dateOnly(daysAgo(14)),
|
||||
features: [
|
||||
{
|
||||
id: 'feat_arc_001',
|
||||
featureText: 'Legacy board import',
|
||||
sortOrder: 10,
|
||||
},
|
||||
{ id: 'feat_arc_002', featureText: 'Snapshot export', sortOrder: 20 },
|
||||
],
|
||||
tagIds: ['tag_team'],
|
||||
},
|
||||
];
|
||||
|
||||
await prisma.tool.update({
|
||||
where: { id: downloadToolId },
|
||||
data: { latestArtifactId: artifactId },
|
||||
});
|
||||
for (const tool of tools) {
|
||||
await createToolWithRelations(tool);
|
||||
}
|
||||
|
||||
await prisma.hotKeyword.createMany({
|
||||
data: [
|
||||
{ id: 'kw_001', keyword: 'agent', sortOrder: 10, isActive: true },
|
||||
{ id: 'kw_002', keyword: 'automation', sortOrder: 20, isActive: true },
|
||||
{ id: 'kw_003', keyword: 'open-source', sortOrder: 30, isActive: true },
|
||||
{ id: 'kw_003', keyword: 'mcp', sortOrder: 30, isActive: true },
|
||||
{ id: 'kw_004', keyword: 'design', sortOrder: 40, isActive: true },
|
||||
{ id: 'kw_005', keyword: 'workflow', sortOrder: 50, isActive: true },
|
||||
{ id: 'kw_006', keyword: 'self-hosted', sortOrder: 60, isActive: false },
|
||||
],
|
||||
});
|
||||
|
||||
const passwordHash = await argon2.hash('admin123456', { type: argon2.argon2id });
|
||||
await prisma.adminUser.create({
|
||||
data: {
|
||||
id: 'u_admin_001',
|
||||
username: 'admin',
|
||||
passwordHash,
|
||||
displayName: 'System Admin',
|
||||
status: AdminUserStatus.active,
|
||||
},
|
||||
await prisma.openRecord.createMany({
|
||||
data: [
|
||||
...buildOpenRecords(
|
||||
'tool_web_001',
|
||||
[14, 17, 19, 21, 24, 26, 28],
|
||||
'web',
|
||||
'/',
|
||||
),
|
||||
...buildOpenRecords(
|
||||
'tool_web_002',
|
||||
[8, 10, 12, 14, 16, 18, 20],
|
||||
'web',
|
||||
'/tools',
|
||||
),
|
||||
...buildOpenRecords(
|
||||
'tool_web_003',
|
||||
[4, 6, 7, 8, 8, 9, 10],
|
||||
'web',
|
||||
'/design',
|
||||
),
|
||||
...buildOpenRecords('tool_web_004', [3, 4, 5, 6, 5, 7, 6], 'web', '/ops'),
|
||||
...buildOpenRecords(
|
||||
'tool_web_005',
|
||||
[2, 3, 3, 4, 4, 5, 6],
|
||||
'web',
|
||||
'/workspace',
|
||||
),
|
||||
...buildOpenRecords(
|
||||
'tool_dl_002',
|
||||
[1, 1, 2, 2, 2, 3, 3],
|
||||
'desktop',
|
||||
'/admin/tools',
|
||||
),
|
||||
],
|
||||
});
|
||||
|
||||
await prisma.downloadRecord.createMany({
|
||||
data: [
|
||||
...buildDownloadRecords(
|
||||
'tool_dl_001',
|
||||
'art_002',
|
||||
[3, 4, 5, 6, 8, 9, 10],
|
||||
'desktop',
|
||||
'1.1.0',
|
||||
),
|
||||
...buildDownloadRecords(
|
||||
'tool_dl_002',
|
||||
'art_101',
|
||||
[2, 2, 3, 4, 4, 5, 6],
|
||||
'cli',
|
||||
'0.9.2',
|
||||
),
|
||||
...buildDownloadRecords(
|
||||
'tool_dl_003',
|
||||
'art_202',
|
||||
[1, 2, 2, 3, 3, 4, 5],
|
||||
'agent',
|
||||
'2.1.0',
|
||||
),
|
||||
{
|
||||
toolId: 'tool_dl_003',
|
||||
artifactId: 'art_202',
|
||||
ticket: 'ticket_failed_001',
|
||||
downloadedAt: daysAgo(2, 23, 15),
|
||||
clientIp: '10.24.99.40',
|
||||
userAgent: 'curl/8.7.1',
|
||||
channel: 'agent',
|
||||
clientVersion: '2.1.0',
|
||||
status: DownloadRecordStatus.failed,
|
||||
errorMessage: 'checksum mismatch',
|
||||
},
|
||||
{
|
||||
toolId: 'tool_dl_001',
|
||||
artifactId: 'art_002',
|
||||
ticket: 'ticket_failed_002',
|
||||
downloadedAt: daysAgo(5, 7, 50),
|
||||
clientIp: '10.24.99.41',
|
||||
userAgent: 'ToolsShowDesktop/1.1.0',
|
||||
channel: 'desktop',
|
||||
clientVersion: '1.1.0',
|
||||
status: DownloadRecordStatus.failed,
|
||||
errorMessage: 'network timeout',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await prisma.downloadTicket.createMany({
|
||||
data: [
|
||||
{
|
||||
ticket: 'seed_ticket_001',
|
||||
toolId: 'tool_dl_001',
|
||||
artifactId: 'art_002',
|
||||
channel: 'desktop',
|
||||
clientVersion: '1.1.0',
|
||||
requestIp: '10.24.88.11',
|
||||
expiresAt: daysAgo(-1, 12, 0),
|
||||
consumedAt: null,
|
||||
createdAt: daysAgo(0, 11, 45),
|
||||
},
|
||||
{
|
||||
ticket: 'seed_ticket_002',
|
||||
toolId: 'tool_dl_002',
|
||||
artifactId: 'art_101',
|
||||
channel: 'cli',
|
||||
clientVersion: '0.9.2',
|
||||
requestIp: '10.24.88.12',
|
||||
expiresAt: daysAgo(0, 13, 0),
|
||||
consumedAt: daysAgo(0, 12, 10),
|
||||
createdAt: daysAgo(0, 12, 0),
|
||||
},
|
||||
{
|
||||
ticket: 'seed_ticket_003',
|
||||
toolId: 'tool_dl_003',
|
||||
artifactId: 'art_202',
|
||||
channel: 'agent',
|
||||
clientVersion: '2.1.0',
|
||||
requestIp: '10.24.88.13',
|
||||
expiresAt: daysAgo(1, 14, 0),
|
||||
consumedAt: null,
|
||||
createdAt: daysAgo(1, 13, 20),
|
||||
},
|
||||
{
|
||||
ticket: 'seed_ticket_004',
|
||||
toolId: 'tool_dl_001',
|
||||
artifactId: 'art_002',
|
||||
channel: 'desktop',
|
||||
clientVersion: '1.1.0',
|
||||
requestIp: '10.24.88.14',
|
||||
expiresAt: daysAgo(3, 10, 0),
|
||||
consumedAt: daysAgo(3, 9, 12),
|
||||
createdAt: daysAgo(3, 9, 0),
|
||||
},
|
||||
{
|
||||
ticket: 'seed_ticket_005',
|
||||
toolId: 'tool_dl_003',
|
||||
artifactId: 'art_202',
|
||||
channel: 'agent',
|
||||
clientVersion: '2.1.0',
|
||||
requestIp: '10.24.88.15',
|
||||
expiresAt: daysAgo(6, 17, 0),
|
||||
consumedAt: null,
|
||||
createdAt: daysAgo(6, 16, 30),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await prisma.adminAuditLog.createMany({
|
||||
data: [
|
||||
{
|
||||
adminUserId: 'u_admin_001',
|
||||
action: 'LOGIN',
|
||||
resourceType: 'auth',
|
||||
resourceId: 'u_admin_001',
|
||||
requestMethod: 'POST',
|
||||
requestPath: '/admin/auth/login',
|
||||
requestBody: JSON.stringify({ username: 'admin' }),
|
||||
ip: '10.24.77.10',
|
||||
userAgent: USER_AGENTS[0],
|
||||
createdAt: daysAgo(0, 9, 25),
|
||||
},
|
||||
{
|
||||
adminUserId: 'u_admin_001',
|
||||
action: 'CREATE_TOOL',
|
||||
resourceType: 'tool',
|
||||
resourceId: 'tool_draft_001',
|
||||
requestMethod: 'POST',
|
||||
requestPath: '/admin/tools',
|
||||
requestBody: JSON.stringify({
|
||||
name: 'Local Agent Kit',
|
||||
accessMode: 'download',
|
||||
}),
|
||||
ip: '10.24.77.10',
|
||||
userAgent: USER_AGENTS[0],
|
||||
createdAt: daysAgo(0, 10, 5),
|
||||
},
|
||||
{
|
||||
adminUserId: 'u_admin_002',
|
||||
action: 'UPLOAD_ARTIFACT',
|
||||
resourceType: 'artifact',
|
||||
resourceId: 'art_202',
|
||||
requestMethod: 'POST',
|
||||
requestPath: '/admin/tools/tool_dl_003/artifacts',
|
||||
requestBody: JSON.stringify({ version: '2.1.0' }),
|
||||
ip: '10.24.77.21',
|
||||
userAgent: USER_AGENTS[1],
|
||||
createdAt: daysAgo(1, 14, 12),
|
||||
},
|
||||
{
|
||||
adminUserId: 'u_admin_002',
|
||||
action: 'SET_LATEST_ARTIFACT',
|
||||
resourceType: 'tool',
|
||||
resourceId: 'tool_dl_003',
|
||||
requestMethod: 'PATCH',
|
||||
requestPath: '/admin/tools/tool_dl_003/artifacts/art_202/latest',
|
||||
requestBody: null,
|
||||
ip: '10.24.77.21',
|
||||
userAgent: USER_AGENTS[1],
|
||||
createdAt: daysAgo(1, 14, 18),
|
||||
},
|
||||
{
|
||||
adminUserId: 'u_admin_001',
|
||||
action: 'UPDATE_TOOL_STATUS',
|
||||
resourceType: 'tool',
|
||||
resourceId: 'tool_dl_001',
|
||||
requestMethod: 'PATCH',
|
||||
requestPath: '/admin/tools/tool_dl_001/status',
|
||||
requestBody: JSON.stringify({ status: 'published' }),
|
||||
ip: '10.24.77.10',
|
||||
userAgent: USER_AGENTS[0],
|
||||
createdAt: daysAgo(2, 11, 40),
|
||||
},
|
||||
{
|
||||
adminUserId: 'u_admin_002',
|
||||
action: 'UPDATE_TOOL',
|
||||
resourceType: 'tool',
|
||||
resourceId: 'tool_web_004',
|
||||
requestMethod: 'PUT',
|
||||
requestPath: '/admin/tools/tool_web_004',
|
||||
requestBody: JSON.stringify({ openInNewTab: false }),
|
||||
ip: '10.24.77.21',
|
||||
userAgent: USER_AGENTS[2],
|
||||
createdAt: daysAgo(2, 17, 5),
|
||||
},
|
||||
{
|
||||
adminUserId: 'u_admin_001',
|
||||
action: 'CREATE_CATEGORY',
|
||||
resourceType: 'category',
|
||||
resourceId: 'cat_productivity',
|
||||
requestMethod: 'POST',
|
||||
requestPath: '/admin/categories',
|
||||
requestBody: JSON.stringify({ name: 'Productivity' }),
|
||||
ip: '10.24.77.10',
|
||||
userAgent: USER_AGENTS[0],
|
||||
createdAt: daysAgo(3, 9, 45),
|
||||
},
|
||||
{
|
||||
adminUserId: 'u_admin_001',
|
||||
action: 'CREATE_TAG',
|
||||
resourceType: 'tag',
|
||||
resourceId: 'tag_recommended',
|
||||
requestMethod: 'POST',
|
||||
requestPath: '/admin/tags',
|
||||
requestBody: JSON.stringify({ name: 'Recommended' }),
|
||||
ip: '10.24.77.10',
|
||||
userAgent: USER_AGENTS[0],
|
||||
createdAt: daysAgo(3, 10, 10),
|
||||
},
|
||||
{
|
||||
adminUserId: 'u_admin_002',
|
||||
action: 'UPDATE_ARTIFACT_STATUS',
|
||||
resourceType: 'artifact',
|
||||
resourceId: 'art_001',
|
||||
requestMethod: 'PATCH',
|
||||
requestPath: '/admin/tools/tool_dl_001/artifacts/art_001/status',
|
||||
requestBody: JSON.stringify({ status: 'deprecated' }),
|
||||
ip: '10.24.77.21',
|
||||
userAgent: USER_AGENTS[3],
|
||||
createdAt: daysAgo(4, 15, 30),
|
||||
},
|
||||
{
|
||||
adminUserId: 'u_admin_002',
|
||||
action: 'LOGIN',
|
||||
resourceType: 'auth',
|
||||
resourceId: 'u_admin_002',
|
||||
requestMethod: 'POST',
|
||||
requestPath: '/admin/auth/login',
|
||||
requestBody: JSON.stringify({ username: 'ops-admin' }),
|
||||
ip: '10.24.77.21',
|
||||
userAgent: USER_AGENTS[1],
|
||||
createdAt: daysAgo(5, 8, 55),
|
||||
},
|
||||
{
|
||||
adminUserId: 'u_admin_001',
|
||||
action: 'DELETE_ARTIFACT',
|
||||
resourceType: 'artifact',
|
||||
resourceId: 'art_201',
|
||||
requestMethod: 'DELETE',
|
||||
requestPath: '/admin/tools/tool_dl_003/artifacts/art_201',
|
||||
requestBody: null,
|
||||
ip: '10.24.77.10',
|
||||
userAgent: USER_AGENTS[0],
|
||||
createdAt: daysAgo(6, 16, 40),
|
||||
},
|
||||
{
|
||||
adminUserId: null,
|
||||
action: 'SYSTEM_BOOTSTRAP',
|
||||
resourceType: 'system',
|
||||
resourceId: null,
|
||||
requestMethod: 'POST',
|
||||
requestPath: '/system/bootstrap',
|
||||
requestBody: JSON.stringify({ source: 'seed' }),
|
||||
ip: '127.0.0.1',
|
||||
userAgent: 'seed-script',
|
||||
createdAt: daysAgo(6, 7, 0),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user