mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git.labs.intellij.net:idea/ultimate
This commit is contained in:
@@ -360,6 +360,8 @@
|
||||
implementationClass="com.jetbrains.python.buildout.config.BuildoutCfgHighlighterFactory"/>
|
||||
<inspectionToolProvider implementation="com.jetbrains.python.buildout.config.inspection.BuildoutInspectionToolProvider"/>
|
||||
<colorSettingsPage implementation="com.jetbrains.python.buildout.config.BuildoutCfgColorsPage"/>
|
||||
<projectService serviceInterface="com.jetbrains.python.testing.TestRunnerService"
|
||||
serviceImplementation="com.jetbrains.python.testing.TestRunnerService"/>
|
||||
</extensions>
|
||||
|
||||
<extensionPoints>
|
||||
|
||||
+12
-2
@@ -37,12 +37,22 @@ public class PyDictLiteralFormToConstructorIntention extends BaseIntentionAction
|
||||
|
||||
if (dictExpression != null) {
|
||||
PyKeyValueExpression[] elements = dictExpression.getElements();
|
||||
boolean canConvert = true;
|
||||
if (elements.length != 0) {
|
||||
for (PyKeyValueExpression element : elements) {
|
||||
if (! (element.getKey() instanceof PyStringLiteralExpression)) return false;
|
||||
PyExpression key = element.getKey();
|
||||
if (! (key instanceof PyStringLiteralExpression)) canConvert = false;
|
||||
String str = ((PyStringLiteralExpression)key).getStringValue();
|
||||
if(Character.isDigit(str.charAt(0))) canConvert = false;
|
||||
try {
|
||||
Integer.parseInt(str) ;
|
||||
canConvert = false;
|
||||
} catch (NumberFormatException e) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
if (canConvert) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -16,87 +16,36 @@
|
||||
|
||||
package com.jetbrains.python.testing;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.ui.CollectionComboBoxModel;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListDataListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* User: catherine
|
||||
*/
|
||||
public class PythonTestConfigurationsModel implements ComboBoxModel {
|
||||
|
||||
public class PythonTestConfigurationsModel extends CollectionComboBoxModel {
|
||||
public static final String PYTHONS_UNITTEST_NAME = PyBundle.message("runcfg.unittest.display_name");
|
||||
public static final String PYTHONS_NOSETEST_NAME = PyBundle.message("runcfg.nosetests.display_name");
|
||||
public static final String PY_TEST_NAME = PyBundle.message("runcfg.pytest.display_name");
|
||||
private static final PythonTestConfigurationsModel INSTANCE = new PythonTestConfigurationsModel();
|
||||
|
||||
private final List<String> myConfigurationTypes = new ArrayList<String>();
|
||||
private Set<ListDataListener> myListDataListeners = new HashSet<ListDataListener>();
|
||||
|
||||
private String myDefault;
|
||||
private String myProjectConfiguration;
|
||||
private String myGlobalSelected;
|
||||
private Project myProject;
|
||||
|
||||
private PythonTestConfigurationsModel() {
|
||||
myDefault = PYTHONS_UNITTEST_NAME;
|
||||
myProjectConfiguration = PYTHONS_UNITTEST_NAME;
|
||||
myGlobalSelected = myDefault;
|
||||
public PythonTestConfigurationsModel(final List items, final Object selection, Project project) {
|
||||
super(items, selection);
|
||||
myProject = project;
|
||||
myProjectConfiguration = TestRunnerService.getInstance(myProject).getProjectConfiguration();
|
||||
}
|
||||
|
||||
public void addConfiguration(final String newConfiguration, boolean changeSelection) {
|
||||
myConfigurationTypes.add(newConfiguration);
|
||||
if (changeSelection) {
|
||||
setSelectedItem(newConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
myDefault = myProjectConfiguration;
|
||||
setSelectedItem(myProjectConfiguration);
|
||||
}
|
||||
|
||||
public void apply() {
|
||||
myProjectConfiguration = myGlobalSelected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedItem(Object o) {
|
||||
if (myGlobalSelected != o) {
|
||||
myGlobalSelected = (String)o;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSelectedItem() {
|
||||
return myGlobalSelected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return myConfigurationTypes.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int i) {
|
||||
return myConfigurationTypes.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListDataListener(ListDataListener listDataListener) {
|
||||
myListDataListeners.add(listDataListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListDataListener(ListDataListener listDataListener) {
|
||||
myListDataListeners.remove(listDataListener);
|
||||
}
|
||||
|
||||
public static PythonTestConfigurationsModel getInstance() {
|
||||
return INSTANCE;
|
||||
myProjectConfiguration = (String)getSelectedItem();
|
||||
TestRunnerService.getInstance(myProject).setProjectConfiguration(myProjectConfiguration);
|
||||
}
|
||||
|
||||
public Object getProjectConfiguration() {
|
||||
|
||||
@@ -12,7 +12,6 @@ import com.intellij.execution.configurations.ConfigurationTypeUtil;
|
||||
import com.intellij.execution.junit.RuntimeConfigurationProducer;
|
||||
import com.intellij.facet.Facet;
|
||||
import com.intellij.facet.FacetManager;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -29,7 +28,6 @@ import java.util.List;
|
||||
|
||||
public class PythonUnitTestConfigurationProducer extends RuntimeConfigurationProducer {
|
||||
private PsiElement myPsiElement;
|
||||
private boolean isActive = true;
|
||||
|
||||
public PythonUnitTestConfigurationProducer() {
|
||||
super(ConfigurationTypeUtil.findConfigurationType(PythonUnitTestConfigurationType.class));
|
||||
@@ -42,17 +40,19 @@ public class PythonUnitTestConfigurationProducer extends RuntimeConfigurationPro
|
||||
|
||||
@Override
|
||||
protected RunnerAndConfigurationSettings createConfigurationByElement(Location location, ConfigurationContext context) {
|
||||
if (!isActive) return null;
|
||||
PsiElement element = location.getPsiElement();
|
||||
if (! (TestRunnerService.getInstance(element.getProject()).getProjectConfiguration().equals(
|
||||
PythonTestConfigurationsModel.PYTHONS_UNITTEST_NAME))) return null;
|
||||
RunnerAndConfigurationSettings settings;
|
||||
/*Module module = location.getModule();
|
||||
|
||||
Module module = location.getModule();
|
||||
if (module != null) {
|
||||
for (RunnableUnitTestFilter f : Extensions.getExtensions(RunnableUnitTestFilter.EP_NAME)) {
|
||||
if (f.isRunnableUnitTest(location.getPsiElement().getContainingFile(), module)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if (PythonUnitTestRunnableScriptFilter.isIfNameMain(location)) {
|
||||
return null;
|
||||
@@ -215,9 +215,6 @@ public class PythonUnitTestConfigurationProducer extends RuntimeConfigurationPro
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public void setActive(boolean active) {
|
||||
isActive = active;
|
||||
}
|
||||
|
||||
public int compareTo(Object o) {
|
||||
return PREFERED;
|
||||
|
||||
@@ -27,13 +27,11 @@ public class PythonUnitTestConfigurationType extends ConfigurationTypeBase {
|
||||
private final static Icon ICON = IconLoader.getIcon("/com/jetbrains/python/icons/python.png");
|
||||
|
||||
private static class PythonUnitTestConfigurationFactory extends ConfigurationFactory {
|
||||
final private PythonTestConfigurationsModel myModel = PythonTestConfigurationsModel.getInstance();
|
||||
protected PythonUnitTestConfigurationFactory(ConfigurationType configurationType) {
|
||||
super(configurationType);
|
||||
}
|
||||
|
||||
public RunConfiguration createTemplateConfiguration(Project project) {
|
||||
myModel.addConfiguration(PythonTestConfigurationsModel.PYTHONS_UNITTEST_NAME, false);
|
||||
return new PythonUnitTestRunConfiguration(new RunConfigurationModule(project), this, "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,11 @@ package com.jetbrains.python.testing;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.NonDefaultProjectConfigurable;
|
||||
import com.jetbrains.python.testing.nosetest.PythonNoseTestConfigurationProducer;
|
||||
import com.jetbrains.python.testing.pytest.PyTestConfigurationProducer;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User: catherine
|
||||
@@ -18,7 +16,11 @@ public class TestRunnerConfigurable implements Configurable, NonDefaultProjectCo
|
||||
private JPanel myMainPanel;
|
||||
private JComboBox myComboBox;
|
||||
private PythonTestConfigurationsModel myModel;
|
||||
private Project myProject;
|
||||
|
||||
public TestRunnerConfigurable(Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
@Nls
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
@@ -37,35 +39,16 @@ public class TestRunnerConfigurable implements Configurable, NonDefaultProjectCo
|
||||
|
||||
@Override
|
||||
public JComponent createComponent() {
|
||||
myModel = PythonTestConfigurationsModel.getInstance();
|
||||
List<String> configurations = TestRunnerService.getInstance(myProject).getConfigurations();
|
||||
myModel = new PythonTestConfigurationsModel(configurations, TestRunnerService.getInstance(myProject).getProjectConfiguration(),
|
||||
myProject);
|
||||
updateConfigurations();
|
||||
return myMainPanel;
|
||||
}
|
||||
|
||||
private void updateConfigurations() {
|
||||
myComboBox.setModel(myModel);
|
||||
myComboBox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
JComboBox cb = (JComboBox)actionEvent.getSource();
|
||||
String selectedItem = (String)cb.getSelectedItem();
|
||||
if (selectedItem.equals(PythonTestConfigurationsModel.PYTHONS_UNITTEST_NAME)) {
|
||||
PythonUnitTestConfigurationProducer.getInstance(PythonUnitTestConfigurationProducer.class).setActive(true);
|
||||
PythonNoseTestConfigurationProducer.getInstance(PythonNoseTestConfigurationProducer.class).setActive(false);
|
||||
PyTestConfigurationProducer.getInstance(PyTestConfigurationProducer.class).setActive(false);
|
||||
}
|
||||
else if (selectedItem.equals(PythonTestConfigurationsModel.PYTHONS_NOSETEST_NAME)) {
|
||||
PythonNoseTestConfigurationProducer.getInstance(PythonNoseTestConfigurationProducer.class).setActive(true);
|
||||
PythonUnitTestConfigurationProducer.getInstance(PythonUnitTestConfigurationProducer.class).setActive(false);
|
||||
PyTestConfigurationProducer.getInstance(PyTestConfigurationProducer.class).setActive(false);
|
||||
}
|
||||
else if (selectedItem.equals(PythonTestConfigurationsModel.PY_TEST_NAME)) {
|
||||
PyTestConfigurationProducer.getInstance(PyTestConfigurationProducer.class).setActive(true);
|
||||
PythonNoseTestConfigurationProducer.getInstance(PythonNoseTestConfigurationProducer.class).setActive(false);
|
||||
PythonUnitTestConfigurationProducer.getInstance(PythonUnitTestConfigurationProducer.class).setActive(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.jetbrains.python.testing;
|
||||
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User: catherine
|
||||
*/
|
||||
@State(name = "TestRunnerService",
|
||||
storages = {
|
||||
@Storage(id = "default", file = "$PROJECT_FILE$"),
|
||||
@Storage(id = "dir", file = "$PROJECT_CONFIG_DIR$/testrunner.xml", scheme = StorageScheme.DIRECTORY_BASED)
|
||||
}
|
||||
)
|
||||
public class TestRunnerService implements PersistentStateComponent<TestRunnerService> {
|
||||
private List<String> myConfigurations = new ArrayList<String>();
|
||||
public String PROJECT_CONFIGURATION = PythonTestConfigurationsModel.PYTHONS_UNITTEST_NAME;
|
||||
|
||||
public TestRunnerService() {
|
||||
myConfigurations.add(PythonTestConfigurationsModel.PYTHONS_UNITTEST_NAME);
|
||||
myConfigurations.add(PythonTestConfigurationsModel.PYTHONS_NOSETEST_NAME);
|
||||
myConfigurations.add(PythonTestConfigurationsModel.PY_TEST_NAME);
|
||||
}
|
||||
|
||||
public List<String> getConfigurations() {
|
||||
return myConfigurations;
|
||||
}
|
||||
public void registerConfiguration(final String newConfiguration) {
|
||||
myConfigurations.add(newConfiguration);
|
||||
}
|
||||
@Override
|
||||
public TestRunnerService getState() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(TestRunnerService state) {
|
||||
XmlSerializerUtil.copyBean(state, this);
|
||||
}
|
||||
|
||||
public void setProjectConfiguration(String projectConfiguration) {
|
||||
PROJECT_CONFIGURATION = projectConfiguration;
|
||||
}
|
||||
|
||||
public static TestRunnerService getInstance(Project project) {
|
||||
return ServiceManager.getService(project, TestRunnerService.class);
|
||||
}
|
||||
public String getProjectConfiguration() {
|
||||
return PROJECT_CONFIGURATION;
|
||||
}
|
||||
}
|
||||
+9
-14
@@ -12,7 +12,6 @@ import com.intellij.execution.configurations.ConfigurationTypeUtil;
|
||||
import com.intellij.execution.junit.RuntimeConfigurationProducer;
|
||||
import com.intellij.facet.Facet;
|
||||
import com.intellij.facet.FacetManager;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -22,7 +21,10 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.PythonModuleTypeBase;
|
||||
import com.jetbrains.python.facet.PythonFacetSettings;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.testing.*;
|
||||
import com.jetbrains.python.testing.PythonTestConfigurationsModel;
|
||||
import com.jetbrains.python.testing.PythonUnitTestRunnableScriptFilter;
|
||||
import com.jetbrains.python.testing.PythonUnitTestUtil;
|
||||
import com.jetbrains.python.testing.TestRunnerService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -30,7 +32,6 @@ import java.util.List;
|
||||
|
||||
public class PythonNoseTestConfigurationProducer extends RuntimeConfigurationProducer {
|
||||
private PsiElement myPsiElement;
|
||||
private boolean isActive = false;
|
||||
|
||||
public PythonNoseTestConfigurationProducer() {
|
||||
super(ConfigurationTypeUtil.findConfigurationType(PythonNoseTestRunConfigurationType.class));
|
||||
@@ -43,37 +44,34 @@ public class PythonNoseTestConfigurationProducer extends RuntimeConfigurationPro
|
||||
|
||||
@Override
|
||||
protected RunnerAndConfigurationSettings createConfigurationByElement(Location location, ConfigurationContext context) {
|
||||
if (!isActive) return null;
|
||||
PsiElement element = location.getPsiElement();
|
||||
if (! (TestRunnerService.getInstance(element.getProject()).getProjectConfiguration().equals(
|
||||
PythonTestConfigurationsModel.PYTHONS_NOSETEST_NAME))) return null;
|
||||
RunnerAndConfigurationSettings settings;
|
||||
/*Module module = location.getModule();
|
||||
|
||||
Module module = location.getModule();
|
||||
if (module != null) {
|
||||
for (RunnableUnitTestFilter f : Extensions.getExtensions(RunnableUnitTestFilter.EP_NAME)) {
|
||||
if (f.isRunnableUnitTest(location.getPsiElement().getContainingFile(), module)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}*/
|
||||
if (PythonUnitTestRunnableScriptFilter.isIfNameMain(location)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
settings = createConfigurationFromFolder(location);
|
||||
if (settings != null) return settings;
|
||||
|
||||
final PyElement pyElement = PsiTreeUtil.getParentOfType(location.getPsiElement(), PyElement.class);
|
||||
if (pyElement != null) {
|
||||
settings = createConfigurationFromFunction(location, pyElement);
|
||||
if (settings != null) return settings;
|
||||
|
||||
settings = createConfigurationFromClass(location, pyElement);
|
||||
if (settings != null) return settings;
|
||||
}
|
||||
|
||||
settings = createConfigurationFromFile(location, location.getPsiElement());
|
||||
if (settings != null) return settings;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -222,7 +220,4 @@ public class PythonNoseTestConfigurationProducer extends RuntimeConfigurationPro
|
||||
return PREFERED;
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
isActive = active;
|
||||
}
|
||||
}
|
||||
-3
@@ -4,7 +4,6 @@ import com.intellij.execution.configurations.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.testing.PythonTestConfigurationsModel;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
@@ -27,13 +26,11 @@ public class PythonNoseTestRunConfigurationType extends ConfigurationTypeBase {
|
||||
private final static Icon ICON = IconLoader.getIcon("/com/jetbrains/python/icons/python.png");
|
||||
|
||||
private static class PythonNoseTestConfigurationFactory extends ConfigurationFactory {
|
||||
final private PythonTestConfigurationsModel myModel = PythonTestConfigurationsModel.getInstance();
|
||||
protected PythonNoseTestConfigurationFactory(ConfigurationType configurationType) {
|
||||
super(configurationType);
|
||||
}
|
||||
|
||||
public RunConfiguration createTemplateConfiguration(Project project) {
|
||||
myModel.addConfiguration(PythonTestConfigurationsModel.PYTHONS_NOSETEST_NAME, false);
|
||||
return new PythonNoseTestRunConfiguration(new RunConfigurationModule(project), this, "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import com.jetbrains.python.psi.PyStatement;
|
||||
import com.jetbrains.python.testing.PythonTestConfigurationsModel;
|
||||
import com.jetbrains.python.testing.PythonUnitTestConfigurationProducer;
|
||||
import com.jetbrains.python.testing.TestRunnerService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -29,7 +31,6 @@ import java.util.List;
|
||||
|
||||
public class PyTestConfigurationProducer extends RuntimeConfigurationProducer {
|
||||
private PsiElement myPsiElement;
|
||||
private boolean isActive = false;
|
||||
|
||||
public PyTestConfigurationProducer() {
|
||||
super(ConfigurationTypeUtil.findConfigurationType(PyTestRunConfigurationType.class));
|
||||
@@ -42,8 +43,10 @@ public class PyTestConfigurationProducer extends RuntimeConfigurationProducer {
|
||||
|
||||
@Override
|
||||
protected RunnerAndConfigurationSettings createConfigurationByElement(Location location, ConfigurationContext context) {
|
||||
if (!isActive) return null;
|
||||
PsiElement element = location.getPsiElement();
|
||||
if (! (TestRunnerService.getInstance(element.getProject()).getProjectConfiguration().equals(
|
||||
PythonTestConfigurationsModel.PY_TEST_NAME))) return null;
|
||||
|
||||
PsiFileSystemItem file = element instanceof PsiDirectory ? (PsiDirectory)element : element.getContainingFile();
|
||||
if (file == null) return null;
|
||||
myPsiElement = file;
|
||||
@@ -119,7 +122,4 @@ public class PyTestConfigurationProducer extends RuntimeConfigurationProducer {
|
||||
}
|
||||
return PREFERED;
|
||||
}
|
||||
public void setActive(boolean active) {
|
||||
isActive = active;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import com.intellij.execution.configurations.RunConfigurationModule;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.PythonFileType;
|
||||
import com.jetbrains.python.testing.PythonTestConfigurationsModel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -41,13 +40,11 @@ public class PyTestRunConfigurationType implements ConfigurationType {
|
||||
|
||||
|
||||
private static class PyTestRunConfigurationFactory extends ConfigurationFactory {
|
||||
final private PythonTestConfigurationsModel myModel = PythonTestConfigurationsModel.getInstance();
|
||||
protected PyTestRunConfigurationFactory(ConfigurationType type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
public RunConfiguration createTemplateConfiguration(Project project) {
|
||||
myModel.addConfiguration(PythonTestConfigurationsModel.PY_TEST_NAME, false);
|
||||
return new PyTestRunConfiguration("", new RunConfigurationModule(project), this);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user