Merge remote-tracking branch 'upstream/main'
This commit is contained in:
118
scripts/dev/start-all-parallel.bat
Normal file
118
scripts/dev/start-all-parallel.bat
Normal file
@@ -0,0 +1,118 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
REM 스크립트가 있는 디렉토리에서 루트로 이동
|
||||
cd /d "%~dp0\..\.."
|
||||
|
||||
REM 시작 시간 기록
|
||||
set START_TIME=%DATE% %TIME%
|
||||
|
||||
echo ============================================
|
||||
echo WACE 솔루션 - 전체 서비스 시작 (병렬 최적화)
|
||||
echo ============================================
|
||||
echo [시작 시간] %START_TIME%
|
||||
echo.
|
||||
|
||||
REM Docker Desktop 실행 확인
|
||||
echo [1/5] Docker Desktop 상태 확인 중...
|
||||
docker --version >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo [ERROR] Docker Desktop이 실행되지 않았습니다!
|
||||
echo Docker Desktop을 먼저 실행해주세요.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo [OK] Docker Desktop이 실행 중입니다.
|
||||
echo.
|
||||
|
||||
REM 기존 컨테이너 및 이미지 정리
|
||||
echo [2/5] 기존 컨테이너 및 이미지 정리 중...
|
||||
docker rm -f pms-backend-win pms-frontend-win 2>nul
|
||||
docker rmi -f erp-node-backend erp-node-frontend 2>nul
|
||||
docker network rm pms-network 2>nul
|
||||
docker network create pms-network 2>nul
|
||||
docker system prune -f >nul 2>&1
|
||||
echo [OK] 컨테이너 및 이미지 정리 완료
|
||||
echo.
|
||||
|
||||
REM 병렬 빌드 (docker-compose 자체가 병렬 처리)
|
||||
echo [3/5] 이미지 빌드 중... (백엔드 + 프론트엔드 병렬)
|
||||
echo 이 작업은 시간이 걸릴 수 있습니다...
|
||||
echo.
|
||||
|
||||
REM 백엔드 빌드 (캐시 없이 완전 재빌드)
|
||||
docker-compose -f docker-compose.backend.win.yml build --no-cache
|
||||
if %errorlevel% neq 0 (
|
||||
echo [ERROR] 백엔드 빌드 실패!
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo [OK] 백엔드 빌드 완료
|
||||
echo.
|
||||
|
||||
REM 프론트엔드 빌드 (캐시 없이 완전 재빌드)
|
||||
docker-compose -f docker-compose.frontend.win.yml build --no-cache
|
||||
if %errorlevel% neq 0 (
|
||||
echo [ERROR] 프론트엔드 빌드 실패!
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo [OK] 프론트엔드 빌드 완료
|
||||
echo.
|
||||
|
||||
REM 기존 컨테이너 정리 후 서비스 시작
|
||||
echo [4/5] 서비스 시작 중...
|
||||
docker-compose -f docker-compose.backend.win.yml down -v 2>nul
|
||||
docker-compose -f docker-compose.frontend.win.yml down -v 2>nul
|
||||
|
||||
REM 백엔드 시작
|
||||
echo 백엔드 서비스 시작...
|
||||
docker-compose -f docker-compose.backend.win.yml up -d
|
||||
if %errorlevel% neq 0 (
|
||||
echo [ERROR] 백엔드 시작 실패!
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM 프론트엔드 시작
|
||||
echo 프론트엔드 서비스 시작...
|
||||
docker-compose -f docker-compose.frontend.win.yml up -d
|
||||
if %errorlevel% neq 0 (
|
||||
echo [ERROR] 프론트엔드 시작 실패!
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo [OK] 서비스 시작 완료
|
||||
echo.
|
||||
|
||||
REM 안정화 대기
|
||||
echo [5/5] 서비스 안정화 대기 중... (10초)
|
||||
timeout /t 10 /nobreak >nul
|
||||
echo.
|
||||
|
||||
echo ============================================
|
||||
echo [완료] 모든 서비스가 시작되었습니다!
|
||||
echo ============================================
|
||||
echo.
|
||||
echo [DATABASE] PostgreSQL: http://39.117.244.52:11132
|
||||
echo [BACKEND] Node.js API: http://localhost:8080/api
|
||||
echo [FRONTEND] Next.js: http://localhost:9771
|
||||
echo.
|
||||
echo [서비스 상태 확인]
|
||||
echo docker-compose -f docker-compose.backend.win.yml ps
|
||||
echo docker-compose -f docker-compose.frontend.win.yml ps
|
||||
echo.
|
||||
echo [로그 확인]
|
||||
echo 백엔드: docker-compose -f docker-compose.backend.win.yml logs -f
|
||||
echo 프론트엔드: docker-compose -f docker-compose.frontend.win.yml logs -f
|
||||
echo.
|
||||
echo [서비스 중지]
|
||||
echo scripts\dev\stop-all.bat
|
||||
echo.
|
||||
|
||||
set END_TIME=%DATE% %TIME%
|
||||
echo [종료 시간] %END_TIME%
|
||||
echo ============================================
|
||||
|
||||
pause
|
||||
183
scripts/dev/start-all-parallel.ps1
Normal file
183
scripts/dev/start-all-parallel.ps1
Normal file
@@ -0,0 +1,183 @@
|
||||
# WACE 솔루션 - 전체 서비스 시작 (병렬 최적화) - PowerShell 버전
|
||||
# 실행 방법: powershell -ExecutionPolicy Bypass -File .\scripts\dev\start-all-parallel.ps1
|
||||
|
||||
# UTF-8 출력 설정
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
$OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
# 스크립트 위치에서 루트 디렉토리로 이동
|
||||
$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||
Set-Location (Join-Path $scriptPath "..\..")
|
||||
|
||||
# 시작 시간 기록
|
||||
$startTime = Get-Date
|
||||
$startTimeFormatted = $startTime.ToString("yyyy-MM-dd HH:mm:ss")
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "============================================" -ForegroundColor Cyan
|
||||
Write-Host "WACE 솔루션 - 전체 서비스 시작 (병렬 최적화)" -ForegroundColor Cyan
|
||||
Write-Host "============================================" -ForegroundColor Cyan
|
||||
Write-Host "[시작 시간] $startTimeFormatted" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
# Docker Desktop 실행 확인
|
||||
Write-Host "[1/5] Docker Desktop 상태 확인 중..." -ForegroundColor White
|
||||
$dockerCheck = docker --version 2>&1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "[ERROR] Docker Desktop이 실행되지 않았습니다!" -ForegroundColor Red
|
||||
Write-Host " Docker Desktop을 먼저 실행해주세요." -ForegroundColor Red
|
||||
Read-Host "계속하려면 Enter를 누르세요"
|
||||
exit 1
|
||||
}
|
||||
Write-Host "[OK] Docker Desktop이 실행 중입니다." -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# 기존 컨테이너 정리
|
||||
Write-Host "[2/5] 기존 컨테이너 정리 중..." -ForegroundColor White
|
||||
docker rm -f pms-backend-win pms-frontend-win 2>$null | Out-Null
|
||||
docker network rm pms-network 2>$null | Out-Null
|
||||
docker network create pms-network 2>$null | Out-Null
|
||||
Write-Host "[OK] 컨테이너 정리 완료" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# 병렬 빌드 시작
|
||||
$parallelStart = Get-Date
|
||||
Write-Host "[3/5] 이미지 빌드 중... (백엔드 + 프론트엔드 병렬)" -ForegroundColor White
|
||||
Write-Host " 이 작업은 시간이 걸릴 수 있습니다..." -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# 병렬 빌드 실행
|
||||
$backendBuildJob = Start-Job -ScriptBlock {
|
||||
param($workDir)
|
||||
Set-Location $workDir
|
||||
$output = docker-compose -f docker-compose.backend.win.yml build 2>&1
|
||||
return @{
|
||||
Success = $LASTEXITCODE -eq 0
|
||||
Output = $output
|
||||
}
|
||||
} -ArgumentList $PWD.Path
|
||||
|
||||
$frontendBuildJob = Start-Job -ScriptBlock {
|
||||
param($workDir)
|
||||
Set-Location $workDir
|
||||
$output = docker-compose -f docker-compose.frontend.win.yml build 2>&1
|
||||
return @{
|
||||
Success = $LASTEXITCODE -eq 0
|
||||
Output = $output
|
||||
}
|
||||
} -ArgumentList $PWD.Path
|
||||
|
||||
Write-Host " 백엔드 빌드 진행 중..." -ForegroundColor Gray
|
||||
Write-Host " 프론트엔드 빌드 진행 중..." -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# 빌드 완료 대기
|
||||
$null = Wait-Job -Job $backendBuildJob, $frontendBuildJob
|
||||
|
||||
$backendResult = Receive-Job -Job $backendBuildJob
|
||||
$frontendResult = Receive-Job -Job $frontendBuildJob
|
||||
|
||||
Remove-Job -Job $backendBuildJob, $frontendBuildJob -Force
|
||||
|
||||
# 빌드 결과 확인
|
||||
$buildFailed = $false
|
||||
|
||||
if ($backendResult.Success) {
|
||||
Write-Host "[OK] 백엔드 빌드 완료" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[ERROR] 백엔드 빌드 실패!" -ForegroundColor Red
|
||||
Write-Host $backendResult.Output -ForegroundColor Red
|
||||
$buildFailed = $true
|
||||
}
|
||||
|
||||
if ($frontendResult.Success) {
|
||||
Write-Host "[OK] 프론트엔드 빌드 완료" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[ERROR] 프론트엔드 빌드 실패!" -ForegroundColor Red
|
||||
Write-Host $frontendResult.Output -ForegroundColor Red
|
||||
$buildFailed = $true
|
||||
}
|
||||
|
||||
if ($buildFailed) {
|
||||
Read-Host "빌드 실패. Enter를 누르면 종료됩니다"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$parallelEnd = Get-Date
|
||||
$parallelDuration = ($parallelEnd - $parallelStart).TotalSeconds
|
||||
Write-Host "[INFO] 빌드 소요 시간: $([math]::Round($parallelDuration))초" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
# 서비스 시작
|
||||
$serviceStart = Get-Date
|
||||
Write-Host "[4/5] 서비스 시작 중..." -ForegroundColor White
|
||||
|
||||
# 기존 컨테이너 정리
|
||||
docker-compose -f docker-compose.backend.win.yml down -v 2>$null | Out-Null
|
||||
docker-compose -f docker-compose.frontend.win.yml down -v 2>$null | Out-Null
|
||||
|
||||
# 백엔드 시작
|
||||
Write-Host " 백엔드 서비스 시작..." -ForegroundColor Gray
|
||||
docker-compose -f docker-compose.backend.win.yml up -d 2>&1 | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "[ERROR] 백엔드 시작 실패!" -ForegroundColor Red
|
||||
Read-Host "계속하려면 Enter를 누르세요"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 프론트엔드 시작
|
||||
Write-Host " 프론트엔드 서비스 시작..." -ForegroundColor Gray
|
||||
docker-compose -f docker-compose.frontend.win.yml up -d 2>&1 | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "[ERROR] 프론트엔드 시작 실패!" -ForegroundColor Red
|
||||
Read-Host "계속하려면 Enter를 누르세요"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "[OK] 서비스 시작 완료" -ForegroundColor Green
|
||||
|
||||
$serviceEnd = Get-Date
|
||||
$serviceDuration = ($serviceEnd - $serviceStart).TotalSeconds
|
||||
Write-Host "[INFO] 서비스 시작 소요 시간: $([math]::Round($serviceDuration))초" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
# 안정화 대기
|
||||
Write-Host "[5/5] 서비스 안정화 대기 중... (10초)" -ForegroundColor White
|
||||
Start-Sleep -Seconds 10
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "============================================" -ForegroundColor Cyan
|
||||
Write-Host "[완료] 모든 서비스가 시작되었습니다!" -ForegroundColor Green
|
||||
Write-Host "============================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "[DATABASE] PostgreSQL: http://39.117.244.52:11132" -ForegroundColor White
|
||||
Write-Host "[BACKEND] Node.js API: http://localhost:8080/api" -ForegroundColor White
|
||||
Write-Host "[FRONTEND] Next.js: http://localhost:9771" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "[서비스 상태 확인]" -ForegroundColor Yellow
|
||||
Write-Host " docker-compose -f docker-compose.backend.win.yml ps" -ForegroundColor Gray
|
||||
Write-Host " docker-compose -f docker-compose.frontend.win.yml ps" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "[로그 확인]" -ForegroundColor Yellow
|
||||
Write-Host " 백엔드: docker-compose -f docker-compose.backend.win.yml logs -f" -ForegroundColor Gray
|
||||
Write-Host " 프론트엔드: docker-compose -f docker-compose.frontend.win.yml logs -f" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "[서비스 중지]" -ForegroundColor Yellow
|
||||
Write-Host " .\scripts\dev\stop-all.ps1" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# 종료 시간 계산
|
||||
$endTime = Get-Date
|
||||
$endTimeFormatted = $endTime.ToString("yyyy-MM-dd HH:mm:ss")
|
||||
$totalDuration = ($endTime - $startTime).TotalSeconds
|
||||
$minutes = [math]::Floor($totalDuration / 60)
|
||||
$seconds = [math]::Round($totalDuration % 60)
|
||||
|
||||
Write-Host "============================================" -ForegroundColor Cyan
|
||||
Write-Host "[종료 시간] $endTimeFormatted" -ForegroundColor Yellow
|
||||
Write-Host "[총 소요 시간] ${minutes}분 ${seconds}초" -ForegroundColor Yellow
|
||||
Write-Host " - 빌드: $([math]::Round($parallelDuration))초" -ForegroundColor Gray
|
||||
Write-Host " - 서비스 시작: $([math]::Round($serviceDuration))초" -ForegroundColor Gray
|
||||
Write-Host "============================================" -ForegroundColor Cyan
|
||||
|
||||
Read-Host "계속하려면 Enter를 누르세요"
|
||||
30
scripts/dev/stop-all.bat
Normal file
30
scripts/dev/stop-all.bat
Normal file
@@ -0,0 +1,30 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
|
||||
REM 스크립트가 있는 디렉토리에서 루트로 이동
|
||||
cd /d "%~dp0\..\.."
|
||||
|
||||
echo ============================================
|
||||
echo WACE 솔루션 - 전체 서비스 중지
|
||||
echo ============================================
|
||||
echo.
|
||||
|
||||
echo 🛑 백엔드 서비스 중지 중...
|
||||
docker-compose -f docker-compose.backend.win.yml down -v 2>nul
|
||||
echo ✅ 백엔드 서비스 중지 완료
|
||||
echo.
|
||||
|
||||
echo 🛑 프론트엔드 서비스 중지 중...
|
||||
docker-compose -f docker-compose.frontend.win.yml down -v 2>nul
|
||||
echo ✅ 프론트엔드 서비스 중지 완료
|
||||
echo.
|
||||
|
||||
echo 🧹 네트워크 정리 중...
|
||||
docker network rm pms-network 2>nul
|
||||
echo.
|
||||
|
||||
echo ============================================
|
||||
echo 🎉 모든 서비스가 중지되었습니다!
|
||||
echo ============================================
|
||||
|
||||
pause
|
||||
33
scripts/dev/stop-all.ps1
Normal file
33
scripts/dev/stop-all.ps1
Normal file
@@ -0,0 +1,33 @@
|
||||
# WACE 솔루션 - 전체 서비스 중지 - PowerShell 버전
|
||||
# 실행 방법: powershell -ExecutionPolicy Bypass -File .\scripts\dev\stop-all.ps1
|
||||
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
# 스크립트 위치에서 루트 디렉토리로 이동
|
||||
$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||
Set-Location (Join-Path $scriptPath "..\..")
|
||||
|
||||
Write-Host "============================================" -ForegroundColor Cyan
|
||||
Write-Host "WACE 솔루션 - 전체 서비스 중지" -ForegroundColor Cyan
|
||||
Write-Host "============================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "🛑 백엔드 서비스 중지 중..." -ForegroundColor Yellow
|
||||
docker-compose -f docker-compose.backend.win.yml down -v 2>$null
|
||||
Write-Host "✅ 백엔드 서비스 중지 완료" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "🛑 프론트엔드 서비스 중지 중..." -ForegroundColor Yellow
|
||||
docker-compose -f docker-compose.frontend.win.yml down -v 2>$null
|
||||
Write-Host "✅ 프론트엔드 서비스 중지 완료" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "🧹 네트워크 정리 중..." -ForegroundColor Yellow
|
||||
docker network rm pms-network 2>$null
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "============================================" -ForegroundColor Cyan
|
||||
Write-Host "🎉 모든 서비스가 중지되었습니다!" -ForegroundColor Green
|
||||
Write-Host "============================================" -ForegroundColor Cyan
|
||||
|
||||
Read-Host "계속하려면 Enter를 누르세요"
|
||||
60
scripts/remove-logs.js
Normal file
60
scripts/remove-logs.js
Normal file
@@ -0,0 +1,60 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const filePath = path.join(__dirname, '../frontend/lib/utils/buttonActions.ts');
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
// 디버깅 console.log 제거 (전체 줄)
|
||||
// console.log로 시작하는 줄만 제거 (이모지 포함)
|
||||
const patterns = [
|
||||
// 디버깅 로그 (이모지 포함)
|
||||
/^\s*console\.log\s*\([^)]*["'`]🔍[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]📦[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]📋[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🔗[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🔄[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🎯[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]✅[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]⏭️[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]📊[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🏗️[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]📝[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]💾[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🔐[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🔑[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🔒[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🧹[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🗑️[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]📂[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]📤[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]📥[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🔎[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🆕[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]📌[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🔥[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]⚡[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🎉[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🚀[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]📡[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🌐[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]👤[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🚫[^]*?\);\s*$/gm,
|
||||
/^\s*console\.log\s*\([^)]*["'`]🔧[^]*?\);\s*$/gm,
|
||||
];
|
||||
|
||||
let totalRemoved = 0;
|
||||
|
||||
patterns.forEach(pattern => {
|
||||
const matches = content.match(pattern);
|
||||
if (matches) {
|
||||
totalRemoved += matches.length;
|
||||
content = content.replace(pattern, '');
|
||||
}
|
||||
});
|
||||
|
||||
// 연속된 빈 줄 제거 (3개 이상의 빈 줄을 2개로)
|
||||
content = content.replace(/\n\n\n+/g, '\n\n');
|
||||
|
||||
fs.writeFileSync(filePath, content, 'utf8');
|
||||
console.log(`Removed ${totalRemoved} console.log statements`);
|
||||
|
||||
Reference in New Issue
Block a user