Remove BackupMXFOrExternalMX from domain and email module. This allows email configuration to be refactored into the email module (only).
This commit is contained in:
parent
f3a2ac9123
commit
775f9f98e6
@ -1,6 +1,5 @@
|
|||||||
package de.hsadmin.mods.dom;
|
package de.hsadmin.mods.dom;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -34,17 +33,12 @@ public class DomainProcessorFactory implements EntityProcessorFactory {
|
|||||||
public <T extends AbstractEntity> Processor createCreateProcessor(EntityManager em, T entity) throws ProcessorException {
|
public <T extends AbstractEntity> Processor createCreateProcessor(EntityManager em, T entity) throws ProcessorException {
|
||||||
String hiveName = entity.getHiveName();
|
String hiveName = entity.getHiveName();
|
||||||
Domain dom = (Domain) entity;
|
Domain dom = (Domain) entity;
|
||||||
UnixUser domUser = dom.getUser();
|
|
||||||
Pac pac = domUser.getPac();
|
|
||||||
WaitingTasksProcessor mainProcessor = new WaitingTasksProcessor(createHiveDNSSetupProcessor(em, dom));
|
WaitingTasksProcessor mainProcessor = new WaitingTasksProcessor(createHiveDNSSetupProcessor(em, dom));
|
||||||
mainProcessor.appendProcessor(hiveName, createHiveEMailSetupProcessor(em, dom), "Setup EMail");
|
mainProcessor.appendProcessor(hiveName, createHiveEMailSetupProcessor(em, dom), "Setup EMail");
|
||||||
Config config = Config.getInstance();
|
Config config = Config.getInstance();
|
||||||
for (String queueName : config.getProperty("queues.dns").split(",")) {
|
for (String queueName : config.getProperty("queues.dns").split(",")) {
|
||||||
mainProcessor.appendProcessor(queueName, createDNSServerConfigProcessor(em), queueName + ".hostsharing.net");
|
mainProcessor.appendProcessor(queueName, createDNSServerConfigProcessor(em), queueName + ".hostsharing.net");
|
||||||
}
|
}
|
||||||
for (String queueName : config.getProperty("queues.mail").split(",")) {
|
|
||||||
mainProcessor.appendProcessor(queueName, createMailinSetupProcessor(em, dom, pac), queueName + ".hostsharing.net");
|
|
||||||
}
|
|
||||||
mainProcessor.appendProcessor(hiveName, createDomainDirectoriesProcessor(dom), "Setup Domain Directories");
|
mainProcessor.appendProcessor(hiveName, createDomainDirectoriesProcessor(dom), "Setup Domain Directories");
|
||||||
mainProcessor.appendProcessor(hiveName, createApacheVHostSetupProcessor(em, dom), "Setup Apache VHost");
|
mainProcessor.appendProcessor(hiveName, createApacheVHostSetupProcessor(em, dom), "Setup Apache VHost");
|
||||||
mainProcessor.appendProcessor(hiveName, createACMEBotProcessor(em, dom), "Setup ACMEBot");
|
mainProcessor.appendProcessor(hiveName, createACMEBotProcessor(em, dom), "Setup ACMEBot");
|
||||||
@ -54,17 +48,11 @@ public class DomainProcessorFactory implements EntityProcessorFactory {
|
|||||||
|
|
||||||
public <T extends AbstractEntity> Processor createUpdateProcessor(final EntityManager em, final T entity) throws ProcessorException {
|
public <T extends AbstractEntity> Processor createUpdateProcessor(final EntityManager em, final T entity) throws ProcessorException {
|
||||||
final Domain dom = (Domain) entity;
|
final Domain dom = (Domain) entity;
|
||||||
final UnixUser domUser = dom.getUser();
|
|
||||||
final Pac pac = domUser.getPac();
|
|
||||||
final Processor apacheVHostSetupProcessor = createApacheVHostSetupProcessor(em, dom);
|
final Processor apacheVHostSetupProcessor = createApacheVHostSetupProcessor(em, dom);
|
||||||
final Processor letencryptSetupProcessor = createACMEBotProcessor(em, dom);
|
final Processor letencryptSetupProcessor = createACMEBotProcessor(em, dom);
|
||||||
final Processor triggerAcmebotProcessor = createTriggerAcmebotProcessor(em, dom);
|
final Processor triggerAcmebotProcessor = createTriggerAcmebotProcessor(em, dom);
|
||||||
final WaitingTasksProcessor processor = new WaitingTasksProcessor(
|
final WaitingTasksProcessor processor = new WaitingTasksProcessor(
|
||||||
new CompoundProcessor(apacheVHostSetupProcessor, letencryptSetupProcessor, triggerAcmebotProcessor));
|
new CompoundProcessor(apacheVHostSetupProcessor, letencryptSetupProcessor, triggerAcmebotProcessor));
|
||||||
final Config config = Config.getInstance();
|
|
||||||
for (String queueName : config.getProperty("queues.mail").split(",")) {
|
|
||||||
processor.appendProcessor(queueName, createMailinSetupProcessor(em, dom, pac), queueName + ".hostsharing.net");
|
|
||||||
}
|
|
||||||
return processor;
|
return processor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,9 +66,6 @@ public class DomainProcessorFactory implements EntityProcessorFactory {
|
|||||||
for (String queueName : config.getProperty("queues.dns").split(",")) {
|
for (String queueName : config.getProperty("queues.dns").split(",")) {
|
||||||
mainProcessor.appendProcessor(queueName, createDNSServerConfigProcessor(em), queueName + ".hostsharing.net");
|
mainProcessor.appendProcessor(queueName, createDNSServerConfigProcessor(em), queueName + ".hostsharing.net");
|
||||||
}
|
}
|
||||||
for (String queueName : config.getProperty("queues.mail").split(",")) {
|
|
||||||
mainProcessor.appendProcessor(queueName, createMailinUnsetupProcessor(em, dom), queueName + ".hostsharing.net");
|
|
||||||
}
|
|
||||||
mainProcessor.appendProcessor(dom.getHiveName(), createApacheVHostDeleteProcessor(dom), "remove apache vhost");
|
mainProcessor.appendProcessor(dom.getHiveName(), createApacheVHostDeleteProcessor(dom), "remove apache vhost");
|
||||||
mainProcessor.appendProcessor(dom.getHiveName(), createACMEBotProcessor(em, dom), "remove letsencrypt config");
|
mainProcessor.appendProcessor(dom.getHiveName(), createACMEBotProcessor(em, dom), "remove letsencrypt config");
|
||||||
return mainProcessor;
|
return mainProcessor;
|
||||||
@ -129,7 +114,7 @@ public class DomainProcessorFactory implements EntityProcessorFactory {
|
|||||||
" && invoke-rc.d bind9 reload");
|
" && invoke-rc.d bind9 reload");
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompoundProcessor createHiveEMailSetupProcessor(EntityManager em, Domain dom) {
|
private CompoundProcessor createHiveEMailSetupProcessor(EntityManager em, Domain dom) throws ProcessorException {
|
||||||
final EMailAddressProcessorFactory eMailAddressProcessorFactory = new EMailAddressProcessorFactory();
|
final EMailAddressProcessorFactory eMailAddressProcessorFactory = new EMailAddressProcessorFactory();
|
||||||
final CompoundProcessor emailAdrProcessor = new CompoundProcessor();
|
final CompoundProcessor emailAdrProcessor = new CompoundProcessor();
|
||||||
final Query query = em.createQuery(
|
final Query query = em.createQuery(
|
||||||
@ -144,75 +129,7 @@ public class DomainProcessorFactory implements EntityProcessorFactory {
|
|||||||
return emailAdrProcessor;
|
return emailAdrProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Processor createMailinSetupProcessor(EntityManager em, Domain dom, Pac pac) throws ProcessorException {
|
|
||||||
final String inetAddr = pac.getCurINetAddr().getInetAddr();
|
|
||||||
final CompoundProcessor cp = new CompoundProcessor(
|
|
||||||
createPostgreyConfiguration(em),
|
|
||||||
new ShellProcessor("postmap -r -i /etc/postfix-mailin/relaydomains",
|
|
||||||
dom.getName() + " anything\n" +
|
|
||||||
"." + dom.getName() + " anything\n"));
|
|
||||||
final Query query = em.createQuery("SELECT d FROM Domains d WHERE d.domainoptions.name = :option AND d.name = :domname");
|
|
||||||
query.setParameter("domname", dom.getName());
|
|
||||||
query.setParameter("option", "backupmxforexternalmx");
|
|
||||||
if (query.getResultList().isEmpty()) {
|
|
||||||
cp.appendProcessor(
|
|
||||||
new ShellProcessor("postmap -r -i /etc/postfix-mailin/transport",
|
|
||||||
dom.getName() + " smtp:" + inetAddr + ":225\n" +
|
|
||||||
"." + dom.getName() + " smtp:" + inetAddr + ":225\n")
|
|
||||||
);
|
|
||||||
cp.appendProcessor(
|
|
||||||
new ShellProcessor("postmap -r -i /etc/postfix-mailin/relayrecipients",
|
|
||||||
"@" + dom.getName() + " anything\n")
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
cp.appendProcessor(
|
|
||||||
new ShellProcessor(
|
|
||||||
"postmap -d '@" + dom.getName() + "' /etc/postfix-mailin/relayrecipients")
|
|
||||||
);
|
|
||||||
cp.appendProcessor(
|
|
||||||
new ShellProcessor(
|
|
||||||
"postmap -d '" + dom.getName() + "' /etc/postfix-mailin/transport && " +
|
|
||||||
"postmap -d '." + dom.getName() + "' /etc/postfix-mailin/transport")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return cp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Processor createPostgreyConfiguration(EntityManager em) throws ProcessorException {
|
|
||||||
final List<Domain> whitelistDoms = new ArrayList<Domain>();
|
|
||||||
final Query query = em.createQuery("SELECT DISTINCT dom FROM Domains dom WHERE NOT EXISTS " +
|
|
||||||
"( SELECT postgreyDom FROM Domains postgreyDom " +
|
|
||||||
" WHERE postgreyDom.domainoptions.name = :option" +
|
|
||||||
" AND postgreyDom.name = dom.name )");
|
|
||||||
query.setParameter("option", "greylisting");
|
|
||||||
final List<?> result = query.getResultList();
|
|
||||||
for (Object dom : result) {
|
|
||||||
if (dom instanceof Domain) {
|
|
||||||
whitelistDoms.add((Domain) dom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final HashMap<String, Object> templateVars = new HashMap<String, Object>();
|
|
||||||
templateVars.put("whitelist", whitelistDoms);
|
|
||||||
return new CompoundProcessor(
|
|
||||||
new VelocityProcessor("/de/hsadmin/mods/dom/postgrey-whitelist-recipients.vm",
|
|
||||||
templateVars, "/etc/postgrey/whitelist_recipients.tmp", true),
|
|
||||||
new ShellProcessor(" ( diff -q /etc/postgrey/whitelist_recipients.tmp /etc/postgrey/whitelist_recipients && rm /etc/postgrey/whitelist_recipients.tmp ) " +
|
|
||||||
"|| ( mv /etc/postgrey/whitelist_recipients.tmp /etc/postgrey/whitelist_recipients && invoke-rc.d postgrey reload )")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Processor createMailinUnsetupProcessor(EntityManager em, Domain dom) throws ProcessorException {
|
|
||||||
Processor mailQueueProcessor = new CompoundProcessor(
|
|
||||||
createPostgreyConfiguration(em),
|
|
||||||
new ShellProcessor(
|
|
||||||
"postmap -d '@" + dom.getName() + "' /etc/postfix-mailin/relayrecpients && " +
|
|
||||||
"postmap -d '" + dom.getName() + "' /etc/postfix-mailin/relaydomains && " +
|
|
||||||
"postmap -d '" + dom.getName() + "' /etc/postfix-mailin/transport && " +
|
|
||||||
"postmap -d '." + dom.getName() + "' /etc/postfix-mailin/relaydomains && " +
|
|
||||||
"postmap -d '." + dom.getName() + "' /etc/postfix-mailin/transport"));
|
|
||||||
return mailQueueProcessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CompoundProcessor createDomainDirectoriesProcessor(Domain dom) throws ProcessorException {
|
private CompoundProcessor createDomainDirectoriesProcessor(Domain dom) throws ProcessorException {
|
||||||
final Map<String, Object> templateVars = new HashMap<String, Object>();
|
final Map<String, Object> templateVars = new HashMap<String, Object>();
|
||||||
final UnixUser domUser = dom.getUser();
|
final UnixUser domUser = dom.getUser();
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package de.hsadmin.mods.email;
|
package de.hsadmin.mods.email;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
@ -9,19 +11,20 @@ import de.hsadmin.core.model.AbstractEntity;
|
|||||||
import de.hsadmin.core.qserv.CompoundProcessor;
|
import de.hsadmin.core.qserv.CompoundProcessor;
|
||||||
import de.hsadmin.core.qserv.EntityProcessorFactory;
|
import de.hsadmin.core.qserv.EntityProcessorFactory;
|
||||||
import de.hsadmin.core.qserv.Processor;
|
import de.hsadmin.core.qserv.Processor;
|
||||||
|
import de.hsadmin.core.qserv.ProcessorException;
|
||||||
import de.hsadmin.core.qserv.ShellProcessor;
|
import de.hsadmin.core.qserv.ShellProcessor;
|
||||||
|
import de.hsadmin.core.qserv.VelocityProcessor;
|
||||||
import de.hsadmin.core.qserv.WaitingTasksProcessor;
|
import de.hsadmin.core.qserv.WaitingTasksProcessor;
|
||||||
import de.hsadmin.core.util.Config;
|
import de.hsadmin.core.util.Config;
|
||||||
|
import de.hsadmin.mods.dom.Domain;
|
||||||
import de.hsadmin.mods.pac.Pac;
|
import de.hsadmin.mods.pac.Pac;
|
||||||
|
|
||||||
public class EMailAddressProcessorFactory implements EntityProcessorFactory {
|
public class EMailAddressProcessorFactory implements EntityProcessorFactory {
|
||||||
|
|
||||||
public <T extends AbstractEntity> Processor createCreateProcessor(EntityManager em, T entity) {
|
public <T extends AbstractEntity> Processor createCreateProcessor(EntityManager em, T entity)
|
||||||
// TODO: combine both keys in a single call (optimization)
|
throws ProcessorException {
|
||||||
EMailAddress email = (EMailAddress) entity;
|
EMailAddress email = (EMailAddress) entity;
|
||||||
CompoundProcessor cp = new CompoundProcessor();
|
CompoundProcessor cp = new CompoundProcessor();
|
||||||
cp.appendProcessor(
|
|
||||||
new ShellProcessor("postmap -r -i /etc/postfix-mailin/virtual", email.getFullDomain() + " -"));
|
|
||||||
cp.appendProcessor(new ShellProcessor("postmap -r -i /etc/postfix-mailin/virtual",
|
cp.appendProcessor(new ShellProcessor("postmap -r -i /etc/postfix-mailin/virtual",
|
||||||
email.getEMailAddress() + " " + email.getTarget()));
|
email.getEMailAddress() + " " + email.getTarget()));
|
||||||
WaitingTasksProcessor waitingTasksProcessor = new WaitingTasksProcessor(cp);
|
WaitingTasksProcessor waitingTasksProcessor = new WaitingTasksProcessor(cp);
|
||||||
@ -32,33 +35,48 @@ public class EMailAddressProcessorFactory implements EntityProcessorFactory {
|
|||||||
email.getEMailAddress() + " anything"),
|
email.getEMailAddress() + " anything"),
|
||||||
"Add to relayrecipients");
|
"Add to relayrecipients");
|
||||||
}
|
}
|
||||||
|
if (emailAddressCount(em, email) == 1) {
|
||||||
|
Domain dom = email.getDomain();
|
||||||
|
Pac pac = dom.getUser().getPac();
|
||||||
|
cp.appendProcessor(new ShellProcessor("postmap -r -i /etc/postfix-mailin/virtual",
|
||||||
|
dom.getName() + " -\n" +
|
||||||
|
"." + dom.getName() + " -\n"));
|
||||||
|
for (String queueName : config.getProperty("queues.mail").split(",")) {
|
||||||
|
waitingTasksProcessor.appendProcessor(queueName, createMailinSetupProcessor(em, dom, pac),
|
||||||
|
"Setup Mailin");
|
||||||
|
}
|
||||||
|
}
|
||||||
return waitingTasksProcessor;
|
return waitingTasksProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends AbstractEntity> Processor createUpdateProcessor(EntityManager em, T entity) {
|
public <T extends AbstractEntity> Processor createUpdateProcessor(EntityManager em, T entity)
|
||||||
// TODO: if update is specified by primary-key or DB query instead of
|
throws ProcessorException {
|
||||||
// OID, a postmap -d might be neccessary
|
|
||||||
return createCreateProcessor(em, entity);
|
return createCreateProcessor(em, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends AbstractEntity> Processor createDeleteProcessor(EntityManager em, T entity) {
|
public <T extends AbstractEntity> Processor createDeleteProcessor(EntityManager em, T entity)
|
||||||
CompoundProcessor cp = new CompoundProcessor();
|
throws ProcessorException {
|
||||||
EMailAddress email = (EMailAddress) entity;
|
EMailAddress email = (EMailAddress) entity;
|
||||||
if (emailAddressCount(em, email) == 0) {
|
CompoundProcessor cp = new CompoundProcessor();
|
||||||
// last email address removed
|
|
||||||
String fullDomain = email.getFullDomain();
|
|
||||||
cp.appendProcessor(new ShellProcessor("postmap -d '" + fullDomain + "' /etc/postfix-mailin/virtual"));
|
|
||||||
}
|
|
||||||
cp.appendProcessor(
|
cp.appendProcessor(
|
||||||
new ShellProcessor("postmap -d '" + email.getEMailAddress() + "' /etc/postfix-mailin/virtual"));
|
new ShellProcessor("postmap -d - /etc/postfix-mailin/virtual", email.getEMailAddress() + "\n"));
|
||||||
Config config = Config.getInstance();
|
Config config = Config.getInstance();
|
||||||
WaitingTasksProcessor waitingTasksProcessor = new WaitingTasksProcessor(cp);
|
WaitingTasksProcessor waitingTasksProcessor = new WaitingTasksProcessor(cp);
|
||||||
for (String queueName : config.getProperty("queues.mail").split(",")) {
|
for (String queueName : config.getProperty("queues.mail").split(",")) {
|
||||||
waitingTasksProcessor.appendProcessor(queueName,
|
waitingTasksProcessor.appendProcessor(queueName,
|
||||||
new ShellProcessor(
|
new ShellProcessor("postmap -d - /etc/postfix-mailin/relayrecipients",
|
||||||
"postmap -d '" + email.getEMailAddress() + "' /etc/postfix-mailin/relayrecipients"),
|
email.getEMailAddress() + "\n"),
|
||||||
"Remove from relayrecipients");
|
"Remove from relayrecipients");
|
||||||
}
|
}
|
||||||
|
if (emailAddressCount(em, email) == 0) {
|
||||||
|
Domain dom = email.getDomain();
|
||||||
|
cp.appendProcessor(new ShellProcessor("postmap -d - /etc/postfix-mailin/virtual",
|
||||||
|
dom.getName() + "\n" +
|
||||||
|
"." + dom.getName() + "\n"));
|
||||||
|
for (String queueName : config.getProperty("queues.mail").split(",")) {
|
||||||
|
waitingTasksProcessor.appendProcessor(queueName, createMailinUnsetupProcessor(em, dom), "Unsetup Mailin");
|
||||||
|
}
|
||||||
|
}
|
||||||
return waitingTasksProcessor;
|
return waitingTasksProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,4 +97,50 @@ public class EMailAddressProcessorFactory implements EntityProcessorFactory {
|
|||||||
return result.size();
|
return result.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Processor createPostgreyConfigurationUpdateProcessor(EntityManager em) throws ProcessorException {
|
||||||
|
final List<Domain> whitelistDoms = new ArrayList<Domain>();
|
||||||
|
final Query query = em.createQuery("SELECT DISTINCT dom FROM Domains dom WHERE NOT EXISTS "
|
||||||
|
+ "(SELECT postgreyDom FROM Domains postgreyDom "
|
||||||
|
+ "WHERE postgreyDom.domainoptions.name = :option"
|
||||||
|
+ "AND postgreyDom.name = dom.name)");
|
||||||
|
query.setParameter("option", "greylisting");
|
||||||
|
final List<?> result = query.getResultList();
|
||||||
|
for (Object dom : result) {
|
||||||
|
if (dom instanceof Domain) {
|
||||||
|
whitelistDoms.add((Domain) dom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final HashMap<String, Object> templateVars = new HashMap<String, Object>();
|
||||||
|
templateVars.put("whitelist", whitelistDoms);
|
||||||
|
return new CompoundProcessor(
|
||||||
|
new VelocityProcessor("/de/hsadmin/mods/dom/postgrey-whitelist-recipients.vm", templateVars,
|
||||||
|
"/etc/postgrey/whitelist_recipients.tmp", true),
|
||||||
|
new ShellProcessor(
|
||||||
|
" ( diff -q /etc/postgrey/whitelist_recipients.tmp /etc/postgrey/whitelist_recipients && rm /etc/postgrey/whitelist_recipients.tmp ) "
|
||||||
|
+ "|| ( mv /etc/postgrey/whitelist_recipients.tmp /etc/postgrey/whitelist_recipients && invoke-rc.d postgrey reload )"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Processor createMailinSetupProcessor(EntityManager em, Domain dom, Pac pac) throws ProcessorException {
|
||||||
|
final String inetAddr = pac.getCurINetAddr().getInetAddr();
|
||||||
|
final CompoundProcessor cp = new CompoundProcessor(createPostgreyConfigurationUpdateProcessor(em));
|
||||||
|
cp.appendProcessor(new ShellProcessor("postmap -r -i /etc/postfix-mailin/relaydomains",
|
||||||
|
dom.getName() + " anything\n" +
|
||||||
|
"." + dom.getName() + " anything\n"));
|
||||||
|
cp.appendProcessor(new ShellProcessor("postmap -r -i /etc/postfix-mailin/transport",
|
||||||
|
dom.getName() + " smtp:" + inetAddr + ":225\n" +
|
||||||
|
"." + dom.getName() + " smtp:" + inetAddr + ":225\n"));
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Processor createMailinUnsetupProcessor(EntityManager em, Domain dom) throws ProcessorException {
|
||||||
|
final CompoundProcessor cp = new CompoundProcessor(createPostgreyConfigurationUpdateProcessor(em));
|
||||||
|
cp.appendProcessor(new ShellProcessor("postmap -d - /etc/postfix-mailin/relaydomains",
|
||||||
|
dom.getName() + "\n" +
|
||||||
|
"." + dom.getName() + "\n"));
|
||||||
|
cp.appendProcessor(new ShellProcessor("postmap -d - /etc/postfix-mailin/transport",
|
||||||
|
dom.getName() + "\n" +
|
||||||
|
"." + dom.getName() + "\n"));
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user