Merge branch 'release/release-1.5.0'
This commit is contained in:
commit
c8bc923525
37
pom.xml
37
pom.xml
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>org.sadtech.autoresponder</groupId>
|
<groupId>org.sadtech.autoresponder</groupId>
|
||||||
<artifactId>autoresponder</artifactId>
|
<artifactId>autoresponder</artifactId>
|
||||||
<version>1.4.0-RELEASE</version>
|
<version>1.5.0-RELEASE</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
@ -22,18 +22,8 @@
|
|||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<developers>
|
|
||||||
<developer>
|
|
||||||
<id>uPagge</id>
|
|
||||||
<name>Struchkov Mark</name>
|
|
||||||
<email>upagge@mail.ru</email>
|
|
||||||
</developer>
|
|
||||||
</developers>
|
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<log4j>1.2.17</log4j>
|
<log4j>1.2.17</log4j>
|
||||||
<junit.ver>4.12</junit.ver>
|
|
||||||
<mocito.ver>2.23.4</mocito.ver>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -42,22 +32,15 @@
|
|||||||
<artifactId>log4j</artifactId>
|
<artifactId>log4j</artifactId>
|
||||||
<version>${log4j}</version>
|
<version>${log4j}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- https://mvnrepository.com/artifact/junit/junit -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>${junit.ver}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-core</artifactId>
|
|
||||||
<version>${mocito.ver}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<id>uPagge</id>
|
||||||
|
<name>Struchkov Mark</name>
|
||||||
|
<email>upagge@mail.ru</email>
|
||||||
|
<organization>SADTECH</organization>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -2,10 +2,10 @@ package org.sadtech.autoresponder;
|
|||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.sadtech.autoresponder.compare.UnitPriorityComparator;
|
import org.sadtech.autoresponder.compare.UnitPriorityComparator;
|
||||||
import org.sadtech.autoresponder.entity.Person;
|
import org.sadtech.autoresponder.entity.UnitPointer;
|
||||||
import org.sadtech.autoresponder.entity.Unit;
|
import org.sadtech.autoresponder.entity.Unit;
|
||||||
import org.sadtech.autoresponder.service.PersonService;
|
import org.sadtech.autoresponder.service.UnitPointerService;
|
||||||
import org.sadtech.autoresponder.submodule.parser.Parser;
|
import org.sadtech.autoresponder.util.Parser;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -15,54 +15,54 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
public class Autoresponder {
|
public class Autoresponder {
|
||||||
|
|
||||||
public static final Logger log = Logger.getLogger(Autoresponder.class);
|
private static final Logger log = Logger.getLogger(Autoresponder.class);
|
||||||
|
|
||||||
private Set<Unit> menuUnits;
|
private Set<Unit> menuUnits;
|
||||||
private PersonService personService;
|
private UnitPointerService unitPointerService;
|
||||||
|
|
||||||
public Autoresponder(PersonService personService) {
|
public Autoresponder(UnitPointerService unitPointerService) {
|
||||||
this.personService = personService;
|
this.unitPointerService = unitPointerService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMenuUnits(Set<Unit> menuUnits) {
|
public void setMenuUnits(Set<Unit> menuUnits) {
|
||||||
this.menuUnits = menuUnits;
|
this.menuUnits = menuUnits;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PersonService getPersonService() {
|
public UnitPointerService getUnitPointerService() {
|
||||||
return personService;
|
return unitPointerService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPersonService(PersonService personService) {
|
public void setUnitPointerService(UnitPointerService unitPointerService) {
|
||||||
this.personService = personService;
|
this.unitPointerService = unitPointerService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Unit answer(Integer idPerson, String message) {
|
public Unit answer(Integer idPerson, String message) {
|
||||||
Person person = checkAndAddPerson(idPerson);
|
UnitPointer unitPointer = checkAndAddPerson(idPerson);
|
||||||
Unit unit;
|
Unit unit;
|
||||||
if (person.getUnit() == null) {
|
if (unitPointer.getUnit() == null) {
|
||||||
unit = nextUnit(menuUnits, message);
|
unit = nextUnit(menuUnits, message);
|
||||||
} else {
|
} else {
|
||||||
if (person.getUnit().getNextUnits() == null) {
|
if (unitPointer.getUnit().getNextUnits() == null) {
|
||||||
unit = nextUnit(menuUnits, message);
|
unit = nextUnit(menuUnits, message);
|
||||||
} else {
|
} else {
|
||||||
unit = nextUnit(person.getUnit().getNextUnits(), message);
|
unit = nextUnit(unitPointer.getUnit().getNextUnits(), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (unit != null) {
|
if (unit != null) {
|
||||||
person.setUnit(unit);
|
unitPointer.setUnit(unit);
|
||||||
}
|
}
|
||||||
return unit;
|
return unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Person checkAndAddPerson(Integer idPerson) {
|
private UnitPointer checkAndAddPerson(Integer idPerson) {
|
||||||
Person person;
|
UnitPointer unitPointer;
|
||||||
if (personService.checkPerson(idPerson)) {
|
if (unitPointerService.check(idPerson)) {
|
||||||
person = personService.getPersonById(idPerson);
|
unitPointer = unitPointerService.getByEntityId(idPerson);
|
||||||
} else {
|
} else {
|
||||||
person = new Person(idPerson);
|
unitPointer = new UnitPointer(idPerson);
|
||||||
personService.addPerson(person);
|
unitPointerService.add(unitPointer);
|
||||||
}
|
}
|
||||||
return person;
|
return unitPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Unit nextUnit(Set<Unit> nextUnits, String message) {
|
private Unit nextUnit(Set<Unit> nextUnits, String message) {
|
||||||
@ -71,14 +71,15 @@ public class Autoresponder {
|
|||||||
Optional<Unit> patternUnits = nextUnits.stream().filter(nextUnit -> nextUnit.getPattern() != null).filter(nextUnit -> patternReg(nextUnit, message)).max(unitPriorityComparator);
|
Optional<Unit> patternUnits = nextUnits.stream().filter(nextUnit -> nextUnit.getPattern() != null).filter(nextUnit -> patternReg(nextUnit, message)).max(unitPriorityComparator);
|
||||||
|
|
||||||
if (!patternUnits.isPresent()) {
|
if (!patternUnits.isPresent()) {
|
||||||
Parser parser = new Parser();
|
patternUnits = nextUnits.stream()
|
||||||
parser.setText(message);
|
.filter(nextUnit -> textPercentageMatch(nextUnit, Parser.parse(message)) >= nextUnit.getMatchThreshold())
|
||||||
parser.parse();
|
.max(unitPriorityComparator);
|
||||||
patternUnits = nextUnits.stream().filter(nextUnit -> textPercentageMatch(nextUnit, parser.getWords()) >= nextUnit.getMatchThreshold()).max(unitPriorityComparator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!patternUnits.isPresent()) {
|
if (!patternUnits.isPresent()) {
|
||||||
patternUnits = nextUnits.stream().filter(nextUnit -> (nextUnit.getPattern() == null && nextUnit.getKeyWords() == null)).max(unitPriorityComparator);
|
patternUnits = nextUnits.stream()
|
||||||
|
.filter(nextUnit -> (nextUnit.getPattern() == null && nextUnit.getKeyWords() == null))
|
||||||
|
.max(unitPriorityComparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
return patternUnits.orElse(null);
|
return patternUnits.orElse(null);
|
||||||
@ -90,10 +91,7 @@ public class Autoresponder {
|
|||||||
private boolean patternReg(Unit unit, String message) {
|
private boolean patternReg(Unit unit, String message) {
|
||||||
Pattern pattern = unit.getPattern();
|
Pattern pattern = unit.getPattern();
|
||||||
Matcher m = pattern.matcher(message);
|
Matcher m = pattern.matcher(message);
|
||||||
while (m.find()) {
|
return m.find();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Double textPercentageMatch(Unit unit, Set<String> words) {
|
private Double textPercentageMatch(Unit unit, Set<String> words) {
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
package org.sadtech.autoresponder.entity;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class Person {
|
|
||||||
|
|
||||||
private Integer id;
|
|
||||||
private Unit unit;
|
|
||||||
private Boolean replyStatus;
|
|
||||||
|
|
||||||
public Person(Integer id, Unit unit) {
|
|
||||||
this.id = id;
|
|
||||||
this.unit = unit;
|
|
||||||
replyStatus = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Person(Integer id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Integer id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Unit getUnit() {
|
|
||||||
return unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUnit(Unit unit) {
|
|
||||||
this.unit = unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getReplyStatus() {
|
|
||||||
return replyStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setReplyStatus(Boolean replyStatus) {
|
|
||||||
this.replyStatus = replyStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
Person person = (Person) o;
|
|
||||||
return Objects.equals(id, person.id) &&
|
|
||||||
Objects.equals(unit, person.unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(id, unit);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,48 @@
|
|||||||
|
package org.sadtech.autoresponder.entity;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class UnitPointer {
|
||||||
|
|
||||||
|
private Integer entityId;
|
||||||
|
private Unit unit;
|
||||||
|
|
||||||
|
public UnitPointer(Integer entityId, Unit unit) {
|
||||||
|
this.entityId = entityId;
|
||||||
|
this.unit = unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnitPointer(Integer entityId) {
|
||||||
|
this.entityId = entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getEntityId() {
|
||||||
|
return entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEntityId(Integer entityId) {
|
||||||
|
this.entityId = entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Unit getUnit() {
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnit(Unit unit) {
|
||||||
|
this.unit = unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
UnitPointer unitPointer = (UnitPointer) o;
|
||||||
|
return Objects.equals(entityId, unitPointer.entityId) &&
|
||||||
|
Objects.equals(unit, unitPointer.unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(entityId, unit);
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
package org.sadtech.autoresponder.repository;
|
|
||||||
|
|
||||||
import org.sadtech.autoresponder.entity.Person;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public interface PersonRepository {
|
|
||||||
|
|
||||||
void addPerson(Person person);
|
|
||||||
|
|
||||||
void removePerson(Person person);
|
|
||||||
|
|
||||||
void addPersonAll(Map<Integer, Person> personCollection);
|
|
||||||
|
|
||||||
Person getPersonById(Integer idPerson);
|
|
||||||
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package org.sadtech.autoresponder.repository;
|
|
||||||
|
|
||||||
import org.sadtech.autoresponder.entity.Person;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class PersonRepositoryMap implements PersonRepository {
|
|
||||||
|
|
||||||
private Map<Integer, Person> people = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addPerson(Person person) {
|
|
||||||
people.put(person.getId(), person);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removePerson(Person person) {
|
|
||||||
people.remove(person.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addPersonAll(Map<Integer, Person> personCollection) {
|
|
||||||
people.putAll(personCollection);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Person getPersonById(Integer idPerson) {
|
|
||||||
return people.get(idPerson);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,17 @@
|
|||||||
|
package org.sadtech.autoresponder.repository;
|
||||||
|
|
||||||
|
import org.sadtech.autoresponder.entity.UnitPointer;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface UnitPointerRepository {
|
||||||
|
|
||||||
|
Integer add(UnitPointer unitPointer);
|
||||||
|
|
||||||
|
void remove(Integer entityId);
|
||||||
|
|
||||||
|
void addAll(Map<Integer, UnitPointer> unitPointerMap);
|
||||||
|
|
||||||
|
UnitPointer findByEntityId(Integer entityId);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package org.sadtech.autoresponder.repository;
|
||||||
|
|
||||||
|
import org.sadtech.autoresponder.entity.UnitPointer;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class UnitPointerRepositoryMap implements UnitPointerRepository {
|
||||||
|
|
||||||
|
private Map<Integer, UnitPointer> unitPointerMap = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer add(UnitPointer unitPointer) {
|
||||||
|
unitPointerMap.put(unitPointer.getEntityId(), unitPointer);
|
||||||
|
return unitPointer.getEntityId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(Integer entityId) {
|
||||||
|
unitPointerMap.remove(entityId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAll(Map<Integer, UnitPointer> unitPointerMap) {
|
||||||
|
this.unitPointerMap.putAll(unitPointerMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnitPointer findByEntityId(Integer entityId) {
|
||||||
|
return unitPointerMap.get(entityId);
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
package org.sadtech.autoresponder.service;
|
|
||||||
|
|
||||||
import org.sadtech.autoresponder.entity.Person;
|
|
||||||
|
|
||||||
public interface PersonService {
|
|
||||||
|
|
||||||
Person getPersonById(Integer integer);
|
|
||||||
|
|
||||||
void addPerson(Person person);
|
|
||||||
|
|
||||||
boolean checkPerson(Integer idPerson);
|
|
||||||
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
package org.sadtech.autoresponder.service;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.sadtech.autoresponder.entity.Person;
|
|
||||||
import org.sadtech.autoresponder.repository.PersonRepository;
|
|
||||||
import org.sadtech.autoresponder.repository.PersonRepositoryMap;
|
|
||||||
|
|
||||||
public class PersonServiceImpl implements PersonService {
|
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(PersonServiceImpl.class);
|
|
||||||
|
|
||||||
private PersonRepository personRepository;
|
|
||||||
|
|
||||||
public PersonServiceImpl() {
|
|
||||||
this.personRepository = new PersonRepositoryMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PersonServiceImpl(PersonRepository personRepository) {
|
|
||||||
this.personRepository = personRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Person getPersonById(Integer integer) {
|
|
||||||
return personRepository.getPersonById(integer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addPerson(Person person) {
|
|
||||||
personRepository.addPerson(person);
|
|
||||||
log.info("Пользователь отправлен в репозиторий");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkPerson(Integer idPerson) {
|
|
||||||
return personRepository.getPersonById(idPerson) != null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,13 @@
|
|||||||
|
package org.sadtech.autoresponder.service;
|
||||||
|
|
||||||
|
import org.sadtech.autoresponder.entity.UnitPointer;
|
||||||
|
|
||||||
|
public interface UnitPointerService {
|
||||||
|
|
||||||
|
void add(UnitPointer unitPointer);
|
||||||
|
|
||||||
|
boolean check(Integer entityId);
|
||||||
|
|
||||||
|
UnitPointer getByEntityId(Integer entityId);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package org.sadtech.autoresponder.service;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.sadtech.autoresponder.entity.UnitPointer;
|
||||||
|
import org.sadtech.autoresponder.repository.UnitPointerRepository;
|
||||||
|
import org.sadtech.autoresponder.repository.UnitPointerRepositoryMap;
|
||||||
|
|
||||||
|
public class UnitPointerServiceImpl implements UnitPointerService {
|
||||||
|
|
||||||
|
private static final Logger log = Logger.getLogger(UnitPointerServiceImpl.class);
|
||||||
|
|
||||||
|
private UnitPointerRepository unitPointerRepository;
|
||||||
|
|
||||||
|
public UnitPointerServiceImpl() {
|
||||||
|
this.unitPointerRepository = new UnitPointerRepositoryMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnitPointerServiceImpl(UnitPointerRepository unitPointerRepository) {
|
||||||
|
this.unitPointerRepository = unitPointerRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnitPointer getByEntityId(Integer entityId) {
|
||||||
|
return unitPointerRepository.findByEntityId(entityId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(UnitPointer unitPointer) {
|
||||||
|
unitPointerRepository.add(unitPointer);
|
||||||
|
log.info("Пользователь отправлен в репозиторий");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean check(Integer entityId) {
|
||||||
|
return unitPointerRepository.findByEntityId(entityId) != null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package org.sadtech.autoresponder.submodule.parser;
|
package org.sadtech.autoresponder.util;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -7,23 +7,18 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
public class Parser {
|
public class Parser {
|
||||||
|
|
||||||
private Set<String> words = new HashSet<>();
|
private Parser() {
|
||||||
private String text;
|
throw new IllegalStateException("Utility Class");
|
||||||
|
|
||||||
public Set<String> getWords() {
|
|
||||||
return words;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setText(String text) {
|
public static Set<String> parse(String text) {
|
||||||
this.text = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void parse() {
|
|
||||||
Pattern p = Pattern.compile("[а-яА-Я0-9]+");
|
Pattern p = Pattern.compile("[а-яА-Я0-9]+");
|
||||||
Matcher m = p.matcher(text);
|
Matcher m = p.matcher(text);
|
||||||
|
Set<String> words = new HashSet<>();
|
||||||
while (m.find()) {
|
while (m.find()) {
|
||||||
words.add(m.group().toLowerCase());
|
words.add(m.group().toLowerCase());
|
||||||
}
|
}
|
||||||
|
return words;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user