3997 |
14 Jun 16 |
nicklas |
1 |
package net.sf.basedb.reggie.servlet; |
3997 |
14 Jun 16 |
nicklas |
2 |
|
3997 |
14 Jun 16 |
nicklas |
3 |
|
3997 |
14 Jun 16 |
nicklas |
4 |
import java.io.IOException; |
4004 |
20 Jun 16 |
nicklas |
5 |
import java.io.InputStream; |
4004 |
20 Jun 16 |
nicklas |
6 |
import java.io.OutputStream; |
4008 |
22 Jun 16 |
nicklas |
7 |
import java.util.Date; |
4034 |
29 Jul 16 |
nicklas |
8 |
import java.util.HashSet; |
4000 |
17 Jun 16 |
nicklas |
9 |
import java.util.List; |
4034 |
29 Jul 16 |
nicklas |
10 |
import java.util.Set; |
3997 |
14 Jun 16 |
nicklas |
11 |
|
3997 |
14 Jun 16 |
nicklas |
12 |
import javax.servlet.ServletException; |
3997 |
14 Jun 16 |
nicklas |
13 |
import javax.servlet.http.HttpServlet; |
3997 |
14 Jun 16 |
nicklas |
14 |
import javax.servlet.http.HttpServletRequest; |
3997 |
14 Jun 16 |
nicklas |
15 |
import javax.servlet.http.HttpServletResponse; |
3997 |
14 Jun 16 |
nicklas |
16 |
|
3997 |
14 Jun 16 |
nicklas |
17 |
import org.json.simple.JSONArray; |
3997 |
14 Jun 16 |
nicklas |
18 |
import org.json.simple.JSONObject; |
3997 |
14 Jun 16 |
nicklas |
19 |
|
4031 |
26 Jul 16 |
nicklas |
20 |
import net.sf.basedb.core.AnyToAny; |
4007 |
21 Jun 16 |
nicklas |
21 |
import net.sf.basedb.core.Application; |
4004 |
20 Jun 16 |
nicklas |
22 |
import net.sf.basedb.core.ChangeHistory; |
3997 |
14 Jun 16 |
nicklas |
23 |
import net.sf.basedb.core.DbControl; |
4028 |
26 Jul 16 |
nicklas |
24 |
import net.sf.basedb.core.Directory; |
4000 |
17 Jun 16 |
nicklas |
25 |
import net.sf.basedb.core.File; |
4000 |
17 Jun 16 |
nicklas |
26 |
import net.sf.basedb.core.Item; |
4031 |
26 Jul 16 |
nicklas |
27 |
import net.sf.basedb.core.ItemNotFoundException; |
4000 |
17 Jun 16 |
nicklas |
28 |
import net.sf.basedb.core.ItemQuery; |
4004 |
20 Jun 16 |
nicklas |
29 |
import net.sf.basedb.core.ItemResultIterator; |
4028 |
26 Jul 16 |
nicklas |
30 |
import net.sf.basedb.core.Path; |
4000 |
17 Jun 16 |
nicklas |
31 |
import net.sf.basedb.core.Sample; |
3997 |
14 Jun 16 |
nicklas |
32 |
import net.sf.basedb.core.SessionControl; |
4034 |
29 Jul 16 |
nicklas |
33 |
import net.sf.basedb.core.SharedItem; |
4000 |
17 Jun 16 |
nicklas |
34 |
import net.sf.basedb.core.Type; |
4007 |
21 Jun 16 |
nicklas |
35 |
import net.sf.basedb.core.User; |
3997 |
14 Jun 16 |
nicklas |
36 |
import net.sf.basedb.core.authentication.LoginRequest; |
4004 |
20 Jun 16 |
nicklas |
37 |
import net.sf.basedb.core.log.ChangeType; |
4004 |
20 Jun 16 |
nicklas |
38 |
import net.sf.basedb.core.log.ManualLogEntry; |
4000 |
17 Jun 16 |
nicklas |
39 |
import net.sf.basedb.core.query.Annotations; |
4000 |
17 Jun 16 |
nicklas |
40 |
import net.sf.basedb.core.query.Expressions; |
4000 |
17 Jun 16 |
nicklas |
41 |
import net.sf.basedb.core.query.Hql; |
4000 |
17 Jun 16 |
nicklas |
42 |
import net.sf.basedb.core.query.Orders; |
4000 |
17 Jun 16 |
nicklas |
43 |
import net.sf.basedb.core.query.Restrictions; |
4000 |
17 Jun 16 |
nicklas |
44 |
import net.sf.basedb.core.snapshot.SnapshotManager; |
3997 |
14 Jun 16 |
nicklas |
45 |
import net.sf.basedb.reggie.JsonUtil; |
3997 |
14 Jun 16 |
nicklas |
46 |
import net.sf.basedb.reggie.Reggie; |
4000 |
17 Jun 16 |
nicklas |
47 |
import net.sf.basedb.reggie.XmlConfig; |
4000 |
17 Jun 16 |
nicklas |
48 |
import net.sf.basedb.reggie.dao.Annotationtype; |
3997 |
14 Jun 16 |
nicklas |
49 |
import net.sf.basedb.reggie.dao.ClientApp; |
4000 |
17 Jun 16 |
nicklas |
50 |
import net.sf.basedb.reggie.dao.Patient; |
4000 |
17 Jun 16 |
nicklas |
51 |
import net.sf.basedb.reggie.dao.SpecimenTube; |
4000 |
17 Jun 16 |
nicklas |
52 |
import net.sf.basedb.reggie.dao.Subtype; |
4000 |
17 Jun 16 |
nicklas |
53 |
import net.sf.basedb.reggie.json.LoadMoreJson; |
4028 |
26 Jul 16 |
nicklas |
54 |
import net.sf.basedb.reggie.pdf.PdfReportTemplate; |
4028 |
26 Jul 16 |
nicklas |
55 |
import net.sf.basedb.reggie.pdf.PdfToBaseFileCombiner; |
4000 |
17 Jun 16 |
nicklas |
56 |
import net.sf.basedb.reggie.pdf.PilotReportWorker; |
4004 |
20 Jun 16 |
nicklas |
57 |
import net.sf.basedb.util.FileUtil; |
4004 |
20 Jun 16 |
nicklas |
58 |
import net.sf.basedb.util.Values; |
3997 |
14 Jun 16 |
nicklas |
59 |
import net.sf.basedb.util.error.ThrowableUtil; |
3997 |
14 Jun 16 |
nicklas |
60 |
|
3997 |
14 Jun 16 |
nicklas |
61 |
/** |
3997 |
14 Jun 16 |
nicklas |
Servlet handling requests for the report delivery. |
3997 |
14 Jun 16 |
nicklas |
63 |
|
3997 |
14 Jun 16 |
nicklas |
@author nicklas |
3997 |
14 Jun 16 |
nicklas |
@since 4.6 |
3997 |
14 Jun 16 |
nicklas |
66 |
*/ |
3997 |
14 Jun 16 |
nicklas |
67 |
public class DeliveryServlet |
3997 |
14 Jun 16 |
nicklas |
68 |
extends HttpServlet |
3997 |
14 Jun 16 |
nicklas |
69 |
{ |
3997 |
14 Jun 16 |
nicklas |
70 |
|
4028 |
26 Jul 16 |
nicklas |
71 |
|
4028 |
26 Jul 16 |
nicklas |
72 |
/** |
4028 |
26 Jul 16 |
nicklas |
Get the subfolder in the delivery folder structure for an item with the |
4028 |
26 Jul 16 |
nicklas |
given name. |
4028 |
26 Jul 16 |
nicklas |
75 |
|
4028 |
26 Jul 16 |
nicklas |
The name can be the name of any item in the SCAN-B data model that |
4028 |
26 Jul 16 |
nicklas |
is a specimen or descendent of a specimen. Delivery is assumed to be |
4028 |
26 Jul 16 |
nicklas |
on a per-specimen basis and only the specimen name information is used |
4028 |
26 Jul 16 |
nicklas |
to create the subfolder name. Example: |
4028 |
26 Jul 16 |
nicklas |
80 |
|
4028 |
26 Jul 16 |
nicklas |
1234567.1 --> /12/1234567.1 |
4028 |
26 Jul 16 |
nicklas |
1234567.1.l.r.m.c.lib.g.k.a.t --> /12/1234567.1 |
4028 |
26 Jul 16 |
nicklas |
83 |
|
4028 |
26 Jul 16 |
nicklas |
84 |
*/ |
4028 |
26 Jul 16 |
nicklas |
85 |
public static String generateDeliveryFolder(String itemName) |
4028 |
26 Jul 16 |
nicklas |
86 |
{ |
4028 |
26 Jul 16 |
nicklas |
87 |
return itemName.replaceFirst("^((\\d{2})\\d+\\.\\d+).*", "/$2/$1"); |
4028 |
26 Jul 16 |
nicklas |
88 |
} |
4028 |
26 Jul 16 |
nicklas |
89 |
|
4141 |
30 Sep 16 |
nicklas |
// Milliseconds in one day |
4141 |
30 Sep 16 |
nicklas |
91 |
private static long MILLIS_PER_DAY = 24L*3600L*1000L; |
4141 |
30 Sep 16 |
nicklas |
92 |
|
3997 |
14 Jun 16 |
nicklas |
93 |
private static final long serialVersionUID = -5722246375117117921L; |
3997 |
14 Jun 16 |
nicklas |
94 |
|
3997 |
14 Jun 16 |
nicklas |
95 |
public DeliveryServlet() |
3997 |
14 Jun 16 |
nicklas |
96 |
{} |
4000 |
17 Jun 16 |
nicklas |
97 |
|
4000 |
17 Jun 16 |
nicklas |
98 |
@Override |
4000 |
17 Jun 16 |
nicklas |
99 |
protected void doGet(HttpServletRequest req, HttpServletResponse resp) |
4000 |
17 Jun 16 |
nicklas |
100 |
throws ServletException, IOException |
4000 |
17 Jun 16 |
nicklas |
101 |
{ |
4000 |
17 Jun 16 |
nicklas |
102 |
JSONObject json = new JSONObject(); |
4009 |
23 Jun 16 |
nicklas |
103 |
JSONArray jsonMessages = new JSONArray(); |
4000 |
17 Jun 16 |
nicklas |
104 |
json.put("status", "ok"); |
4000 |
17 Jun 16 |
nicklas |
105 |
|
4000 |
17 Jun 16 |
nicklas |
106 |
DbControl dc = null; |
4000 |
17 Jun 16 |
nicklas |
107 |
try |
4000 |
17 Jun 16 |
nicklas |
108 |
{ |
4009 |
23 Jun 16 |
nicklas |
109 |
JsonUtil.setJsonResponseHeaders(resp); |
4009 |
23 Jun 16 |
nicklas |
110 |
String cmd = req.getParameter("cmd"); |
4009 |
23 Jun 16 |
nicklas |
111 |
|
4009 |
23 Jun 16 |
nicklas |
112 |
final SessionControl sc = Reggie.getSessionControl(req, ClientApp.SCANB_DELIVERY, true); |
4000 |
17 Jun 16 |
nicklas |
113 |
if ("LoadYellowSpecimen".equals(cmd)) |
4000 |
17 Jun 16 |
nicklas |
114 |
{ |
4006 |
21 Jun 16 |
nicklas |
115 |
String search = Values.getStringOrNull(req.getParameter("query")); |
4006 |
21 Jun 16 |
nicklas |
116 |
|
4008 |
22 Jun 16 |
nicklas |
117 |
int month = Values.getInt(req.getParameter("month"))+1; |
4008 |
22 Jun 16 |
nicklas |
118 |
int year = Values.getInt(req.getParameter("year")); |
4008 |
22 Jun 16 |
nicklas |
119 |
|
4009 |
23 Jun 16 |
nicklas |
120 |
/* |
4037 |
29 Jul 16 |
nicklas |
// For debugging the error handling code on the web client |
4009 |
23 Jun 16 |
nicklas |
if (month == 2 && year == 2016) |
4009 |
23 Jun 16 |
nicklas |
123 |
{ |
4009 |
23 Jun 16 |
nicklas |
throw new RuntimeException("An internal server error..."); |
4009 |
23 Jun 16 |
nicklas |
125 |
} |
4009 |
23 Jun 16 |
nicklas |
126 |
*/ |
4009 |
23 Jun 16 |
nicklas |
127 |
|
6337 |
16 Jun 21 |
nicklas |
128 |
dc = sc.newDbControl(":List YellowLabel specimen"); |
4009 |
23 Jun 16 |
nicklas |
129 |
|
4009 |
23 Jun 16 |
nicklas |
// Preload annotation types to make sure they are accessible |
4009 |
23 Jun 16 |
nicklas |
// and get predictable error handling |
4009 |
23 Jun 16 |
nicklas |
132 |
Annotationtype.YELLOW_LABEL.load(dc); |
4009 |
23 Jun 16 |
nicklas |
133 |
Annotationtype.ARRIVAL_DATE.load(dc); |
4009 |
23 Jun 16 |
nicklas |
134 |
Annotationtype.PERSONAL_NUMBER.load(dc); |
4009 |
23 Jun 16 |
nicklas |
135 |
Annotationtype.ALL_FIRST_NAMES.load(dc); |
4009 |
23 Jun 16 |
nicklas |
136 |
Annotationtype.FAMILY_NAME.load(dc); |
4037 |
29 Jul 16 |
nicklas |
137 |
Annotationtype.PAD.load(dc); |
4040 |
29 Jul 16 |
nicklas |
138 |
Annotationtype.COMPLETED_DATE.load(dc); |
4009 |
23 Jun 16 |
nicklas |
139 |
|
4000 |
17 Jun 16 |
nicklas |
140 |
ItemQuery<Sample> query = Sample.getQuery(); |
4000 |
17 Jun 16 |
nicklas |
141 |
Subtype.SPECIMEN.addFilter(dc, query); |
4000 |
17 Jun 16 |
nicklas |
142 |
query.setIncludes(Reggie.INCLUDE_SHARED_TO_ME); |
4000 |
17 Jun 16 |
nicklas |
143 |
query.join(Annotations.innerJoin(Annotationtype.YELLOW_LABEL.get(dc), "yl")); |
4000 |
17 Jun 16 |
nicklas |
144 |
query.join(Annotations.innerJoin(Annotationtype.ARRIVAL_DATE.get(dc), "ad")); |
4000 |
17 Jun 16 |
nicklas |
145 |
query.join(Hql.innerJoin("parent", "p")); |
4000 |
17 Jun 16 |
nicklas |
146 |
query.order(Orders.asc(Hql.alias("ad"))); |
4000 |
17 Jun 16 |
nicklas |
147 |
query.order(Orders.asc(Hql.property("name"))); |
4000 |
17 Jun 16 |
nicklas |
148 |
|
4006 |
21 Jun 16 |
nicklas |
149 |
if (search != null) |
4006 |
21 Jun 16 |
nicklas |
150 |
{ |
4006 |
21 Jun 16 |
nicklas |
151 |
query.join(Hql.innerJoin("parent", "c")); // Joins the case |
4006 |
21 Jun 16 |
nicklas |
152 |
query.join(Hql.innerJoin("c", "parent", "pat")); // Joins the patient |
4037 |
29 Jul 16 |
nicklas |
153 |
query.join(Annotations.leftJoin("pat", Annotationtype.PERSONAL_NUMBER.get(dc), "pnr")); // Joins the personal number |
4037 |
29 Jul 16 |
nicklas |
154 |
query.join(Annotations.leftJoin(Annotationtype.PAD.get(dc), "pad")); // Joins the PAD |
4006 |
21 Jun 16 |
nicklas |
155 |
|
4037 |
29 Jul 16 |
nicklas |
// Exact match on Personal number/PAD or wildcard match on SCAN-B ID |
4006 |
21 Jun 16 |
nicklas |
157 |
query.restrict( |
4006 |
21 Jun 16 |
nicklas |
158 |
Restrictions.or( |
4006 |
21 Jun 16 |
nicklas |
159 |
Restrictions.eq(Hql.alias("pnr"), Expressions.string(search)), |
4037 |
29 Jul 16 |
nicklas |
160 |
Restrictions.eq(Hql.alias("pad"), Expressions.string(search)), |
4006 |
21 Jun 16 |
nicklas |
161 |
Restrictions.like(Hql.property("name"), Expressions.string(search + "%")) |
4006 |
21 Jun 16 |
nicklas |
162 |
)); |
4006 |
21 Jun 16 |
nicklas |
163 |
} |
4008 |
22 Jun 16 |
nicklas |
164 |
else if (year >= 2010) |
4008 |
22 Jun 16 |
nicklas |
165 |
{ |
4008 |
22 Jun 16 |
nicklas |
166 |
query.restrict( |
4008 |
22 Jun 16 |
nicklas |
167 |
Restrictions.between( |
4008 |
22 Jun 16 |
nicklas |
168 |
Hql.alias("ad"), |
4008 |
22 Jun 16 |
nicklas |
169 |
Expressions.parameter("startDate"), Expressions.parameter("endDate") |
4008 |
22 Jun 16 |
nicklas |
170 |
)); |
4008 |
22 Jun 16 |
nicklas |
171 |
|
4008 |
22 Jun 16 |
nicklas |
172 |
Date startDate = Reggie.CONVERTER_STRING_TO_DATE.convert(year+zeroPad(month)+"01"); |
4008 |
22 Jun 16 |
nicklas |
173 |
month++; |
4008 |
22 Jun 16 |
nicklas |
174 |
if (month > 12) |
4008 |
22 Jun 16 |
nicklas |
175 |
{ |
4008 |
22 Jun 16 |
nicklas |
176 |
month = 1; |
4008 |
22 Jun 16 |
nicklas |
177 |
year++; |
4008 |
22 Jun 16 |
nicklas |
178 |
} |
4008 |
22 Jun 16 |
nicklas |
179 |
Date endDate = Reggie.CONVERTER_STRING_TO_DATE.convert(year+zeroPad(month)+"01");; |
4008 |
22 Jun 16 |
nicklas |
180 |
query.setParameter("startDate", startDate, Type.DATE); |
4008 |
22 Jun 16 |
nicklas |
181 |
query.setParameter("endDate", endDate, Type.DATE); |
4008 |
22 Jun 16 |
nicklas |
182 |
} |
4008 |
22 Jun 16 |
nicklas |
183 |
else |
4008 |
22 Jun 16 |
nicklas |
184 |
{ |
4008 |
22 Jun 16 |
nicklas |
// Last 30 days |
4008 |
22 Jun 16 |
nicklas |
186 |
query.restrict( |
4008 |
22 Jun 16 |
nicklas |
187 |
Restrictions.gteq(Hql.alias("ad"), Expressions.parameter("startDate")) |
4008 |
22 Jun 16 |
nicklas |
188 |
); |
4141 |
30 Sep 16 |
nicklas |
189 |
Date startDate = new Date(System.currentTimeMillis() - 30 * MILLIS_PER_DAY); |
4008 |
22 Jun 16 |
nicklas |
190 |
query.setParameter("startDate", startDate, Type.DATE); |
4008 |
22 Jun 16 |
nicklas |
191 |
} |
4006 |
21 Jun 16 |
nicklas |
192 |
|
4000 |
17 Jun 16 |
nicklas |
193 |
SnapshotManager manager = new SnapshotManager(); |
4000 |
17 Jun 16 |
nicklas |
194 |
List<SpecimenTube> result = SpecimenTube.toList(query.list(dc)); |
3997 |
14 Jun 16 |
nicklas |
195 |
|
4000 |
17 Jun 16 |
nicklas |
// We devide the specimen into 3 categories: |
4000 |
17 Jun 16 |
nicklas |
// - those with reports that are not downloaded |
4000 |
17 Jun 16 |
nicklas |
// - those with no report (ongoing work) |
4000 |
17 Jun 16 |
nicklas |
// - those with reports that has been downloaded |
4000 |
17 Jun 16 |
nicklas |
200 |
JSONArray jsonNewReports = new JSONArray(); |
4000 |
17 Jun 16 |
nicklas |
201 |
JSONArray jsonWorkInProgress = new JSONArray(); |
4000 |
17 Jun 16 |
nicklas |
202 |
JSONArray jsonArchive = new JSONArray(); |
4000 |
17 Jun 16 |
nicklas |
203 |
|
4040 |
29 Jul 16 |
nicklas |
// Limit for new->old specimen that has been completed without report |
4141 |
30 Sep 16 |
nicklas |
205 |
Date sevenDaysAgo = new Date(System.currentTimeMillis() - 7 * MILLIS_PER_DAY); |
4040 |
29 Jul 16 |
nicklas |
206 |
|
4000 |
17 Jun 16 |
nicklas |
207 |
for (SpecimenTube sp : result) |
4000 |
17 Jun 16 |
nicklas |
208 |
{ |
4000 |
17 Jun 16 |
nicklas |
209 |
JSONArray jsonC = jsonWorkInProgress; |
4000 |
17 Jun 16 |
nicklas |
210 |
sp.loadAnnotations(dc, manager, "ArrivalDate", Annotationtype.ARRIVAL_DATE, Reggie.CONVERTER_DATE_TO_STRING); |
4037 |
29 Jul 16 |
nicklas |
211 |
sp.loadAnnotations(dc, manager, "PAD", Annotationtype.PAD, null); |
4040 |
29 Jul 16 |
nicklas |
212 |
sp.loadAnnotations(dc, manager, "CompletedDate", Annotationtype.COMPLETED_DATE, Reggie.CONVERTER_DATE_TO_STRING); |
4040 |
29 Jul 16 |
nicklas |
213 |
Date completed = (Date)Annotationtype.COMPLETED_DATE.getAnnotationValue(dc, sp.getItem()); |
4000 |
17 Jun 16 |
nicklas |
214 |
|
4000 |
17 Jun 16 |
nicklas |
215 |
Patient pat = Patient.findByCase(dc, sp.getCase()); |
4040 |
29 Jul 16 |
nicklas |
216 |
pat.loadAnnotations(dc, manager, "PersonalNo", Annotationtype.PERSONAL_NUMBER, null); |
4040 |
29 Jul 16 |
nicklas |
217 |
pat.loadAnnotations(dc, manager, "AllFirstNames", Annotationtype.ALL_FIRST_NAMES, null); |
4040 |
29 Jul 16 |
nicklas |
218 |
pat.loadAnnotations(dc, manager, "FamilyName", Annotationtype.FAMILY_NAME, null); |
4000 |
17 Jun 16 |
nicklas |
219 |
sp.setAnnotation("patient", pat.asJSONObject()); |
4000 |
17 Jun 16 |
nicklas |
220 |
|
4031 |
26 Jul 16 |
nicklas |
221 |
XmlConfig cfg = Reggie.getConfig(); |
4031 |
26 Jul 16 |
nicklas |
222 |
String pdfName = cfg.getConfig("rscript/pilot-report/pdf-name", null, PilotReportWorker.DEFAULT_PDF_NAME); |
4031 |
26 Jul 16 |
nicklas |
223 |
JSONObject jsonPilot = JsonUtil.loadLinkedItem(dc, sp.getItem(), pdfName, Item.FILE, |
4031 |
26 Jul 16 |
nicklas |
224 |
new LoadMoreJson<File>() |
4000 |
17 Jun 16 |
nicklas |
225 |
{ |
4031 |
26 Jul 16 |
nicklas |
226 |
@Override |
4031 |
26 Jul 16 |
nicklas |
227 |
public void addMore(DbControl dc, JSONObject json, File file) |
4000 |
17 Jun 16 |
nicklas |
228 |
{ |
4031 |
26 Jul 16 |
nicklas |
229 |
json.put("lastUpdatedDate", Reggie.CONVERTER_DATE_TO_STRING.convert(file.getLastUpdate())); |
4000 |
17 Jun 16 |
nicklas |
230 |
} |
4031 |
26 Jul 16 |
nicklas |
231 |
}); |
4031 |
26 Jul 16 |
nicklas |
232 |
if (jsonPilot != null) |
4031 |
26 Jul 16 |
nicklas |
233 |
{ |
4031 |
26 Jul 16 |
nicklas |
234 |
sp.setAnnotation("pilotReport", jsonPilot); |
4031 |
26 Jul 16 |
nicklas |
235 |
jsonC = jsonNewReports; |
4031 |
26 Jul 16 |
nicklas |
236 |
|
4031 |
26 Jul 16 |
nicklas |
237 |
ItemQuery<ChangeHistory> historyQuery = ChangeHistory.getHistoryOf(sp.getItem()); |
4031 |
26 Jul 16 |
nicklas |
238 |
historyQuery.restrict(Restrictions.eq(Hql.property("changeType"), Expressions.integer(ChangeType.DOWNLOAD.getValue()))); |
4031 |
26 Jul 16 |
nicklas |
239 |
historyQuery.order(Orders.desc(Hql.property("changeHistory.time"))); |
4031 |
26 Jul 16 |
nicklas |
240 |
historyQuery.setCacheResult(true); |
4031 |
26 Jul 16 |
nicklas |
241 |
historyQuery.setReturnTotalCount(true); |
4031 |
26 Jul 16 |
nicklas |
242 |
historyQuery.setMaxResults(1); |
4031 |
26 Jul 16 |
nicklas |
243 |
|
4031 |
26 Jul 16 |
nicklas |
244 |
ItemResultIterator<ChangeHistory> it = historyQuery.iterate(dc); |
4031 |
26 Jul 16 |
nicklas |
245 |
|
4031 |
26 Jul 16 |
nicklas |
246 |
long downloadCount = it.getTotalCount(); |
4031 |
26 Jul 16 |
nicklas |
247 |
jsonPilot.put("downloadCount", downloadCount); |
4031 |
26 Jul 16 |
nicklas |
248 |
jsonC = jsonNewReports; |
4031 |
26 Jul 16 |
nicklas |
249 |
if (downloadCount > 0) |
4031 |
26 Jul 16 |
nicklas |
250 |
{ |
4031 |
26 Jul 16 |
nicklas |
251 |
ChangeHistory ch = it.next(); |
4031 |
26 Jul 16 |
nicklas |
252 |
jsonPilot.put("downloadedDate", Reggie.CONVERTER_DATE_TO_STRING.convert(ch.getTime())); |
4031 |
26 Jul 16 |
nicklas |
253 |
jsonC = jsonArchive; |
4000 |
17 Jun 16 |
nicklas |
254 |
} |
4031 |
26 Jul 16 |
nicklas |
255 |
it.close(); |
4000 |
17 Jun 16 |
nicklas |
256 |
} |
4040 |
29 Jul 16 |
nicklas |
257 |
else if (completed != null) |
4040 |
29 Jul 16 |
nicklas |
258 |
{ |
4040 |
29 Jul 16 |
nicklas |
// Marked as completed but there is not published report |
4040 |
29 Jul 16 |
nicklas |
// Typically an indication of some kind of problem (eg. Flagged RNA, etc) |
4040 |
29 Jul 16 |
nicklas |
261 |
if (completed.before(sevenDaysAgo)) |
4040 |
29 Jul 16 |
nicklas |
262 |
{ |
4040 |
29 Jul 16 |
nicklas |
// More than 7 days old |
4040 |
29 Jul 16 |
nicklas |
264 |
jsonC = jsonArchive; |
4040 |
29 Jul 16 |
nicklas |
265 |
} |
4040 |
29 Jul 16 |
nicklas |
266 |
else |
4040 |
29 Jul 16 |
nicklas |
267 |
{ |
4040 |
29 Jul 16 |
nicklas |
268 |
jsonC = jsonNewReports; |
4040 |
29 Jul 16 |
nicklas |
269 |
} |
4040 |
29 Jul 16 |
nicklas |
270 |
} |
4000 |
17 Jun 16 |
nicklas |
271 |
|
4000 |
17 Jun 16 |
nicklas |
272 |
jsonC.add(sp.asJSONObject()); |
4000 |
17 Jun 16 |
nicklas |
273 |
} |
4009 |
23 Jun 16 |
nicklas |
// Thread.sleep(2500); |
4006 |
21 Jun 16 |
nicklas |
275 |
|
4000 |
17 Jun 16 |
nicklas |
276 |
json.put("newReports", jsonNewReports); |
4000 |
17 Jun 16 |
nicklas |
277 |
json.put("workInProgress", jsonWorkInProgress); |
4000 |
17 Jun 16 |
nicklas |
278 |
json.put("archived", jsonArchive); |
4007 |
21 Jun 16 |
nicklas |
279 |
json.put("user", loadCurrentUserInformation(dc)); |
4006 |
21 Jun 16 |
nicklas |
280 |
|
4000 |
17 Jun 16 |
nicklas |
281 |
} |
4004 |
20 Jun 16 |
nicklas |
282 |
else if ("DownloadReport".equals(cmd)) |
4004 |
20 Jun 16 |
nicklas |
283 |
{ |
4004 |
20 Jun 16 |
nicklas |
284 |
json = null; // No JSON output |
6337 |
16 Jun 21 |
nicklas |
285 |
dc = sc.newDbControl(":Download report"); |
4004 |
20 Jun 16 |
nicklas |
286 |
|
4004 |
20 Jun 16 |
nicklas |
287 |
int fileId = Values.getInt(req.getParameter("fileId")); |
4004 |
20 Jun 16 |
nicklas |
288 |
File pdf = File.getById(dc, fileId); |
4004 |
20 Jun 16 |
nicklas |
289 |
String pdfPath = pdf.getPath().toString(); |
4004 |
20 Jun 16 |
nicklas |
290 |
|
4004 |
20 Jun 16 |
nicklas |
291 |
int specimenId = Values.getInt(req.getParameter("specimenId")); |
4004 |
20 Jun 16 |
nicklas |
292 |
Sample specimen = Sample.getById(dc, specimenId); |
4004 |
20 Jun 16 |
nicklas |
293 |
|
4009 |
23 Jun 16 |
nicklas |
// We create one DOWNLOAD log entry on the file and one on the specimen |
4009 |
23 Jun 16 |
nicklas |
295 |
dc.logEntry(new ManualLogEntry(pdf, ChangeType.DOWNLOAD, null)); |
4009 |
23 Jun 16 |
nicklas |
296 |
dc.logEntry(new ManualLogEntry(specimen, ChangeType.DOWNLOAD, pdfPath)); |
4009 |
23 Jun 16 |
nicklas |
297 |
|
4038 |
29 Jul 16 |
nicklas |
298 |
resp.setHeader("Content-Disposition", "attachment; filename=" + Path.makeSafeFilename(specimen.getName(), "")+".pdf"); |
4004 |
20 Jun 16 |
nicklas |
299 |
resp.setContentType(pdf.getMimeType()); |
4004 |
20 Jun 16 |
nicklas |
300 |
resp.setContentLengthLong(pdf.getSize()); |
4004 |
20 Jun 16 |
nicklas |
301 |
|
4038 |
29 Jul 16 |
nicklas |
302 |
OutputStream out = null; |
4038 |
29 Jul 16 |
nicklas |
303 |
InputStream in = null; |
4038 |
29 Jul 16 |
nicklas |
304 |
try |
4038 |
29 Jul 16 |
nicklas |
305 |
{ |
4038 |
29 Jul 16 |
nicklas |
306 |
out = resp.getOutputStream(); |
4038 |
29 Jul 16 |
nicklas |
307 |
in = pdf.getDownloadStream(0); |
4038 |
29 Jul 16 |
nicklas |
308 |
|
4038 |
29 Jul 16 |
nicklas |
// For debugging |
4038 |
29 Jul 16 |
nicklas |
// if (fileId == 807879) throw new RuntimeException("Download failed"); |
4038 |
29 Jul 16 |
nicklas |
311 |
|
4038 |
29 Jul 16 |
nicklas |
312 |
FileUtil.copy(in, out); |
4038 |
29 Jul 16 |
nicklas |
313 |
out.flush(); |
4038 |
29 Jul 16 |
nicklas |
314 |
dc.commit(); |
4038 |
29 Jul 16 |
nicklas |
315 |
} |
4038 |
29 Jul 16 |
nicklas |
316 |
finally |
4038 |
29 Jul 16 |
nicklas |
317 |
{ |
4038 |
29 Jul 16 |
nicklas |
318 |
FileUtil.close(out); |
4038 |
29 Jul 16 |
nicklas |
319 |
FileUtil.close(in); |
4038 |
29 Jul 16 |
nicklas |
320 |
} |
4009 |
23 Jun 16 |
nicklas |
321 |
|
4004 |
20 Jun 16 |
nicklas |
322 |
} |
4007 |
21 Jun 16 |
nicklas |
323 |
else if ("Logout".equals(cmd)) |
4007 |
21 Jun 16 |
nicklas |
324 |
{ |
4007 |
21 Jun 16 |
nicklas |
325 |
Thread.sleep(2500); |
4007 |
21 Jun 16 |
nicklas |
326 |
sc.logout(); |
4010 |
23 Jun 16 |
nicklas |
327 |
sc.close(); |
4007 |
21 Jun 16 |
nicklas |
328 |
} |
4000 |
17 Jun 16 |
nicklas |
329 |
} |
4000 |
17 Jun 16 |
nicklas |
330 |
catch (Throwable t) |
4000 |
17 Jun 16 |
nicklas |
331 |
{ |
4000 |
17 Jun 16 |
nicklas |
332 |
t.printStackTrace(); |
4004 |
20 Jun 16 |
nicklas |
333 |
if (json != null) |
4004 |
20 Jun 16 |
nicklas |
334 |
{ |
4004 |
20 Jun 16 |
nicklas |
335 |
json.clear(); |
4004 |
20 Jun 16 |
nicklas |
336 |
json.put("status", "error"); |
4004 |
20 Jun 16 |
nicklas |
337 |
json.put("message", t.getMessage()); |
4004 |
20 Jun 16 |
nicklas |
338 |
json.put("stacktrace", ThrowableUtil.stackTraceToString(t)); |
4004 |
20 Jun 16 |
nicklas |
339 |
} |
4004 |
20 Jun 16 |
nicklas |
340 |
else |
4004 |
20 Jun 16 |
nicklas |
341 |
{ |
4009 |
23 Jun 16 |
nicklas |
342 |
resp.reset(); |
4004 |
20 Jun 16 |
nicklas |
343 |
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, t.getMessage()); |
4004 |
20 Jun 16 |
nicklas |
344 |
} |
4000 |
17 Jun 16 |
nicklas |
345 |
} |
4000 |
17 Jun 16 |
nicklas |
346 |
finally |
4000 |
17 Jun 16 |
nicklas |
347 |
{ |
4000 |
17 Jun 16 |
nicklas |
348 |
if (dc != null) dc.close(); |
4004 |
20 Jun 16 |
nicklas |
349 |
if (json != null) json.writeJSONString(resp.getWriter()); |
4000 |
17 Jun 16 |
nicklas |
350 |
} |
4000 |
17 Jun 16 |
nicklas |
351 |
|
4000 |
17 Jun 16 |
nicklas |
352 |
} |
5320 |
28 Feb 19 |
nicklas |
353 |
|
3997 |
14 Jun 16 |
nicklas |
354 |
@Override |
3997 |
14 Jun 16 |
nicklas |
355 |
protected void doPost(HttpServletRequest req, HttpServletResponse resp) |
3997 |
14 Jun 16 |
nicklas |
356 |
throws ServletException, IOException |
3997 |
14 Jun 16 |
nicklas |
357 |
{ |
3997 |
14 Jun 16 |
nicklas |
358 |
JSONObject json = new JSONObject(); |
4009 |
23 Jun 16 |
nicklas |
359 |
JSONArray jsonMessages = new JSONArray(); |
3997 |
14 Jun 16 |
nicklas |
360 |
json.put("status", "ok"); |
3998 |
15 Jun 16 |
nicklas |
361 |
|
3997 |
14 Jun 16 |
nicklas |
362 |
DbControl dc = null; |
4010 |
23 Jun 16 |
nicklas |
363 |
SessionControl sc = null; |
3997 |
14 Jun 16 |
nicklas |
364 |
try |
3997 |
14 Jun 16 |
nicklas |
365 |
{ |
3998 |
15 Jun 16 |
nicklas |
366 |
JsonUtil.setJsonResponseHeaders(resp); |
3998 |
15 Jun 16 |
nicklas |
367 |
String cmd = req.getParameter("cmd"); |
3998 |
15 Jun 16 |
nicklas |
368 |
|
3997 |
14 Jun 16 |
nicklas |
369 |
if ("Login".equals(cmd)) |
3997 |
14 Jun 16 |
nicklas |
370 |
{ |
3997 |
14 Jun 16 |
nicklas |
371 |
JSONObject jsonReq = JsonUtil.parseRequest(req); |
3997 |
14 Jun 16 |
nicklas |
372 |
String username = (String)jsonReq.get("username"); |
3997 |
14 Jun 16 |
nicklas |
373 |
String password = (String)jsonReq.get("password"); |
3997 |
14 Jun 16 |
nicklas |
374 |
String yubikey = (String)jsonReq.get("yubikey"); |
3997 |
14 Jun 16 |
nicklas |
375 |
|
3997 |
14 Jun 16 |
nicklas |
376 |
LoginRequest login = new LoginRequest(yubikey, password); |
3997 |
14 Jun 16 |
nicklas |
377 |
login.setAttribute("username", username); |
5163 |
03 Dec 18 |
nicklas |
378 |
login.setAttribute("login-form", "net.sf.basedb.yubikey.login-form"); |
3997 |
14 Jun 16 |
nicklas |
379 |
|
4010 |
23 Jun 16 |
nicklas |
380 |
sc = Application.newSessionControl(ClientApp.SCANB_DELIVERY.getExternalId(), req.getRemoteAddr(), null); |
3997 |
14 Jun 16 |
nicklas |
381 |
sc.login(login); |
4010 |
23 Jun 16 |
nicklas |
382 |
json.put("ID", sc.getId()); |
3997 |
14 Jun 16 |
nicklas |
383 |
} |
3997 |
14 Jun 16 |
nicklas |
384 |
|
3997 |
14 Jun 16 |
nicklas |
385 |
json.put("messages", jsonMessages); |
3997 |
14 Jun 16 |
nicklas |
386 |
} |
3997 |
14 Jun 16 |
nicklas |
387 |
catch (Throwable t) |
3997 |
14 Jun 16 |
nicklas |
388 |
{ |
4010 |
23 Jun 16 |
nicklas |
// Cleanup after failed login attempt |
4010 |
23 Jun 16 |
nicklas |
390 |
if (sc != null) sc.close(); |
3997 |
14 Jun 16 |
nicklas |
391 |
t.printStackTrace(); |
3997 |
14 Jun 16 |
nicklas |
392 |
json.clear(); |
3997 |
14 Jun 16 |
nicklas |
393 |
json.put("status", "error"); |
3997 |
14 Jun 16 |
nicklas |
394 |
json.put("message", t.getMessage()); |
3997 |
14 Jun 16 |
nicklas |
395 |
json.put("stacktrace", ThrowableUtil.stackTraceToString(t)); |
3997 |
14 Jun 16 |
nicklas |
396 |
} |
3997 |
14 Jun 16 |
nicklas |
397 |
finally |
3997 |
14 Jun 16 |
nicklas |
398 |
{ |
3997 |
14 Jun 16 |
nicklas |
399 |
if (dc != null) dc.close(); |
3997 |
14 Jun 16 |
nicklas |
400 |
json.writeJSONString(resp.getWriter()); |
3997 |
14 Jun 16 |
nicklas |
401 |
} |
3997 |
14 Jun 16 |
nicklas |
402 |
} |
4000 |
17 Jun 16 |
nicklas |
403 |
|
4007 |
21 Jun 16 |
nicklas |
404 |
public static JSONObject loadCurrentUserInformation(DbControl dc) |
4007 |
21 Jun 16 |
nicklas |
405 |
{ |
4007 |
21 Jun 16 |
nicklas |
406 |
SessionControl sc = dc.getSessionControl(); |
4007 |
21 Jun 16 |
nicklas |
407 |
User u = User.getById(dc, sc.getLoggedInUserId()); |
4007 |
21 Jun 16 |
nicklas |
408 |
|
4007 |
21 Jun 16 |
nicklas |
409 |
JSONObject json = new JSONObject(); |
4007 |
21 Jun 16 |
nicklas |
410 |
json.put("id", u.getId()); |
4007 |
21 Jun 16 |
nicklas |
411 |
json.put("username", u.getLogin()); |
4007 |
21 Jun 16 |
nicklas |
412 |
json.put("name", u.getName()); |
4007 |
21 Jun 16 |
nicklas |
413 |
|
4007 |
21 Jun 16 |
nicklas |
// Calculate timeout from last access |
4007 |
21 Jun 16 |
nicklas |
// Use 1 minute less to allow user to react before it is too late |
4007 |
21 Jun 16 |
nicklas |
416 |
long timeout = sc.getLastAccess() + (Application.sessionCacheTimeout()-1) * 60000; |
4007 |
21 Jun 16 |
nicklas |
// long timeout = sc.getLastAccess() + 2 * 60000; |
4007 |
21 Jun 16 |
nicklas |
418 |
json.put("timeout", timeout); |
4007 |
21 Jun 16 |
nicklas |
419 |
|
4007 |
21 Jun 16 |
nicklas |
420 |
return json; |
4007 |
21 Jun 16 |
nicklas |
421 |
} |
4008 |
22 Jun 16 |
nicklas |
422 |
|
4008 |
22 Jun 16 |
nicklas |
423 |
private String zeroPad(int month) |
4008 |
22 Jun 16 |
nicklas |
424 |
{ |
4008 |
22 Jun 16 |
nicklas |
425 |
return (month < 10 ? "0" : "") + month; |
4008 |
22 Jun 16 |
nicklas |
426 |
} |
4008 |
22 Jun 16 |
nicklas |
427 |
|
4028 |
26 Jul 16 |
nicklas |
428 |
/** |
4028 |
26 Jul 16 |
nicklas |
Extends the copy pdf file combiner with support for |
4028 |
26 Jul 16 |
nicklas |
saving files in the correct subfolder inside the |
4028 |
26 Jul 16 |
nicklas |
{@link Reggie#DELIVERY_DIR}. |
4028 |
26 Jul 16 |
nicklas |
432 |
*/ |
4028 |
26 Jul 16 |
nicklas |
433 |
public static class CombineForDelivery |
4028 |
26 Jul 16 |
nicklas |
434 |
extends PdfToBaseFileCombiner |
4028 |
26 Jul 16 |
nicklas |
435 |
{ |
4028 |
26 Jul 16 |
nicklas |
436 |
|
4028 |
26 Jul 16 |
nicklas |
437 |
private final PdfReportTemplate report; |
4028 |
26 Jul 16 |
nicklas |
438 |
private final String rootPath; |
4034 |
29 Jul 16 |
nicklas |
439 |
|
4141 |
30 Sep 16 |
nicklas |
440 |
private Set<SharedItem> itemsToPublish; |
4028 |
26 Jul 16 |
nicklas |
441 |
|
4028 |
26 Jul 16 |
nicklas |
442 |
public CombineForDelivery(DbControl dc, Directory rootDir, PdfReportTemplate report) |
4028 |
26 Jul 16 |
nicklas |
443 |
{ |
4028 |
26 Jul 16 |
nicklas |
444 |
super(dc, rootDir); |
4028 |
26 Jul 16 |
nicklas |
445 |
this.report = report; |
4028 |
26 Jul 16 |
nicklas |
446 |
this.rootPath = rootDir.getPath().toString(); |
4141 |
30 Sep 16 |
nicklas |
447 |
this.itemsToPublish = new HashSet<>(); |
4028 |
26 Jul 16 |
nicklas |
448 |
} |
4028 |
26 Jul 16 |
nicklas |
449 |
|
4028 |
26 Jul 16 |
nicklas |
450 |
@Override |
4028 |
26 Jul 16 |
nicklas |
451 |
protected File createOrGetFile(DbControl dc, String pdfName) |
4028 |
26 Jul 16 |
nicklas |
452 |
{ |
4028 |
26 Jul 16 |
nicklas |
453 |
String folder = DeliveryServlet.generateDeliveryFolder(pdfName); |
4028 |
26 Jul 16 |
nicklas |
454 |
Path p = new Path(rootPath + folder, Path.Type.DIRECTORY); |
4028 |
26 Jul 16 |
nicklas |
455 |
|
4028 |
26 Jul 16 |
nicklas |
456 |
Directory d = Directory.getNew(dc, p); |
4028 |
26 Jul 16 |
nicklas |
457 |
File f = File.getFile(dc, d, report.getDefaultFilename(), true); |
4031 |
26 Jul 16 |
nicklas |
// The immediate parent directory has the same name as the specimen |
4141 |
30 Sep 16 |
nicklas |
459 |
String specimenName = d.getName(); |
4141 |
30 Sep 16 |
nicklas |
460 |
if (!f.isInDatabase()) |
4034 |
29 Jul 16 |
nicklas |
461 |
{ |
4141 |
30 Sep 16 |
nicklas |
// Make sure new items are not shared to default project, etc. |
4141 |
30 Sep 16 |
nicklas |
// Collect the PDF file and parent directories up to /home/Delivery |
4141 |
30 Sep 16 |
nicklas |
// Permissions will be updated by the SetPermissionsForDelivery plug-in later |
4141 |
30 Sep 16 |
nicklas |
465 |
f.setItemKey(null); |
4141 |
30 Sep 16 |
nicklas |
466 |
f.setProjectKey(null); |
4141 |
30 Sep 16 |
nicklas |
467 |
dc.saveItem(f); |
4141 |
30 Sep 16 |
nicklas |
468 |
|
4141 |
30 Sep 16 |
nicklas |
469 |
while (d != null && !d.isInDatabase()) |
4141 |
30 Sep 16 |
nicklas |
470 |
{ |
4141 |
30 Sep 16 |
nicklas |
471 |
d.setItemKey(null); |
4141 |
30 Sep 16 |
nicklas |
472 |
d.setProjectKey(null); |
4141 |
30 Sep 16 |
nicklas |
473 |
d = d.getParent(); |
4141 |
30 Sep 16 |
nicklas |
474 |
} |
4034 |
29 Jul 16 |
nicklas |
475 |
} |
4141 |
30 Sep 16 |
nicklas |
476 |
|
4141 |
30 Sep 16 |
nicklas |
// Link the file to the specimen item |
4141 |
30 Sep 16 |
nicklas |
478 |
SpecimenTube sp = SpecimenTube.findByTubeName(dc, specimenName); |
4141 |
30 Sep 16 |
nicklas |
479 |
if (sp == null) throw new ItemNotFoundException("Specimen tube: " + specimenName); |
4034 |
29 Jul 16 |
nicklas |
480 |
|
4034 |
29 Jul 16 |
nicklas |
481 |
AnyToAny link = AnyToAny.getNewOrExisting(dc, sp.getItem(), f.getName(), f, false); |
4031 |
26 Jul 16 |
nicklas |
482 |
if (!link.isInDatabase()) dc.saveItem(link); |
4031 |
26 Jul 16 |
nicklas |
483 |
link.setDescription("Pilot report for delivery to site"); |
4031 |
26 Jul 16 |
nicklas |
484 |
|
4141 |
30 Sep 16 |
nicklas |
485 |
itemsToPublish.add(f); |
4028 |
26 Jul 16 |
nicklas |
486 |
|
4028 |
26 Jul 16 |
nicklas |
487 |
return f; |
4028 |
26 Jul 16 |
nicklas |
488 |
} |
4028 |
26 Jul 16 |
nicklas |
489 |
|
4034 |
29 Jul 16 |
nicklas |
490 |
public int numberOfItemsToPublish() |
4034 |
29 Jul 16 |
nicklas |
491 |
{ |
4141 |
30 Sep 16 |
nicklas |
492 |
return itemsToPublish.size(); |
4034 |
29 Jul 16 |
nicklas |
493 |
} |
4028 |
26 Jul 16 |
nicklas |
494 |
|
4141 |
30 Sep 16 |
nicklas |
495 |
public Set<SharedItem> getItemsToPublish() |
4034 |
29 Jul 16 |
nicklas |
496 |
{ |
4034 |
29 Jul 16 |
nicklas |
497 |
return itemsToPublish; |
4034 |
29 Jul 16 |
nicklas |
498 |
} |
4034 |
29 Jul 16 |
nicklas |
499 |
|
4028 |
26 Jul 16 |
nicklas |
500 |
} |
3997 |
14 Jun 16 |
nicklas |
501 |
} |