• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DataBiosphere / consent / #5834

02 May 2025 06:55PM UTC coverage: 78.772% (+0.04%) from 78.733%
#5834

push

web-flow
[DT-1601] Add a check that all datasets in a progress report must be approved (#2510)

5 of 5 new or added lines in 1 file covered. (100.0%)

54 existing lines in 6 files now uncovered.

10075 of 12790 relevant lines covered (78.77%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.04
/src/main/java/org/broadinstitute/consent/http/models/DataAccessRequest.java
1
package org.broadinstitute.consent.http.models;
2

3
import com.fasterxml.jackson.annotation.JsonInclude;
4
import com.fasterxml.jackson.annotation.JsonInclude.Include;
5
import com.fasterxml.jackson.annotation.JsonProperty;
6
import com.google.common.base.CaseFormat;
7
import com.google.gson.Gson;
8
import com.google.gson.GsonBuilder;
9
import com.google.gson.JsonObject;
10
import com.google.gson.JsonPrimitive;
11
import com.google.gson.JsonSerializer;
12
import com.google.gson.reflect.TypeToken;
13
import java.lang.reflect.Type;
14
import java.sql.Timestamp;
15
import java.util.ArrayList;
16
import java.util.Date;
17
import java.util.HashMap;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.Objects;
21
import java.util.concurrent.TimeUnit;
22
import java.util.stream.Collectors;
23
import java.util.stream.Stream;
24

25
@JsonInclude(Include.NON_NULL)
26
public class DataAccessRequest {
27

28
  public static final long EXPIRATION_DURATION_MILLIS = TimeUnit.DAYS.toMillis(365);
1✔
29

30
  @JsonProperty
31
  public Integer id;
32

33
  @JsonProperty
34
  public String referenceId;
35

36
  @JsonProperty
37
  public Integer collectionId;
38

39
  @JsonProperty
40
  public String parentId;
41

42
  @JsonProperty
43
  public DataAccessRequestData data;
44

45
  @JsonProperty
46
  public String darCode;
47

48
  @JsonProperty
1✔
49
  public Boolean draft = true;
1✔
50

51
  @JsonProperty
1✔
52
  public Boolean expired = false;
1✔
53

54
  @JsonProperty
55
  public Timestamp expiresAt;
56

57
  @JsonProperty
58
  public Integer userId;
59

60
  @JsonProperty
61
  public Timestamp createDate;
62

63
  /*
64
   * Legacy property on DARs. Used to display the sort order for a DAR. In practice, this also
65
   * functions as the Update Date. See also https://broadinstitute.atlassian.net/browse/DUOS-728
66
   */
67
  @JsonProperty
68
  public Timestamp sortDate;
69

70
  @JsonProperty
71
  public Timestamp submissionDate;
72

73
  @JsonProperty
74
  public Timestamp updateDate;
75
  @JsonProperty
76
  public List<Integer> datasetIds;
77
  @JsonProperty
78
  private Map<Integer, Election> elections;
79

80
  public DataAccessRequest() {
1✔
81
    this.elections = new HashMap<>();
1✔
82
  }
1✔
83

84
  public static boolean isCanceled(DataAccessRequest dar) {
85
    return
1✔
86
        Objects.nonNull(dar) &&
1✔
87
            Objects.nonNull(dar.getData()) &&
1✔
88
            Objects.nonNull(dar.getData().getStatus()) &&
1✔
89
            dar.getData().getStatus().equalsIgnoreCase("canceled");
1✔
90
  }
91

92
  public Integer getId() {
93
    return id;
1✔
94
  }
95

96
  public void setId(Integer id) {
97
    this.id = id;
1✔
98
  }
1✔
99

100
  public String getReferenceId() {
101
    return referenceId;
1✔
102
  }
103

104
  public void setReferenceId(String referenceId) {
105
    this.referenceId = referenceId;
1✔
106
  }
1✔
107

108
  public Integer getCollectionId() {
109
    return collectionId;
1✔
110
  }
111

112
  public void setCollectionId(Integer collectionId) {
113
    this.collectionId = collectionId;
1✔
114
  }
1✔
115

116
  public String getParentId() {
117
    return parentId;
1✔
118
  }
119

120
  public void setParentId(String parentId) {
121
    this.parentId = parentId;
1✔
122
  }
1✔
123

124
  public DataAccessRequestData getData() {
125
    return data;
1✔
126
  }
127

128
  public void setData(DataAccessRequestData data) {
129
    this.data = data;
1✔
130
  }
1✔
131

132
  public Boolean getDraft() {
133
    return draft;
1✔
134
  }
135

136
  public boolean getExpired() {
137
    return expired;
1✔
138
  }
139

140
  public Timestamp getExpiresAt() {
141
    return expiresAt;
1✔
142
  }
143

144
  public Integer getUserId() {
145
    return userId;
1✔
146
  }
147

148
  public void setUserId(Integer userId) {
149
    this.userId = userId;
1✔
150
  }
1✔
151

152
  public Date getCreateDate() {
153
    return createDate;
1✔
154
  }
155

156
  public void setCreateDate(Timestamp createDate) {
157
    this.createDate = createDate;
1✔
158
  }
1✔
159

160
  public Date getSortDate() {
161
    return sortDate;
1✔
162
  }
163

164
  public void setSortDate(Timestamp sortDate) {
165
    this.sortDate = sortDate;
1✔
166
  }
1✔
167

168
  public Timestamp getSubmissionDate() {
169
    return submissionDate;
1✔
170
  }
171

172
  public void setSubmissionDate(Timestamp submissionDate) {
173
    this.submissionDate = submissionDate;
1✔
174
    draft = submissionDate == null;
1✔
175
    expired = submissionDate != null
1✔
176
        && submissionDate.before(
1✔
177
        new Timestamp(System.currentTimeMillis() - EXPIRATION_DURATION_MILLIS));
1✔
178
    expiresAt = (submissionDate != null) ? new Timestamp(
1✔
179
        submissionDate.getTime() + EXPIRATION_DURATION_MILLIS) : null;
1✔
180
  }
1✔
181

182
  public Timestamp getUpdateDate() {
183
    return updateDate;
1✔
184
  }
185

186
  public void setUpdateDate(Timestamp updateDate) {
187
    this.updateDate = updateDate;
1✔
188
  }
1✔
189

190
  public Map<Integer, Election> getElections() {
191
    return elections;
1✔
192
  }
193

194
  public void setElections(Map<Integer, Election> elections) {
UNCOV
195
    this.elections = elections;
×
UNCOV
196
  }
×
197

198
  public void addElection(Election election) {
199
    if (Objects.isNull(elections)) {
1✔
UNCOV
200
      this.setElections(new HashMap<>());
×
201
    }
202
    if (Objects.nonNull(election)) {
1✔
203
      Integer electionId = election.getElectionId();
1✔
204
      Election savedRecord = elections.get(electionId);
1✔
205
      if (Objects.isNull(savedRecord)) {
1✔
206
        elections.put(electionId, election);
1✔
207
      }
208
    }
209
  }
1✔
210

211
  public List<Integer> getDatasetIds() {
212
    if (Objects.isNull(datasetIds)) {
1✔
213
      return List.of();
1✔
214
    }
215
    return datasetIds;
1✔
216
  }
217

218
  public void setDatasetIds(List<Integer> datasetIds) {
219
    this.datasetIds = datasetIds;
1✔
220
  }
1✔
221

222
  public void addDatasetId(Integer id) {
223
    if (Objects.isNull(datasetIds)) {
1✔
224
      datasetIds = new ArrayList<>();
1✔
225
    }
226
    if (!datasetIds.contains(id)) {
1✔
227
      datasetIds.add(id);
1✔
228
    }
229
  }
1✔
230

231
  public void addDatasetIds(List<Integer> ids) {
232
    if (Objects.isNull(datasetIds)) {
1✔
233
      datasetIds = new ArrayList<>();
1✔
234
    }
235
    if (Objects.nonNull(ids) && !ids.isEmpty()) {
1✔
236
      datasetIds = Stream.of(datasetIds, ids)
1✔
237
          .flatMap(List::stream)
1✔
238
          .distinct()
1✔
239
          .collect(Collectors.toList());
1✔
240
    }
241
  }
1✔
242

243
  public void setDarCode(String darCode) {
244
    this.darCode = darCode;
1✔
245
  }
1✔
246

247
  public String getDarCode() {
248
    return darCode;
1✔
249
  }
250

251
  /**
252
   * Merges the DAR and the DAR Data into a single Map Ignores a series of deprecated keys Null
253
   * values are ignored by default
254
   *
255
   * @return Map<String, Object> Dar in simple map format
256
   */
257
  public Map<String, Object> convertToSimplifiedDar() {
258
    // Serialize dates/timestamps as longs, but do not deserialize longs into dates so we can
259
    // output long values in the final result.
260
    Gson gson = new GsonBuilder()
1✔
261
        .registerTypeAdapter(Date.class,
1✔
UNCOV
262
            (JsonSerializer<Date>) (date, type, jsonSerializationContext) -> new JsonPrimitive(
×
UNCOV
263
                date.getTime()))
×
264
        .registerTypeAdapter(Timestamp.class,
1✔
UNCOV
265
            (JsonSerializer<Timestamp>) (timestamp, type, jsonSerializationContext) -> new JsonPrimitive(
×
UNCOV
266
                timestamp.getTime()))
×
267
        .create();
1✔
268
    DataAccessRequestData dataCopy = this.getData();
1✔
269
    this.setData(null);
1✔
270

271
    String serializedDar = gson.toJson(shallowCopy(this));
1✔
272
    JsonObject dar = gson.fromJson(serializedDar, JsonObject.class);
1✔
273

274
    String serializedDarData = gson.toJson(dataCopy);
1✔
275
    JsonObject darData = gson.fromJson(serializedDarData, JsonObject.class);
1✔
276

277
    DataAccessRequestData.DEPRECATED_PROPS.forEach(darData::remove);
1✔
278
    for (String dataKey : darData.keySet()) {
1✔
279
      String camelCasedDataKey =
280
          dataKey.contains("_")
1✔
UNCOV
281
              ? CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, dataKey)
×
282
              : dataKey;
1✔
283
      if (!dar.has(camelCasedDataKey)) {
1✔
284
        dar.add(camelCasedDataKey, darData.get(dataKey));
1✔
285
      }
286
    }
1✔
287
    Type darMapType = new TypeToken<Map<String, Object>>() {
1✔
288
    }.getType();
1✔
289
    return gson.fromJson(dar.toString(), darMapType);
1✔
290
  }
291

292
  public boolean requiresManualReview() {
293
    return
1✔
294
        Objects.nonNull(this.getData()) && (
1✔
295
            (Objects.nonNull(this.getData().getPoa()) && this.getData().getPoa()) ||
1✔
296
                (Objects.nonNull(this.getData().getPopulation()) && this.getData().getPopulation())
1✔
297
                ||
298
                (Objects.nonNull(this.getData().getOther()) && this.getData().getOther()) ||
1✔
299
                (Objects.nonNull(this.getData().getOtherText()) && !this.getData().getOtherText()
1✔
300
                    .isBlank()) ||
1✔
301
                (Objects.nonNull(this.getData().getIllegalBehavior()) && this.getData()
1✔
302
                    .getIllegalBehavior()) ||
1✔
303
                (Objects.nonNull(this.getData().getAddiction()) && this.getData().getAddiction()) ||
1✔
304
                (Objects.nonNull(this.getData().getSexualDiseases()) && this.getData()
1✔
305
                    .getSexualDiseases()) ||
1✔
306
                (Objects.nonNull(this.getData().getStigmatizedDiseases()) && this.getData()
1✔
307
                    .getStigmatizedDiseases()) ||
1✔
308
                (Objects.nonNull(this.getData().getVulnerablePopulation()) && this.getData()
1✔
309
                    .getVulnerablePopulation()) ||
1✔
310
                (Objects.nonNull(this.getData().getPopulationMigration()) && this.getData()
1✔
311
                    .getPopulationMigration()) ||
1✔
312
                (Objects.nonNull(this.getData().getPsychiatricTraits()) && this.getData()
1✔
313
                    .getPsychiatricTraits()) ||
1✔
314
                (Objects.nonNull(this.getData().getNotHealth()) && this.getData().getNotHealth())
1✔
315
        );
316
  }
317

318
  /**
319
   * Make a shallow copy of the dar. This is mostly a workaround for problems serializing dates when
320
   * calling Gson.toJson on `this`
321
   *
322
   * @param dar DataAccessRequest
323
   * @return Shallow copy of DataAccessRequest
324
   */
325
  private Map<String, Object> shallowCopy(DataAccessRequest dar) {
326
    Map<String, Object> copy = new HashMap<>();
1✔
327
    if (Objects.nonNull(dar.getCreateDate())) {
1✔
328
      copy.put("createDate", dar.getCreateDate().getTime());
1✔
329
    }
330
    if (Objects.nonNull(dar.getDraft())) {
1✔
331
      copy.put("draft", dar.getDraft());
1✔
332
    }
333
    copy.put("expired", dar.getExpired());
1✔
334
    copy.put("expiredAt", dar.getExpiresAt());
1✔
335
    if (Objects.nonNull(dar.getId())) {
1✔
336
      copy.put("id", dar.getId());
1✔
337
    }
338
    if (Objects.nonNull(dar.getReferenceId())) {
1✔
339
      copy.put("referenceId", dar.getReferenceId());
1✔
340
    }
341
    if (Objects.nonNull(dar.getSortDate())) {
1✔
342
      copy.put("sortDate", dar.getSortDate().getTime());
1✔
343
    }
344
    if (Objects.nonNull(dar.getSubmissionDate())) {
1✔
UNCOV
345
      copy.put("submissionDate", dar.getSubmissionDate().getTime());
×
346
    }
347
    if (Objects.nonNull(dar.getUpdateDate())) {
1✔
348
      copy.put("updateDate", dar.getUpdateDate().getTime());
1✔
349
    }
350
    if (Objects.nonNull(dar.getUserId())) {
1✔
351
      copy.put("userId", dar.getUserId());
1✔
352
    }
353
    if (Objects.nonNull(dar.getCollectionId())) {
1✔
354
      copy.put("collectionId", dar.getCollectionId());
1✔
355
    }
356
    if (Objects.nonNull(dar.getDatasetIds())) {
1✔
357
      copy.put("datasetIds", dar.getDatasetIds());
1✔
358
    }
359
    if (Objects.nonNull(dar.getParentId())) {
1✔
UNCOV
360
      copy.put("parentId", dar.getParentId());
×
361
    }
362
    if (Objects.nonNull(dar.getDarCode())) {
1✔
UNCOV
363
      copy.put("darCode", dar.getDarCode());
×
364
    }
365
    return copy;
1✔
366
  }
367
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc