mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix code
This commit is contained in:
parent
ec966de41c
commit
da00aa3969
@ -14,13 +14,16 @@ package org.dromara.hutool.core.io.resource;
|
|||||||
|
|
||||||
import org.dromara.hutool.core.collection.iter.EnumerationIter;
|
import org.dromara.hutool.core.collection.iter.EnumerationIter;
|
||||||
import org.dromara.hutool.core.compress.ZipUtil;
|
import org.dromara.hutool.core.compress.ZipUtil;
|
||||||
|
import org.dromara.hutool.core.exception.HutoolException;
|
||||||
import org.dromara.hutool.core.io.IORuntimeException;
|
import org.dromara.hutool.core.io.IORuntimeException;
|
||||||
import org.dromara.hutool.core.io.IoUtil;
|
import org.dromara.hutool.core.io.IoUtil;
|
||||||
|
import org.dromara.hutool.core.io.file.FileUtil;
|
||||||
import org.dromara.hutool.core.net.url.URLUtil;
|
import org.dromara.hutool.core.net.url.URLUtil;
|
||||||
import org.dromara.hutool.core.text.AntPathMatcher;
|
import org.dromara.hutool.core.text.AntPathMatcher;
|
||||||
import org.dromara.hutool.core.text.CharUtil;
|
import org.dromara.hutool.core.text.CharUtil;
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.JarURLConnection;
|
import java.net.JarURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@ -59,14 +62,18 @@ public class ResourceFinder {
|
|||||||
final MultiResource result = new MultiResource();
|
final MultiResource result = new MultiResource();
|
||||||
// 遍历根目录下所有资源,并过滤保留符合条件的资源
|
// 遍历根目录下所有资源,并过滤保留符合条件的资源
|
||||||
for (final Resource rootResource : ResourceUtil.getResources(rootDirPath, classLoader)) {
|
for (final Resource rootResource : ResourceUtil.getResources(rootDirPath, classLoader)) {
|
||||||
if (URLUtil.isJarURL(rootResource.getUrl())) {
|
if (rootResource instanceof JarResource) {
|
||||||
|
// 在jar包中
|
||||||
try {
|
try {
|
||||||
result.addAll(findInJar(rootResource, subPattern));
|
result.addAll(findInJar((JarResource) rootResource, subPattern));
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
throw new IORuntimeException(e);
|
throw new IORuntimeException(e);
|
||||||
}
|
}
|
||||||
|
} else if (rootResource instanceof FileResource) {
|
||||||
|
// 文件夹中
|
||||||
|
result.addAll(findInDir((FileResource) rootResource, subPattern));
|
||||||
} else {
|
} else {
|
||||||
result.addAll(findInDir(rootResource, subPattern));
|
throw new HutoolException("Unsupported resource type: {}", rootResource.getClass().getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,12 +88,11 @@ public class ResourceFinder {
|
|||||||
* @return 符合条件的资源
|
* @return 符合条件的资源
|
||||||
* @throws IOException IO异常
|
* @throws IOException IO异常
|
||||||
*/
|
*/
|
||||||
protected MultiResource findInJar(final Resource rootResource, final String subPattern) throws IOException {
|
protected MultiResource findInJar(final JarResource rootResource, final String subPattern) throws IOException {
|
||||||
final URL rootDirURL = rootResource.getUrl();
|
final URL rootDirURL = rootResource.getUrl();
|
||||||
final URLConnection conn = rootDirURL.openConnection();
|
final URLConnection conn = rootDirURL.openConnection();
|
||||||
|
|
||||||
final JarFile jarFile;
|
final JarFile jarFile;
|
||||||
final String jarFileUrl;
|
|
||||||
String rootEntryPath;
|
String rootEntryPath;
|
||||||
final boolean closeJarFile;
|
final boolean closeJarFile;
|
||||||
|
|
||||||
@ -98,7 +104,7 @@ public class ResourceFinder {
|
|||||||
rootEntryPath = (jarEntry != null ? jarEntry.getName() : StrUtil.EMPTY);
|
rootEntryPath = (jarEntry != null ? jarEntry.getName() : StrUtil.EMPTY);
|
||||||
closeJarFile = !jarCon.getUseCaches();
|
closeJarFile = !jarCon.getUseCaches();
|
||||||
} else {
|
} else {
|
||||||
//
|
// 去除子路径后重新获取jar文件
|
||||||
final String urlFile = rootDirURL.getFile();
|
final String urlFile = rootDirURL.getFile();
|
||||||
try {
|
try {
|
||||||
int separatorIndex = urlFile.indexOf(URLUtil.WAR_URL_SEPARATOR);
|
int separatorIndex = urlFile.indexOf(URLUtil.WAR_URL_SEPARATOR);
|
||||||
@ -106,7 +112,7 @@ public class ResourceFinder {
|
|||||||
separatorIndex = urlFile.indexOf(URLUtil.JAR_URL_SEPARATOR);
|
separatorIndex = urlFile.indexOf(URLUtil.JAR_URL_SEPARATOR);
|
||||||
}
|
}
|
||||||
if (separatorIndex != -1) {
|
if (separatorIndex != -1) {
|
||||||
jarFileUrl = urlFile.substring(0, separatorIndex);
|
final String jarFileUrl = urlFile.substring(0, separatorIndex);
|
||||||
rootEntryPath = urlFile.substring(separatorIndex + 2); // both separators are 2 chars
|
rootEntryPath = urlFile.substring(separatorIndex + 2); // both separators are 2 chars
|
||||||
jarFile = ZipUtil.ofJar(jarFileUrl);
|
jarFile = ZipUtil.ofJar(jarFileUrl);
|
||||||
} else {
|
} else {
|
||||||
@ -130,7 +136,7 @@ public class ResourceFinder {
|
|||||||
if (entryPath.startsWith(rootEntryPath)) {
|
if (entryPath.startsWith(rootEntryPath)) {
|
||||||
final String relativePath = entryPath.substring(rootEntryPath.length());
|
final String relativePath = entryPath.substring(rootEntryPath.length());
|
||||||
if (pathMatcher.match(subPattern, relativePath)) {
|
if (pathMatcher.match(subPattern, relativePath)) {
|
||||||
result.add(new UrlResource(URLUtil.getURL(rootDirURL, relativePath)));
|
result.add(ResourceUtil.getResource(URLUtil.getURL(rootDirURL, relativePath)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,8 +149,23 @@ public class ResourceFinder {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MultiResource findInDir(final Resource rootResource, final String subPattern) {
|
/**
|
||||||
|
* 遍历目录查找指定表达式匹配的文件列表
|
||||||
|
*
|
||||||
|
* @param resource 文件资源
|
||||||
|
* @param subPattern 子表达式
|
||||||
|
* @return 满足条件的文件
|
||||||
|
*/
|
||||||
|
protected MultiResource findInDir(final FileResource resource, final String subPattern) {
|
||||||
|
final MultiResource result = new MultiResource();
|
||||||
|
final File rootDir = resource.getFile();
|
||||||
|
FileUtil.walkFiles(rootDir, (file -> {
|
||||||
|
if (pathMatcher.match(subPattern, file.getName())) {
|
||||||
|
result.add(new FileResource(file));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +17,7 @@ import org.dromara.hutool.core.collection.iter.IterUtil;
|
|||||||
import org.dromara.hutool.core.io.file.FileUtil;
|
import org.dromara.hutool.core.io.file.FileUtil;
|
||||||
import org.dromara.hutool.core.io.IORuntimeException;
|
import org.dromara.hutool.core.io.IORuntimeException;
|
||||||
import org.dromara.hutool.core.lang.Assert;
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
|
import org.dromara.hutool.core.net.url.UrlProtocolUtil;
|
||||||
import org.dromara.hutool.core.util.CharsetUtil;
|
import org.dromara.hutool.core.util.CharsetUtil;
|
||||||
import org.dromara.hutool.core.classloader.ClassLoaderUtil;
|
import org.dromara.hutool.core.classloader.ClassLoaderUtil;
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
@ -253,6 +254,11 @@ public class ResourceUtil {
|
|||||||
* @since 6.0.0
|
* @since 6.0.0
|
||||||
*/
|
*/
|
||||||
public static Resource getResource(final URL url) {
|
public static Resource getResource(final URL url) {
|
||||||
|
if(UrlProtocolUtil.isJarURL(url)){
|
||||||
|
return new JarResource(url);
|
||||||
|
} else if(UrlProtocolUtil.isFileURL(url)){
|
||||||
|
return new FileResource(url.getFile());
|
||||||
|
}
|
||||||
return new UrlResource(url);
|
return new UrlResource(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ package org.dromara.hutool.core.io.resource;
|
|||||||
import org.dromara.hutool.core.io.file.FileNameUtil;
|
import org.dromara.hutool.core.io.file.FileNameUtil;
|
||||||
import org.dromara.hutool.core.io.file.FileUtil;
|
import org.dromara.hutool.core.io.file.FileUtil;
|
||||||
import org.dromara.hutool.core.net.url.URLUtil;
|
import org.dromara.hutool.core.net.url.URLUtil;
|
||||||
|
import org.dromara.hutool.core.net.url.UrlProtocolUtil;
|
||||||
import org.dromara.hutool.core.util.ObjUtil;
|
import org.dromara.hutool.core.util.ObjUtil;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -64,7 +65,7 @@ public class UrlResource implements Resource, Serializable {
|
|||||||
*/
|
*/
|
||||||
public UrlResource(final URL url, final String name) {
|
public UrlResource(final URL url, final String name) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
if (null != url && URLUtil.URL_PROTOCOL_FILE.equals(url.getProtocol())) {
|
if (null != url && UrlProtocolUtil.URL_PROTOCOL_FILE.equals(url.getProtocol())) {
|
||||||
this.lastModified = FileUtil.file(url).lastModified();
|
this.lastModified = FileUtil.file(url).lastModified();
|
||||||
}
|
}
|
||||||
this.name = ObjUtil.defaultIfNull(name, () -> (null != url ? FileNameUtil.getName(url.getPath()) : null));
|
this.name = ObjUtil.defaultIfNull(name, () -> (null != url ? FileNameUtil.getName(url.getPath()) : null));
|
||||||
|
@ -16,7 +16,6 @@ import org.dromara.hutool.core.classloader.ClassLoaderUtil;
|
|||||||
import org.dromara.hutool.core.exception.HutoolException;
|
import org.dromara.hutool.core.exception.HutoolException;
|
||||||
import org.dromara.hutool.core.io.IORuntimeException;
|
import org.dromara.hutool.core.io.IORuntimeException;
|
||||||
import org.dromara.hutool.core.io.IoUtil;
|
import org.dromara.hutool.core.io.IoUtil;
|
||||||
import org.dromara.hutool.core.io.file.FileNameUtil;
|
|
||||||
import org.dromara.hutool.core.io.file.FileUtil;
|
import org.dromara.hutool.core.io.file.FileUtil;
|
||||||
import org.dromara.hutool.core.io.resource.ResourceUtil;
|
import org.dromara.hutool.core.io.resource.ResourceUtil;
|
||||||
import org.dromara.hutool.core.lang.Assert;
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
@ -64,34 +63,6 @@ public class URLUtil {
|
|||||||
* URL 前缀表示war: "war:"
|
* URL 前缀表示war: "war:"
|
||||||
*/
|
*/
|
||||||
public static final String WAR_URL_PREFIX = "war:";
|
public static final String WAR_URL_PREFIX = "war:";
|
||||||
/**
|
|
||||||
* URL 协议表示文件: "file"
|
|
||||||
*/
|
|
||||||
public static final String URL_PROTOCOL_FILE = "file";
|
|
||||||
/**
|
|
||||||
* URL 协议表示Jar文件: "jar"
|
|
||||||
*/
|
|
||||||
public static final String URL_PROTOCOL_JAR = "jar";
|
|
||||||
/**
|
|
||||||
* URL 协议表示zip文件: "zip"
|
|
||||||
*/
|
|
||||||
public static final String URL_PROTOCOL_ZIP = "zip";
|
|
||||||
/**
|
|
||||||
* URL 协议表示WebSphere文件: "wsjar"
|
|
||||||
*/
|
|
||||||
public static final String URL_PROTOCOL_WSJAR = "wsjar";
|
|
||||||
/**
|
|
||||||
* URL 协议表示JBoss zip文件: "vfszip"
|
|
||||||
*/
|
|
||||||
public static final String URL_PROTOCOL_VFSZIP = "vfszip";
|
|
||||||
/**
|
|
||||||
* URL 协议表示JBoss文件: "vfsfile"
|
|
||||||
*/
|
|
||||||
public static final String URL_PROTOCOL_VFSFILE = "vfsfile";
|
|
||||||
/**
|
|
||||||
* URL 协议表示JBoss VFS资源: "vfs"
|
|
||||||
*/
|
|
||||||
public static final String URL_PROTOCOL_VFS = "vfs";
|
|
||||||
/**
|
/**
|
||||||
* Jar路径以及内部文件路径的分界符: "!/"
|
* Jar路径以及内部文件路径的分界符: "!/"
|
||||||
*/
|
*/
|
||||||
@ -429,50 +400,6 @@ public class URLUtil {
|
|||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
/**
|
|
||||||
* 提供的URL是否为文件<br>
|
|
||||||
* 文件协议包括"file", "vfsfile" 或 "vfs".
|
|
||||||
*
|
|
||||||
* @param url {@link URL}
|
|
||||||
* @return 是否为文件
|
|
||||||
* @since 3.0.9
|
|
||||||
*/
|
|
||||||
public static boolean isFileURL(final URL url) {
|
|
||||||
Assert.notNull(url, "URL must be not null");
|
|
||||||
final String protocol = url.getProtocol();
|
|
||||||
return (URL_PROTOCOL_FILE.equals(protocol) || //
|
|
||||||
URL_PROTOCOL_VFSFILE.equals(protocol) || //
|
|
||||||
URL_PROTOCOL_VFS.equals(protocol));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提供的URL是否为jar包URL 协议包括: "jar", "zip", "vfszip" 或 "wsjar".
|
|
||||||
*
|
|
||||||
* @param url {@link URL}
|
|
||||||
* @return 是否为jar包URL
|
|
||||||
*/
|
|
||||||
public static boolean isJarURL(final URL url) {
|
|
||||||
Assert.notNull(url, "URL must be not null");
|
|
||||||
final String protocol = url.getProtocol();
|
|
||||||
return (URL_PROTOCOL_JAR.equals(protocol) || //
|
|
||||||
URL_PROTOCOL_ZIP.equals(protocol) || //
|
|
||||||
URL_PROTOCOL_VFSZIP.equals(protocol) || //
|
|
||||||
URL_PROTOCOL_WSJAR.equals(protocol));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提供的URL是否为Jar文件URL 判断依据为file协议且扩展名为.jar
|
|
||||||
*
|
|
||||||
* @param url the URL to check
|
|
||||||
* @return whether the URL has been identified as a JAR file URL
|
|
||||||
* @since 4.1
|
|
||||||
*/
|
|
||||||
public static boolean isJarFileURL(final URL url) {
|
|
||||||
Assert.notNull(url, "URL must be not null");
|
|
||||||
return (URL_PROTOCOL_FILE.equals(url.getProtocol()) && //
|
|
||||||
url.getPath().toLowerCase().endsWith(FileNameUtil.EXT_JAR));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从URL中获取流
|
* 从URL中获取流
|
||||||
*
|
*
|
||||||
@ -704,7 +631,7 @@ public class URLUtil {
|
|||||||
* @since 6.0.0
|
* @since 6.0.0
|
||||||
*/
|
*/
|
||||||
public static long size(final URL url) {
|
public static long size(final URL url) {
|
||||||
if (URLUtil.isFileURL(url)) {
|
if (UrlProtocolUtil.isFileOrVfsURL(url)) {
|
||||||
// 如果资源以独立文件形式存在,尝试获取文件长度
|
// 如果资源以独立文件形式存在,尝试获取文件长度
|
||||||
final File file = FileUtil.file(url);
|
final File file = FileUtil.file(url);
|
||||||
final long length = file.length();
|
final long length = file.length();
|
||||||
|
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023. looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* https://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.dromara.hutool.core.net.url;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.io.file.FileNameUtil;
|
||||||
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class UrlProtocolUtil {
|
||||||
|
/**
|
||||||
|
* URL 协议表示文件: "file"
|
||||||
|
*/
|
||||||
|
public static final String URL_PROTOCOL_FILE = "file";
|
||||||
|
/**
|
||||||
|
* URL 协议表示Jar文件: "jar"
|
||||||
|
*/
|
||||||
|
public static final String URL_PROTOCOL_JAR = "jar";
|
||||||
|
/**
|
||||||
|
* URL 协议表示zip文件: "zip"
|
||||||
|
*/
|
||||||
|
public static final String URL_PROTOCOL_ZIP = "zip";
|
||||||
|
/**
|
||||||
|
* URL 协议表示WebSphere文件: "wsjar"
|
||||||
|
*/
|
||||||
|
public static final String URL_PROTOCOL_WSJAR = "wsjar";
|
||||||
|
/**
|
||||||
|
* URL 协议表示JBoss zip文件: "vfszip"
|
||||||
|
*/
|
||||||
|
public static final String URL_PROTOCOL_VFSZIP = "vfszip";
|
||||||
|
/**
|
||||||
|
* URL 协议表示JBoss文件: "vfsfile"
|
||||||
|
*/
|
||||||
|
public static final String URL_PROTOCOL_VFSFILE = "vfsfile";
|
||||||
|
/**
|
||||||
|
* URL 协议表示JBoss VFS资源: "vfs"
|
||||||
|
*/
|
||||||
|
public static final String URL_PROTOCOL_VFS = "vfs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供的URL是否为文件<br>
|
||||||
|
* 文件协议包括"file", "vfsfile" 或 "vfs".
|
||||||
|
*
|
||||||
|
* @param url {@link URL}
|
||||||
|
* @return 是否为文件
|
||||||
|
* @since 3.0.9
|
||||||
|
*/
|
||||||
|
public static boolean isFileOrVfsURL(final URL url) {
|
||||||
|
Assert.notNull(url, "URL must be not null");
|
||||||
|
return isFileURL(url) || isVfsURL(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供的URL是否为文件<br>
|
||||||
|
* 文件协议包括"file".
|
||||||
|
*
|
||||||
|
* @param url {@link URL}
|
||||||
|
* @return 是否为文件
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static boolean isFileURL(final URL url) {
|
||||||
|
Assert.notNull(url, "URL must be not null");
|
||||||
|
final String protocol = url.getProtocol();
|
||||||
|
return URL_PROTOCOL_FILE.equals(protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供的URL是否为文件<br>
|
||||||
|
* 文件协议包括"vfsfile" 或 "vfs".
|
||||||
|
*
|
||||||
|
* @param url {@link URL}
|
||||||
|
* @return 是否为文件
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static boolean isVfsURL(final URL url) {
|
||||||
|
Assert.notNull(url, "URL must be not null");
|
||||||
|
final String protocol = url.getProtocol();
|
||||||
|
return (URL_PROTOCOL_VFSFILE.equals(protocol) || //
|
||||||
|
URL_PROTOCOL_VFS.equals(protocol));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供的URL是否为jar包URL 协议包括: "jar", "zip", "vfszip" 或 "wsjar".
|
||||||
|
*
|
||||||
|
* @param url {@link URL}
|
||||||
|
* @return 是否为jar包URL
|
||||||
|
*/
|
||||||
|
public static boolean isJarURL(final URL url) {
|
||||||
|
Assert.notNull(url, "URL must be not null");
|
||||||
|
final String protocol = url.getProtocol();
|
||||||
|
return (URL_PROTOCOL_JAR.equals(protocol) || //
|
||||||
|
URL_PROTOCOL_ZIP.equals(protocol) || //
|
||||||
|
URL_PROTOCOL_VFSZIP.equals(protocol) || //
|
||||||
|
URL_PROTOCOL_WSJAR.equals(protocol));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供的URL是否为Jar文件URL 判断依据为file协议且扩展名为.jar
|
||||||
|
*
|
||||||
|
* @param url the URL to check
|
||||||
|
* @return whether the URL has been identified as a JAR file URL
|
||||||
|
* @since 4.1
|
||||||
|
*/
|
||||||
|
public static boolean isJarFileURL(final URL url) {
|
||||||
|
Assert.notNull(url, "URL must be not null");
|
||||||
|
return (URL_PROTOCOL_FILE.equals(url.getProtocol()) && //
|
||||||
|
url.getPath().toLowerCase().endsWith(FileNameUtil.EXT_JAR));
|
||||||
|
}
|
||||||
|
}
|
@ -190,7 +190,7 @@ public final class Props extends Properties implements TypeGetter<CharSequence>
|
|||||||
* @since 5.5.2
|
* @since 5.5.2
|
||||||
*/
|
*/
|
||||||
public void load(final URL url) {
|
public void load(final URL url) {
|
||||||
load(new UrlResource(url));
|
load(ResourceUtil.getResource(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user