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

CeON / dataverse / 1370

26 Jun 2024 06:59AM UTC coverage: 25.503% (-0.004%) from 25.507%
1370

push

jenkins

web-flow
Closes #2496: Make the banner link optional (#2503)

17782 of 69725 relevant lines covered (25.5%)

0.26 hits per line

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

0.49
/dataverse-webapp/src/main/java/edu/harvard/iq/dataverse/DataverseDao.java
1
package edu.harvard.iq.dataverse;
2

3
import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean;
4
import edu.harvard.iq.dataverse.authorization.groups.GroupServiceBean;
5
import edu.harvard.iq.dataverse.dataaccess.ImageThumbConverter;
6
import edu.harvard.iq.dataverse.dataverse.DataverseLinkingService;
7
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
8
import edu.harvard.iq.dataverse.persistence.dataset.Dataset;
9
import edu.harvard.iq.dataverse.persistence.dataset.DatasetRepository;
10
import edu.harvard.iq.dataverse.persistence.dataset.MetadataBlock;
11
import edu.harvard.iq.dataverse.persistence.dataverse.Dataverse;
12
import edu.harvard.iq.dataverse.persistence.group.Group;
13
import edu.harvard.iq.dataverse.persistence.user.AuthenticatedUser;
14
import edu.harvard.iq.dataverse.persistence.user.DataverseRole;
15
import edu.harvard.iq.dataverse.persistence.user.Permission;
16
import edu.harvard.iq.dataverse.persistence.user.RoleAssignment;
17
import edu.harvard.iq.dataverse.search.index.IndexServiceBean;
18

19
import javax.ejb.EJB;
20
import javax.ejb.Stateless;
21
import javax.inject.Inject;
22
import javax.inject.Named;
23
import javax.json.Json;
24
import javax.json.JsonArrayBuilder;
25
import javax.persistence.EntityManager;
26
import javax.persistence.NoResultException;
27
import javax.persistence.NonUniqueResultException;
28
import javax.persistence.PersistenceContext;
29
import javax.persistence.TypedQuery;
30
import java.io.File;
31
import java.sql.Timestamp;
32
import java.util.ArrayList;
33
import java.util.Date;
34
import java.util.HashMap;
35
import java.util.List;
36
import java.util.Map;
37
import java.util.Properties;
38
import java.util.concurrent.Future;
39
import java.util.logging.Logger;
40

41
/**
42
 * @author gdurand
43
 */
44
@Stateless
45
@Named
46
public class DataverseDao implements java.io.Serializable {
×
47

48
    private static final Logger logger = Logger.getLogger(DataverseDao.class.getCanonicalName());
1✔
49
    @EJB
50
    private IndexServiceBean indexService;
51

52
    @EJB
53
    private AuthenticationServiceBean authService;
54

55
    @EJB
56
    private DatasetRepository datasetRepository;
57

58
    @EJB
59
    private DataverseLinkingService dataverseLinkingService;
60

61
    @EJB
62
    private DatasetLinkingServiceBean datasetLinkingService;
63

64
    @EJB
65
    private GroupServiceBean groupService;
66

67
    @EJB
68
    private DataverseRoleServiceBean rolesService;
69

70
    @EJB
71
    private PermissionServiceBean permissionService;
72

73
    @PersistenceContext(unitName = "VDCNet-ejbPU")
74
    private EntityManager em;
75

76
    @Inject
77
    private ImageThumbConverter imageThumbConverter;
78

79
    public Dataverse save(Dataverse dataverse) {
80

81
        dataverse.setModificationTime(new Timestamp(new Date().getTime()));
×
82
        Dataverse savedDataverse = em.merge(dataverse);
×
83
        /**
84
         * @todo check the result to see if indexing was successful or not
85
         */
86
        Future<String> indexingResult = indexService.indexDataverse(savedDataverse);
×
87
//        logger.log(Level.INFO, "during dataverse save, indexing result was: {0}", indexingResult);
88
        return savedDataverse;
×
89
    }
90

91
    public Dataverse find(Object pk) {
92
        return em.find(Dataverse.class, pk);
×
93
    }
94

95
    public List<Dataverse> findAll() {
96
        return em.createNamedQuery("Dataverse.findAll").getResultList();
×
97
    }
98

99
    /**
100
     * @param numPartitions The number of partitions you intend to split the
101
     *                      indexing job into. Perhaps you have three Glassfish servers and you'd
102
     *                      like each one to operate on a subset of dataverses.
103
     * @param partitionId   Maybe "partitionId" is the wrong term but it's what we
104
     *                      call in the (text) UI. If you've specified three partitions the three
105
     *                      partitionIds are 0, 1, and 2. We do `dataverseId % numPartitions =
106
     *                      partitionId` to figure out which partition the dataverseId falls into.
107
     * @param skipIndexed   If true, will skip any dvObjects that have a indexTime set
108
     * @return All dataverses if you say numPartitions=1 and partitionId=0.
109
     * Otherwise, a subset of dataverses.
110
     */
111
    public List<Dataverse> findAllOrSubset(long numPartitions, long partitionId, boolean skipIndexed) {
112
        if (numPartitions < 1) {
×
113
            long saneNumPartitions = 1;
×
114
            numPartitions = saneNumPartitions;
×
115
        }
116
        String skipClause = skipIndexed ? "AND o.indexTime is null " : "";
×
117
        TypedQuery<Dataverse> typedQuery = em.createQuery("SELECT OBJECT(o) FROM Dataverse AS o WHERE MOD( o.id, :numPartitions) = :partitionId " +
×
118
                                                                  skipClause +
119
                                                                  "ORDER BY o.id", Dataverse.class);
120
        typedQuery.setParameter("numPartitions", numPartitions);
×
121
        typedQuery.setParameter("partitionId", partitionId);
×
122
        return typedQuery.getResultList();
×
123
    }
124

125
    public List<Long> findDataverseIdsForIndexing(boolean skipIndexed) {
126
        if (skipIndexed) {
×
127
            return em.createQuery("SELECT o.id FROM Dataverse o WHERE o.indexTime IS null ORDER BY o.id", Long.class).getResultList();
×
128
        }
129
        return em.createQuery("SELECT o.id FROM Dataverse o ORDER BY o.id", Long.class).getResultList();
×
130

131
    }
132

133
    public List<Dataverse> findByOwnerId(Long ownerId) {
134
        return em.createNamedQuery("Dataverse.findByOwnerId").setParameter("ownerId", ownerId).getResultList();
×
135
    }
136

137
    public List<Long> findIdsByOwnerId(Long ownerId) {
138
        String qr = "select o.id from Dataverse as o where o.owner.id =:ownerId order by o.id";
×
139
        return em.createQuery(qr, Long.class).setParameter("ownerId", ownerId).getResultList();
×
140
    }
141

142
    /**
143
     * @return the root dataverse
144
     * @todo Do we really want this method to sometimes throw a
145
     * NoResultException which is a RuntimeException?
146
     */
147
    public Dataverse findRootDataverse() {
148
        return em.createNamedQuery("Dataverse.findRoot", Dataverse.class).getSingleResult();
×
149
    }
150

151
    /**
152
     * A lookup of a dataverse alias should be case insensitive. If "cfa"
153
     * belongs to the Center for Astrophysics, we don't want to allow Code for
154
     * America to start using "CFA". Force all queries to be lower case.
155
     */
156
    public Dataverse findByAlias(String anAlias) {
157
        try {
158
            return (anAlias.equalsIgnoreCase(":root"))
×
159
                    ? findRootDataverse()
×
160
                    : em.createNamedQuery("Dataverse.findByAlias", Dataverse.class)
×
161
                    .setParameter("alias", anAlias.toLowerCase())
×
162
                    .getSingleResult();
×
163
        } catch (NoResultException | NonUniqueResultException ex) {
×
164
            logger.fine("Unable to find a single dataverse using alias \"" + anAlias + "\": " + ex);
×
165
            return null;
×
166
        }
167
    }
168

169
    public boolean hasData(Dataverse dv) {
170
        TypedQuery<Long> amountQry = em.createNamedQuery("Dataverse.ownedObjectsById", Long.class)
×
171
                .setParameter("id", dv.getId());
×
172

173
        return (amountQry.getSingleResult() > 0);
×
174
    }
175

176
    public boolean isRootDataverseExists() {
177
        long count = em.createQuery("SELECT count(dv) FROM Dataverse dv WHERE dv.owner.id=null", Long.class).getSingleResult();
×
178
        return (count == 1);
×
179
    }
180

181
    public String determineDataversePath(Dataverse dataverse) {
182
        List<String> dataversePathSegments = indexService.findPathSegments(dataverse);
×
183
        StringBuilder dataversePath = new StringBuilder();
×
184
        for (String segment : dataversePathSegments) {
×
185
            dataversePath.append("/").append(segment);
×
186
        }
×
187
        return dataversePath.toString();
×
188
    }
189

190
    public MetadataBlock findMDB(Long id) {
191
        return em.find(MetadataBlock.class, id);
×
192
    }
193

194
    public MetadataBlock findMDBByName(String name) {
195
        return em.createQuery("select m from MetadataBlock m WHERE m.name=:name", MetadataBlock.class)
×
196
                .setParameter("name", name)
×
197
                .getSingleResult();
×
198
    }
199

200
    public List<MetadataBlock> findAllMetadataBlocks() {
201
        return em.createQuery("select object(o) from MetadataBlock as o order by o.id", MetadataBlock.class).getResultList();
×
202
    }
203

204
    public List<MetadataBlock> findSystemMetadataBlocks() {
205
        String qr = "select object(o) from MetadataBlock as o where o.owner.id=null  order by o.id";
×
206
        return em.createQuery(qr, MetadataBlock.class).getResultList();
×
207
    }
208

209
    public List<MetadataBlock> findMetadataBlocksByDataverseId(Long dataverse_id) {
210
        String qr = "select object(o) from MetadataBlock as o where o.owner.id=:dataverse_id order by o.id";
×
211
        return em.createQuery(qr, MetadataBlock.class)
×
212
                .setParameter("dataverse_id", dataverse_id).getResultList();
×
213
    }
214

215
    public String getDataverseLogoThumbnailFilePath(Long dvId) {
216

217
        File dataverseLogoFile = getLogoById(dvId);
×
218

219
        if (dataverseLogoFile != null) {
×
220
            String logoThumbNailPath = dataverseLogoFile + ".thumb" + 48;
×
221

222
            if (new File(logoThumbNailPath).exists()) {
×
223
                return logoThumbNailPath;
×
224
            } else {
225
                imageThumbConverter.generateImageThumbnailFromFile(dataverseLogoFile.getAbsolutePath(), 48, logoThumbNailPath);
×
226

227
                if (new File(logoThumbNailPath).exists()) {
×
228
                    return logoThumbNailPath;
×
229
                }
230
            }
231
        }
232
        return null;
×
233
    }
234

235
    private File getLogoById(Long id) {
236
        if (id == null) {
×
237
            return null;
×
238
        }
239

240
        String logoFileName;
241

242
        try {
243
            logoFileName = (String) em.createNativeQuery("SELECT logo FROM dataversetheme WHERE dataverse_id = " + id).getSingleResult();
×
244

245
        } catch (Exception ex) {
×
246
            return null;
×
247
        }
×
248

249
        if (logoFileName != null && !logoFileName.isEmpty()) {
×
250
            Properties p = System.getProperties();
×
251
            String domainRoot = p.getProperty("com.sun.aas.instanceRoot");
×
252

253
            if (domainRoot != null && !"".equals(domainRoot)) {
×
254
                return new File(domainRoot + File.separator +
×
255
                                        "docroot" + File.separator +
256
                                        "logos" + File.separator +
257
                                        id + File.separator +
258
                                        logoFileName);
259
            }
260
        }
261

262
        return null;
×
263
    }
264

265
    public List<Dataverse> findDataversesThisIdHasLinkedTo(long dataverseId) {
266
        return dataverseLinkingService.findLinkedDataverses(dataverseId);
×
267
    }
268

269
    public List<Dataverse> findDataversesThatLinkToThisDvId(long dataverseId) {
270
        return dataverseLinkingService.findLinkingDataverses(dataverseId);
×
271
    }
272

273
    public List<Dataset> findDatasetsThisIdHasLinkedTo(long dataverseId) {
274
        return datasetLinkingService.findDatasetsThisDataverseIdHasLinkedTo(dataverseId);
×
275
    }
276

277
    public List<Dataverse> findDataversesThatLinkToThisDatasetId(long datasetId) {
278
        return datasetLinkingService.findLinkingDataverses(datasetId);
×
279
    }
280

281
    public List<Dataverse> filterByAliasQuery(String filterQuery) {
282
        //Query query = em.createNativeQuery("select o from Dataverse o where o.alias LIKE '" + filterQuery + "%' order by o.alias");
283
        //Query query = em.createNamedQuery("Dataverse.filterByAlias", Dataverse.class).setParameter("alias", filterQuery.toLowerCase() + "%");
284
        List<Dataverse> ret = em.createNamedQuery("Dataverse.filterByAliasNameAffiliation", Dataverse.class)
×
285
                .setParameter("alias", filterQuery.toLowerCase() + "%")
×
286
                .setParameter("name", "%" + filterQuery.toLowerCase() + "%")
×
287
                .setParameter("affiliation", "%" + filterQuery.toLowerCase() + "%").getResultList();
×
288
        //logger.info("created native query: select o from Dataverse o where o.alias LIKE '" + filterQuery + "%' order by o.alias");
289
        logger.info("created named query");
×
290
        if (ret != null) {
×
291
            logger.info("results list: " + ret.size() + " results.");
×
292
        }
293
        return ret;
×
294
    }
295

296
    public List<Dataverse> filterDataversesForLinking(String query, DataverseRequest req, Dataset dataset) {
297

298
        List<Dataverse> dataverseList = new ArrayList<>();
×
299

300
        List<Dataverse> results = em.createNamedQuery("Dataverse.filterByAliasName", Dataverse.class)
×
301
                .setParameter("alias", query.toLowerCase() + "%")
×
302
                .setParameter("name", "%" + query.toLowerCase() + "%")
×
303
                .getResultList();
×
304

305
        List<Object> alreadyLinkeddv_ids = em.createNativeQuery(
×
306
                "SELECT linkingdataverse_id   FROM datasetlinkingdataverse WHERE dataset_id = " + dataset.getId())
×
307
                .getResultList();
×
308
        List<Dataverse> toRemove = new ArrayList<>();
×
309

310
        if (alreadyLinkeddv_ids != null && !alreadyLinkeddv_ids.isEmpty()) {
×
311
            alreadyLinkeddv_ids.stream().map(this::find).forEachOrdered(toRemove::add);
×
312
        }
313

314
        for (Dataverse res : results) {
×
315
            if (!toRemove.contains(res)) {
×
316
                if (permissionService.requestOn(req, res).has(Permission.PublishDataset)) {
×
317
                    dataverseList.add(res);
×
318
                }
319
            }
320
        }
×
321

322
        return dataverseList;
×
323
    }
324

325
    public Long countDataverses() {
326
        TypedQuery<Long> countQuery = em.createQuery("SELECT count(dv) FROM Dataverse dv", Long.class);
×
327
        return countQuery.getSingleResult();
×
328
    }
329

330
    public Long countDataversesWithParent(Long parentId) {
331
        return (Long) em.createNativeQuery("SELECT count(1) FROM dvobject WHERE dtype='Dataverse' AND owner_id = ?1")
×
332
                .setParameter(1, parentId)
×
333
                .getSingleResult();
×
334
    }
335

336
    public List<Object[]> getParentAliasesForIds(List<Long> ids) {
337
        return em.createQuery("SELECT o.id, dv.alias FROM Dataverse dv, DvObject o " +
×
338
                "WHERE dv.id = o.owner.id AND o.id IN :ids", Object[].class)
339
                .setParameter("ids", ids)
×
340
                .getResultList();
×
341
    }
342

343
    /**
344
     * Method to recursively find ids of all children of a dataverse that
345
     * are also of type dataverse
346
     */
347
    public List<Long> findAllDataverseDataverseChildren(Long dvId) {
348
        // get list of Dataverse children
349
        List<Long> dataverseChildren = findIdsByOwnerId(dvId);
×
350

351
        if (dataverseChildren == null) {
×
352
            return dataverseChildren;
×
353
        } else {
354
            List<Long> newChildren = new ArrayList<>();
×
355
            for (Long childDvId : dataverseChildren) {
×
356
                newChildren.addAll(findAllDataverseDataverseChildren(childDvId));
×
357
            }
×
358
            dataverseChildren.addAll(newChildren);
×
359
            return dataverseChildren;
×
360
        }
361
    }
362

363
    // function to recursively find ids of all children of a dataverse that are
364
    // of type dataset
365
    public List<Long> findAllDataverseDatasetChildren(Long dvId) {
366
        // get list of Dataverse children
367
        List<Long> dataverseChildren = findIdsByOwnerId(dvId);
×
368
        // get list of Dataset children
369
        List<Long> datasetChildren = datasetRepository.findIdsByOwnerId(dvId);
×
370

371
        for (Long childDvId : dataverseChildren) {
×
372
            datasetChildren.addAll(findAllDataverseDatasetChildren(childDvId));
×
373
        }
×
374
        return datasetChildren;
×
375
    }
376

377
    public String addRoleAssignmentsToChildren(Dataverse owner, List<String> rolesToInherit,
378
                                               boolean inheritAllRoles) {
379
        /*
380
         * This query recursively finds all Dataverses that are inside/children of the
381
         * specified one. It recursively finds dvobjects of dtype 'Dataverse' whose
382
         * owner_id equals an id already in the list and then returns the list of ids
383
         * found, excluding the id of the original specified Dataverse.
384
         */
385
        String qstr = "WITH RECURSIVE path_elements AS ((" + " SELECT id, dtype FROM dvobject WHERE id in ("
×
386
                + owner.getId() + "))" + " UNION\n"
×
387
                + " SELECT o.id, o.dtype FROM path_elements p, dvobject o WHERE o.owner_id = p.id and o.dtype='Dataverse') "
388
                + "SELECT id FROM path_elements WHERE id !=" + owner.getId() + ";";
×
389

390
        List<Integer> childIds;
391
        try {
392
            childIds = em.createNativeQuery(qstr).getResultList();
×
393
        } catch (Exception ex) {
×
394
            childIds = null;
×
395
        }
×
396

397
        // Set up to track the set of users/groups that get assigned a role and those
398
        // that don't
399
        JsonArrayBuilder usedNames = Json.createArrayBuilder();
×
400
        JsonArrayBuilder unusedNames = Json.createArrayBuilder();
×
401
        // Set up to track the list of dataverses, by id and alias, that are traversed.
402
        JsonArrayBuilder dataverseIds = Json.createArrayBuilder();
×
403
        JsonArrayBuilder dataverseAliases = Json.createArrayBuilder();
×
404
        // Get the Dataverses for the returned ids
405

406
        List<Dataverse> children = new ArrayList<>();
×
407

408
        for (Integer childId : childIds) {
×
409
            Dataverse child = find(childId.longValue());
×
410
            if (child != null) {
×
411
                // Add to the list of Dataverses
412
                children.add(child);
×
413
                // Add ids and aliases to the tracking arrays
414
                dataverseIds.add(childId.longValue());
×
415
                dataverseAliases.add(child.getAlias());
×
416
            }
417
        }
×
418
        // Find the role assignments on the specified Dataverse
419
        List<RoleAssignment> allRAsOnOwner = rolesService.directRoleAssignments(owner);
×
420

421
        // Create a list of just the inheritable role assignments on the original
422
        // dataverse
423
        List<RoleAssignment> inheritableRAsOnOwner = new ArrayList<>();
×
424
        for (RoleAssignment role : allRAsOnOwner) {
×
425
            if (inheritAllRoles || rolesToInherit.contains(role.getRole().getAlias())) {
×
426
                //Only supporting built-in/non-dataverse-specific custom roles. Custom roles all have an owner.
427
                if (role.getRole().getOwner() == null) {
×
428
                    inheritableRAsOnOwner.add(role);
×
429
                }
430
            }
431
        }
×
432

433
        String privateUrlToken = null;
×
434
        // Create lists of the existing inheritable roles for each child Dataverse
435
        Map<Long, List<RoleAssignment>> existingRAs = new HashMap<>();
×
436
        for (Dataverse childDv : children) {
×
437
            List<RoleAssignment> allRAsOnChild = rolesService.directRoleAssignments(childDv);
×
438
            List<RoleAssignment> inheritableRoles = new ArrayList<>();
×
439
            for (RoleAssignment role : allRAsOnChild) {
×
440
                if (inheritAllRoles || rolesToInherit.contains(role.getRole().getAlias())) {
×
441
                    inheritableRoles.add(role);
×
442
                }
443
            }
×
444
            existingRAs.put(childDv.getId(), inheritableRoles);
×
445
        }
×
446

447
        for (RoleAssignment roleAssignment : inheritableRAsOnOwner) {
×
448
            DataverseRole inheritableRole = roleAssignment.getRole();
×
449
            String identifier = roleAssignment.getAssigneeIdentifier();
×
450
            if (identifier.startsWith(AuthenticatedUser.IDENTIFIER_PREFIX)) {
×
451
                // The RoleAssignment is for an individual user
452
                // Add their name to the tracking list
453
                usedNames.add(identifier);
×
454
                // Strip the Identifier prefix so we can retrieve the user
455
                identifier = identifier.substring(AuthenticatedUser.IDENTIFIER_PREFIX.length());
×
456
                AuthenticatedUser roleUser = authService.getAuthenticatedUser(identifier);
×
457
                // Now loop over all children and add the roleUser in this role if they don't
458
                // yet have this role
459
                for (Dataverse childDv : children) {
×
460
                    try {
461
                        RoleAssignment ra = new RoleAssignment(inheritableRole, roleUser, childDv, privateUrlToken);
×
462
                        if (!existingRAs.get(childDv.getId()).contains(ra)) {
×
463
                            rolesService.save(ra);
×
464
                        }
465
                    } catch (Exception e) {
×
466
                        logger.warning("Unable to assign " + roleAssignment.getAssigneeIdentifier()
×
467
                                               + "as an admin for new Dataverse: " + childDv.getName());
×
468
                        logger.warning(e.getMessage());
×
469
                        throw (e);
×
470
                    }
×
471
                }
×
472
            } else if (identifier.startsWith(Group.IDENTIFIER_PREFIX)) {
×
473
                // The role assignment is for a group
474
                usedNames.add(identifier);
×
475
                identifier = identifier.substring(Group.IDENTIFIER_PREFIX.length());
×
476
                Group roleGroup = groupService.getGroup(identifier);
×
477
                if (roleGroup != null) {
×
478
                    for (Dataverse childDv : children) {
×
479
                        try {
480
                            RoleAssignment ra = new RoleAssignment(inheritableRole, roleGroup, childDv,
×
481
                                                                   privateUrlToken);
482
                            if (!existingRAs.get(childDv.getId()).contains(ra)) {
×
483
                                rolesService.save(ra);
×
484
                            }
485
                        } catch (Exception e) {
×
486
                            logger.warning("Unable to assign " + roleAssignment.getAssigneeIdentifier()
×
487
                                                   + "as an admin for new Dataverse: " + childDv.getName());
×
488
                            logger.warning(e.getMessage());
×
489
                            throw (e);
×
490
                        }
×
491
                    }
×
492
                } else {
493
                    // Add any groups of types not yet supported
494
                    unusedNames.add(identifier);
×
495
                }
496
            } else {
×
497
                // Add any other types of entity found (not user or group) that aren't supported
498
                unusedNames.add(identifier);
×
499
            }
500
        }
×
501
        /*
502
         * Report the list of Dataverses affected and the set of users/groups that
503
         * should now have admin roles on them (they may already have had them) and any
504
         * entities that had an admin role on the specified dataverse which were not
505
         * handled. Add this to the log and the API return message.
506
         */
507
        String result = Json.createObjectBuilder().add("Dataverses Updated", dataverseIds)
×
508
                .add("Updated Dataverse Aliases", dataverseAliases).add("Assignments added for", usedNames)
×
509
                .add("Assignments not added for", unusedNames).build().toString();
×
510
        logger.info(result);
×
511
        return (result);
×
512
    }
513
}
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