package hycom.dao; import hycom.exceptions.DbException; import hycom.model.Attachment; import hycom.model.Document; import hycom.model.Form; import hycom.model.User; import hycom.utils.AppUtils; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.LinkedList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.tomcat.util.http.fileupload.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * DAO for populated forms */ @Component @RequestMapping("/logger") public class FormDao extends BaseDao { private static final Logger logger = LoggerFactory.getLogger(FormDao.class); @Value("${orbeon.address}") private String hostAddress; @Value("${form.name.input}") private String formName; @Value("${form.category.select}") private String formCategory; @Value("${form.pillar.select}") private String formPillar; @Value("${form.directory.temp}") private String tmpDir; byte[] buffer = new byte[1024]; public List
getForms(Integer offset, Integer limit, String fromDate, String toDate, String formNameSearch, String category, String pillar, String name) throws DbException { StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder .append("SELECT ofd.document_id, s.send_date, ofd.form_version, ofd.id, ofd.app, ofd.form, ofda.count, name.val AS name, category.val AS category, pillar.val AS pillar \n" + "FROM orbeon_form_data ofd\n" + "INNER JOIN submitted_forms s ON ofd.id = s.form_id \n" + "LEFT JOIN (\n" + "SELECT document_id, COUNT(*) AS count FROM orbeon_form_data_attach \n" + "GROUP BY document_id) ofda ON ofd.document_id = ofda.document_id\n" + "LEFT JOIN (SELECT data_id, val FROM orbeon_i_control_text WHERE control LIKE '%" + formName + "%') name ON ofd.id=name.data_id\n" + "LEFT JOIN (SELECT data_id, val FROM orbeon_i_control_text WHERE control LIKE '%" + formCategory + "%') category ON ofd.id=category.data_id\n" + "LEFT JOIN (SELECT data_id, val FROM orbeon_i_control_text WHERE control LIKE '%" + formPillar + "%') pillar ON ofd.id=pillar.data_id WHERE (1=1)"); if (!StringUtils.isEmpty(fromDate) && !fromDate.equals("*")) { sqlBuilder.append(" AND s.send_date >= '").append(fromDate).append("'"); } if (!StringUtils.isEmpty(toDate) && !toDate.equals("*")) { sqlBuilder.append(" AND s.send_date <= '").append(toDate).append("'"); } if (!StringUtils.isEmpty(formNameSearch) && !formNameSearch.equals("*")) { sqlBuilder.append(" AND ofd.form LIKE '%").append(formNameSearch).append("%'"); } if (!StringUtils.isEmpty(category) && !category.equals("*")) { sqlBuilder.append(" AND category.val LIKE '%").append(category).append("%'"); } if (!StringUtils.isEmpty(name) && !name.equals("*")) { sqlBuilder.append(" AND name.val LIKE '%").append(name).append("%'"); } if (!StringUtils.isEmpty(pillar) && !pillar.equals("*")) { sqlBuilder.append(" AND pillar.val LIKE '%").append(pillar).append("%'"); } sqlBuilder.append(" ORDER BY send_date DESC"); if (offset != null) { sqlBuilder.append(" OFFSET ").append(offset); } if (limit != null) { sqlBuilder.append(" LIMIT ").append(limit); } List forms = jdbcTemplate.query(sqlBuilder.toString(), (rs, i) -> { String appName = rs.getString("app"); String formName = rs.getString("form"); String formId = rs.getString("document_id"); Form form = new Form(); form.setFormName(formName); form.setLink(AppUtils.generateLink(hostAddress, appName, formName, formId)); form.setAttachment(rs.getInt("count") > 0); form.setSendDate(rs.getTimestamp("send_date")); form.setName(rs.getString("name")); form.setCategory(rs.getString("category")); form.setPillar(rs.getString("pillar")); return form; }); return forms; } public Long getFormsCount(String fromDate, String toDate, String formNameSearch, String category, String pillar, String name) throws DbException { StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder.append("SELECT count(ofd.id) \n" + "FROM orbeon_form_data ofd\n" + "INNER JOIN submitted_forms s ON ofd.id = s.form_id \n" + "LEFT JOIN (\n" + "SELECT document_id, COUNT(*) AS count FROM orbeon_form_data_attach \n" + "GROUP BY document_id) ofda ON ofd.document_id = ofda.document_id\n" + "LEFT JOIN (SELECT data_id, val FROM orbeon_i_control_text WHERE control LIKE '%" + formName + "%') name ON ofd.id=name.data_id\n" + "LEFT JOIN (SELECT data_id, val FROM orbeon_i_control_text WHERE control LIKE '%" + formCategory + "%') category ON ofd.id=category.data_id\n" + "LEFT JOIN (SELECT data_id, val FROM orbeon_i_control_text WHERE control LIKE '%" + formPillar + "%') pillar ON ofd.id=pillar.data_id WHERE (1=1)"); if (!StringUtils.isEmpty(fromDate) && !fromDate.equals("*")) { sqlBuilder.append(" AND s.send_date >= '").append(fromDate).append("'"); } if (!StringUtils.isEmpty(toDate) && !toDate.equals("*")) { sqlBuilder.append(" AND s.send_date <= '").append(toDate).append("'"); } if (!StringUtils.isEmpty(formNameSearch) && !formNameSearch.equals("*")) { sqlBuilder.append(" AND ofd.form LIKE '%").append(formNameSearch).append("%'"); } if (!StringUtils.isEmpty(category) && !category.equals("*")) { sqlBuilder.append(" AND category.val LIKE '%").append(category).append("%'"); } if (!StringUtils.isEmpty(name) && !name.equals("*")) { sqlBuilder.append(" AND name.val LIKE '%").append(name).append("%'"); } if (!StringUtils.isEmpty(pillar) && !pillar.equals("*")) { sqlBuilder.append(" AND pillar.val LIKE '%").append(pillar).append("%'"); } Long count = jdbcTemplate.queryForObject(sqlBuilder.toString(), (rs, i) -> { return rs.getLong("count"); }); return count; } public List getUsersContainsAttachments() throws DbException { String sql = "SELECT DISTINCT att.username from orbeon_form_data_attach att \n" + "INNER JOIN orbeon_form_data ofd ON ofd.document_id = att.document_id \n" + "INNER JOIN submitted_forms sf ON sf.form_id = ofd.id\n" + "WHERE att.username IS NOT NULL"; List users = jdbcTemplate.query(sql, (rs, i) -> { User user = new User(); user.setUserName(rs.getString("username")); user.setMember(true); return user; }); return users; } public String getAttachments(String userName) throws DbException { String sql = "SELECT ofd.document_id, ofd.form_version, ofd.xml, ofd.app, ofd.form from orbeon_form_data ofd\n" + "INNER JOIN submitted_forms sf ON sf.form_id = ofd.id\n" + "WHERE EXISTS (SELECT 1 FROM orbeon_form_data_attach att WHERE att.document_id = ofd.document_id)\n" + "AND ofd.username = '" + userName + "';"; List documents = jdbcTemplate.query(sql, (rs, i) -> { String documentId = rs.getString("document_id"); String xmlFile = rs.getString("xml"); String appName = rs.getString("app"); String formName = rs.getString("form"); String formVersion = rs.getString("form_version"); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = null; try { dBuilder = dbFactory.newDocumentBuilder(); InputStream stream = new ByteArrayInputStream(xmlFile.getBytes(StandardCharsets.UTF_8)); org.w3c.dom.Document doc = dBuilder.parse(stream); doc.getDocumentElement().normalize(); Element element = doc.getDocumentElement(); NodeList nodeList = element.getChildNodes(); Document document = new Document(); document.setDocumentId(documentId); document.setAppName(appName); document.setFormName(formName); document.setVersion(Long.parseLong(formVersion)); List attachments = new LinkedList<>(); attachments = populateList(nodeList, attachments); document.setAttachments(attachments); return document; } catch (ParserConfigurationException | IOException | SAXException e) { e.printStackTrace(); } return null; }); if (!CollectionUtils.isEmpty(documents)) { File directory = new File(tmpDir + "/" + userName); if (!directory.exists()) { directory.mkdir(); } } for (Document document : documents) { for (Attachment attachment : document.getAttachments()) { String sql2 = "SELECT file_content FROM orbeon_form_data_attach WHERE file_name = '" + attachment.getFileEncodedName() + "' "; jdbcTemplate.query(sql2, (rs, i) -> { try { InputStream inputStream = rs.getBinaryStream("file_content"); OutputStream outputStream = new FileOutputStream(tmpDir + "/" + userName + "/" + attachment.getFileName()); int bytesRead = -1; byte[] buffer = new byte[1024]; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } inputStream.close(); outputStream.close(); } catch (IOException e) { e.getMessage(); } return null; }); } try { FileOutputStream fos = new FileOutputStream(tmpDir + "/" + userName + ".zip"); ZipOutputStream zos = new ZipOutputStream(fos); File folder = new File(tmpDir + "/" + userName); for (File file : folder.listFiles()) { ZipEntry ze = new ZipEntry(file.getName()); zos.putNextEntry(ze); FileInputStream in = new FileInputStream(file.getPath()); int len; while ((len = in.read(buffer)) > 0) { zos.write(buffer, 0, len); } in.close(); zos.closeEntry(); } zos.close(); } catch (IOException e) { logger.error("Cannot remove attachments for :" ); } return tmpDir + "/" + userName + ".zip"; } return null; } public void removeAttachments(String userName) throws DbException { File folder = new File(tmpDir + "/" + userName); File zipFile = new File(tmpDir + "/" + userName + ".zip"); try { FileUtils.deleteDirectory(folder); } catch (IOException e) { logger.error("Cannot remove temp directory for user {} : {}", userName, e.getMessage()); } zipFile.delete(); String deleteAttachmentsSql = "DELETE FROM orbeon_form_data_attach AS ofda USING orbeon_form_data AS ofd WHERE ofda.document_id = ofd.document_id AND EXISTS (SELECT 1 FROM submitted_forms sf WHERE sf.form_id = ofd.id) AND ofd.username = '" + userName + "'; "; String updateAttachmentsSql = "UPDATE submitted_forms sf SET attachments_moved = TRUE where form_id IN (\n" + "SELECT sf.form_id FROM submitted_forms sf \n" + "inner JOIN orbeon_form_data ofd ON sf.form_id = ofd.id \n" + "WHERE ofd.username = '" + userName + "');"; try { int i = jdbcTemplate.update(deleteAttachmentsSql); int j = jdbcTemplate.update(updateAttachmentsSql); logger.info("There are {} deleted attachments for user: {}", i, userName); } catch (Exception e) { logger.error("Cannot remove attachments for user {} : {}", userName, e.getMessage()); } } /** * Populete list of attachments for xml file node elements * * @param nodeList node list from xml file * * @param attachments list to populate * * @return populated list of attachments */ private List populateList(NodeList nodeList, List attachments) { for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { if (node.hasAttributes() && ((Element) node).hasAttribute("filename")) { String fileName = ((Element) node).getAttribute("filename"); String mediaType = ((Element) node).getAttribute("mediatype"); String fileEncodedName = getFileEncodedName(node.getTextContent()); System.out.println(((Element) node).getAttribute("size")); Attachment attachment = new Attachment(); attachment.setFileName(fileName); attachment.setMediaType(mediaType); attachment.setFileEncodedName(fileEncodedName); attachments.add(attachment); } else { if (node.getChildNodes().getLength() > 0) { populateList(node.getChildNodes(), attachments); } else { continue; } } } else { continue; } } return attachments; } /** * Returns filename from xml node * * @param nodeContent node with file element * * @return filename */ private String getFileEncodedName(String nodeContent) { int lastIndex = nodeContent.lastIndexOf("/"); return nodeContent.substring(lastIndex + 1); } public List getForms() throws DbException { return getForms(null, null, null, null, null, null, null, null); } public Form getForm(int formId) throws DbException { String sql = "SELECT app, form FROM orbeon_form_data WHERE id = " + formId; return jdbcTemplate.query(sql, rs -> { if (rs.next()) { Form form = new Form(); form.setFormName(rs.getString("app")); form.setName(rs.getString("form")); return form; } return null; }); } public void submitForm(String id) throws DbException { String sql = "INSERT INTO submitted_forms (form_id, send_date) VALUES ((SELECT id FROM orbeon_form_data ofd\n" + "INNER JOIN (\n" + "SELECT app, form, document_id, MAX(last_modified_time) AS max_last_modified\n" + "FROM orbeon_form_data o GROUP BY app, form, document_id) forms ON ofd.app = forms.app AND ofd.form = forms.form\n" + "WHERE ofd.document_id = '" + id + "'\n" + "AND ofd.last_modified_time = forms.max_last_modified), CURRENT_TIMESTAMP)"; jdbcTemplate.update(sql); } public void deleteSubmittedForm(String documentId) { String sql = "DELETE FROM submitted_forms WHERE id IN (SELECT submitted_forms.id FROM submitted_forms INNER JOIN orbeon_form_data ON submitted_forms.form_id = orbeon_form_data.id WHERE document_id ='" + documentId + "')"; jdbcTemplate.update(sql); } public Boolean hasRemovedAttachments(String documentId) throws DbException { String sql = "SELECT sf.id FROM submitted_forms sf INNER JOIN orbeon_form_data ofd ON sf.form_id = ofd.id AND sf.attachments_moved = TRUE AND ofd.document_id = '" + documentId + "';"; return jdbcTemplate.query(sql, rs -> { if (rs.next()) { return true; } return false; }); } public boolean isFormSubmitted(String documentId) throws DbException { String sql = "SELECT sf.id from submitted_forms sf INNER JOIN orbeon_form_data ofd ON sf.form_id = ofd.id WHERE ofd.document_id = '" + documentId + "';"; return jdbcTemplate.query(sql, rs -> { if (rs.next()) { return true; } return false; }); } }