Základní implementace podepisování PDF dokumentů. Podpis implementován pouze pro sestavu schválení služební cesty (natvrdo v kódu). Spouští se univerzální podepisovací aplikace, která čte certifikát ze souboru.
closes #224
This commit is contained in:
@@ -168,4 +168,7 @@ public class Constants {
|
||||
public final static int LEN_TEXT = 255;
|
||||
public final static int LEN_DESCRIPTION = 8192;
|
||||
public final static int LEN_RESULT_MESSAGE = 8192;
|
||||
|
||||
public final static String KEY_SIGN_DATA = "SIGN_DATA";
|
||||
public final static String KEY_SIGN_GUID = "SIGN_GUID";
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import info.bukova.isspst.data.User;
|
||||
import info.bukova.isspst.data.Workgroup;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -13,16 +14,18 @@ public class SessionData implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -764426911263559758L;
|
||||
private static final long serialVersionUID = -764426911263559759L;
|
||||
|
||||
private List<Workgroup> userCentres;
|
||||
private List<Workgroup> userWorkgroups;
|
||||
private User currentUser;
|
||||
private Map<Integer, List<Role>> workgroupRoles;
|
||||
private boolean loginFailed;
|
||||
|
||||
private Map<String, Object> properties;
|
||||
|
||||
public SessionData() {
|
||||
loginFailed = false;
|
||||
properties = new HashMap<String, Object>();
|
||||
}
|
||||
|
||||
public List<Workgroup> getUserCentres() {
|
||||
@@ -65,4 +68,11 @@ public class SessionData implements Serializable {
|
||||
this.loginFailed = loginFailed;
|
||||
}
|
||||
|
||||
public void setProperty(String key, Object value) {
|
||||
properties.put(key, value);
|
||||
}
|
||||
|
||||
public Object getProperty(String key) {
|
||||
return properties.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package info.bukova.isspst.reporting;
|
||||
|
||||
import com.lowagie.text.Rectangle;
|
||||
import com.lowagie.text.pdf.PdfAnnotation;
|
||||
import com.lowagie.text.pdf.PdfFormField;
|
||||
import com.lowagie.text.pdf.PdfName;
|
||||
import net.sf.jasperreports.engine.JRGenericPrintElement;
|
||||
import net.sf.jasperreports.engine.JRPropertiesMap;
|
||||
import net.sf.jasperreports.engine.export.GenericElementHandler;
|
||||
import net.sf.jasperreports.engine.export.GenericElementHandlerBundle;
|
||||
import net.sf.jasperreports.engine.export.GenericElementPdfHandler;
|
||||
import net.sf.jasperreports.engine.export.JRPdfExporter;
|
||||
import net.sf.jasperreports.engine.export.JRPdfExporterContext;
|
||||
import net.sf.jasperreports.extensions.ExtensionsRegistry;
|
||||
import net.sf.jasperreports.extensions.ExtensionsRegistryFactory;
|
||||
import net.sf.jasperreports.extensions.SingletonExtensionRegistry;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public class SignaturePdfHandler implements GenericElementPdfHandler, GenericElementHandlerBundle, ExtensionsRegistryFactory {
|
||||
|
||||
@Override
|
||||
public ExtensionsRegistry createRegistry(String registryId, JRPropertiesMap properties) {
|
||||
return new SingletonExtensionRegistry<GenericElementHandlerBundle>(GenericElementHandlerBundle.class, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportElement(JRPdfExporterContext exporterContext, JRGenericPrintElement element) {
|
||||
PdfFormField field = PdfFormField.createSignature(exporterContext.getPdfWriter());
|
||||
field.setFieldName("signature");
|
||||
field.setFieldFlags(PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_LOCKED);
|
||||
field.setWidget(new Rectangle(element.getX(), element.getY(), element.getX() + element.getWidth(), element.getY() + element.getHeight()), PdfName.HIGHLIGHT);
|
||||
exporterContext.getPdfWriter().addAnnotation(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean toExport(JRGenericPrintElement element) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return "urn:sig:sig";
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericElementHandler getHandler(String elementName, String exporterKey) {
|
||||
if (elementName.equals("signature") && exporterKey.equals(JRPdfExporter.PDF_EXPORTER_KEY)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package info.bukova.isspst.signapi;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public interface JnlpGenerator {
|
||||
|
||||
public byte[] generate();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package info.bukova.isspst.signapi;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public class JnlpGeneratorImpl implements JnlpGenerator {
|
||||
|
||||
@Autowired
|
||||
private HttpServletRequest request;
|
||||
|
||||
@Override
|
||||
public byte[] generate() {
|
||||
String sessionId;
|
||||
|
||||
if (request.getParameter("id") != null && !request.getParameter("id").isEmpty()) {
|
||||
sessionId = request.getParameter("id");
|
||||
} else {
|
||||
sessionId = request.getSession().getId();
|
||||
}
|
||||
|
||||
try {
|
||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
||||
|
||||
Document document = docBuilder.newDocument();
|
||||
Element root = document.createElement("jnlp");
|
||||
root.setAttribute("spec", "1.0+");
|
||||
|
||||
String signerUrl = request.getRequestURL().toString();
|
||||
signerUrl = signerUrl.substring(0, signerUrl.indexOf(request.getServletPath())) + "/api/sign";
|
||||
|
||||
root.setAttribute("codebase", signerUrl);
|
||||
root.setAttribute("href", "signer.jnlp" + "?id=" + sessionId);
|
||||
document.appendChild(root);
|
||||
|
||||
Element info = document.createElement("information");
|
||||
Element title = document.createElement("title");
|
||||
title.appendChild(document.createTextNode("Signer component"));
|
||||
info.appendChild(title);
|
||||
Element vendor = document.createElement("vendor");
|
||||
vendor.appendChild(document.createTextNode("bukova.info"));
|
||||
info.appendChild(vendor);
|
||||
root.appendChild(info);
|
||||
|
||||
Element security = document.createElement("security");
|
||||
security.appendChild(document.createElement("all-permissions"));
|
||||
root.appendChild(security);
|
||||
|
||||
Element resources = document.createElement("resources");
|
||||
Element j2se = document.createElement("j2se");
|
||||
j2se.setAttribute("version", "1.8+");
|
||||
Element jar = document.createElement("jar");
|
||||
jar.setAttribute("href", "pdfsigner.jar");
|
||||
resources.appendChild(j2se);
|
||||
resources.appendChild(jar);
|
||||
root.appendChild(resources);
|
||||
|
||||
Element appDesc = document.createElement("application-desc");
|
||||
appDesc.setAttribute("main-class", "info.bukova.pdfsigner.Main");
|
||||
Element argUrl = document.createElement("argument");
|
||||
argUrl.appendChild(document.createTextNode(signerUrl + "/data"));
|
||||
appDesc.appendChild(argUrl);
|
||||
Element argSession = document.createElement("argument");
|
||||
argSession.appendChild(document.createTextNode(sessionId));
|
||||
appDesc.appendChild(argSession);
|
||||
root.appendChild(appDesc);
|
||||
|
||||
|
||||
System.out.println(signerUrl);
|
||||
System.out.println(request.getSession().getId());
|
||||
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
DOMSource source = new DOMSource(document);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
StreamResult result = new StreamResult(bos);
|
||||
|
||||
transformer.transform(source, result);
|
||||
|
||||
return bos.toByteArray();
|
||||
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (TransformerConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (TransformerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package info.bukova.isspst.signapi;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public class SignData implements Serializable {
|
||||
|
||||
private byte[] pdfData;
|
||||
private byte[] signImg;
|
||||
private int areaId;
|
||||
private Date signDate;
|
||||
private String description;
|
||||
private String numser;
|
||||
private boolean signed;
|
||||
private String signGuid;
|
||||
private boolean signSuccess;
|
||||
|
||||
public byte[] getPdfData() {
|
||||
return pdfData;
|
||||
}
|
||||
|
||||
public void setPdfData(byte[] pdfData) {
|
||||
this.pdfData = pdfData;
|
||||
}
|
||||
|
||||
public Date getSignDate() {
|
||||
return signDate;
|
||||
}
|
||||
|
||||
public void setSignDate(Date signDate) {
|
||||
this.signDate = signDate;
|
||||
}
|
||||
|
||||
public String getNumser() {
|
||||
return numser;
|
||||
}
|
||||
|
||||
public void setNumser(String numser) {
|
||||
this.numser = numser;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public boolean isSigned() {
|
||||
return signed;
|
||||
}
|
||||
|
||||
public void setSigned(boolean signed) {
|
||||
this.signed = signed;
|
||||
}
|
||||
|
||||
public String getSignGuid() {
|
||||
return signGuid;
|
||||
}
|
||||
|
||||
public void setSignGuid(String signGuid) {
|
||||
this.signGuid = signGuid;
|
||||
}
|
||||
|
||||
public boolean isSignSuccess() {
|
||||
return signSuccess;
|
||||
}
|
||||
|
||||
public void setSignSuccess(boolean signSuccess) {
|
||||
this.signSuccess = signSuccess;
|
||||
}
|
||||
|
||||
public byte[] getSignImg() {
|
||||
return signImg;
|
||||
}
|
||||
|
||||
public void setSignImg(byte[] signImg) {
|
||||
this.signImg = signImg;
|
||||
}
|
||||
|
||||
public int getAreaId() {
|
||||
return areaId;
|
||||
}
|
||||
|
||||
public void setAreaId(int areaId) {
|
||||
this.areaId = areaId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package info.bukova.isspst.signapi;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
public class SignUploadResponse implements Serializable {
|
||||
|
||||
private boolean ok;
|
||||
private String errorMessage;
|
||||
|
||||
public boolean isOk() {
|
||||
return ok;
|
||||
}
|
||||
|
||||
public void setOk(boolean ok) {
|
||||
this.ok = ok;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public void setErrorMessage(String errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package info.bukova.isspst.signapi;
|
||||
|
||||
import info.bukova.isspst.Constants;
|
||||
import info.bukova.isspst.SessionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
*/
|
||||
|
||||
@Controller
|
||||
public class SigningController {
|
||||
|
||||
@Autowired
|
||||
private SessionData sessionData;
|
||||
@Autowired
|
||||
private JnlpGenerator jnlpGenerator;
|
||||
@Autowired
|
||||
private ServletContext context;
|
||||
|
||||
@RequestMapping(value="/sign/data", method= RequestMethod.GET)
|
||||
public void dataForSign(HttpServletResponse response, HttpServletRequest request) {
|
||||
SignData data = (SignData) sessionData.getProperty(Constants.KEY_SIGN_DATA);
|
||||
ObjectOutputStream os = null;
|
||||
|
||||
try {
|
||||
os = new ObjectOutputStream(response.getOutputStream());
|
||||
response.setContentType("application/x-java-serialized-object");
|
||||
os.writeObject(data);
|
||||
os.flush();
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (os != null) {
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RequestMapping(value="/sign/data", method= RequestMethod.POST)
|
||||
public void signedData(HttpServletRequest request, HttpServletResponse response) {
|
||||
ObjectInputStream ois = null;
|
||||
ObjectOutputStream os = null;
|
||||
String error = null;
|
||||
|
||||
try {
|
||||
ois = new ObjectInputStream(request.getInputStream());
|
||||
SignData data = (SignData) ois.readObject();
|
||||
sessionData.setProperty(Constants.KEY_SIGN_DATA, data);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
error = "IO error";
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
error = "Loading error";
|
||||
}
|
||||
|
||||
try {
|
||||
SignUploadResponse resp = new SignUploadResponse();
|
||||
|
||||
if (error == null) {
|
||||
resp.setOk(true);
|
||||
} else {
|
||||
resp.setOk(false);
|
||||
resp.setErrorMessage(error);
|
||||
}
|
||||
|
||||
os = new ObjectOutputStream(response.getOutputStream());
|
||||
response.setContentType("application/x-java-serialized-object");
|
||||
os.writeObject(resp);
|
||||
os.flush();
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value="/sign/signer.jnlp", method= RequestMethod.GET)
|
||||
public void jnlp(HttpServletResponse response) {
|
||||
byte[] data = jnlpGenerator.generate();
|
||||
sendByte(response, data, "application/x-java-jnlp-file");
|
||||
}
|
||||
|
||||
@RequestMapping(value="/sign/pdfsigner.jar", method= RequestMethod.GET)
|
||||
public void pdfsigner(HttpServletResponse response) {
|
||||
File inputJar = new File(context.getRealPath("/WEB-INF/signer/PDFSigner.jar"));
|
||||
|
||||
try {
|
||||
byte[] data = new byte[(int) inputJar.length()];
|
||||
FileInputStream is = new FileInputStream(inputJar);
|
||||
is.read(data);
|
||||
sendByte(response, data, "application/java-archive");
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void sendByte(HttpServletResponse response, byte[] data, String contentType) {
|
||||
ServletOutputStream os = null;
|
||||
|
||||
try {
|
||||
os = response.getOutputStream();
|
||||
response.setContentType(contentType);
|
||||
response.setContentLength(data.length);
|
||||
os.write(data);
|
||||
os.flush();
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +1,32 @@
|
||||
package info.bukova.isspst.ui.main;
|
||||
|
||||
import info.bukova.isspst.Constants;
|
||||
import info.bukova.isspst.SessionData;
|
||||
import info.bukova.isspst.StringUtils;
|
||||
import info.bukova.isspst.data.RequirementBase;
|
||||
import info.bukova.isspst.reporting.Generator;
|
||||
import info.bukova.isspst.reporting.GeneratorFactory;
|
||||
import info.bukova.isspst.reporting.ParamFiller;
|
||||
import info.bukova.isspst.reporting.Report;
|
||||
import info.bukova.isspst.reporting.ReportDefinition;
|
||||
import info.bukova.isspst.services.Service;
|
||||
import info.bukova.isspst.services.requirement.ApproveException;
|
||||
import info.bukova.isspst.services.requirement.RequirementBaseService;
|
||||
import info.bukova.isspst.signapi.SignData;
|
||||
import info.bukova.isspst.ui.ListViewModel;
|
||||
import org.zkoss.bind.BindUtils;
|
||||
import org.zkoss.bind.annotation.BindingParam;
|
||||
import org.zkoss.bind.annotation.Command;
|
||||
import org.zkoss.bind.annotation.ExecutionArgParam;
|
||||
import org.zkoss.bind.annotation.Init;
|
||||
import org.zkoss.bind.annotation.NotifyChange;
|
||||
import org.zkoss.zk.ui.Executions;
|
||||
import org.zkoss.zk.ui.select.annotation.WireVariable;
|
||||
import org.zkoss.zul.Messagebox;
|
||||
import org.zkoss.zul.Window;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Pepa Rokos
|
||||
@@ -24,6 +37,16 @@ public class ApproveDialogVM {
|
||||
private RequirementBase requirement;
|
||||
private ListViewModel grid;
|
||||
private Date approveDate;
|
||||
@WireVariable
|
||||
private SessionData sessionData;
|
||||
@WireVariable
|
||||
private ReportDefinition reportDefinition;
|
||||
@WireVariable
|
||||
private GeneratorFactory genFactory;
|
||||
@WireVariable
|
||||
private ParamFiller paramFiller;
|
||||
private boolean signed;
|
||||
private boolean timer;
|
||||
|
||||
public Date getApproveDate() {
|
||||
return approveDate;
|
||||
@@ -41,6 +64,9 @@ public class ApproveDialogVM {
|
||||
this.requirement = requirement;
|
||||
this.grid = grid;
|
||||
this.approveDate = new Date();
|
||||
|
||||
this.signed = false;
|
||||
this.timer = false;
|
||||
}
|
||||
|
||||
@Command
|
||||
@@ -57,4 +83,51 @@ public class ApproveDialogVM {
|
||||
}
|
||||
}
|
||||
|
||||
@Command
|
||||
@NotifyChange("timer")
|
||||
public void signPdf() {
|
||||
SignData data = new SignData();
|
||||
sessionData.setProperty(Constants.KEY_SIGN_DATA, data);
|
||||
data.setSignGuid(UUID.randomUUID().toString());
|
||||
sessionData.setProperty(Constants.KEY_SIGN_GUID, data.getSignGuid());
|
||||
|
||||
// ToDo: Generovat report
|
||||
reportDefinition.clear();
|
||||
reportDefinition.setSingleObject(requirement);
|
||||
reportDefinition.setReport(new Report(0, true, "", "tripRequirementApp", false, true, true));
|
||||
reportDefinition.setService((Service) service);
|
||||
|
||||
paramFiller.fill();
|
||||
Generator gen = genFactory.createGenerator(reportDefinition);
|
||||
data.setPdfData(gen.generate());
|
||||
data.setDescription(requirement.getDescription());
|
||||
data.setNumser(requirement.getNumser());
|
||||
|
||||
timer = true;
|
||||
|
||||
Executions.getCurrent().sendRedirect("/api/sign/signer.jnlp", "signer");
|
||||
}
|
||||
|
||||
@Command
|
||||
@NotifyChange({"signed", "timer"})
|
||||
public void onTimer() {
|
||||
String guid = (String) sessionData.getProperty(Constants.KEY_SIGN_GUID);
|
||||
SignData data = (SignData) sessionData.getProperty(Constants.KEY_SIGN_DATA);
|
||||
|
||||
if (guid.equals(data.getSignGuid()) && data.isSignSuccess()) {
|
||||
signed = true;
|
||||
timer = false;
|
||||
} else {
|
||||
signed = false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSigned() {
|
||||
return signed;
|
||||
}
|
||||
|
||||
public boolean isTimer() {
|
||||
return timer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
net.sf.jasperreports.extension.registry.factory.sig=info.bukova.isspst.reporting.SignaturePdfHandler
|
||||
Binary file not shown.
@@ -0,0 +1,356 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="tripRequirement" pageWidth="612" pageHeight="792" columnWidth="572" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="0b7fa2d2-d452-4a1f-b1c0-2d8e16a22525">
|
||||
<property name="ireport.zoom" value="1.5"/>
|
||||
<property name="ireport.x" value="0"/>
|
||||
<property name="ireport.y" value="272"/>
|
||||
<style name="table">
|
||||
<box>
|
||||
<pen lineWidth="1.0" lineColor="#000000"/>
|
||||
</box>
|
||||
</style>
|
||||
<style name="table_TH" mode="Opaque" backcolor="#F0F8FF">
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineColor="#000000"/>
|
||||
</box>
|
||||
</style>
|
||||
<style name="table_CH" mode="Opaque" backcolor="#BFE1FF">
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineColor="#000000"/>
|
||||
</box>
|
||||
</style>
|
||||
<style name="table_TD" mode="Opaque" backcolor="#FFFFFF">
|
||||
<box>
|
||||
<pen lineWidth="0.5" lineColor="#000000"/>
|
||||
</box>
|
||||
</style>
|
||||
<subDataset name="Passengers" uuid="89ee82de-f017-493e-85d1-439a0ff3be72">
|
||||
<queryString>
|
||||
<![CDATA[]]>
|
||||
</queryString>
|
||||
<field name="fullName" class="java.lang.String">
|
||||
<fieldDescription><![CDATA[fullName]]></fieldDescription>
|
||||
</field>
|
||||
</subDataset>
|
||||
<subDataset name="dataset1" uuid="2030e480-17f9-4ac5-a8f1-7499b269f3b4"/>
|
||||
<parameter name="P_USER_SIGNATURE" class="java.lang.String"/>
|
||||
<parameter name="P_APPROVE_DATE" class="java.util.Date"/>
|
||||
<parameter name="P_APPROVER_SIGNATURE" class="java.lang.String"/>
|
||||
<parameter name="P_LOGO" class="java.lang.String"/>
|
||||
<parameter name="P_MAIN_ADDRESS" class="java.lang.String"/>
|
||||
<parameter name="P_PREV_APPROVE_DATE" class="java.util.Date"/>
|
||||
<parameter name="P_PREV_APPROVER_SIGNATURE" class="java.lang.String"/>
|
||||
<parameter name="SUBREPORT_DIR" class="java.lang.String"/>
|
||||
<field name="ownedBy" class="info.bukova.isspst.data.User"/>
|
||||
<field name="reqDate" class="java.util.Date"/>
|
||||
<field name="from" class="java.lang.String"/>
|
||||
<field name="tripDate" class="java.util.Date"/>
|
||||
<field name="to" class="java.lang.String"/>
|
||||
<field name="description" class="java.lang.String"/>
|
||||
<field name="end" class="java.lang.String"/>
|
||||
<field name="endDate" class="java.util.Date"/>
|
||||
<field name="passengers" class="java.util.Collection"/>
|
||||
<field name="foreignPersons" class="java.lang.String"/>
|
||||
<field name="vehicle" class="info.bukova.isspst.data.Vehicle"/>
|
||||
<field name="vehicle.code" class="java.lang.String"/>
|
||||
<field name="requireDownPayment" class="java.lang.Boolean"/>
|
||||
<field name="downPayment" class="java.math.BigDecimal"/>
|
||||
<field name="ownedBy.address" class="info.bukova.isspst.data.UsersAddress"/>
|
||||
<field name="ownedBy.address.street" class="java.lang.String"/>
|
||||
<field name="ownedBy.address.houseNumber" class="java.lang.String"/>
|
||||
<field name="ownedBy.address.zipCode" class="java.lang.String"/>
|
||||
<field name="ownedBy.address.city" class="java.lang.String"/>
|
||||
<background>
|
||||
<band splitType="Stretch"/>
|
||||
</background>
|
||||
<title>
|
||||
<band height="79" splitType="Stretch">
|
||||
<image onErrorType="Blank">
|
||||
<reportElement uuid="ef1dc796-f5c6-4036-99eb-26e7b6b7abbc" x="0" y="0" width="100" height="79" isRemoveLineWhenBlank="true">
|
||||
<printWhenExpression><![CDATA[$P{P_LOGO} != null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<imageExpression><![CDATA[$P{P_LOGO}]]></imageExpression>
|
||||
</image>
|
||||
<textField>
|
||||
<reportElement uuid="3e2074cd-220c-4c9a-b94c-a0a254cc24a6" x="100" y="0" width="471" height="34"/>
|
||||
<textElement textAlignment="Center">
|
||||
<font isBold="true" pdfEncoding="Cp1250"/>
|
||||
</textElement>
|
||||
<textFieldExpression><![CDATA[$P{P_MAIN_ADDRESS}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement uuid="a7a82c52-e8b8-41cf-b13a-ebc54d30d04f" x="101" y="34" width="470" height="45"/>
|
||||
<textElement textAlignment="Center" verticalAlignment="Bottom">
|
||||
<font size="14" isBold="true" pdfEncoding="Cp1250"/>
|
||||
</textElement>
|
||||
<text><![CDATA[CESTOVNÍ PŘÍKAZ
|
||||
k tuzemské pracovní cestě]]></text>
|
||||
</staticText>
|
||||
</band>
|
||||
</title>
|
||||
<detail>
|
||||
<band height="529" splitType="Stretch">
|
||||
<staticText>
|
||||
<reportElement uuid="f6445d7f-1e96-4d17-9f1d-27eaa8f15022" x="0" y="7" width="143" height="20"/>
|
||||
<textElement/>
|
||||
<text><![CDATA[Příjmení, jméno, titul:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement uuid="6f073490-98cc-445b-8b51-81facf335657" x="0" y="27" width="100" height="20"/>
|
||||
<textElement/>
|
||||
<text><![CDATA[Bydliště:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement uuid="a3e2a5d3-ea50-48bd-94ea-4530f6624b52" x="0" y="51" width="572" height="20"/>
|
||||
<textElement textAlignment="Center">
|
||||
<font size="12" pdfFontName="Helvetica-Bold"/>
|
||||
</textElement>
|
||||
<text><![CDATA[Souhlasím s vysláním na pracovní cestu]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement uuid="306f2b85-5dc6-40a6-8c44-76ed46831680" x="0" y="76" width="143" height="20"/>
|
||||
<textElement/>
|
||||
<text><![CDATA[Požaduji poskytnutí zálohy:]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement uuid="029f1b4c-5f59-4a5e-8d3d-b644af41b657" x="301" y="121" width="271" height="1"/>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement uuid="2f0f450a-b89d-4862-b82e-4eb1e9861927" x="301" y="128" width="271" height="20"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<text><![CDATA[Datum a podpis]]></text>
|
||||
</staticText>
|
||||
<textField pattern="dd. MM. yyyy">
|
||||
<reportElement uuid="dd5f12d3-9ce1-4565-83ed-fe9004e3a6c3" x="301" y="101" width="77" height="20"/>
|
||||
<textElement/>
|
||||
<textFieldExpression><![CDATA[$F{reqDate}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement uuid="a2912fef-ae4a-4c7e-b08c-3f5f6b92a534" x="0" y="157" width="572" height="20"/>
|
||||
<textElement textAlignment="Center">
|
||||
<font size="16" isBold="true" pdfFontName="Helvetica-Bold" isPdfEmbedded="true"/>
|
||||
</textElement>
|
||||
<text><![CDATA[PODMÍNKY PRACOVNÍ CESTY]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement uuid="b415fa20-91d9-4772-9b73-fd26b6cf32a3" x="0" y="177" width="572" height="1"/>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement uuid="74a5cf40-10b4-4f99-8945-5e14323a7b98" x="0" y="253" width="572" height="1"/>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement uuid="a3a337aa-8b1c-4f4f-abc0-4b5a6cba04d5" x="0" y="156" width="572" height="1"/>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement uuid="ed4e3928-9a68-4f61-9876-254547efa04e" x="0" y="180" width="143" height="27"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<text><![CDATA[Počátek cesty (místo, datum, hodina)]]></text>
|
||||
</staticText>
|
||||
<textField>
|
||||
<reportElement uuid="ed4a676e-2647-4a91-a1b5-1ff326f50359" x="0" y="208" width="143" height="20"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<textFieldExpression><![CDATA[$F{from}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField pattern="dd. MM. yyyy">
|
||||
<reportElement uuid="fd80824e-0a50-4e37-abd5-1c8bf92ded4a" x="0" y="228" width="90" height="20"/>
|
||||
<textElement/>
|
||||
<textFieldExpression><![CDATA[$F{tripDate}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField pattern="hh:mm">
|
||||
<reportElement uuid="4d004341-3dc5-4b77-a0f2-d93c93aff176" x="90" y="228" width="53" height="20"/>
|
||||
<textElement/>
|
||||
<textFieldExpression><![CDATA[$F{tripDate}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement uuid="36c8b801-3fdf-4464-99d7-4f07539d76f8" x="143" y="180" width="143" height="27"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<text><![CDATA[Místo jednání]]></text>
|
||||
</staticText>
|
||||
<textField>
|
||||
<reportElement uuid="6e9e44fe-3022-4802-854e-607238cb21be" x="143" y="208" width="143" height="20"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<textFieldExpression><![CDATA[$F{to}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement uuid="398372d7-7995-42fa-a53a-f50b0f8936db" x="286" y="179" width="143" height="27"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<text><![CDATA[Účel cesty]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement uuid="3dbc8b8d-7ac4-40d8-b43c-89e81d26f15c" x="429" y="180" width="143" height="26"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<text><![CDATA[Konec cesty (místo, datum)]]></text>
|
||||
</staticText>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement uuid="3b52420d-1c84-4042-bc88-16f4f36a3af8" x="286" y="208" width="143" height="40"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<textFieldExpression><![CDATA[$F{description}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField>
|
||||
<reportElement uuid="3e9b796b-fc9e-42e4-93d6-a966ce78c771" x="429" y="208" width="143" height="20"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<textFieldExpression><![CDATA[$F{end}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField pattern="dd. MM. yyyy">
|
||||
<reportElement uuid="6ae75bed-b03b-4857-b624-71daeb35513d" x="429" y="228" width="143" height="20"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<textFieldExpression><![CDATA[$F{endDate}]]></textFieldExpression>
|
||||
</textField>
|
||||
<textField>
|
||||
<reportElement uuid="ad778808-c5cc-419c-b34f-fc84effc1958" x="186" y="7" width="181" height="20"/>
|
||||
<textElement/>
|
||||
<textFieldExpression><![CDATA[$F{ownedBy}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement uuid="deafc33f-99ed-483e-8682-57a18872941d" x="0" y="265" width="143" height="20"/>
|
||||
<textElement/>
|
||||
<text><![CDATA[Spolucestující:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement uuid="ab2fbb7c-28d3-4e6b-beb9-93c6fc8745c8" x="0" y="307" width="348" height="20"/>
|
||||
<textElement/>
|
||||
<text><![CDATA[Určený dopravní prostředek (u vlastního vozidla druh a reg. značka):]]></text>
|
||||
</staticText>
|
||||
<textField>
|
||||
<reportElement uuid="1a52f009-c560-443a-9b84-cd9502b6b0c5" x="348" y="307" width="60" height="20"/>
|
||||
<textElement/>
|
||||
<textFieldExpression><![CDATA[$F{vehicle.code}]]></textFieldExpression>
|
||||
</textField>
|
||||
<staticText>
|
||||
<reportElement uuid="8355e20a-124b-4c63-ab9c-4d64be5b912e" x="0" y="327" width="572" height="40"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<text><![CDATA[A - autobus, V - vlak
|
||||
AUV - auto vlastní, AUS - auto služební, AUC - auto cizí
|
||||
L - letadlo, P - pěšky, T - taxi]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement uuid="94f07671-9d8f-4542-9afe-f1c0b8ae1a02" x="0" y="369" width="143" height="20"/>
|
||||
<textElement/>
|
||||
<text><![CDATA[Ubytování:]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement uuid="b1cd5f7d-48fc-4f1b-82e1-69f81026b5ac" x="0" y="398" width="143" height="20"/>
|
||||
<textElement/>
|
||||
<text><![CDATA[Poskytnutí zálohy ve výši:]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement uuid="57398205-845b-4633-89db-3b0c4b31f03c" x="301" y="418" width="271" height="1"/>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement uuid="e33b0435-12e0-4d9f-9d3f-44f54eed9505" x="301" y="423" width="271" height="20"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<text><![CDATA[Datum a podpis oprávněné osoby]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement uuid="cad8d17d-5fdc-41a8-a74d-54ea34e4cdad" x="0" y="449" width="100" height="20"/>
|
||||
<textElement/>
|
||||
<text><![CDATA[Povolená záloha]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement uuid="2b462c95-65b1-4295-ac47-7d2ac3e16f40" x="0" y="469" width="143" height="20"/>
|
||||
<textElement/>
|
||||
<text><![CDATA[Pokladní doklad číslo]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement uuid="4cfe5623-901b-4508-9161-920d90cd0405" x="301" y="449" width="100" height="20"/>
|
||||
<textElement/>
|
||||
<text><![CDATA[Vyplacená dne:]]></text>
|
||||
</staticText>
|
||||
<line>
|
||||
<reportElement uuid="39f180e0-0300-4087-89b2-dbd9441d1e94" x="149" y="500" width="280" height="1"/>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement uuid="a7218a5e-4d69-41fe-a26b-a51dd240cfb1" x="149" y="508" width="280" height="20"/>
|
||||
<textElement textAlignment="Center"/>
|
||||
<text><![CDATA[Podpis pokladníka]]></text>
|
||||
</staticText>
|
||||
<line direction="BottomUp">
|
||||
<reportElement uuid="0276901c-8949-4307-a4a6-efa1a9b83341" x="571" y="-79" width="1" height="607"/>
|
||||
</line>
|
||||
<line direction="BottomUp">
|
||||
<reportElement uuid="01ad15ce-276d-4fb8-af37-d896fa7eb77a" x="-1" y="-79" width="1" height="607"/>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement uuid="31fec8f3-7de4-4c34-934e-dbc2ad813c49" x="-1" y="-80" width="573" height="1"/>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement uuid="11f1abd0-78a2-4cee-9553-c960a59a00d3" x="-1" y="528" width="573" height="1"/>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement uuid="00689195-f270-4b32-9878-74c6d5d353cd" x="-1" y="0" width="573" height="1"/>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement uuid="0d8ef0ad-db1e-4be9-8153-b3a885fb8ace" x="0" y="148" width="572" height="1"/>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement uuid="c9713d6e-9b2e-4ce6-8837-3fbbe320fa8b" x="143" y="178" width="1" height="75"/>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement uuid="4e1fb287-81be-477a-95c2-96691d638916" x="285" y="178" width="1" height="75"/>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement uuid="bc2f55db-f6e3-46eb-81cd-1b4161ceeffd" x="428" y="178" width="1" height="75"/>
|
||||
</line>
|
||||
<line>
|
||||
<reportElement uuid="0e93a41e-d13e-4f12-83cb-70d69bb3c0fb" x="0" y="442" width="572" height="1"/>
|
||||
</line>
|
||||
<staticText>
|
||||
<reportElement uuid="548c1550-c12d-42b3-a297-c9be96dbb2e8" x="144" y="76" width="31" height="20">
|
||||
<printWhenExpression><![CDATA[$F{requireDownPayment}]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<textElement/>
|
||||
<text><![CDATA[Ano]]></text>
|
||||
</staticText>
|
||||
<staticText>
|
||||
<reportElement uuid="e06aba6d-b74d-4ab1-9737-1134a6ac6519" x="144" y="76" width="32" height="20">
|
||||
<printWhenExpression><![CDATA[$F{requireDownPayment} == null || $F{requireDownPayment} == false]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<textElement/>
|
||||
<text><![CDATA[Ne]]></text>
|
||||
</staticText>
|
||||
<textField pattern="###0.00;-###0.00" isBlankWhenNull="true">
|
||||
<reportElement uuid="ac95738d-56c8-4ee2-8721-cad00e1b06e4" x="144" y="398" width="57" height="20"/>
|
||||
<textElement textAlignment="Right"/>
|
||||
<textFieldExpression><![CDATA[$F{downPayment}]]></textFieldExpression>
|
||||
</textField>
|
||||
<image onErrorType="Blank">
|
||||
<reportElement uuid="954e517f-5d23-4166-b776-7c31b4409ddd" x="378" y="69" width="183" height="50">
|
||||
<printWhenExpression><![CDATA[$P{P_USER_SIGNATURE} != null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<imageExpression><![CDATA[$P{P_USER_SIGNATURE}]]></imageExpression>
|
||||
</image>
|
||||
<textField pattern="dd. MM. yyyy" isBlankWhenNull="true">
|
||||
<reportElement uuid="97daa8a7-dab0-4104-babb-c3889faac21a" x="301" y="399" width="77" height="20"/>
|
||||
<textElement/>
|
||||
<textFieldExpression><![CDATA[$P{P_PREV_APPROVE_DATE}]]></textFieldExpression>
|
||||
<anchorNameExpression><![CDATA["SIGN_1"]]></anchorNameExpression>
|
||||
</textField>
|
||||
<image onErrorType="Blank">
|
||||
<reportElement uuid="baf922bc-b6fb-4dbf-abc9-250f448baef3" x="378" y="368" width="183" height="50">
|
||||
<printWhenExpression><![CDATA[$P{P_PREV_APPROVER_SIGNATURE} != null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<imageExpression><![CDATA[$P{P_PREV_APPROVER_SIGNATURE}]]></imageExpression>
|
||||
</image>
|
||||
<textField>
|
||||
<reportElement uuid="16e5c4e2-a366-4eca-ad27-7db7fef6771c" x="186" y="27" width="375" height="20">
|
||||
<printWhenExpression><![CDATA[$F{ownedBy.address} != null]]></printWhenExpression>
|
||||
</reportElement>
|
||||
<textElement/>
|
||||
<textFieldExpression><![CDATA[$F{ownedBy.address}]]></textFieldExpression>
|
||||
</textField>
|
||||
<subreport>
|
||||
<reportElement uuid="b8144a34-f2c4-4b5a-9f48-b74b5dc99e8c" x="143" y="265" width="428" height="20"/>
|
||||
<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{passengers})]]></dataSourceExpression>
|
||||
<subreportExpression><![CDATA[$P{SUBREPORT_DIR} + "tripRequirementPassengers.jasper"]]></subreportExpression>
|
||||
</subreport>
|
||||
<textField isBlankWhenNull="true">
|
||||
<reportElement uuid="f8e2f8b5-373d-46fd-9c61-5a6c1da44351" x="143" y="285" width="428" height="20"/>
|
||||
<textElement/>
|
||||
<textFieldExpression><![CDATA[$F{foreignPersons}]]></textFieldExpression>
|
||||
</textField>
|
||||
<genericElement>
|
||||
<reportElement uuid="c1d18650-66b9-425c-acbe-7b4e952bfd16" x="442" y="460" width="119" height="48"/>
|
||||
<genericElementType namespace="urn:sig:sig" name="signature"/>
|
||||
</genericElement>
|
||||
</band>
|
||||
</detail>
|
||||
</jasperReport>
|
||||
Binary file not shown.
@@ -456,6 +456,8 @@
|
||||
<bean id="tripBillApprovalService" class="info.bukova.isspst.services.tripbill.TripBillApprovalServiceImpl">
|
||||
<property name="dao" ref="tripBillApprovalDao"/>
|
||||
</bean>
|
||||
|
||||
<bean id="jnlpGenerator" class="info.bukova.isspst.signapi.JnlpGeneratorImpl"/>
|
||||
|
||||
<bean id="signedDocumentService" class="info.bukova.isspst.services.signeddocs.SignedDocumentServiceImpl">
|
||||
<property name="dao" ref="signedDocumentDao"/>
|
||||
|
||||
@@ -17,15 +17,20 @@
|
||||
<label value="${labels.RequirementApproveDate}"/>
|
||||
<datebox
|
||||
value="@bind(vm.approveDate)"
|
||||
format="${labels.DateFormat}" />
|
||||
format="${labels.DateFormat}" disabled="@load(vm.signed)"/>
|
||||
</hbox>
|
||||
<separator bar="true" hflex="1"/>
|
||||
<hbox>
|
||||
<button image="/img/approve-016.png" label="${labels.Confirm}" onClick="@command('approve', window=approveWin)" sclass="nicebutton"/>
|
||||
<button label="Podepsat" onClick="@command('signPdf')" sclass="nicebutton" disabled="@load(vm.signed)"/>
|
||||
<button image="/img/approve-016.png" label="${labels.Confirm}" onClick="@command('approve', window=approveWin)" sclass="nicebutton" disabled="@load(not vm.signed)"/>
|
||||
<button image="~./zul/img/misc/drag-disallow.png" label="${labels.ButtonStorno}" onClick="approveWin.detach()" sclass="nicebutton"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
<timer onTimer="@command('onTimer')" running="@load(vm.timer)" repeats="true" delay="500"/>
|
||||
|
||||
<iframe name="signer" width="5px" height="5px"/>
|
||||
|
||||
</window>
|
||||
|
||||
</zk>
|
||||
Reference in New Issue
Block a user