mirror of
https://github.com/langgenius/dify.git
synced 2026-01-08 07:14:14 +00:00
chore: adopt StrEnum and auto() for some string-typed enums (#25129)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
This commit is contained in:
@@ -42,7 +42,7 @@ class TestAdvancedPromptTemplateService:
|
||||
|
||||
# Test data for Baichuan model
|
||||
args = {
|
||||
"app_mode": AppMode.CHAT.value,
|
||||
"app_mode": AppMode.CHAT,
|
||||
"model_mode": "completion",
|
||||
"model_name": "baichuan-13b-chat",
|
||||
"has_context": "true",
|
||||
@@ -77,7 +77,7 @@ class TestAdvancedPromptTemplateService:
|
||||
|
||||
# Test data for common model
|
||||
args = {
|
||||
"app_mode": AppMode.CHAT.value,
|
||||
"app_mode": AppMode.CHAT,
|
||||
"model_mode": "completion",
|
||||
"model_name": "gpt-3.5-turbo",
|
||||
"has_context": "true",
|
||||
@@ -116,7 +116,7 @@ class TestAdvancedPromptTemplateService:
|
||||
|
||||
for model_name in test_cases:
|
||||
args = {
|
||||
"app_mode": AppMode.CHAT.value,
|
||||
"app_mode": AppMode.CHAT,
|
||||
"model_mode": "completion",
|
||||
"model_name": model_name,
|
||||
"has_context": "true",
|
||||
@@ -144,7 +144,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Act: Execute the method under test
|
||||
result = AdvancedPromptTemplateService.get_common_prompt(AppMode.CHAT.value, "completion", "true")
|
||||
result = AdvancedPromptTemplateService.get_common_prompt(AppMode.CHAT, "completion", "true")
|
||||
|
||||
# Assert: Verify the expected outcomes
|
||||
assert result is not None
|
||||
@@ -173,7 +173,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Act: Execute the method under test
|
||||
result = AdvancedPromptTemplateService.get_common_prompt(AppMode.CHAT.value, "chat", "true")
|
||||
result = AdvancedPromptTemplateService.get_common_prompt(AppMode.CHAT, "chat", "true")
|
||||
|
||||
# Assert: Verify the expected outcomes
|
||||
assert result is not None
|
||||
@@ -202,7 +202,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Act: Execute the method under test
|
||||
result = AdvancedPromptTemplateService.get_common_prompt(AppMode.COMPLETION.value, "completion", "true")
|
||||
result = AdvancedPromptTemplateService.get_common_prompt(AppMode.COMPLETION, "completion", "true")
|
||||
|
||||
# Assert: Verify the expected outcomes
|
||||
assert result is not None
|
||||
@@ -230,7 +230,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Act: Execute the method under test
|
||||
result = AdvancedPromptTemplateService.get_common_prompt(AppMode.COMPLETION.value, "chat", "true")
|
||||
result = AdvancedPromptTemplateService.get_common_prompt(AppMode.COMPLETION, "chat", "true")
|
||||
|
||||
# Assert: Verify the expected outcomes
|
||||
assert result is not None
|
||||
@@ -257,7 +257,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Act: Execute the method under test
|
||||
result = AdvancedPromptTemplateService.get_common_prompt(AppMode.CHAT.value, "completion", "false")
|
||||
result = AdvancedPromptTemplateService.get_common_prompt(AppMode.CHAT, "completion", "false")
|
||||
|
||||
# Assert: Verify the expected outcomes
|
||||
assert result is not None
|
||||
@@ -303,7 +303,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Act: Execute the method under test
|
||||
result = AdvancedPromptTemplateService.get_common_prompt(AppMode.CHAT.value, "unsupported_mode", "true")
|
||||
result = AdvancedPromptTemplateService.get_common_prompt(AppMode.CHAT, "unsupported_mode", "true")
|
||||
|
||||
# Assert: Verify empty dict is returned
|
||||
assert result == {}
|
||||
@@ -442,7 +442,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Act: Execute the method under test
|
||||
result = AdvancedPromptTemplateService.get_baichuan_prompt(AppMode.CHAT.value, "completion", "true")
|
||||
result = AdvancedPromptTemplateService.get_baichuan_prompt(AppMode.CHAT, "completion", "true")
|
||||
|
||||
# Assert: Verify the expected outcomes
|
||||
assert result is not None
|
||||
@@ -473,7 +473,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Act: Execute the method under test
|
||||
result = AdvancedPromptTemplateService.get_baichuan_prompt(AppMode.CHAT.value, "chat", "true")
|
||||
result = AdvancedPromptTemplateService.get_baichuan_prompt(AppMode.CHAT, "chat", "true")
|
||||
|
||||
# Assert: Verify the expected outcomes
|
||||
assert result is not None
|
||||
@@ -502,7 +502,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Act: Execute the method under test
|
||||
result = AdvancedPromptTemplateService.get_baichuan_prompt(AppMode.COMPLETION.value, "completion", "true")
|
||||
result = AdvancedPromptTemplateService.get_baichuan_prompt(AppMode.COMPLETION, "completion", "true")
|
||||
|
||||
# Assert: Verify the expected outcomes
|
||||
assert result is not None
|
||||
@@ -530,7 +530,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Act: Execute the method under test
|
||||
result = AdvancedPromptTemplateService.get_baichuan_prompt(AppMode.COMPLETION.value, "chat", "true")
|
||||
result = AdvancedPromptTemplateService.get_baichuan_prompt(AppMode.COMPLETION, "chat", "true")
|
||||
|
||||
# Assert: Verify the expected outcomes
|
||||
assert result is not None
|
||||
@@ -557,7 +557,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Act: Execute the method under test
|
||||
result = AdvancedPromptTemplateService.get_baichuan_prompt(AppMode.CHAT.value, "completion", "false")
|
||||
result = AdvancedPromptTemplateService.get_baichuan_prompt(AppMode.CHAT, "completion", "false")
|
||||
|
||||
# Assert: Verify the expected outcomes
|
||||
assert result is not None
|
||||
@@ -603,7 +603,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Act: Execute the method under test
|
||||
result = AdvancedPromptTemplateService.get_baichuan_prompt(AppMode.CHAT.value, "unsupported_mode", "true")
|
||||
result = AdvancedPromptTemplateService.get_baichuan_prompt(AppMode.CHAT, "unsupported_mode", "true")
|
||||
|
||||
# Assert: Verify empty dict is returned
|
||||
assert result == {}
|
||||
@@ -621,7 +621,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Test all app modes
|
||||
app_modes = [AppMode.CHAT.value, AppMode.COMPLETION.value]
|
||||
app_modes = [AppMode.CHAT, AppMode.COMPLETION]
|
||||
model_modes = ["completion", "chat"]
|
||||
|
||||
for app_mode in app_modes:
|
||||
@@ -653,7 +653,7 @@ class TestAdvancedPromptTemplateService:
|
||||
fake = Faker()
|
||||
|
||||
# Test all app modes
|
||||
app_modes = [AppMode.CHAT.value, AppMode.COMPLETION.value]
|
||||
app_modes = [AppMode.CHAT, AppMode.COMPLETION]
|
||||
model_modes = ["completion", "chat"]
|
||||
|
||||
for app_mode in app_modes:
|
||||
@@ -686,10 +686,10 @@ class TestAdvancedPromptTemplateService:
|
||||
# Test edge cases
|
||||
edge_cases = [
|
||||
{"app_mode": "", "model_mode": "completion", "model_name": "gpt-3.5-turbo", "has_context": "true"},
|
||||
{"app_mode": AppMode.CHAT.value, "model_mode": "", "model_name": "gpt-3.5-turbo", "has_context": "true"},
|
||||
{"app_mode": AppMode.CHAT.value, "model_mode": "completion", "model_name": "", "has_context": "true"},
|
||||
{"app_mode": AppMode.CHAT, "model_mode": "", "model_name": "gpt-3.5-turbo", "has_context": "true"},
|
||||
{"app_mode": AppMode.CHAT, "model_mode": "completion", "model_name": "", "has_context": "true"},
|
||||
{
|
||||
"app_mode": AppMode.CHAT.value,
|
||||
"app_mode": AppMode.CHAT,
|
||||
"model_mode": "completion",
|
||||
"model_name": "gpt-3.5-turbo",
|
||||
"has_context": "",
|
||||
@@ -723,7 +723,7 @@ class TestAdvancedPromptTemplateService:
|
||||
|
||||
# Test with context
|
||||
args = {
|
||||
"app_mode": AppMode.CHAT.value,
|
||||
"app_mode": AppMode.CHAT,
|
||||
"model_mode": "completion",
|
||||
"model_name": "gpt-3.5-turbo",
|
||||
"has_context": "true",
|
||||
@@ -757,7 +757,7 @@ class TestAdvancedPromptTemplateService:
|
||||
|
||||
# Test with context
|
||||
args = {
|
||||
"app_mode": AppMode.CHAT.value,
|
||||
"app_mode": AppMode.CHAT,
|
||||
"model_mode": "completion",
|
||||
"model_name": "baichuan-13b-chat",
|
||||
"has_context": "true",
|
||||
@@ -786,25 +786,25 @@ class TestAdvancedPromptTemplateService:
|
||||
# Test different scenarios
|
||||
test_scenarios = [
|
||||
{
|
||||
"app_mode": AppMode.CHAT.value,
|
||||
"app_mode": AppMode.CHAT,
|
||||
"model_mode": "completion",
|
||||
"model_name": "gpt-3.5-turbo",
|
||||
"has_context": "true",
|
||||
},
|
||||
{
|
||||
"app_mode": AppMode.CHAT.value,
|
||||
"app_mode": AppMode.CHAT,
|
||||
"model_mode": "chat",
|
||||
"model_name": "gpt-3.5-turbo",
|
||||
"has_context": "true",
|
||||
},
|
||||
{
|
||||
"app_mode": AppMode.COMPLETION.value,
|
||||
"app_mode": AppMode.COMPLETION,
|
||||
"model_mode": "completion",
|
||||
"model_name": "gpt-3.5-turbo",
|
||||
"has_context": "true",
|
||||
},
|
||||
{
|
||||
"app_mode": AppMode.COMPLETION.value,
|
||||
"app_mode": AppMode.COMPLETION,
|
||||
"model_mode": "chat",
|
||||
"model_name": "gpt-3.5-turbo",
|
||||
"has_context": "true",
|
||||
@@ -843,25 +843,25 @@ class TestAdvancedPromptTemplateService:
|
||||
# Test different scenarios
|
||||
test_scenarios = [
|
||||
{
|
||||
"app_mode": AppMode.CHAT.value,
|
||||
"app_mode": AppMode.CHAT,
|
||||
"model_mode": "completion",
|
||||
"model_name": "baichuan-13b-chat",
|
||||
"has_context": "true",
|
||||
},
|
||||
{
|
||||
"app_mode": AppMode.CHAT.value,
|
||||
"app_mode": AppMode.CHAT,
|
||||
"model_mode": "chat",
|
||||
"model_name": "baichuan-13b-chat",
|
||||
"has_context": "true",
|
||||
},
|
||||
{
|
||||
"app_mode": AppMode.COMPLETION.value,
|
||||
"app_mode": AppMode.COMPLETION,
|
||||
"model_mode": "completion",
|
||||
"model_name": "baichuan-13b-chat",
|
||||
"has_context": "true",
|
||||
},
|
||||
{
|
||||
"app_mode": AppMode.COMPLETION.value,
|
||||
"app_mode": AppMode.COMPLETION,
|
||||
"model_mode": "chat",
|
||||
"model_name": "baichuan-13b-chat",
|
||||
"has_context": "true",
|
||||
|
||||
@@ -255,7 +255,7 @@ class TestMetadataService:
|
||||
mock_external_service_dependencies["current_user"].id = account.id
|
||||
|
||||
# Try to create metadata with built-in field name
|
||||
built_in_field_name = BuiltInField.document_name.value
|
||||
built_in_field_name = BuiltInField.document_name
|
||||
metadata_args = MetadataArgs(type="string", name=built_in_field_name)
|
||||
|
||||
# Act & Assert: Verify proper error handling
|
||||
@@ -375,7 +375,7 @@ class TestMetadataService:
|
||||
metadata = MetadataService.create_metadata(dataset.id, metadata_args)
|
||||
|
||||
# Try to update with built-in field name
|
||||
built_in_field_name = BuiltInField.document_name.value
|
||||
built_in_field_name = BuiltInField.document_name
|
||||
|
||||
with pytest.raises(ValueError, match="Metadata name already exists in Built-in fields."):
|
||||
MetadataService.update_metadata_name(dataset.id, metadata.id, built_in_field_name)
|
||||
@@ -540,11 +540,11 @@ class TestMetadataService:
|
||||
field_names = [field["name"] for field in result]
|
||||
field_types = [field["type"] for field in result]
|
||||
|
||||
assert BuiltInField.document_name.value in field_names
|
||||
assert BuiltInField.uploader.value in field_names
|
||||
assert BuiltInField.upload_date.value in field_names
|
||||
assert BuiltInField.last_update_date.value in field_names
|
||||
assert BuiltInField.source.value in field_names
|
||||
assert BuiltInField.document_name in field_names
|
||||
assert BuiltInField.uploader in field_names
|
||||
assert BuiltInField.upload_date in field_names
|
||||
assert BuiltInField.last_update_date in field_names
|
||||
assert BuiltInField.source in field_names
|
||||
|
||||
# Verify field types
|
||||
assert "string" in field_types
|
||||
@@ -682,11 +682,11 @@ class TestMetadataService:
|
||||
|
||||
# Set document metadata with built-in fields
|
||||
document.doc_metadata = {
|
||||
BuiltInField.document_name.value: document.name,
|
||||
BuiltInField.uploader.value: "test_uploader",
|
||||
BuiltInField.upload_date.value: 1234567890.0,
|
||||
BuiltInField.last_update_date.value: 1234567890.0,
|
||||
BuiltInField.source.value: "test_source",
|
||||
BuiltInField.document_name: document.name,
|
||||
BuiltInField.uploader: "test_uploader",
|
||||
BuiltInField.upload_date: 1234567890.0,
|
||||
BuiltInField.last_update_date: 1234567890.0,
|
||||
BuiltInField.source: "test_source",
|
||||
}
|
||||
db.session.add(document)
|
||||
db.session.commit()
|
||||
|
||||
@@ -96,7 +96,7 @@ class TestWorkflowService:
|
||||
app.tenant_id = fake.uuid4()
|
||||
app.name = fake.company()
|
||||
app.description = fake.text()
|
||||
app.mode = AppMode.WORKFLOW.value
|
||||
app.mode = AppMode.WORKFLOW
|
||||
app.icon_type = "emoji"
|
||||
app.icon = "🤖"
|
||||
app.icon_background = "#FFEAD5"
|
||||
@@ -883,7 +883,7 @@ class TestWorkflowService:
|
||||
|
||||
# Create chat mode app
|
||||
app = self._create_test_app(db_session_with_containers, fake)
|
||||
app.mode = AppMode.CHAT.value
|
||||
app.mode = AppMode.CHAT
|
||||
|
||||
# Create app model config (required for conversion)
|
||||
from models.model import AppModelConfig
|
||||
@@ -926,7 +926,7 @@ class TestWorkflowService:
|
||||
|
||||
# Assert
|
||||
assert result is not None
|
||||
assert result.mode == AppMode.ADVANCED_CHAT.value # CHAT mode converts to ADVANCED_CHAT, not WORKFLOW
|
||||
assert result.mode == AppMode.ADVANCED_CHAT # CHAT mode converts to ADVANCED_CHAT, not WORKFLOW
|
||||
assert result.name == conversion_args["name"]
|
||||
assert result.icon == conversion_args["icon"]
|
||||
assert result.icon_type == conversion_args["icon_type"]
|
||||
@@ -945,7 +945,7 @@ class TestWorkflowService:
|
||||
|
||||
# Create completion mode app
|
||||
app = self._create_test_app(db_session_with_containers, fake)
|
||||
app.mode = AppMode.COMPLETION.value
|
||||
app.mode = AppMode.COMPLETION
|
||||
|
||||
# Create app model config (required for conversion)
|
||||
from models.model import AppModelConfig
|
||||
@@ -988,7 +988,7 @@ class TestWorkflowService:
|
||||
|
||||
# Assert
|
||||
assert result is not None
|
||||
assert result.mode == AppMode.WORKFLOW.value
|
||||
assert result.mode == AppMode.WORKFLOW
|
||||
assert result.name == conversion_args["name"]
|
||||
assert result.icon == conversion_args["icon"]
|
||||
assert result.icon_type == conversion_args["icon_type"]
|
||||
@@ -1007,7 +1007,7 @@ class TestWorkflowService:
|
||||
|
||||
# Create workflow mode app (already in workflow mode)
|
||||
app = self._create_test_app(db_session_with_containers, fake)
|
||||
app.mode = AppMode.WORKFLOW.value
|
||||
app.mode = AppMode.WORKFLOW
|
||||
|
||||
from extensions.ext_database import db
|
||||
|
||||
@@ -1030,7 +1030,7 @@ class TestWorkflowService:
|
||||
# Arrange
|
||||
fake = Faker()
|
||||
app = self._create_test_app(db_session_with_containers, fake)
|
||||
app.mode = AppMode.ADVANCED_CHAT.value
|
||||
app.mode = AppMode.ADVANCED_CHAT
|
||||
|
||||
from extensions.ext_database import db
|
||||
|
||||
@@ -1061,7 +1061,7 @@ class TestWorkflowService:
|
||||
# Arrange
|
||||
fake = Faker()
|
||||
app = self._create_test_app(db_session_with_containers, fake)
|
||||
app.mode = AppMode.WORKFLOW.value
|
||||
app.mode = AppMode.WORKFLOW
|
||||
|
||||
from extensions.ext_database import db
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class TestHandleMCPRequest:
|
||||
"""Setup test fixtures"""
|
||||
self.app = Mock(spec=App)
|
||||
self.app.name = "test_app"
|
||||
self.app.mode = AppMode.CHAT.value
|
||||
self.app.mode = AppMode.CHAT
|
||||
|
||||
self.mcp_server = Mock(spec=AppMCPServer)
|
||||
self.mcp_server.description = "Test server"
|
||||
@@ -196,7 +196,7 @@ class TestIndividualHandlers:
|
||||
def test_handle_list_tools(self):
|
||||
"""Test list tools handler"""
|
||||
app_name = "test_app"
|
||||
app_mode = AppMode.CHAT.value
|
||||
app_mode = AppMode.CHAT
|
||||
description = "Test server"
|
||||
parameters_dict: dict[str, str] = {}
|
||||
user_input_form: list[VariableEntity] = []
|
||||
@@ -212,7 +212,7 @@ class TestIndividualHandlers:
|
||||
def test_handle_call_tool(self, mock_app_generate):
|
||||
"""Test call tool handler"""
|
||||
app = Mock(spec=App)
|
||||
app.mode = AppMode.CHAT.value
|
||||
app.mode = AppMode.CHAT
|
||||
|
||||
# Create mock request
|
||||
mock_request = Mock()
|
||||
@@ -252,7 +252,7 @@ class TestUtilityFunctions:
|
||||
|
||||
def test_build_parameter_schema_chat_mode(self):
|
||||
"""Test building parameter schema for chat mode"""
|
||||
app_mode = AppMode.CHAT.value
|
||||
app_mode = AppMode.CHAT
|
||||
parameters_dict: dict[str, str] = {"name": "Enter your name"}
|
||||
|
||||
user_input_form = [
|
||||
@@ -275,7 +275,7 @@ class TestUtilityFunctions:
|
||||
|
||||
def test_build_parameter_schema_workflow_mode(self):
|
||||
"""Test building parameter schema for workflow mode"""
|
||||
app_mode = AppMode.WORKFLOW.value
|
||||
app_mode = AppMode.WORKFLOW
|
||||
parameters_dict: dict[str, str] = {"input_text": "Enter text"}
|
||||
|
||||
user_input_form = [
|
||||
@@ -298,7 +298,7 @@ class TestUtilityFunctions:
|
||||
def test_prepare_tool_arguments_chat_mode(self):
|
||||
"""Test preparing tool arguments for chat mode"""
|
||||
app = Mock(spec=App)
|
||||
app.mode = AppMode.CHAT.value
|
||||
app.mode = AppMode.CHAT
|
||||
|
||||
arguments = {"query": "test question", "name": "John"}
|
||||
|
||||
@@ -312,7 +312,7 @@ class TestUtilityFunctions:
|
||||
def test_prepare_tool_arguments_workflow_mode(self):
|
||||
"""Test preparing tool arguments for workflow mode"""
|
||||
app = Mock(spec=App)
|
||||
app.mode = AppMode.WORKFLOW.value
|
||||
app.mode = AppMode.WORKFLOW
|
||||
|
||||
arguments = {"input_text": "test input"}
|
||||
|
||||
@@ -324,7 +324,7 @@ class TestUtilityFunctions:
|
||||
def test_prepare_tool_arguments_completion_mode(self):
|
||||
"""Test preparing tool arguments for completion mode"""
|
||||
app = Mock(spec=App)
|
||||
app.mode = AppMode.COMPLETION.value
|
||||
app.mode = AppMode.COMPLETION
|
||||
|
||||
arguments = {"name": "John"}
|
||||
|
||||
@@ -336,7 +336,7 @@ class TestUtilityFunctions:
|
||||
def test_extract_answer_from_mapping_response_chat(self):
|
||||
"""Test extracting answer from mapping response for chat mode"""
|
||||
app = Mock(spec=App)
|
||||
app.mode = AppMode.CHAT.value
|
||||
app.mode = AppMode.CHAT
|
||||
|
||||
response = {"answer": "test answer", "other": "data"}
|
||||
|
||||
@@ -347,7 +347,7 @@ class TestUtilityFunctions:
|
||||
def test_extract_answer_from_mapping_response_workflow(self):
|
||||
"""Test extracting answer from mapping response for workflow mode"""
|
||||
app = Mock(spec=App)
|
||||
app.mode = AppMode.WORKFLOW.value
|
||||
app.mode = AppMode.WORKFLOW
|
||||
|
||||
response = {"data": {"outputs": {"result": "test result"}}}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ def test__convert_to_http_request_node_for_chatbot(default_variables):
|
||||
app_model = MagicMock()
|
||||
app_model.id = "app_id"
|
||||
app_model.tenant_id = "tenant_id"
|
||||
app_model.mode = AppMode.CHAT.value
|
||||
app_model.mode = AppMode.CHAT
|
||||
|
||||
api_based_extension_id = "api_based_extension_id"
|
||||
mock_api_based_extension = APIBasedExtension(
|
||||
@@ -127,7 +127,7 @@ def test__convert_to_http_request_node_for_workflow_app(default_variables):
|
||||
app_model = MagicMock()
|
||||
app_model.id = "app_id"
|
||||
app_model.tenant_id = "tenant_id"
|
||||
app_model.mode = AppMode.WORKFLOW.value
|
||||
app_model.mode = AppMode.WORKFLOW
|
||||
|
||||
api_based_extension_id = "api_based_extension_id"
|
||||
mock_api_based_extension = APIBasedExtension(
|
||||
|
||||
Reference in New Issue
Block a user