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

DataBiosphere / consent / #5724

23 Apr 2025 07:05PM UTC coverage: 79.021% (+0.04%) from 78.981%
#5724

push

web-flow
[DT-1520] DAR Expiration. (#2491)

25 of 27 new or added lines in 4 files covered. (92.59%)

1 existing line in 1 file now uncovered.

10234 of 12951 relevant lines covered (79.02%)

0.79 hits per line

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

92.81
/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
1✔
46
  public Boolean draft = true;
1✔
47

48
  @JsonProperty
1✔
49
  public Boolean expired = false;
1✔
50

51
  @JsonProperty
52
  public Timestamp expiresAt;
53

54
  @JsonProperty
55
  public Integer userId;
56

57
  @JsonProperty
58
  public Timestamp createDate;
59

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

67
  @JsonProperty
68
  public Timestamp submissionDate;
69

70
  @JsonProperty
71
  public Timestamp updateDate;
72
  @JsonProperty
73
  public List<Integer> datasetIds;
74
  @JsonProperty
75
  private Map<Integer, Election> elections;
76

77
  public DataAccessRequest() {
1✔
78
    this.elections = new HashMap<>();
1✔
79
  }
1✔
80

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

89
  public Integer getId() {
90
    return id;
1✔
91
  }
92

93
  public void setId(Integer id) {
94
    this.id = id;
1✔
95
  }
1✔
96

97
  public String getReferenceId() {
98
    return referenceId;
1✔
99
  }
100

101
  public void setReferenceId(String referenceId) {
102
    this.referenceId = referenceId;
1✔
103
  }
1✔
104

105
  public Integer getCollectionId() {
106
    return collectionId;
1✔
107
  }
108

109
  public void setCollectionId(Integer collectionId) {
110
    this.collectionId = collectionId;
1✔
111
  }
1✔
112

113
  public String getParentId() {
114
    return parentId;
1✔
115
  }
116

117
  public void setParentId(String parentId) {
118
    this.parentId = parentId;
1✔
119
  }
1✔
120

121
  public DataAccessRequestData getData() {
122
    return data;
1✔
123
  }
124

125
  public void setData(DataAccessRequestData data) {
126
    this.data = data;
1✔
127
  }
1✔
128

129
  public Boolean getDraft() {
130
    return draft;
1✔
131
  }
132

133
  public boolean getExpired() {
134
    return expired;
1✔
135
  }
136

137
  public Timestamp getExpiresAt() {
138
    return expiresAt;
1✔
139
  }
140

141
  public Integer getUserId() {
142
    return userId;
1✔
143
  }
144

145
  public void setUserId(Integer userId) {
146
    this.userId = userId;
1✔
147
  }
1✔
148

149
  public Date getCreateDate() {
150
    return createDate;
1✔
151
  }
152

153
  public void setCreateDate(Timestamp createDate) {
154
    this.createDate = createDate;
1✔
155
  }
1✔
156

157
  public Date getSortDate() {
158
    return sortDate;
1✔
159
  }
160

161
  public void setSortDate(Timestamp sortDate) {
162
    this.sortDate = sortDate;
1✔
163
  }
1✔
164

165
  public Timestamp getSubmissionDate() {
166
    return submissionDate;
1✔
167
  }
168

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

179
  public Timestamp getUpdateDate() {
180
    return updateDate;
1✔
181
  }
182

183
  public void setUpdateDate(Timestamp updateDate) {
184
    this.updateDate = updateDate;
1✔
185
  }
1✔
186

187
  public Map<Integer, Election> getElections() {
188
    return elections;
1✔
189
  }
190

191
  public void setElections(Map<Integer, Election> elections) {
NEW
192
    this.elections = elections;
×
NEW
193
  }
×
194

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

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

215
  public void setDatasetIds(List<Integer> datasetIds) {
216
    this.datasetIds = datasetIds;
1✔
217
  }
1✔
218

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

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

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

260
    String serializedDar = gson.toJson(shallowCopy(this));
1✔
261
    JsonObject dar = gson.fromJson(serializedDar, JsonObject.class);
1✔
262

263
    String serializedDarData = gson.toJson(dataCopy);
1✔
264
    JsonObject darData = gson.fromJson(serializedDarData, JsonObject.class);
1✔
265

266
    DataAccessRequestData.DEPRECATED_PROPS.forEach(darData::remove);
1✔
267
    for (String dataKey : darData.keySet()) {
1✔
268
      String camelCasedDataKey =
269
          dataKey.contains("_")
1✔
270
              ? CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, dataKey)
×
271
              : dataKey;
1✔
272
      if (!dar.has(camelCasedDataKey)) {
1✔
273
        dar.add(camelCasedDataKey, darData.get(dataKey));
1✔
274
      }
275
    }
1✔
276
    Type darMapType = new TypeToken<Map<String, Object>>() {
1✔
277
    }.getType();
1✔
278
    return gson.fromJson(dar.toString(), darMapType);
1✔
279
  }
280

281
  public boolean requiresManualReview() {
282
    return
1✔
283
        Objects.nonNull(this.getData()) && (
1✔
284
            (Objects.nonNull(this.getData().getPoa()) && this.getData().getPoa()) ||
1✔
285
                (Objects.nonNull(this.getData().getPopulation()) && this.getData().getPopulation())
1✔
286
                ||
287
                (Objects.nonNull(this.getData().getOther()) && this.getData().getOther()) ||
1✔
288
                (Objects.nonNull(this.getData().getOtherText()) && !this.getData().getOtherText()
1✔
289
                    .isBlank()) ||
1✔
290
                (Objects.nonNull(this.getData().getIllegalBehavior()) && this.getData()
1✔
291
                    .getIllegalBehavior()) ||
1✔
292
                (Objects.nonNull(this.getData().getAddiction()) && this.getData().getAddiction()) ||
1✔
293
                (Objects.nonNull(this.getData().getSexualDiseases()) && this.getData()
1✔
294
                    .getSexualDiseases()) ||
1✔
295
                (Objects.nonNull(this.getData().getStigmatizedDiseases()) && this.getData()
1✔
296
                    .getStigmatizedDiseases()) ||
1✔
297
                (Objects.nonNull(this.getData().getVulnerablePopulation()) && this.getData()
1✔
298
                    .getVulnerablePopulation()) ||
1✔
299
                (Objects.nonNull(this.getData().getPopulationMigration()) && this.getData()
1✔
300
                    .getPopulationMigration()) ||
1✔
301
                (Objects.nonNull(this.getData().getPsychiatricTraits()) && this.getData()
1✔
302
                    .getPsychiatricTraits()) ||
1✔
303
                (Objects.nonNull(this.getData().getNotHealth()) && this.getData().getNotHealth())
1✔
304
        );
305
  }
306

307
  /**
308
   * Make a shallow copy of the dar. This is mostly a workaround for problems serializing dates when
309
   * calling Gson.toJson on `this`
310
   *
311
   * @param dar DataAccessRequest
312
   * @return Shallow copy of DataAccessRequest
313
   */
314
  private Map<String, Object> shallowCopy(DataAccessRequest dar) {
315
    Map<String, Object> copy = new HashMap<>();
1✔
316
    if (Objects.nonNull(dar.getCreateDate())) {
1✔
317
      copy.put("createDate", dar.getCreateDate().getTime());
1✔
318
    }
319
    if (Objects.nonNull(dar.getDraft())) {
1✔
320
      copy.put("draft", dar.getDraft());
1✔
321
    }
322
    copy.put("expired", dar.getExpired());
1✔
323
    copy.put("expiredAt", dar.getExpiresAt());
1✔
324
    if (Objects.nonNull(dar.getId())) {
1✔
325
      copy.put("id", dar.getId());
×
326
    }
327
    if (Objects.nonNull(dar.getReferenceId())) {
1✔
328
      copy.put("referenceId", dar.getReferenceId());
1✔
329
    }
330
    if (Objects.nonNull(dar.getSortDate())) {
1✔
331
      copy.put("sortDate", dar.getSortDate().getTime());
1✔
332
    }
333
    if (Objects.nonNull(dar.getSubmissionDate())) {
1✔
334
      copy.put("submissionDate", dar.getSubmissionDate().getTime());
×
335
    }
336
    if (Objects.nonNull(dar.getUpdateDate())) {
1✔
337
      copy.put("updateDate", dar.getUpdateDate().getTime());
1✔
338
    }
339
    if (Objects.nonNull(dar.getUserId())) {
1✔
340
      copy.put("userId", dar.getUserId());
1✔
341
    }
342
    if (Objects.nonNull(dar.getCollectionId())) {
1✔
343
      copy.put("collectionId", dar.getCollectionId());
1✔
344
    }
345
    if (Objects.nonNull(dar.getDatasetIds())) {
1✔
346
      copy.put("datasetIds", dar.getDatasetIds());
1✔
347
    }
348
    if (Objects.nonNull(dar.getParentId())) {
1✔
349
      copy.put("parentId", dar.getParentId());
×
350
    }
351
    return copy;
1✔
352
  }
353
}
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