mirror of
https://github.com/soconnor0919/hristudio.git
synced 2025-12-11 14:44:44 -05:00
feat: implement complete plugin store repository synchronization system
• Fix repository sync implementation in admin API (was TODO placeholder) - Add full fetch/parse logic for repository.json and plugin index - Implement robot matching by name/manufacturer patterns - Handle plugin creation/updates with proper error handling - Add comprehensive TypeScript typing throughout • Fix plugin store installation state detection - Add getStudyPlugins API integration to check installed plugins - Update PluginCard component with isInstalled prop and correct button states - Fix repository name display using metadata.repositoryId mapping - Show "Installed" (disabled) vs "Install" (enabled) based on actual state • Resolve admin access and authentication issues - Add missing administrator role to user system roles table - Fix admin route access for repository management - Enable repository sync functionality in admin dashboard • Add repository metadata integration - Update plugin records with proper repositoryId references - Add metadata field to robots.plugins.list API response - Enable repository name display for all plugins from metadata • Fix TypeScript compliance across plugin system - Replace unsafe 'any' types with proper interfaces - Add type definitions for repository and plugin data structures - Use nullish coalescing operators for safer null handling - Remove unnecessary type assertions • Integrate live repository at https://repo.hristudio.com - Successfully loads 3 robot plugins (TurtleBot3 Burger/Waffle, NAO) - Complete ROS2 action definitions with parameter schemas - Trust level categorization (official, verified, community) - Platform and documentation metadata preservation • Update documentation and development workflow - Document plugin repository system in work_in_progress.md - Update quick-reference.md with repository sync examples - Add plugin installation and management guidance - Remove problematic test script with TypeScript errors BREAKING CHANGE: Plugin store now requires repository sync for robot plugins. Run repository sync in admin dashboard after deployment to populate plugin store. Closes: Plugin store repository integration Resolves: Installation state detection and repository name display Fixes: Admin authentication and TypeScript compliance issues
This commit is contained in:
323
scripts/test-seed-data.ts
Normal file
323
scripts/test-seed-data.ts
Normal file
@@ -0,0 +1,323 @@
|
||||
#!/usr/bin/env tsx
|
||||
|
||||
/**
|
||||
* Test script to validate seed data structure
|
||||
* Ensures all user relationships and study memberships are correct
|
||||
*/
|
||||
|
||||
interface User {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
institution: string;
|
||||
}
|
||||
|
||||
interface UserRole {
|
||||
userId: string;
|
||||
role: "administrator" | "researcher" | "wizard" | "observer";
|
||||
assignedBy: string;
|
||||
}
|
||||
|
||||
interface Study {
|
||||
id: string;
|
||||
name: string;
|
||||
createdBy: string;
|
||||
}
|
||||
|
||||
interface StudyMember {
|
||||
studyId: string;
|
||||
userId: string;
|
||||
role: "owner" | "researcher" | "wizard" | "observer";
|
||||
invitedBy: string | null;
|
||||
}
|
||||
|
||||
function validateSeedData() {
|
||||
console.log("🧪 Testing seed data structure...\n");
|
||||
|
||||
// Users data
|
||||
const users: User[] = [
|
||||
{
|
||||
id: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
name: "Sean O'Connor",
|
||||
email: "sean@soconnor.dev",
|
||||
institution: "HRIStudio",
|
||||
},
|
||||
{
|
||||
id: "01234567-89ab-cdef-0123-456789abcde1",
|
||||
name: "Dr. Sarah Chen",
|
||||
email: "sarah.chen@university.edu",
|
||||
institution: "MIT Computer Science",
|
||||
},
|
||||
{
|
||||
id: "01234567-89ab-cdef-0123-456789abcde2",
|
||||
name: "Dr. Michael Rodriguez",
|
||||
email: "m.rodriguez@research.org",
|
||||
institution: "Stanford HCI Lab",
|
||||
},
|
||||
{
|
||||
id: "01234567-89ab-cdef-0123-456789abcde3",
|
||||
name: "Emma Thompson",
|
||||
email: "emma.thompson@university.edu",
|
||||
institution: "MIT Computer Science",
|
||||
},
|
||||
{
|
||||
id: "01234567-89ab-cdef-0123-456789abcde4",
|
||||
name: "Dr. James Wilson",
|
||||
email: "james.wilson@university.edu",
|
||||
institution: "MIT Computer Science",
|
||||
},
|
||||
];
|
||||
|
||||
// User roles
|
||||
const userRoles: UserRole[] = [
|
||||
{
|
||||
userId: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
role: "administrator",
|
||||
assignedBy: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
},
|
||||
{
|
||||
userId: "01234567-89ab-cdef-0123-456789abcde1",
|
||||
role: "researcher",
|
||||
assignedBy: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
},
|
||||
{
|
||||
userId: "01234567-89ab-cdef-0123-456789abcde2",
|
||||
role: "researcher",
|
||||
assignedBy: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
},
|
||||
{
|
||||
userId: "01234567-89ab-cdef-0123-456789abcde3",
|
||||
role: "wizard",
|
||||
assignedBy: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
},
|
||||
{
|
||||
userId: "01234567-89ab-cdef-0123-456789abcde4",
|
||||
role: "observer",
|
||||
assignedBy: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
},
|
||||
];
|
||||
|
||||
// Studies
|
||||
const studies: Study[] = [
|
||||
{
|
||||
id: "11234567-89ab-cdef-0123-456789abcde1",
|
||||
name: "Robot Navigation Assistance Study",
|
||||
createdBy: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
},
|
||||
{
|
||||
id: "11234567-89ab-cdef-0123-456789abcde2",
|
||||
name: "Social Robots in Healthcare Study",
|
||||
createdBy: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
},
|
||||
{
|
||||
id: "11234567-89ab-cdef-0123-456789abcde3",
|
||||
name: "Elderly Care Robot Interaction Study",
|
||||
createdBy: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
},
|
||||
];
|
||||
|
||||
// Study members
|
||||
const studyMembers: StudyMember[] = [
|
||||
// Sean as owner of all studies
|
||||
{
|
||||
studyId: "11234567-89ab-cdef-0123-456789abcde1",
|
||||
userId: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
role: "owner",
|
||||
invitedBy: null,
|
||||
},
|
||||
{
|
||||
studyId: "11234567-89ab-cdef-0123-456789abcde2",
|
||||
userId: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
role: "owner",
|
||||
invitedBy: null,
|
||||
},
|
||||
{
|
||||
studyId: "11234567-89ab-cdef-0123-456789abcde3",
|
||||
userId: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
role: "owner",
|
||||
invitedBy: null,
|
||||
},
|
||||
// Other team members
|
||||
{
|
||||
studyId: "11234567-89ab-cdef-0123-456789abcde1",
|
||||
userId: "01234567-89ab-cdef-0123-456789abcde2",
|
||||
role: "researcher",
|
||||
invitedBy: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
},
|
||||
{
|
||||
studyId: "11234567-89ab-cdef-0123-456789abcde1",
|
||||
userId: "01234567-89ab-cdef-0123-456789abcde3",
|
||||
role: "wizard",
|
||||
invitedBy: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
},
|
||||
{
|
||||
studyId: "11234567-89ab-cdef-0123-456789abcde2",
|
||||
userId: "01234567-89ab-cdef-0123-456789abcde2",
|
||||
role: "researcher",
|
||||
invitedBy: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
},
|
||||
{
|
||||
studyId: "11234567-89ab-cdef-0123-456789abcde3",
|
||||
userId: "01234567-89ab-cdef-0123-456789abcde1",
|
||||
role: "researcher",
|
||||
invitedBy: "01234567-89ab-cdef-0123-456789abcde0",
|
||||
},
|
||||
];
|
||||
|
||||
let errors = 0;
|
||||
|
||||
console.log("👥 Validating users...");
|
||||
console.log(` Users: ${users.length}`);
|
||||
|
||||
// Check for Sean as admin
|
||||
const seanUser = users.find((u) => u.email === "sean@soconnor.dev");
|
||||
if (seanUser) {
|
||||
console.log(` ✅ Sean found: ${seanUser.name} (${seanUser.email})`);
|
||||
} else {
|
||||
console.error(` ❌ Sean not found as user`);
|
||||
errors++;
|
||||
}
|
||||
|
||||
console.log("\n🔐 Validating user roles...");
|
||||
console.log(` User roles: ${userRoles.length}`);
|
||||
|
||||
// Check Sean's admin role
|
||||
const seanRole = userRoles.find(
|
||||
(r) => r.userId === "01234567-89ab-cdef-0123-456789abcde0",
|
||||
);
|
||||
if (seanRole && seanRole.role === "administrator") {
|
||||
console.log(` ✅ Sean has administrator role`);
|
||||
} else {
|
||||
console.error(` ❌ Sean missing administrator role`);
|
||||
errors++;
|
||||
}
|
||||
|
||||
// Check all roles are assigned by Sean
|
||||
const rolesAssignedBySean = userRoles.filter(
|
||||
(r) => r.assignedBy === "01234567-89ab-cdef-0123-456789abcde0",
|
||||
);
|
||||
console.log(
|
||||
` ✅ ${rolesAssignedBySean.length}/${userRoles.length} roles assigned by Sean`,
|
||||
);
|
||||
|
||||
console.log("\n📚 Validating studies...");
|
||||
console.log(` Studies: ${studies.length}`);
|
||||
|
||||
// Check all studies created by Sean
|
||||
const studiesCreatedBySean = studies.filter(
|
||||
(s) => s.createdBy === "01234567-89ab-cdef-0123-456789abcde0",
|
||||
);
|
||||
if (studiesCreatedBySean.length === studies.length) {
|
||||
console.log(` ✅ All ${studies.length} studies created by Sean`);
|
||||
} else {
|
||||
console.error(
|
||||
` ❌ Only ${studiesCreatedBySean.length}/${studies.length} studies created by Sean`,
|
||||
);
|
||||
errors++;
|
||||
}
|
||||
|
||||
console.log("\n👨💼 Validating study memberships...");
|
||||
console.log(` Study memberships: ${studyMembers.length}`);
|
||||
|
||||
// Check Sean is owner of all studies
|
||||
const seanOwnerships = studyMembers.filter(
|
||||
(m) =>
|
||||
m.userId === "01234567-89ab-cdef-0123-456789abcde0" && m.role === "owner",
|
||||
);
|
||||
if (seanOwnerships.length === studies.length) {
|
||||
console.log(` ✅ Sean is owner of all ${studies.length} studies`);
|
||||
} else {
|
||||
console.error(
|
||||
` ❌ Sean only owns ${seanOwnerships.length}/${studies.length} studies`,
|
||||
);
|
||||
errors++;
|
||||
}
|
||||
|
||||
// Check invitation chain
|
||||
const membersInvitedBySean = studyMembers.filter(
|
||||
(m) => m.invitedBy === "01234567-89ab-cdef-0123-456789abcde0",
|
||||
);
|
||||
console.log(` ✅ ${membersInvitedBySean.length} members invited by Sean`);
|
||||
|
||||
// Validate all user references exist
|
||||
console.log("\n🔗 Validating references...");
|
||||
|
||||
const userIds = new Set(users.map((u) => u.id));
|
||||
|
||||
for (const role of userRoles) {
|
||||
if (!userIds.has(role.userId)) {
|
||||
console.error(` ❌ Invalid user reference in role: ${role.userId}`);
|
||||
errors++;
|
||||
}
|
||||
if (!userIds.has(role.assignedBy)) {
|
||||
console.error(
|
||||
` ❌ Invalid assignedBy reference in role: ${role.assignedBy}`,
|
||||
);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
for (const study of studies) {
|
||||
if (!userIds.has(study.createdBy)) {
|
||||
console.error(
|
||||
` ❌ Invalid createdBy reference in study: ${study.createdBy}`,
|
||||
);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
const studyIds = new Set(studies.map((s) => s.id));
|
||||
|
||||
for (const member of studyMembers) {
|
||||
if (!studyIds.has(member.studyId)) {
|
||||
console.error(
|
||||
` ❌ Invalid study reference in membership: ${member.studyId}`,
|
||||
);
|
||||
errors++;
|
||||
}
|
||||
if (!userIds.has(member.userId)) {
|
||||
console.error(
|
||||
` ❌ Invalid user reference in membership: ${member.userId}`,
|
||||
);
|
||||
errors++;
|
||||
}
|
||||
if (member.invitedBy && !userIds.has(member.invitedBy)) {
|
||||
console.error(
|
||||
` ❌ Invalid invitedBy reference in membership: ${member.invitedBy}`,
|
||||
);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (errors === 0) {
|
||||
console.log(" ✅ All references are valid");
|
||||
}
|
||||
|
||||
// Summary
|
||||
console.log(`\n📊 Validation Summary:`);
|
||||
console.log(` Users: ${users.length}`);
|
||||
console.log(` User roles: ${userRoles.length}`);
|
||||
console.log(` Studies: ${studies.length}`);
|
||||
console.log(` Study memberships: ${studyMembers.length}`);
|
||||
console.log(` Errors: ${errors}`);
|
||||
|
||||
if (errors === 0) {
|
||||
console.log(`\n🎉 All validations passed! Seed data structure is correct.`);
|
||||
console.log(` Sean (sean@soconnor.dev) is admin of everything:`);
|
||||
console.log(` • System administrator role`);
|
||||
console.log(` • Owner of all ${studies.length} studies`);
|
||||
console.log(` • Assigned all user roles`);
|
||||
console.log(` • Invited all study members`);
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.log(`\n❌ Validation failed with ${errors} error(s).`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Run the validation
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
validateSeedData();
|
||||
}
|
||||
|
||||
export { validateSeedData };
|
||||
Reference in New Issue
Block a user