🔐 feat: Granular Role-based Permissions + Entra ID Group Discovery (#7804)

WIP: pre-granular-permissions commit

feat: Add category and support contact fields to Agent schema and UI components

Revert "feat: Add category and support contact fields to Agent schema and UI components"

This reverts commit c43a52b4c9.

Fix: Update import for renderHook in useAgentCategories.spec.tsx

fix: Update icon rendering in AgentCategoryDisplay tests to use empty spans

refactor: Improve category synchronization logic and clean up AgentConfig component

refactor: Remove unused UI flow translations from translation.json

feat: agent marketplace features

🔐 feat: Granular Role-based Permissions + Entra ID Group Discovery (#7804)
This commit is contained in:
Danny Avila 2025-06-23 10:22:27 -04:00
parent aec1777a90
commit 28d9deed0a
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
143 changed files with 17590 additions and 629 deletions

View file

@ -199,15 +199,95 @@ export function createUserMethods(mongoose: typeof import('mongoose')) {
}).lean()) as IUser | null;
}
// Return all methods
/**
* Search for users by pattern matching on name, email, or username (case-insensitive)
* @param searchPattern - The pattern to search for
* @param limit - Maximum number of results to return
* @param fieldsToSelect - The fields to include or exclude in the returned documents
* @returns Array of matching user documents
*/
const searchUsers = async function ({
searchPattern,
limit = 20,
fieldsToSelect = null,
}: {
searchPattern: string;
limit?: number;
fieldsToSelect?: string | string[] | null;
}) {
if (!searchPattern || searchPattern.trim().length === 0) {
return [];
}
const regex = new RegExp(searchPattern.trim(), 'i');
const User = mongoose.models.User;
const query = User.find({
$or: [{ email: regex }, { name: regex }, { username: regex }],
}).limit(limit * 2); // Get more results to allow for relevance sorting
if (fieldsToSelect) {
query.select(fieldsToSelect);
}
const users = await query.lean();
// Score results by relevance
const exactRegex = new RegExp(`^${searchPattern.trim()}$`, 'i');
const startsWithPattern = searchPattern.trim().toLowerCase();
const scoredUsers = users.map((user) => {
const searchableFields = [user.name, user.email, user.username].filter(Boolean);
let maxScore = 0;
for (const field of searchableFields) {
const fieldLower = field.toLowerCase();
let score = 0;
// Exact match gets highest score
if (exactRegex.test(field)) {
score = 100;
}
// Starts with query gets high score
else if (fieldLower.startsWith(startsWithPattern)) {
score = 80;
}
// Contains query gets medium score
else if (fieldLower.includes(startsWithPattern)) {
score = 50;
}
// Default score for regex match
else {
score = 10;
}
maxScore = Math.max(maxScore, score);
}
return { ...user, _searchScore: maxScore };
});
/** Top results sorted by relevance */
return scoredUsers
.sort((a, b) => b._searchScore - a._searchScore)
.slice(0, limit)
.map((user) => {
// Remove the search score from final results
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { _searchScore, ...userWithoutScore } = user;
return userWithoutScore;
});
};
return {
findUser,
countUsers,
createUser,
updateUser,
searchUsers,
getUserById,
deleteUserById,
generateToken,
deleteUserById,
toggleUserMemories,
};
}