mirror of
				https://github.com/9technologygroup/patchmon.net.git
				synced 2025-11-04 14:03:17 +00:00 
			
		
		
		
	Fixed issue with users not being updated
Re-worked setup.sh to use last 3 tags and the main branch (development latest)
This commit is contained in:
		@@ -176,6 +176,8 @@ router.get(
 | 
			
		||||
					id: true,
 | 
			
		||||
					username: true,
 | 
			
		||||
					email: true,
 | 
			
		||||
					first_name: true,
 | 
			
		||||
					last_name: true,
 | 
			
		||||
					role: true,
 | 
			
		||||
					is_active: true,
 | 
			
		||||
					last_login: true,
 | 
			
		||||
@@ -314,6 +316,14 @@ router.put(
 | 
			
		||||
			.isLength({ min: 3 })
 | 
			
		||||
			.withMessage("Username must be at least 3 characters"),
 | 
			
		||||
		body("email").optional().isEmail().withMessage("Valid email is required"),
 | 
			
		||||
		body("first_name")
 | 
			
		||||
			.optional()
 | 
			
		||||
			.isLength({ min: 1 })
 | 
			
		||||
			.withMessage("First name must be at least 1 character"),
 | 
			
		||||
		body("last_name")
 | 
			
		||||
			.optional()
 | 
			
		||||
			.isLength({ min: 1 })
 | 
			
		||||
			.withMessage("Last name must be at least 1 character"),
 | 
			
		||||
		body("role")
 | 
			
		||||
			.optional()
 | 
			
		||||
			.custom(async (value) => {
 | 
			
		||||
@@ -326,10 +336,10 @@ router.put(
 | 
			
		||||
				}
 | 
			
		||||
				return true;
 | 
			
		||||
			}),
 | 
			
		||||
		body("isActive")
 | 
			
		||||
		body("is_active")
 | 
			
		||||
			.optional()
 | 
			
		||||
			.isBoolean()
 | 
			
		||||
			.withMessage("isActive must be a boolean"),
 | 
			
		||||
			.withMessage("is_active must be a boolean"),
 | 
			
		||||
	],
 | 
			
		||||
	async (req, res) => {
 | 
			
		||||
		try {
 | 
			
		||||
@@ -340,13 +350,16 @@ router.put(
 | 
			
		||||
				return res.status(400).json({ errors: errors.array() });
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			const { username, email, role, isActive } = req.body;
 | 
			
		||||
			const { username, email, first_name, last_name, role, is_active } =
 | 
			
		||||
				req.body;
 | 
			
		||||
			const updateData = {};
 | 
			
		||||
 | 
			
		||||
			if (username) updateData.username = username;
 | 
			
		||||
			if (email) updateData.email = email;
 | 
			
		||||
			if (first_name !== undefined) updateData.first_name = first_name || null;
 | 
			
		||||
			if (last_name !== undefined) updateData.last_name = last_name || null;
 | 
			
		||||
			if (role) updateData.role = role;
 | 
			
		||||
			if (typeof isActive === "boolean") updateData.is_active = isActive;
 | 
			
		||||
			if (typeof is_active === "boolean") updateData.is_active = is_active;
 | 
			
		||||
 | 
			
		||||
			// Check if user exists
 | 
			
		||||
			const existingUser = await prisma.users.findUnique({
 | 
			
		||||
@@ -381,7 +394,7 @@ router.put(
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Prevent deactivating the last admin
 | 
			
		||||
			if (isActive === false && existingUser.role === "admin") {
 | 
			
		||||
			if (is_active === false && existingUser.role === "admin") {
 | 
			
		||||
				const adminCount = await prisma.users.count({
 | 
			
		||||
					where: {
 | 
			
		||||
						role: "admin",
 | 
			
		||||
@@ -404,6 +417,8 @@ router.put(
 | 
			
		||||
					id: true,
 | 
			
		||||
					username: true,
 | 
			
		||||
					email: true,
 | 
			
		||||
					first_name: true,
 | 
			
		||||
					last_name: true,
 | 
			
		||||
					role: true,
 | 
			
		||||
					is_active: true,
 | 
			
		||||
					last_login: true,
 | 
			
		||||
 
 | 
			
		||||
@@ -92,7 +92,12 @@ const UsersTab = () => {
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const handleEditUser = (user) => {
 | 
			
		||||
		setEditingUser(user);
 | 
			
		||||
		// Reset editingUser first to force re-render with fresh data
 | 
			
		||||
		setEditingUser(null);
 | 
			
		||||
		// Use setTimeout to ensure the modal re-initializes with fresh data
 | 
			
		||||
		setTimeout(() => {
 | 
			
		||||
			setEditingUser(user);
 | 
			
		||||
		}, 0);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const handleResetPassword = (user) => {
 | 
			
		||||
@@ -314,7 +319,9 @@ const UsersTab = () => {
 | 
			
		||||
					user={editingUser}
 | 
			
		||||
					isOpen={!!editingUser}
 | 
			
		||||
					onClose={() => setEditingUser(null)}
 | 
			
		||||
					onUserUpdated={() => updateUserMutation.mutate()}
 | 
			
		||||
					onUserUpdated={() => {
 | 
			
		||||
						queryClient.invalidateQueries(["users"]);
 | 
			
		||||
					}}
 | 
			
		||||
					roles={roles}
 | 
			
		||||
				/>
 | 
			
		||||
			)}
 | 
			
		||||
@@ -352,11 +359,29 @@ const AddUserModal = ({ isOpen, onClose, onUserCreated, roles }) => {
 | 
			
		||||
	});
 | 
			
		||||
	const [isLoading, setIsLoading] = useState(false);
 | 
			
		||||
	const [error, setError] = useState("");
 | 
			
		||||
	const [success, setSuccess] = useState(false);
 | 
			
		||||
 | 
			
		||||
	// Reset form when modal is closed
 | 
			
		||||
	useEffect(() => {
 | 
			
		||||
		if (!isOpen) {
 | 
			
		||||
			setFormData({
 | 
			
		||||
				username: "",
 | 
			
		||||
				email: "",
 | 
			
		||||
				password: "",
 | 
			
		||||
				first_name: "",
 | 
			
		||||
				last_name: "",
 | 
			
		||||
				role: "user",
 | 
			
		||||
			});
 | 
			
		||||
			setError("");
 | 
			
		||||
			setSuccess(false);
 | 
			
		||||
		}
 | 
			
		||||
	}, [isOpen]);
 | 
			
		||||
 | 
			
		||||
	const handleSubmit = async (e) => {
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
		setIsLoading(true);
 | 
			
		||||
		setError("");
 | 
			
		||||
		setSuccess(false);
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			// Only send role if roles are available from API
 | 
			
		||||
@@ -364,12 +389,19 @@ const AddUserModal = ({ isOpen, onClose, onUserCreated, roles }) => {
 | 
			
		||||
				username: formData.username,
 | 
			
		||||
				email: formData.email,
 | 
			
		||||
				password: formData.password,
 | 
			
		||||
				first_name: formData.first_name,
 | 
			
		||||
				last_name: formData.last_name,
 | 
			
		||||
			};
 | 
			
		||||
			if (roles && Array.isArray(roles) && roles.length > 0) {
 | 
			
		||||
				payload.role = formData.role;
 | 
			
		||||
			}
 | 
			
		||||
			await adminUsersAPI.create(payload);
 | 
			
		||||
			setSuccess(true);
 | 
			
		||||
			onUserCreated();
 | 
			
		||||
			// Auto-close after 1.5 seconds
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				onClose();
 | 
			
		||||
			}, 1500);
 | 
			
		||||
		} catch (err) {
 | 
			
		||||
			setError(err.response?.data?.error || "Failed to create user");
 | 
			
		||||
		} finally {
 | 
			
		||||
@@ -517,6 +549,17 @@ const AddUserModal = ({ isOpen, onClose, onUserCreated, roles }) => {
 | 
			
		||||
						</select>
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
					{success && (
 | 
			
		||||
						<div className="bg-green-50 dark:bg-green-900 border border-green-200 dark:border-green-700 rounded-md p-3">
 | 
			
		||||
							<div className="flex items-center">
 | 
			
		||||
								<CheckCircle className="h-4 w-4 text-green-600 dark:text-green-400 mr-2" />
 | 
			
		||||
								<p className="text-sm text-green-700 dark:text-green-300">
 | 
			
		||||
									User created successfully!
 | 
			
		||||
								</p>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					)}
 | 
			
		||||
 | 
			
		||||
					{error && (
 | 
			
		||||
						<div className="bg-danger-50 dark:bg-danger-900 border border-danger-200 dark:border-danger-700 rounded-md p-3">
 | 
			
		||||
							<p className="text-sm text-danger-700 dark:text-danger-300">
 | 
			
		||||
@@ -566,15 +609,44 @@ const EditUserModal = ({ user, isOpen, onClose, onUserUpdated, roles }) => {
 | 
			
		||||
	});
 | 
			
		||||
	const [isLoading, setIsLoading] = useState(false);
 | 
			
		||||
	const [error, setError] = useState("");
 | 
			
		||||
	const [success, setSuccess] = useState(false);
 | 
			
		||||
 | 
			
		||||
	// Update formData when user prop changes or modal opens
 | 
			
		||||
	useEffect(() => {
 | 
			
		||||
		if (user && isOpen) {
 | 
			
		||||
			setFormData({
 | 
			
		||||
				username: user.username || "",
 | 
			
		||||
				email: user.email || "",
 | 
			
		||||
				first_name: user.first_name || "",
 | 
			
		||||
				last_name: user.last_name || "",
 | 
			
		||||
				role: user.role || "user",
 | 
			
		||||
				is_active: user.is_active ?? true,
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}, [user, isOpen]);
 | 
			
		||||
 | 
			
		||||
	// Reset error and success when modal closes
 | 
			
		||||
	useEffect(() => {
 | 
			
		||||
		if (!isOpen) {
 | 
			
		||||
			setError("");
 | 
			
		||||
			setSuccess(false);
 | 
			
		||||
		}
 | 
			
		||||
	}, [isOpen]);
 | 
			
		||||
 | 
			
		||||
	const handleSubmit = async (e) => {
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
		setIsLoading(true);
 | 
			
		||||
		setError("");
 | 
			
		||||
		setSuccess(false);
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			await adminUsersAPI.update(user.id, formData);
 | 
			
		||||
			setSuccess(true);
 | 
			
		||||
			onUserUpdated();
 | 
			
		||||
			// Auto-close after 1.5 seconds
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				onClose();
 | 
			
		||||
			}, 1500);
 | 
			
		||||
		} catch (err) {
 | 
			
		||||
			setError(err.response?.data?.error || "Failed to update user");
 | 
			
		||||
		} finally {
 | 
			
		||||
@@ -718,6 +790,17 @@ const EditUserModal = ({ user, isOpen, onClose, onUserUpdated, roles }) => {
 | 
			
		||||
						</label>
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
					{success && (
 | 
			
		||||
						<div className="bg-green-50 dark:bg-green-900 border border-green-200 dark:border-green-700 rounded-md p-3">
 | 
			
		||||
							<div className="flex items-center">
 | 
			
		||||
								<CheckCircle className="h-4 w-4 text-green-600 dark:text-green-400 mr-2" />
 | 
			
		||||
								<p className="text-sm text-green-700 dark:text-green-300">
 | 
			
		||||
									User updated successfully!
 | 
			
		||||
								</p>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					)}
 | 
			
		||||
 | 
			
		||||
					{error && (
 | 
			
		||||
						<div className="bg-danger-50 dark:bg-danger-900 border border-danger-200 dark:border-danger-700 rounded-md p-3">
 | 
			
		||||
							<p className="text-sm text-danger-700 dark:text-danger-300">
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ import {
 | 
			
		||||
	User,
 | 
			
		||||
} from "lucide-react";
 | 
			
		||||
 | 
			
		||||
import { useId, useState } from "react";
 | 
			
		||||
import { useEffect, useId, useState } from "react";
 | 
			
		||||
 | 
			
		||||
import { useAuth } from "../contexts/AuthContext";
 | 
			
		||||
import { useTheme } from "../contexts/ThemeContext";
 | 
			
		||||
@@ -45,6 +45,18 @@ const Profile = () => {
 | 
			
		||||
		last_name: user?.last_name || "",
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	// Update profileData when user data changes
 | 
			
		||||
	useEffect(() => {
 | 
			
		||||
		if (user) {
 | 
			
		||||
			setProfileData({
 | 
			
		||||
				username: user.username || "",
 | 
			
		||||
				email: user.email || "",
 | 
			
		||||
				first_name: user.first_name || "",
 | 
			
		||||
				last_name: user.last_name || "",
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}, [user]);
 | 
			
		||||
 | 
			
		||||
	const [passwordData, setPasswordData] = useState({
 | 
			
		||||
		currentPassword: "",
 | 
			
		||||
		newPassword: "",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										104
									
								
								setup.sh
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								setup.sh
									
									
									
									
									
								
							@@ -254,7 +254,7 @@ check_prerequisites() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
select_branch() {
 | 
			
		||||
    print_info "Fetching available branches from GitHub repository..."
 | 
			
		||||
    print_info "Fetching available releases from GitHub repository..."
 | 
			
		||||
    
 | 
			
		||||
    # Create temporary directory for git operations
 | 
			
		||||
    TEMP_DIR="/tmp/patchmon_branches_$$"
 | 
			
		||||
@@ -263,84 +263,88 @@ select_branch() {
 | 
			
		||||
    
 | 
			
		||||
    # Try to clone the repository normally
 | 
			
		||||
    if git clone "$DEFAULT_GITHUB_REPO" . 2>/dev/null; then
 | 
			
		||||
        # Get list of remote branches and trim whitespace
 | 
			
		||||
        branches=$(git branch -r | grep -v HEAD | sed 's/origin\///' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//' | sort -u)
 | 
			
		||||
        # Get list of tags sorted by version (semantic versioning)
 | 
			
		||||
        # Using git tag with version sorting
 | 
			
		||||
        tags=$(git tag -l --sort=-v:refname 2>/dev/null | head -3)
 | 
			
		||||
        
 | 
			
		||||
        if [ -n "$branches" ]; then
 | 
			
		||||
            print_info "Available branches with details:"
 | 
			
		||||
        if [ -n "$tags" ]; then
 | 
			
		||||
            print_info "Available releases and branches:"
 | 
			
		||||
            echo ""
 | 
			
		||||
            
 | 
			
		||||
            # Get branch information
 | 
			
		||||
            branch_count=1
 | 
			
		||||
            while IFS= read -r branch; do
 | 
			
		||||
                if [ -n "$branch" ]; then
 | 
			
		||||
                    # Get last commit date for this branch
 | 
			
		||||
                    last_commit=$(git log -1 --format="%ci" "origin/$branch" 2>/dev/null || echo "Unknown")
 | 
			
		||||
                    
 | 
			
		||||
                    # Get release tag associated with this branch (if any)
 | 
			
		||||
                    release_tag=$(git describe --tags --exact-match "origin/$branch" 2>/dev/null || echo "")
 | 
			
		||||
            # Display last 3 release tags
 | 
			
		||||
            option_count=1
 | 
			
		||||
            declare -A options_map
 | 
			
		||||
            
 | 
			
		||||
            while IFS= read -r tag; do
 | 
			
		||||
                if [ -n "$tag" ]; then
 | 
			
		||||
                    # Get tag date and commit info
 | 
			
		||||
                    tag_date=$(git log -1 --format="%ci" "$tag" 2>/dev/null || echo "Unknown")
 | 
			
		||||
                    
 | 
			
		||||
                    # Format the date
 | 
			
		||||
                    if [ "$last_commit" != "Unknown" ]; then
 | 
			
		||||
                        formatted_date=$(date -d "$last_commit" "+%Y-%m-%d %H:%M" 2>/dev/null || echo "$last_commit")
 | 
			
		||||
                    if [ "$tag_date" != "Unknown" ]; then
 | 
			
		||||
                        formatted_date=$(date -d "$tag_date" "+%Y-%m-%d %H:%M" 2>/dev/null || echo "$tag_date")
 | 
			
		||||
                    else
 | 
			
		||||
                        formatted_date="Unknown"
 | 
			
		||||
                    fi
 | 
			
		||||
                    
 | 
			
		||||
                    # Display branch info
 | 
			
		||||
                    printf "%2d. %-20s" "$branch_count" "$branch"
 | 
			
		||||
                    printf " (Last commit: %s)" "$formatted_date"
 | 
			
		||||
                    
 | 
			
		||||
                    if [ -n "$release_tag" ]; then
 | 
			
		||||
                        printf " [Release: %s]" "$release_tag"
 | 
			
		||||
                    # Mark the first one as latest
 | 
			
		||||
                    if [ $option_count -eq 1 ]; then
 | 
			
		||||
                        printf "%2d. %-20s (Latest Release - %s)\n" "$option_count" "$tag" "$formatted_date"
 | 
			
		||||
                    else
 | 
			
		||||
                        printf "%2d. %-20s (Release - %s)\n" "$option_count" "$tag" "$formatted_date"
 | 
			
		||||
                    fi
 | 
			
		||||
                    
 | 
			
		||||
                    echo ""
 | 
			
		||||
                    branch_count=$((branch_count + 1))
 | 
			
		||||
                    # Store the tag for later selection
 | 
			
		||||
                    options_map[$option_count]="$tag"
 | 
			
		||||
                    option_count=$((option_count + 1))
 | 
			
		||||
                fi
 | 
			
		||||
            done <<< "$branches"
 | 
			
		||||
            done <<< "$tags"
 | 
			
		||||
            
 | 
			
		||||
            # Add main branch as an option
 | 
			
		||||
            main_commit=$(git log -1 --format="%ci" "origin/main" 2>/dev/null || echo "Unknown")
 | 
			
		||||
            if [ "$main_commit" != "Unknown" ]; then
 | 
			
		||||
                formatted_main_date=$(date -d "$main_commit" "+%Y-%m-%d %H:%M" 2>/dev/null || echo "$main_commit")
 | 
			
		||||
            else
 | 
			
		||||
                formatted_main_date="Unknown"
 | 
			
		||||
            fi
 | 
			
		||||
            printf "%2d. %-20s (Development Branch - %s)\n" "$option_count" "main" "$formatted_main_date"
 | 
			
		||||
            options_map[$option_count]="main"
 | 
			
		||||
            
 | 
			
		||||
            echo ""
 | 
			
		||||
            
 | 
			
		||||
            # Determine default selection: prefer 'main' if present
 | 
			
		||||
            main_index=$(echo "$branches" | nl -w1 -s':' | awk -F':' '$2=="main"{print $1}' | head -1)
 | 
			
		||||
            if [ -z "$main_index" ]; then
 | 
			
		||||
                main_index=1
 | 
			
		||||
            fi
 | 
			
		||||
            # Default to option 1 (latest release tag)
 | 
			
		||||
            default_option=1
 | 
			
		||||
            
 | 
			
		||||
            while true; do
 | 
			
		||||
                read_input "Select branch number" BRANCH_NUMBER "$main_index"
 | 
			
		||||
                read_input "Select version/branch number" SELECTION_NUMBER "$default_option"
 | 
			
		||||
                
 | 
			
		||||
                if [[ "$BRANCH_NUMBER" =~ ^[0-9]+$ ]]; then
 | 
			
		||||
                    selected_branch=$(echo "$branches" | sed -n "${BRANCH_NUMBER}p" | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
 | 
			
		||||
                    if [ -n "$selected_branch" ]; then
 | 
			
		||||
                        DEPLOYMENT_BRANCH="$selected_branch"
 | 
			
		||||
                if [[ "$SELECTION_NUMBER" =~ ^[0-9]+$ ]]; then
 | 
			
		||||
                    selected_option="${options_map[$SELECTION_NUMBER]}"
 | 
			
		||||
                    if [ -n "$selected_option" ]; then
 | 
			
		||||
                        DEPLOYMENT_BRANCH="$selected_option"
 | 
			
		||||
                        
 | 
			
		||||
                        # Show additional info for selected branch
 | 
			
		||||
                        last_commit=$(git log -1 --format="%ci" "origin/$selected_branch" 2>/dev/null || echo "Unknown")
 | 
			
		||||
                        release_tag=$(git describe --tags --exact-match "origin/$selected_branch" 2>/dev/null || echo "")
 | 
			
		||||
                        
 | 
			
		||||
                        if [ "$last_commit" != "Unknown" ]; then
 | 
			
		||||
                            formatted_date=$(date -d "$last_commit" "+%Y-%m-%d %H:%M" 2>/dev/null || echo "$last_commit")
 | 
			
		||||
                        # Show confirmation
 | 
			
		||||
                        if [ "$selected_option" = "main" ]; then
 | 
			
		||||
                            print_status "Selected branch: main (latest development code)"
 | 
			
		||||
                            print_info "Last commit: $formatted_main_date"
 | 
			
		||||
                        else
 | 
			
		||||
                            formatted_date="Unknown"
 | 
			
		||||
                        fi
 | 
			
		||||
                        
 | 
			
		||||
                        print_status "Selected branch: $DEPLOYMENT_BRANCH"
 | 
			
		||||
                        print_info "Last commit: $formatted_date"
 | 
			
		||||
                        if [ -n "$release_tag" ]; then
 | 
			
		||||
                            print_info "Release tag: $release_tag"
 | 
			
		||||
                            print_status "Selected release: $selected_option"
 | 
			
		||||
                            tag_date=$(git log -1 --format="%ci" "$selected_option" 2>/dev/null || echo "Unknown")
 | 
			
		||||
                            if [ "$tag_date" != "Unknown" ]; then
 | 
			
		||||
                                formatted_date=$(date -d "$tag_date" "+%Y-%m-%d %H:%M" 2>/dev/null || echo "$tag_date")
 | 
			
		||||
                                print_info "Release date: $formatted_date"
 | 
			
		||||
                            fi
 | 
			
		||||
                        fi
 | 
			
		||||
                        break
 | 
			
		||||
                    else
 | 
			
		||||
                        print_error "Invalid branch number. Please try again."
 | 
			
		||||
                        print_error "Invalid selection number. Please try again."
 | 
			
		||||
                    fi
 | 
			
		||||
                else
 | 
			
		||||
                    print_error "Please enter a valid number."
 | 
			
		||||
                fi
 | 
			
		||||
            done
 | 
			
		||||
        else
 | 
			
		||||
            print_warning "No branches found, using default: main"
 | 
			
		||||
            print_warning "No release tags found, using default: main"
 | 
			
		||||
            DEPLOYMENT_BRANCH="main"
 | 
			
		||||
        fi
 | 
			
		||||
    else
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user