Merge branch 'zentaopms_289' of https://gitlab.zcorp.cc/easycorp/zentaopms into zentaopms_289_gfl
This commit is contained in:
@@ -1 +0,0 @@
|
||||
ALTER TABLE `zt_lang` ADD `systemMode` varchar(10) COLLATE 'utf8_general_ci' NOT NULL DEFAULT 'ALM';
|
||||
@@ -2506,29 +2506,9 @@ class baseRouter
|
||||
|
||||
if($config and (!isset($config->$moduleName) or !is_object($config->$moduleName))) $config->$moduleName = new stdclass();
|
||||
|
||||
/* 初始化数组。Init the variables. */
|
||||
$extConfigFiles = array();
|
||||
$commonExtConfigFiles = array();
|
||||
$siteExtConfigFiles = array();
|
||||
|
||||
/* 先获得模块的主配置文件。Get the main config file for current module first. */
|
||||
$mainConfigFile = $this->getModulePath($appName, $moduleName) . 'config.php';
|
||||
|
||||
/* 查找扩展配置文件。Get extension config files. */
|
||||
if($config->framework->extensionLevel > 0) $extConfigPath = $this->getModuleExtPath($appName, $moduleName, 'config');
|
||||
if($config->framework->extensionLevel >= 1)
|
||||
{
|
||||
if(!empty($extConfigPath['common'])) $commonExtConfigFiles = helper::ls($extConfigPath['common'], '.php');
|
||||
if(!empty($extConfigPath['xuan'])) $commonExtConfigFiles = array_merge($commonExtConfigFiles, helper::ls($extConfigPath['xuan'], '.php'));
|
||||
if(!empty($extConfigPath['vision'])) $commonExtConfigFiles = array_merge($commonExtConfigFiles, helper::ls($extConfigPath['vision'], '.php'));
|
||||
if(!empty($extConfigPath['saas'])) $commonExtConfigFiles = array_merge($commonExtConfigFiles, helper::ls($extConfigPath['saas'], '.php'));
|
||||
if(!empty($extConfigPath['custom'])) $commonExtConfigFiles = array_merge($commonExtConfigFiles, helper::ls($extConfigPath['custom'], '.php'));
|
||||
}
|
||||
if($config->framework->extensionLevel == 2 and !empty($extConfigPath['site'])) $siteExtConfigFiles = helper::ls($extConfigPath['site'], '.php');
|
||||
$extConfigFiles = array_merge($commonExtConfigFiles, $siteExtConfigFiles);
|
||||
|
||||
/* 将主配置文件和扩展配置文件合并在一起。Put the main config file and extension config files together. */
|
||||
$configFiles = array_merge(array($mainConfigFile), $extConfigFiles);
|
||||
$configFiles = $this->getMainAndExtFiles($moduleName, $appName, 'config');
|
||||
if(empty($configFiles)) return false;
|
||||
|
||||
/* 加载每一个配置文件。Load every config file. */
|
||||
static $loadedConfigs = array();
|
||||
@@ -2670,36 +2650,8 @@ class baseRouter
|
||||
*/
|
||||
public function loadLang($moduleName, $appName = '')
|
||||
{
|
||||
/* 初始化变量。Init vars. */
|
||||
$modulePath = $this->getModulePath($appName, $moduleName);
|
||||
$extLangFiles = array();
|
||||
$langFilesToLoad = array();
|
||||
|
||||
/* 判断主语言文件是否存在。Whether the main lang file exists or not. */
|
||||
$mainLangFile = $this->getMainLangFile($moduleName, $appName);
|
||||
if($mainLangFile) $langFilesToLoad[] = $mainLangFile;
|
||||
|
||||
/* 获取扩展语言文件。If extensionLevel > 0, get extension lang files. */
|
||||
if($this->config->framework->extensionLevel > 0)
|
||||
{
|
||||
$commonExtLangFiles = array();
|
||||
$siteExtLangFiles = array();
|
||||
|
||||
$extLangPath = $this->getModuleExtPath($appName, $moduleName, 'lang');
|
||||
if($this->config->framework->extensionLevel >= 1)
|
||||
{
|
||||
if(!empty($extLangPath['common'])) $commonExtLangFiles = helper::ls($extLangPath['common'] . $this->clientLang, '.php');
|
||||
if(!empty($extLangPath['xuan'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['xuan'] . $this->clientLang, '.php'));
|
||||
if(!empty($extLangPath['vision'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['vision'] . $this->clientLang, '.php'));
|
||||
if(!empty($extLangPath['custom'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['custom'] . $this->clientLang, '.php'));
|
||||
if(!empty($extLangPath['saas'])) $commonExtLangFiles = array_merge($commonExtLangFiles, helper::ls($extLangPath['saas'] . $this->clientLang, '.php'));
|
||||
}
|
||||
if($this->config->framework->extensionLevel == 2 and !empty($extLangPath['site'])) $siteExtLangFiles = helper::ls($extLangPath['site'] . $this->clientLang, '.php');
|
||||
$extLangFiles = array_merge($commonExtLangFiles, $siteExtLangFiles);
|
||||
}
|
||||
|
||||
/* 计算最终要加载的语言文件。 Get the lang files to be loaded. */
|
||||
$langFilesToLoad = array_merge($langFilesToLoad, $extLangFiles);
|
||||
$langFilesToLoad = $this->getMainAndExtFiles($moduleName, $appName, 'lang');
|
||||
if(empty($langFilesToLoad)) return false;
|
||||
|
||||
/* 加载语言文件。Load lang files. */
|
||||
@@ -2972,6 +2924,59 @@ class baseRouter
|
||||
{
|
||||
return strtolower(getenv('IS_CONTAINER')) == 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get main file and ext files.
|
||||
*
|
||||
* @param string $moduleName
|
||||
* @param string $appName
|
||||
* @param string $type lang|config|control|model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getMainAndExtFiles($moduleName, $appName = '', $type = 'lang')
|
||||
{
|
||||
/* 初始化变量。Init vars. */
|
||||
$modulePath = $this->getModulePath($appName, $moduleName);
|
||||
$extFiles = array();
|
||||
$filesToLoad = array();
|
||||
|
||||
/* 判断主文件是否存在。Whether the main file exists or not. */
|
||||
if($type == 'lang')
|
||||
{
|
||||
$mainFile = $this->getMainLangFile($moduleName, $appName);
|
||||
}
|
||||
else
|
||||
{
|
||||
$mainFile = $modulePath . $type . '.php';
|
||||
}
|
||||
if($mainFile) $filesToLoad[] = $mainFile;
|
||||
|
||||
/* 获取扩展文件。If extensionLevel > 0, get extension files. */
|
||||
if($this->config->framework->extensionLevel > 0)
|
||||
{
|
||||
$commonExtFiles = array();
|
||||
$siteExtFiles = array();
|
||||
|
||||
$extPath = $this->getModuleExtPath($appName, $moduleName, $type);
|
||||
if($this->config->framework->extensionLevel >= 1)
|
||||
{
|
||||
$client = $type == 'lang' and isset($this->client) ? $this->client : '';
|
||||
if(!empty($extPath['common'])) $commonExtFiles = helper::ls($extPath['common'] . $client, '.php');
|
||||
if(!empty($extPath['xuan'])) $commonExtFiles = array_merge($commonExtFiles, helper::ls($extPath['xuan'] . $client, '.php'));
|
||||
if(!empty($extPath['vision'])) $commonExtFiles = array_merge($commonExtFiles, helper::ls($extPath['vision'] . $client, '.php'));
|
||||
if(!empty($extPath['custom'])) $commonExtFiles = array_merge($commonExtFiles, helper::ls($extPath['custom'] . $client, '.php'));
|
||||
if(!empty($extPath['saas'])) $commonExtFiles = array_merge($commonExtFiles, helper::ls($extPath['saas'] . $client, '.php'));
|
||||
}
|
||||
if($this->config->framework->extensionLevel == 2 and !empty($extPath['site'])) $siteExtFiles = helper::ls($extPath['site'] . $client, '.php');
|
||||
$extFiles = array_merge($commonExtFiles, $siteExtFiles);
|
||||
}
|
||||
|
||||
/* 计算最终要加载的文件。 Get the files to be loaded. */
|
||||
$filesToLoad = array_merge($filesToLoad, $extFiles);
|
||||
if(empty($filesToLoad)) return false;
|
||||
return $filesToLoad;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -111,7 +111,7 @@ class router extends baseRouter
|
||||
/* Replace main nav lang. */
|
||||
if($moduleName == 'common' and $this->dbh and !empty($this->config->db->name))
|
||||
{
|
||||
$customMenus = $this->dbh->query('SELECT * FROM' . TABLE_LANG . "WHERE `module`='common' AND `section`='mainNav' AND `lang`='{$this->clientLang}' AND `vision`='{$this->config->vision}' AND `systemMode`='{$this->config->systemMode}'")->fetchAll();
|
||||
$customMenus = $this->dbh->query('SELECT * FROM' . TABLE_LANG . "WHERE `module`='common' AND `section`='mainNav' AND `lang`='{$this->clientLang}' AND `vision`='{$this->config->vision}'")->fetchAll();
|
||||
foreach($customMenus as $menu)
|
||||
{
|
||||
$menuKey = $menu->key;
|
||||
@@ -297,7 +297,7 @@ class router extends baseRouter
|
||||
}
|
||||
|
||||
/* Replace common lang. */
|
||||
$customMenus = $this->dbh->query('SELECT * FROM' . TABLE_LANG . "WHERE `module`='common' AND `lang`='{$this->clientLang}' AND `section`='' AND `vision`='{$config->vision}' AND `systemMode`='{$config->systemMode}'")->fetchAll();
|
||||
$customMenus = $this->dbh->query('SELECT * FROM' . TABLE_LANG . "WHERE `module`='common' AND `lang`='{$this->clientLang}' AND `section`='' AND `vision`='{$config->vision}'")->fetchAll();
|
||||
foreach($customMenus as $menu) if(isset($lang->{$menu->key})) $lang->{$menu->key} = $menu->value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3556,8 +3556,8 @@ EOD;
|
||||
{
|
||||
if(strpos($moduleName, 'Menu') === false) continue;
|
||||
|
||||
$isSecondMenu = strpos($moduleName, 'subMenu') === false;
|
||||
$moduleName = str_replace($isSecondMenu ? 'Menu' : 'subMenu', '', $moduleName);
|
||||
$isSecondMenu = strpos($moduleName, 'SubMenu') === false;
|
||||
$moduleName = str_replace($isSecondMenu ? 'Menu' : 'SubMenu', '', $moduleName);
|
||||
|
||||
foreach($sectionMenus as $section => $menus)
|
||||
{
|
||||
@@ -3566,7 +3566,7 @@ EOD;
|
||||
/* Get second menu. */
|
||||
if($isSecondMenu)
|
||||
{
|
||||
$isDropMenu = strpos($section, 'dropMenu') !== false;
|
||||
$isDropMenu = strpos($section, 'DropMenu') !== false;
|
||||
if(!$isDropMenu)
|
||||
{
|
||||
if(!isset($lang->{$moduleName}->{$section})) break;
|
||||
@@ -3576,7 +3576,7 @@ EOD;
|
||||
else
|
||||
{
|
||||
/* Get drop menu in second menu. */
|
||||
$dropMenuKey = str_replace('dropMenu', '', $section);
|
||||
$dropMenuKey = str_replace('DropMenu', '', $section);
|
||||
if(!isset($lang->{$moduleName}->menu->{$dropMenuKey}['dropMenu']->{$key})) break;
|
||||
$settingMenu = &$lang->{$moduleName}->menu->{$dropMenuKey}['dropMenu']->{$key};
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class customModel extends model
|
||||
|
||||
try
|
||||
{
|
||||
$sql = $this->dao->select('*')->from(TABLE_LANG)->where('`lang`')->in("$currentLang,all")->andWhere('vision')->eq($this->config->vision)->andWhere('systemMode')->eq($this->config->systemMode)->orderBy('lang,id')->get();
|
||||
$sql = $this->dao->select('*')->from(TABLE_LANG)->where('`lang`')->in("$currentLang,all")->andWhere('vision')->eq($this->config->vision)->orderBy('lang,id')->get();
|
||||
$stmt = $this->dbh->query($sql);
|
||||
|
||||
$allCustomLang = array();
|
||||
|
||||
+34
-3
@@ -89,10 +89,41 @@ class dev extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function langItem($type = 'common')
|
||||
public function langItem($type = 'common', $module = '', $method = '', $language = 'zh_cn')
|
||||
{
|
||||
$this->view->title = $this->lang->langItem;
|
||||
$this->view->type = $type;
|
||||
$language = str_replace('_', '-', $language);
|
||||
$moduleName = $module;
|
||||
if($type == 'common') $moduleName = 'common';
|
||||
if($type == 'second') $moduleName = $module . 'Menu';
|
||||
if($type == 'third') $moduleName = $module . 'subMenu';
|
||||
|
||||
if($_POST)
|
||||
{
|
||||
$section = '';
|
||||
if($type == 'common') $section = '§ion=';
|
||||
if($type == 'first') $section = '§ion=mainNav';
|
||||
$this->loadModel('custom')->deleteItems("lang={$language}&module={$moduleName}&vision={$this->config->vision}{$section}");
|
||||
|
||||
$data = fixer::input('post')->get();
|
||||
foreach($data as $langKey => $customedLang)
|
||||
{
|
||||
if(strpos($langKey, "{$moduleName}_") !== 0) continue;
|
||||
if(empty($customedLang)) continue;
|
||||
|
||||
$this->custom->setItem("{$language}." . str_replace('_', '.', $langKey), $customedLang);
|
||||
}
|
||||
return $this->send(array('result' => 'success', 'locate' => 'reload', 'message' => $this->lang->saveSuccess));
|
||||
}
|
||||
|
||||
$this->dev->loadDefaultLang();
|
||||
|
||||
$this->view->title = $this->lang->langItem;
|
||||
$this->view->type = $type;
|
||||
$this->view->featureBar = $this->lang->dev->featureBar['langItem'];
|
||||
$this->view->originalLangs = $this->dev->getOriginalLang($type, $module, str_replace('_', '-', $language));
|
||||
$this->view->customedLangs = $this->dev->getCustomedLang($type, $module, str_replace('_', '-', $language));
|
||||
$this->view->moduleName = $moduleName;
|
||||
$this->view->language = $language;
|
||||
$this->display();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ $lang->dev->paramMailto = "填写帐号,多个账号用','分隔。";
|
||||
$lang->dev->noteEditor = "编辑器功能因为安全原因被禁用。使用该功能,请到官网下载安装 <a href='https://www.zentao.net/extension-viewExt-150.html' target='_blank'>扩展编辑器</a> 插件。";
|
||||
$lang->dev->noteTranslate = "翻译功能因为安全原因被禁用。使用该功能,请到官网下载安装 <a href='https://www.zentao.net/extension-viewExt-151.html' target='_blank'>翻译</a> 插件。";
|
||||
|
||||
$lang->dev->UR = '用户需求';
|
||||
$lang->dev->SR = '研发需求';
|
||||
|
||||
$lang->dev->fields = array();
|
||||
$lang->dev->fields['id'] = '序号';
|
||||
$lang->dev->fields['name'] = '字段';
|
||||
|
||||
@@ -284,6 +284,38 @@ class devModel extends model
|
||||
return $extPaths;
|
||||
}
|
||||
|
||||
public function getOriginalLang($type, $module = '', $language = 'zh-cn')
|
||||
{
|
||||
$originalLangs = array();
|
||||
if($type == 'common')
|
||||
{
|
||||
$projectKey = (int)$this->loadModel('setting')->getItem('owner=system&key=sprintConcept');
|
||||
$clientLang = $this->app->getClientLang();
|
||||
$originalLangs['productCommon'] = $this->config->productCommonList[$clientLang][PRODUCT_KEY];
|
||||
$originalLangs['projectCommon'] = $this->config->projectCommonList[$clientLang][PROJECT_KEY];
|
||||
$originalLangs['executionCommon'] = $this->config->executionCommonList[$clientLang][$projectKey];
|
||||
$originalLangs['URCommon'] = $this->lang->dev->UR;
|
||||
$originalLangs['SRCommon'] = $this->lang->dev->SR;
|
||||
}
|
||||
|
||||
return $originalLangs;
|
||||
}
|
||||
|
||||
public function getCustomedLang($type, $module = '', $language = 'zh-cn')
|
||||
{
|
||||
$customedLangs = array();
|
||||
$clientLang = $this->app->getClientLang();
|
||||
if($type == 'common')
|
||||
{
|
||||
$customeds = $this->loadModel('custom')->getItems("lang={$clientLang}&module=common§ion=&vision={$this->config->vision}&systemMode={$this->config->systemMode}");
|
||||
foreach($customeds as $customed) $customedLangs[$customed->key] = $customed->value;
|
||||
$customedLangs['URCommon'] = $this->lang->dev->UR == $this->lang->URCommon ? '' : $this->lang->URCommon;
|
||||
$customedLangs['SRCommon'] = $this->lang->dev->SR == $this->lang->SRCommon ? '' : $this->lang->SRCommon;
|
||||
}
|
||||
|
||||
return $customedLangs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim asterisks and whitespace from the beginning and whitespace from the end of lines.
|
||||
*
|
||||
@@ -295,4 +327,37 @@ class devModel extends model
|
||||
{
|
||||
return ltrim(rtrim($line), "* \t\n\r\0\x0B");
|
||||
}
|
||||
|
||||
/**
|
||||
* Load default lang.
|
||||
*
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function loadDefaultLang($language = 'zh-cn')
|
||||
{
|
||||
$clientLang = $this->app->clientLang;
|
||||
if($language != $clientLang) $this->app->clientLang = $language;
|
||||
$langFilesToLoad = $this->app->getMainAndExtFiles('common');
|
||||
if($language != $clientLang) $this->app->clientLang = $clientLang;
|
||||
if(empty($langFilesToLoad)) return false;
|
||||
|
||||
$lang = new language();
|
||||
$lang->URCommon = $this->lang->URCommon;
|
||||
$lang->SRCommon = $this->lang->SRCommon;
|
||||
$lang->productCommon = $this->lang->productCommon;
|
||||
$lang->projectCommon = $this->lang->projectCommon;
|
||||
$lang->executionCommon = $this->lang->executionCommon;
|
||||
if(!isset($lang->common)) $lang->common = new stdclass();
|
||||
|
||||
$loadedLangs = array();
|
||||
foreach($langFilesToLoad as $langFile)
|
||||
{
|
||||
if(in_array($langFile, $loadedLangs)) continue;
|
||||
include $langFile;
|
||||
$loadedLangs[] = $langFile;
|
||||
}
|
||||
|
||||
return $lang;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,6 @@
|
||||
<div id='mainMenu' class='clearfix'>
|
||||
<div class='btn-toolbar pull-left'><?php // common::printAdminSubMenu('dev');?></div>
|
||||
</div>
|
||||
<?php if(isset($tab)):?>
|
||||
<script>$('#mainMenu #<?php echo $tab;?>').addClass('btn-active-text')</script>
|
||||
<?php endif;?>
|
||||
|
||||
@@ -1,48 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* * The editor view file of dev module of ZenTaoPMS.
|
||||
* *
|
||||
* * @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* * @author Yidong Wang <yidong@cnezsoft.com>
|
||||
* * @package dev
|
||||
* * @version $Id$
|
||||
* * @link http://www.zentao.net
|
||||
* */
|
||||
* The editor view file of dev module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Yidong Wang <yidong@cnezsoft.com>
|
||||
* @package dev
|
||||
* @version $Id$
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include 'header.html.php';?>
|
||||
<div id='mainMenu' class='clearfix'>
|
||||
<div class="btn-toolBar pull-left">
|
||||
<?php foreach($lang->dev->featureBar['langItem'] as $key => $label):?>
|
||||
<?php foreach($featureBar as $key => $label):?>
|
||||
<?php $active = $type == $key ? 'btn-active-text' : '';?>
|
||||
<?php $label = "<span class='text'>$label</span>";?>
|
||||
<?php echo html::a(inlink('langItem', "type=$key"), $label, '', "class='btn btn-link $active'");?>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
</div>
|
||||
<div id='mainContent' class='main-content flex'>
|
||||
<div class="side-left">
|
||||
<div class="title">默认值</div>
|
||||
<div class="label-list">
|
||||
<div labelId="123456Input" class="input-label h-32 my-12">项目集</div>
|
||||
<div labelId="223456Input" class="input-label h-32 my-12">产品</div>
|
||||
<form class='main-form form-ajax' method='post'>
|
||||
<div id='mainContent' class='main-content flex'>
|
||||
<div class="side-left">
|
||||
<div class="title">默认值</div>
|
||||
<div class="label-list">
|
||||
<?php foreach($originalLangs as $langKey => $originalLang):?>
|
||||
<div labelId="<?php echo "{$moduleName}_{$langKey}"?>" class="input-label h-32 my-12"><?php echo $originalLang?></div>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="side-right">
|
||||
<div class="title">修改值</div>
|
||||
<div class="input-list">
|
||||
<div class="input-control h-32 my-12">
|
||||
<input id="123456Input" class="form-control shadow-primary-hover" placeholder="项目集"></input>
|
||||
<i iconId="123456Input" class="icon icon-angle-right text-primary hidden"></i>
|
||||
</div>
|
||||
<div class="input-control h-32 my-12">
|
||||
<input id="223456Input" class="form-control shadow-primary-hover" placeholder="产品"></input>
|
||||
<i iconId="223456Input" class="icon icon-angle-right text-primary hidden"></i>
|
||||
</div>
|
||||
<div class="side-right">
|
||||
<div class="title">修改值</div>
|
||||
<div class="input-list">
|
||||
<?php foreach($originalLangs as $langKey => $originalLang):?>
|
||||
<div class="input-control h-32 my-12">
|
||||
<?php
|
||||
$disabled = '';
|
||||
if($type == 'common' and ($langKey == 'URCommon' or $langKey == 'SRCommon')) $disabled = 'disabled';
|
||||
?>
|
||||
<?php echo html::input("{$moduleName}_{$langKey}", zget($customedLangs, $langKey, ''), "class='form-control shadow-primary-hover {$disabled}' {$disabled} placeholder='{$originalLang}'");?>
|
||||
<i iconId="<?php echo "{$moduleName}_{$langKey}"?>" class="icon icon-angle-right text-primary hidden"></i>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="side-main"></div>
|
||||
</div>
|
||||
<div class="side-main">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user