From 442fb15131fccdb48c2cb020aea00f1f697ca1ad Mon Sep 17 00:00:00 2001 From: JohnDoe6345789 Date: Fri, 26 Dec 2025 00:33:31 +0000 Subject: [PATCH] code: user,tsx,operations (2 files) --- dbal/cpp/src/entities/user_operations.hpp | 245 ++++++++++++++++++ .../nerd-mode-ide/GitConfigDialog.tsx | 91 +++++++ 2 files changed, 336 insertions(+) create mode 100644 dbal/cpp/src/entities/user_operations.hpp create mode 100644 frontends/nextjs/src/components/nerd-mode-ide/GitConfigDialog.tsx diff --git a/dbal/cpp/src/entities/user_operations.hpp b/dbal/cpp/src/entities/user_operations.hpp new file mode 100644 index 000000000..170fb2335 --- /dev/null +++ b/dbal/cpp/src/entities/user_operations.hpp @@ -0,0 +1,245 @@ +/** + * @file user_operations.hpp + * @brief User entity CRUD operations + * + * Single-responsibility module for User entity operations. + * Follows the small-function-file pattern from the Next.js frontend. + */ +#ifndef DBAL_USER_OPERATIONS_HPP +#define DBAL_USER_OPERATIONS_HPP + +#include "dbal/types.hpp" +#include "dbal/errors.hpp" +#include "../store/in_memory_store.hpp" +#include "../validation/user_validation.hpp" + +namespace dbal { +namespace entities { + +/** + * Create a new user in the store + */ +inline Result createUser(InMemoryStore& store, const CreateUserInput& input) { + // Validation + if (!validation::isValidUsername(input.username)) { + return Error::validationError("Invalid username format (alphanumeric, underscore, hyphen only)"); + } + if (!validation::isValidEmail(input.email)) { + return Error::validationError("Invalid email format"); + } + + // Check for duplicate username + for (const auto& [id, user] : store.users) { + if (user.username == input.username) { + return Error::conflict("Username already exists: " + input.username); + } + if (user.email == input.email) { + return Error::conflict("Email already exists: " + input.email); + } + } + + // Create user + User user; + user.id = store.generateId("user", ++store.user_counter); + user.username = input.username; + user.email = input.email; + user.role = input.role; + user.created_at = std::chrono::system_clock::now(); + user.updated_at = user.created_at; + + store.users[user.id] = user; + + return Result(user); +} + +/** + * Get a user by ID + */ +inline Result getUser(InMemoryStore& store, const std::string& id) { + if (id.empty()) { + return Error::validationError("User ID cannot be empty"); + } + + auto it = store.users.find(id); + if (it == store.users.end()) { + return Error::notFound("User not found: " + id); + } + + return Result(it->second); +} + +/** + * Update an existing user + */ +inline Result updateUser(InMemoryStore& store, const std::string& id, const UpdateUserInput& input) { + if (id.empty()) { + return Error::validationError("User ID cannot be empty"); + } + + auto it = store.users.find(id); + if (it == store.users.end()) { + return Error::notFound("User not found: " + id); + } + + User& user = it->second; + + // Validate and check conflicts + if (input.username.has_value()) { + if (!validation::isValidUsername(input.username.value())) { + return Error::validationError("Invalid username format"); + } + // Check for username conflict + for (const auto& [uid, u] : store.users) { + if (uid != id && u.username == input.username.value()) { + return Error::conflict("Username already exists: " + input.username.value()); + } + } + user.username = input.username.value(); + } + + if (input.email.has_value()) { + if (!validation::isValidEmail(input.email.value())) { + return Error::validationError("Invalid email format"); + } + // Check for email conflict + for (const auto& [uid, u] : store.users) { + if (uid != id && u.email == input.email.value()) { + return Error::conflict("Email already exists: " + input.email.value()); + } + } + user.email = input.email.value(); + } + + if (input.role.has_value()) { + user.role = input.role.value(); + } + + user.updated_at = std::chrono::system_clock::now(); + + return Result(user); +} + +/** + * Delete a user by ID + */ +inline Result deleteUser(InMemoryStore& store, const std::string& id) { + if (id.empty()) { + return Error::validationError("User ID cannot be empty"); + } + + auto it = store.users.find(id); + if (it == store.users.end()) { + return Error::notFound("User not found: " + id); + } + + store.users.erase(it); + return Result(true); +} + +/** + * List users with filtering and pagination + */ +inline Result> listUsers(InMemoryStore& store, const ListOptions& options) { + std::vector users; + + for (const auto& [id, user] : store.users) { + // Apply filters if provided + bool matches = true; + + if (options.filter.find("role") != options.filter.end()) { + std::string role_str = options.filter.at("role"); + if (role_str == "admin" && user.role != UserRole::Admin) matches = false; + if (role_str == "user" && user.role != UserRole::User) matches = false; + } + + if (matches) { + users.push_back(user); + } + } + + // Apply sorting + if (options.sort.find("username") != options.sort.end()) { + std::sort(users.begin(), users.end(), [](const User& a, const User& b) { + return a.username < b.username; + }); + } + + // Apply pagination + int start = (options.page - 1) * options.limit; + int end = std::min(start + options.limit, static_cast(users.size())); + + if (start < static_cast(users.size())) { + return Result>(std::vector(users.begin() + start, users.begin() + end)); + } + + return Result>(std::vector()); +} + +/** + * Batch create multiple users + */ +inline Result batchCreateUsers(InMemoryStore& store, const std::vector& inputs) { + if (inputs.empty()) { + return Result(0); + } + + std::vector created_ids; + for (const auto& input : inputs) { + auto result = createUser(store, input); + if (result.isError()) { + // Rollback on error + for (const auto& id : created_ids) { + store.users.erase(id); + } + return result.error(); + } + created_ids.push_back(result.value().id); + } + + return Result(static_cast(created_ids.size())); +} + +/** + * Batch update multiple users + */ +inline Result batchUpdateUsers(InMemoryStore& store, const std::vector& updates) { + if (updates.empty()) { + return Result(0); + } + + int updated = 0; + for (const auto& item : updates) { + auto result = updateUser(store, item.id, item.data); + if (result.isError()) { + return result.error(); + } + updated++; + } + + return Result(updated); +} + +/** + * Batch delete multiple users + */ +inline Result batchDeleteUsers(InMemoryStore& store, const std::vector& ids) { + if (ids.empty()) { + return Result(0); + } + + int deleted = 0; + for (const auto& id : ids) { + auto result = deleteUser(store, id); + if (result.isError()) { + return result.error(); + } + deleted++; + } + + return Result(deleted); +} + +} // namespace entities +} // namespace dbal + +#endif diff --git a/frontends/nextjs/src/components/nerd-mode-ide/GitConfigDialog.tsx b/frontends/nextjs/src/components/nerd-mode-ide/GitConfigDialog.tsx new file mode 100644 index 000000000..651381275 --- /dev/null +++ b/frontends/nextjs/src/components/nerd-mode-ide/GitConfigDialog.tsx @@ -0,0 +1,91 @@ +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui' +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui' +import { Button } from '@/components/ui' +import { Input } from '@/components/ui' +import { Label } from '@/components/ui' +import type { GitConfig } from './types' + +interface GitConfigDialogProps { + open: boolean + gitConfig: GitConfig | null + onUpdate: (updates: Partial) => void + onClose: () => void + onSave: () => void +} + +export function GitConfigDialog({ open, gitConfig, onUpdate, onClose, onSave }: GitConfigDialogProps) { + return ( + (!nextOpen ? onClose() : null)}> + + + Configure Git Integration + Connect to GitHub or GitLab to sync your code + +
+
+ + +
+
+ + onUpdate({ repoUrl: e.target.value })} + /> +
+
+ + onUpdate({ branch: e.target.value })} + /> +
+
+ + onUpdate({ token: e.target.value })} + /> +
+
+ + + + +
+
+ ) +}