fix: Update Gitea workflow to use environment-specific mail and Directus secrets, and refactor Directus branding script for improved CSS management and button styling.
Some checks failed
Build & Deploy KLZ Cables / 🔍 Prepare Environment (push) Successful in 8s
Build & Deploy KLZ Cables / 🏗️ Build App (push) Has been cancelled
Build & Deploy KLZ Cables / 🚀 Deploy (push) Has been cancelled
Build & Deploy KLZ Cables / ⚡ PageSpeed (push) Has been cancelled
Build & Deploy KLZ Cables / 🔔 Notifications (push) Has been cancelled
Build & Deploy KLZ Cables / 🧪 Quality Assurance (push) Has been cancelled
Some checks failed
Build & Deploy KLZ Cables / 🔍 Prepare Environment (push) Successful in 8s
Build & Deploy KLZ Cables / 🏗️ Build App (push) Has been cancelled
Build & Deploy KLZ Cables / 🚀 Deploy (push) Has been cancelled
Build & Deploy KLZ Cables / ⚡ PageSpeed (push) Has been cancelled
Build & Deploy KLZ Cables / 🔔 Notifications (push) Has been cancelled
Build & Deploy KLZ Cables / 🧪 Quality Assurance (push) Has been cancelled
This commit is contained in:
@@ -234,23 +234,23 @@ jobs:
|
|||||||
NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${{ needs.prepare.outputs.target == 'production' && secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_NEXT_PUBLIC_UMAMI_WEBSITE_ID || secrets.TESTING_NEXT_PUBLIC_UMAMI_WEBSITE_ID || secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID) }}
|
NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${{ needs.prepare.outputs.target == 'production' && secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_NEXT_PUBLIC_UMAMI_WEBSITE_ID || secrets.TESTING_NEXT_PUBLIC_UMAMI_WEBSITE_ID || secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID) }}
|
||||||
NEXT_PUBLIC_UMAMI_SCRIPT_URL: ${{ needs.prepare.outputs.target == 'production' && secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_NEXT_PUBLIC_UMAMI_SCRIPT_URL || secrets.TESTING_NEXT_PUBLIC_UMAMI_SCRIPT_URL || secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL) }}
|
NEXT_PUBLIC_UMAMI_SCRIPT_URL: ${{ needs.prepare.outputs.target == 'production' && secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_NEXT_PUBLIC_UMAMI_SCRIPT_URL || secrets.TESTING_NEXT_PUBLIC_UMAMI_SCRIPT_URL || secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL) }}
|
||||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN || vars.SENTRY_DSN || (needs.prepare.outputs.target == 'production' && secrets.SENTRY_DSN || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_SENTRY_DSN || secrets.TESTING_SENTRY_DSN || secrets.SENTRY_DSN)) }}
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN || vars.SENTRY_DSN || (needs.prepare.outputs.target == 'production' && secrets.SENTRY_DSN || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_SENTRY_DSN || secrets.TESTING_SENTRY_DSN || secrets.SENTRY_DSN)) }}
|
||||||
MAIL_HOST: ${{ secrets.MAIL_HOST || vars.MAIL_HOST }}
|
MAIL_HOST: ${{ secrets.MAIL_HOST || vars.MAIL_HOST || (needs.prepare.outputs.target == 'production' && (secrets.MAIL_HOST || vars.MAIL_HOST) || (needs.prepare.outputs.target == 'staging' && (secrets.STAGING_MAIL_HOST || vars.STAGING_MAIL_HOST) || (secrets.TESTING_MAIL_HOST || vars.TESTING_MAIL_HOST) || (secrets.MAIL_HOST || vars.MAIL_HOST))) }}
|
||||||
MAIL_PORT: ${{ secrets.MAIL_PORT || vars.MAIL_PORT }}
|
MAIL_PORT: ${{ secrets.MAIL_PORT || vars.MAIL_PORT || (needs.prepare.outputs.target == 'production' && (secrets.MAIL_PORT || vars.MAIL_PORT) || (needs.prepare.outputs.target == 'staging' && (secrets.STAGING_MAIL_PORT || vars.STAGING_MAIL_PORT) || (secrets.TESTING_MAIL_PORT || vars.TESTING_MAIL_PORT) || (secrets.MAIL_PORT || vars.MAIL_PORT))) }}
|
||||||
MAIL_USERNAME: ${{ secrets.MAIL_USERNAME || vars.MAIL_USERNAME }}
|
MAIL_USERNAME: ${{ secrets.MAIL_USERNAME || vars.MAIL_USERNAME || (needs.prepare.outputs.target == 'production' && (secrets.MAIL_USERNAME || vars.MAIL_USERNAME) || (needs.prepare.outputs.target == 'staging' && (secrets.STAGING_MAIL_USERNAME || vars.STAGING_MAIL_USERNAME) || (secrets.TESTING_MAIL_USERNAME || vars.TESTING_MAIL_USERNAME) || (secrets.MAIL_USERNAME || vars.MAIL_USERNAME))) }}
|
||||||
MAIL_PASSWORD: ${{ secrets.MAIL_PASSWORD }}
|
MAIL_PASSWORD: ${{ secrets.MAIL_PASSWORD || (needs.prepare.outputs.target == 'production' && secrets.MAIL_PASSWORD || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_MAIL_PASSWORD || secrets.TESTING_MAIL_PASSWORD || secrets.MAIL_PASSWORD)) }}
|
||||||
MAIL_FROM: ${{ secrets.MAIL_FROM || vars.MAIL_FROM }}
|
MAIL_FROM: ${{ secrets.MAIL_FROM || vars.MAIL_FROM || (needs.prepare.outputs.target == 'production' && (secrets.MAIL_FROM || vars.MAIL_FROM) || (needs.prepare.outputs.target == 'staging' && (secrets.STAGING_MAIL_FROM || vars.STAGING_MAIL_FROM) || (secrets.TESTING_MAIL_FROM || vars.TESTING_MAIL_FROM) || (secrets.MAIL_FROM || vars.MAIL_FROM))) }}
|
||||||
MAIL_RECIPIENTS: ${{ secrets.MAIL_RECIPIENTS || vars.MAIL_RECIPIENTS }}
|
MAIL_RECIPIENTS: ${{ secrets.MAIL_RECIPIENTS || vars.MAIL_RECIPIENTS || (needs.prepare.outputs.target == 'production' && (secrets.MAIL_RECIPIENTS || vars.MAIL_RECIPIENTS) || (needs.prepare.outputs.target == 'staging' && (secrets.STAGING_MAIL_RECIPIENTS || vars.STAGING_MAIL_RECIPIENTS) || (secrets.TESTING_MAIL_RECIPIENTS || vars.TESTING_MAIL_RECIPIENTS) || (secrets.MAIL_RECIPIENTS || vars.MAIL_RECIPIENTS))) }}
|
||||||
DIRECTUS_URL: ${{ needs.prepare.outputs.directus_url }}
|
DIRECTUS_URL: ${{ needs.prepare.outputs.directus_url }}
|
||||||
DIRECTUS_HOST: ${{ needs.prepare.outputs.directus_host }}
|
DIRECTUS_HOST: ${{ needs.prepare.outputs.directus_host }}
|
||||||
PROJECT_NAME: ${{ needs.prepare.outputs.project_name }}
|
PROJECT_NAME: ${{ needs.prepare.outputs.project_name }}
|
||||||
DIRECTUS_KEY: ${{ secrets.DIRECTUS_KEY }}
|
DIRECTUS_KEY: ${{ secrets.DIRECTUS_KEY || (needs.prepare.outputs.target == 'production' && secrets.DIRECTUS_KEY || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_DIRECTUS_KEY || secrets.TESTING_DIRECTUS_KEY || secrets.DIRECTUS_KEY)) }}
|
||||||
DIRECTUS_SECRET: ${{ secrets.DIRECTUS_SECRET }}
|
DIRECTUS_SECRET: ${{ secrets.DIRECTUS_SECRET || (needs.prepare.outputs.target == 'production' && secrets.DIRECTUS_SECRET || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_DIRECTUS_SECRET || secrets.TESTING_DIRECTUS_SECRET || secrets.DIRECTUS_SECRET)) }}
|
||||||
DIRECTUS_ADMIN_EMAIL: ${{ secrets.DIRECTUS_ADMIN_EMAIL }}
|
DIRECTUS_ADMIN_EMAIL: ${{ secrets.DIRECTUS_ADMIN_EMAIL || (needs.prepare.outputs.target == 'production' && secrets.DIRECTUS_ADMIN_EMAIL || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_DIRECTUS_ADMIN_EMAIL || secrets.TESTING_DIRECTUS_ADMIN_EMAIL || secrets.DIRECTUS_ADMIN_EMAIL)) }}
|
||||||
DIRECTUS_ADMIN_PASSWORD: ${{ secrets.DIRECTUS_ADMIN_PASSWORD }}
|
DIRECTUS_ADMIN_PASSWORD: ${{ secrets.DIRECTUS_ADMIN_PASSWORD || (needs.prepare.outputs.target == 'production' && secrets.DIRECTUS_ADMIN_PASSWORD || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_DIRECTUS_ADMIN_PASSWORD || secrets.TESTING_DIRECTUS_ADMIN_PASSWORD || secrets.DIRECTUS_ADMIN_PASSWORD)) }}
|
||||||
DIRECTUS_DB_NAME: ${{ secrets.DIRECTUS_DB_NAME || 'directus' }}
|
DIRECTUS_DB_NAME: ${{ secrets.DIRECTUS_DB_NAME || 'directus' }}
|
||||||
DIRECTUS_DB_USER: ${{ secrets.DIRECTUS_DB_USER || 'directus' }}
|
DIRECTUS_DB_USER: ${{ secrets.DIRECTUS_DB_USER || 'directus' }}
|
||||||
DIRECTUS_DB_PASSWORD: ${{ secrets.DIRECTUS_DB_PASSWORD }}
|
DIRECTUS_DB_PASSWORD: ${{ secrets.DIRECTUS_DB_PASSWORD || (needs.prepare.outputs.target == 'production' && secrets.DIRECTUS_DB_PASSWORD || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_DIRECTUS_DB_PASSWORD || secrets.TESTING_DIRECTUS_DB_PASSWORD || secrets.DIRECTUS_DB_PASSWORD)) }}
|
||||||
DIRECTUS_API_TOKEN: ${{ secrets.DIRECTUS_API_TOKEN }}
|
DIRECTUS_API_TOKEN: ${{ secrets.DIRECTUS_API_TOKEN || (needs.prepare.outputs.target == 'production' && secrets.DIRECTUS_API_TOKEN || (needs.prepare.outputs.target == 'staging' && secrets.STAGING_DIRECTUS_API_TOKEN || secrets.TESTING_DIRECTUS_API_TOKEN || secrets.DIRECTUS_API_TOKEN)) }}
|
||||||
GATEKEEPER_PASSWORD: ${{ secrets.GATEKEEPER_PASSWORD || 'klz2026' }}
|
GATEKEEPER_PASSWORD: ${{ secrets.GATEKEEPER_PASSWORD || 'klz2026' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
|
|||||||
@@ -21,12 +21,17 @@ async function setupBranding() {
|
|||||||
const getMimeType = (filePath: string) => {
|
const getMimeType = (filePath: string) => {
|
||||||
const ext = path.extname(filePath).toLowerCase();
|
const ext = path.extname(filePath).toLowerCase();
|
||||||
switch (ext) {
|
switch (ext) {
|
||||||
case '.svg': return 'image/svg+xml';
|
case '.svg':
|
||||||
case '.png': return 'image/png';
|
return 'image/svg+xml';
|
||||||
|
case '.png':
|
||||||
|
return 'image/png';
|
||||||
case '.jpg':
|
case '.jpg':
|
||||||
case '.jpeg': return 'image/jpeg';
|
case '.jpeg':
|
||||||
case '.ico': return 'image/x-icon';
|
return 'image/jpeg';
|
||||||
default: return 'application/octet-stream';
|
case '.ico':
|
||||||
|
return 'image/x-icon';
|
||||||
|
default:
|
||||||
|
return 'application/octet-stream';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,13 +50,24 @@ async function setupBranding() {
|
|||||||
return res.id;
|
return res.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
const logoWhiteId = await uploadAsset(path.resolve(__dirname, '../public/logo-white.svg'), 'Logo White');
|
const logoWhiteId = await uploadAsset(
|
||||||
const logoBlueId = await uploadAsset(path.resolve(__dirname, '../public/logo-blue.svg'), 'Logo Blue');
|
path.resolve(__dirname, '../public/logo-white.svg'),
|
||||||
const faviconId = await uploadAsset(path.resolve(__dirname, '../public/favicon.ico'), 'Favicon');
|
'Logo White',
|
||||||
|
);
|
||||||
|
const logoBlueId = await uploadAsset(
|
||||||
|
path.resolve(__dirname, '../public/logo-blue.svg'),
|
||||||
|
'Logo Blue',
|
||||||
|
);
|
||||||
|
const faviconId = await uploadAsset(
|
||||||
|
path.resolve(__dirname, '../public/favicon.ico'),
|
||||||
|
'Favicon',
|
||||||
|
);
|
||||||
|
|
||||||
// Smoother Background SVG
|
// Smoother Background SVG
|
||||||
const bgSvgPath = path.resolve(__dirname, '../public/login-bg.svg');
|
const bgSvgPath = path.resolve(__dirname, '../public/login-bg.svg');
|
||||||
fs.writeFileSync(bgSvgPath, `<svg width="1920" height="1080" viewBox="0 0 1920 1080" fill="none" xmlns="http://www.w3.org/2000/svg">
|
fs.writeFileSync(
|
||||||
|
bgSvgPath,
|
||||||
|
`<svg width="1920" height="1080" viewBox="0 0 1920 1080" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<rect width="1920" height="1080" fill="#001a4d"/>
|
<rect width="1920" height="1080" fill="#001a4d"/>
|
||||||
<ellipse cx="960" cy="540" rx="800" ry="600" fill="url(#paint0_radial_premium)"/>
|
<ellipse cx="960" cy="540" rx="800" ry="600" fill="url(#paint0_radial_premium)"/>
|
||||||
<defs>
|
<defs>
|
||||||
@@ -60,7 +76,8 @@ async function setupBranding() {
|
|||||||
<stop offset="1" stop-color="#001a4d" stop-opacity="0"/>
|
<stop offset="1" stop-color="#001a4d" stop-opacity="0"/>
|
||||||
</radialGradient>
|
</radialGradient>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>`);
|
</svg>`,
|
||||||
|
);
|
||||||
const backgroundId = await uploadAsset(bgSvgPath, 'Login Bg');
|
const backgroundId = await uploadAsset(bgSvgPath, 'Login Bg');
|
||||||
if (fs.existsSync(bgSvgPath)) fs.unlinkSync(bgSvgPath);
|
if (fs.existsSync(bgSvgPath)) fs.unlinkSync(bgSvgPath);
|
||||||
|
|
||||||
@@ -71,8 +88,7 @@ async function setupBranding() {
|
|||||||
const COLOR_ACCENT = '#82ed20'; // Sustainability Green
|
const COLOR_ACCENT = '#82ed20'; // Sustainability Green
|
||||||
const COLOR_SECONDARY = '#003d82';
|
const COLOR_SECONDARY = '#003d82';
|
||||||
|
|
||||||
const cssInjection = `
|
const customCss = `
|
||||||
<style>
|
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
||||||
|
|
||||||
/* Global Login Styles */
|
/* Global Login Styles */
|
||||||
@@ -92,7 +108,7 @@ async function setupBranding() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.public-view .v-button {
|
.public-view .v-button {
|
||||||
border-radius: full !important;
|
border-radius: 9999px !important;
|
||||||
height: 56px !important;
|
height: 56px !important;
|
||||||
font-weight: 600 !important;
|
font-weight: 600 !important;
|
||||||
letter-spacing: -0.01em !important;
|
letter-spacing: -0.01em !important;
|
||||||
@@ -108,71 +124,74 @@ async function setupBranding() {
|
|||||||
--v-input-border-radius: 12px !important;
|
--v-input-border-radius: 12px !important;
|
||||||
--v-input-background-color: #f8f9fa !important;
|
--v-input-background-color: #f8f9fa !important;
|
||||||
}
|
}
|
||||||
</style>
|
`;
|
||||||
|
|
||||||
|
const publicNote = `
|
||||||
<div style="font-family: 'Inter', sans-serif; text-align: center; margin-top: 24px;">
|
<div style="font-family: 'Inter', sans-serif; text-align: center; margin-top: 24px;">
|
||||||
<p style="color: rgba(255,255,255,0.7); font-size: 14px; margin-bottom: 4px; font-weight: 500;">KLZ INFRASTRUCTURE ENGINE</p>
|
<p style="color: rgba(255,255,255,0.7); font-size: 14px; margin-bottom: 4px; font-weight: 500;">KLZ INFRASTRUCTURE ENGINE</p>
|
||||||
<h1 style="color: #ffffff; font-size: 18px; font-weight: 700; margin: 0;">Sustainable Energy. <span style="color: #82ed20;">Industrial Reliability.</span></h1>
|
<h1 style="color: #ffffff; font-size: 18px; font-weight: 700; margin: 0;">Sustainable Energy. <span style="color: #82ed20;">Industrial Reliability.</span></h1>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
await client.request(updateSettings({
|
await client.request(
|
||||||
|
updateSettings({
|
||||||
project_name: 'KLZ Cables',
|
project_name: 'KLZ Cables',
|
||||||
project_url: 'https://klz-cables.com',
|
project_url: 'https://klz-cables.com',
|
||||||
project_color: COLOR_ACCENT,
|
project_color: COLOR_ACCENT,
|
||||||
project_descriptor: 'Sustainable Energy Infrastructure',
|
project_descriptor: 'Sustainable Energy Infrastructure',
|
||||||
project_owner: 'KLZ Cables',
|
|
||||||
|
|
||||||
// FIXED: Use WHITE logo for the Blue Sidebar
|
// FIXED: Use WHITE logo for the Blue Sidebar
|
||||||
project_logo: logoWhiteId as any,
|
project_logo: logoWhiteId as any,
|
||||||
|
|
||||||
public_foreground: logoWhiteId as any,
|
public_foreground: logoWhiteId as any,
|
||||||
public_background: backgroundId as any,
|
public_background: backgroundId as any,
|
||||||
public_note: cssInjection,
|
public_note: publicNote,
|
||||||
public_favicon: faviconId as any,
|
public_favicon: faviconId as any,
|
||||||
|
custom_css: customCss,
|
||||||
|
|
||||||
// DEEP PREMIUM THEME
|
// DEEP PREMIUM THEME
|
||||||
theme_light_overrides: {
|
theme_light_overrides: {
|
||||||
// Brands
|
// Brands
|
||||||
"primary": COLOR_ACCENT, // Buttons/Actions are GREEN like the website
|
primary: COLOR_ACCENT, // Buttons/Actions are GREEN like the website
|
||||||
"secondary": COLOR_SECONDARY,
|
secondary: COLOR_SECONDARY,
|
||||||
|
|
||||||
// Content Area
|
// Content Area
|
||||||
"background": "#f1f3f7",
|
background: '#f1f3f7',
|
||||||
"backgroundNormal": "#ffffff",
|
backgroundNormal: '#ffffff',
|
||||||
"backgroundAccent": "#eef2ff",
|
backgroundAccent: '#eef2ff',
|
||||||
|
|
||||||
// Sidebar Branding
|
// Sidebar Branding
|
||||||
"navigationBackground": COLOR_PRIMARY,
|
navigationBackground: COLOR_PRIMARY,
|
||||||
"navigationForeground": "#ffffff",
|
navigationForeground: '#ffffff',
|
||||||
"navigationBackgroundHover": "rgba(255,255,255,0.05)",
|
navigationBackgroundHover: 'rgba(255,255,255,0.05)',
|
||||||
"navigationForegroundHover": "#ffffff",
|
navigationForegroundHover: '#ffffff',
|
||||||
"navigationBackgroundActive": "rgba(130, 237, 32, 0.15)", // Subtle Green highlight
|
navigationBackgroundActive: 'rgba(130, 237, 32, 0.15)', // Subtle Green highlight
|
||||||
"navigationForegroundActive": COLOR_ACCENT, // Active item is GREEN
|
navigationForegroundActive: COLOR_ACCENT, // Active item is GREEN
|
||||||
|
|
||||||
// Module Bar (Thin far left)
|
// Module Bar (Thin far left)
|
||||||
"moduleBarBackground": "#000d26",
|
moduleBarBackground: '#000d26',
|
||||||
"moduleBarForeground": "#ffffff",
|
moduleBarForeground: '#ffffff',
|
||||||
"moduleBarForegroundActive": COLOR_ACCENT,
|
moduleBarForegroundActive: COLOR_ACCENT,
|
||||||
|
|
||||||
// UI Standards
|
// UI Standards
|
||||||
"borderRadius": "16px", // Larger radius for modern feel
|
borderRadius: '16px', // Larger radius for modern feel
|
||||||
"borderWidth": "1px",
|
borderWidth: '1px',
|
||||||
"borderColor": "#e2e8f0",
|
borderColor: '#e2e8f0',
|
||||||
"formFieldHeight": "48px" // Touch-target height
|
formFieldHeight: '48px', // Touch-target height
|
||||||
} as any,
|
} as any,
|
||||||
|
|
||||||
theme_dark_overrides: {
|
theme_dark_overrides: {
|
||||||
"primary": COLOR_ACCENT,
|
primary: COLOR_ACCENT,
|
||||||
"background": "#0a0a0a",
|
background: '#0a0a0a',
|
||||||
"navigationBackground": "#000000",
|
navigationBackground: '#000000',
|
||||||
"moduleBarBackground": COLOR_PRIMARY,
|
moduleBarBackground: COLOR_PRIMARY,
|
||||||
"borderRadius": "16px",
|
borderRadius: '16px',
|
||||||
"formFieldHeight": "48px"
|
formFieldHeight: '48px',
|
||||||
} as any
|
} as any,
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
console.log('✨ Premium Theme applied successfully!');
|
console.log('✨ Premium Theme applied successfully!');
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('❌ Error:', JSON.stringify(error, null, 2));
|
console.error('❌ Error:', JSON.stringify(error, null, 2));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user