Files
hristudio/scripts/test-seed-data.ts
Sean O'Connor 18f709f879 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
2025-08-07 10:47:29 -04:00

324 lines
9.0 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 };