Skip to content

Commit 76b8e91

Browse files
authored
Merge pull request #7434 from IQSS/7263-dismissable-banner
7263 dismissable banner
2 parents 25cb2eb + 3c4221f commit 76b8e91

18 files changed

Lines changed: 712 additions & 29 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## Major Use Cases
2+
3+
- New API for Banners..
4+
5+
## Notes to Admins
6+
7+
The functionality previously provided by the DB settings :StatusMessageHeader and ::StatusMessageText is no longer supported and is now provided through the Manage Banner Messages API. Learn more in the [Native API Guide](https://guides.dataverse.org/en/5.x/api/).

doc/sphinx-guides/source/api/native-api.rst

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2664,6 +2664,48 @@ Delete Database Setting
26642664
Delete the setting under ``name``::
26652665
26662666
DELETE http://$SERVER/api/admin/settings/$name
2667+
2668+
Manage Banner Messages
2669+
~~~~~~~~~~~~~~~~~~~~~~
2670+
2671+
Communications to users can be handled via banner messages that are displayed at the top of all pages within your Dataverse installation. Two types of banners can be configured:
2672+
2673+
- A banner message where dismissibleByUser is set to false will be displayed to anyone viewing the application. These messages will be dismissible for a given session but will be displayed in any subsequent session until they are deleted by the Admin. This type of banner message is useful for situations such as upcoming maintenance windows and other downtime.
2674+
- A banner message where dismissibleByUser is set to true is intended to be used in situations where the Admin wants to make sure that all logged in users see a certain notification. These banner messages will only be displayed to users when they are logged in and can be dismissed by the logged in user. Once they have been dismissed by a user, that user will not see the message again. This type of banner message is useful for situations where a message needs to communicated once, such as a minor terms of use update or an update about a new workflow in your Dataverse installation.
2675+
2676+
Note that HTML can be included in banner messages.
2677+
2678+
Add a Banner Message::
2679+
2680+
curl -H "Content-type:application/json" -X POST http://$SERVER/api/admin/bannerMessage --upload-file messages.json
2681+
2682+
Where ``messages.json`` looks like this::
2683+
2684+
{
2685+
"dismissibleByUser": "true",
2686+
"messageTexts": [
2687+
{
2688+
"lang": "en",
2689+
"message": "Dismissible Banner Message added via API"
2690+
},
2691+
{
2692+
"lang": "fr",
2693+
"message": "Message de bannière ajouté via l'API"
2694+
}
2695+
]
2696+
}
2697+
2698+
Get a list of active Banner Messages::
2699+
2700+
curl -X GET http://$SERVER/api/admin/bannerMessage
2701+
2702+
Delete a Banner Message by its id::
2703+
2704+
curl -X DELETE http://$SERVER/api/admin/bannerMessage/$id
2705+
2706+
Deactivate a Banner Message by its id (allows you to hide a message while retaining information about which users have dismissed the banner)::
2707+
2708+
curl -X PUT http://$SERVER/api/admin/bannerMessage/$id/deactivate
26672709
26682710
List Authentication Provider Factories
26692711
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

doc/sphinx-guides/source/installation/config.rst

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,22 +1594,6 @@ Make the metrics component on the root dataverse a clickable link to a website w
15941594

15951595
``curl -X PUT -d http://metrics.dataverse.example.edu http://localhost:8080/api/admin/settings/:MetricsUrl``
15961596

1597-
:StatusMessageHeader
1598-
++++++++++++++++++++
1599-
1600-
For dynamically adding an informational header to the top of every page. StatusMessageText must also be set for a message to show. For example, "For testing only..." at the top of https://demo.dataverse.org is set with this:
1601-
1602-
``curl -X PUT -d "For testing only..." http://localhost:8080/api/admin/settings/:StatusMessageHeader``
1603-
1604-
You can make the text clickable and include an additional message in a pop up by setting ``:StatusMessageText``.
1605-
1606-
:StatusMessageText
1607-
++++++++++++++++++
1608-
1609-
Alongside the ``:StatusMessageHeader`` you need to add StatusMessageText for the message to show.:
1610-
1611-
``curl -X PUT -d "This appears in a popup." http://localhost:8080/api/admin/settings/:StatusMessageText``
1612-
16131597
.. _:MaxFileUploadSizeInBytes:
16141598

16151599
:MaxFileUploadSizeInBytes
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"dismissible": "false",
3+
"messageTexts": [
4+
{
5+
"lang": "en",
6+
"text": "Invalid json"
7+
}
8+
]
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"dismissibleByUser": "false",
3+
"messageTexts": [
4+
{
5+
"lang": "en",
6+
"message": "Banner Message added via API"
7+
},
8+
{
9+
"lang": "fr",
10+
"message": "Message de bannière ajouté via l'API"
11+
}
12+
]
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"dismissibleByUser": "false",
3+
"messageTexts": [
4+
{
5+
"lang": "en",
6+
"message": "Banner Message For Deletion"
7+
},
8+
{
9+
"lang": "fr",
10+
"message": "Banner Message For Deletion"
11+
}
12+
]
13+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
2+
package edu.harvard.iq.dataverse;
3+
4+
import edu.harvard.iq.dataverse.util.BundleUtil;
5+
import java.io.Serializable;
6+
import java.util.Collection;
7+
import javax.persistence.CascadeType;
8+
import javax.persistence.Column;
9+
import javax.persistence.Entity;
10+
import javax.persistence.GeneratedValue;
11+
import javax.persistence.GenerationType;
12+
import javax.persistence.Id;
13+
import javax.persistence.OneToMany;
14+
15+
16+
/**
17+
*
18+
* @author skraffmi
19+
*/
20+
@Entity
21+
public class BannerMessage implements Serializable {
22+
23+
@Id
24+
@GeneratedValue(strategy = GenerationType.IDENTITY)
25+
private Long id;
26+
27+
@Column
28+
private boolean dismissibleByUser;
29+
30+
@Column
31+
private boolean active;
32+
33+
@OneToMany(mappedBy = "bannerMessage", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
34+
private Collection<BannerMessageText> bannerMessageTexts;
35+
36+
@OneToMany(mappedBy = "bannerMessage", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
37+
private Collection<UserBannerMessage> userBannerMessages;
38+
39+
public Collection<BannerMessageText> getBannerMessageTexts() {
40+
return this.bannerMessageTexts;
41+
}
42+
43+
public void setBannerMessageTexts(Collection<BannerMessageText> bannerMessageTexts) {
44+
this.bannerMessageTexts = bannerMessageTexts;
45+
}
46+
47+
48+
public String getDisplayValue(){
49+
String retVal = "";
50+
for (BannerMessageText msgTxt : this.getBannerMessageTexts()) {
51+
if (msgTxt.getLang().equals(BundleUtil.getCurrentLocale().getLanguage())) {
52+
retVal = msgTxt.getMessage();
53+
}
54+
}
55+
return retVal;
56+
}
57+
58+
public boolean isDismissibleByUser() {
59+
return dismissibleByUser;
60+
}
61+
62+
public void setDismissibleByUser(boolean dismissibleByUser) {
63+
this.dismissibleByUser = dismissibleByUser;
64+
}
65+
66+
public Long getId() {
67+
return id;
68+
}
69+
70+
public void setId(Long id) {
71+
this.id = id;
72+
}
73+
74+
public boolean isActive() {
75+
return active;
76+
}
77+
78+
public void setActive(boolean active) {
79+
this.active = active;
80+
}
81+
82+
@Override
83+
public int hashCode() {
84+
int hash = 0;
85+
hash += (id != null ? id.hashCode() : 0);
86+
return hash;
87+
}
88+
89+
@Override
90+
public boolean equals(Object object) {
91+
// TODO: Warning - this method won't work in the case the id fields are not set
92+
if (!(object instanceof BannerMessage)) {
93+
return false;
94+
}
95+
BannerMessage other = (BannerMessage) object;
96+
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
97+
return false;
98+
}
99+
return true;
100+
}
101+
102+
@Override
103+
public String toString() {
104+
return "edu.harvard.iq.dataverse.BannerMessage[ id=" + id + " ]";
105+
}
106+
107+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* To change this license header, choose License Headers in Project Properties.
3+
* To change this template file, choose Tools | Templates
4+
* and open the template in the editor.
5+
*/
6+
package edu.harvard.iq.dataverse;
7+
8+
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
9+
import java.sql.Timestamp;
10+
import java.util.Date;
11+
import java.util.List;
12+
import java.util.logging.Logger;
13+
import javax.ejb.Stateless;
14+
import javax.inject.Named;
15+
import javax.persistence.EntityManager;
16+
import javax.persistence.PersistenceContext;
17+
18+
/**
19+
*
20+
* @author skraffmi
21+
*/
22+
@Stateless
23+
@Named
24+
public class BannerMessageServiceBean implements java.io.Serializable {
25+
private static final Logger logger = Logger.getLogger(BannerMessageServiceBean.class.getCanonicalName());
26+
27+
@PersistenceContext(unitName = "VDCNet-ejbPU")
28+
private EntityManager em;
29+
30+
public List<BannerMessage> findBannerMessages() {
31+
return em.createQuery("select object(o) from BannerMessage as o where o.active = 'true' and o.dismissibleByUser = 'false'", BannerMessage.class)
32+
.getResultList();
33+
}
34+
35+
public List<BannerMessage> findBannerMessages(Long auId) {
36+
return em.createQuery("select object(o) from BannerMessage as o where (o.active = 'true' and o.dismissibleByUser = 'false') "
37+
+ " or (o.active = 'true' and o.dismissibleByUser = 'true' and o.id not in (select ubm.bannerMessage.id from UserBannerMessage as ubm where ubm.user.id =:authenticatedUserId))", BannerMessage.class)
38+
.setParameter("authenticatedUserId", auId)
39+
.getResultList();
40+
}
41+
42+
public List<BannerMessage> findAllBannerMessages() {
43+
return em.createQuery("select o from BannerMessage o where o.active = 'true' ")
44+
.getResultList();
45+
}
46+
47+
public void save( BannerMessage message ) {
48+
em.persist(message);
49+
}
50+
51+
public void deleteBannerMessage(Object pk) {
52+
BannerMessage message = em.find(BannerMessage.class, pk);
53+
54+
if (message != null) {
55+
em.remove(message);
56+
}
57+
}
58+
59+
public void deactivateBannerMessage(Object pk) {
60+
BannerMessage message = em.find(BannerMessage.class, pk);
61+
62+
if (message != null) {
63+
message.setActive(false);
64+
em.merge(message);
65+
}
66+
}
67+
68+
public void dismissMessageByUser(BannerMessage message, AuthenticatedUser user) {
69+
70+
UserBannerMessage ubm = new UserBannerMessage();
71+
ubm.setUser(user);
72+
ubm.setBannerMessage(message);
73+
ubm.setBannerDismissalTime(new Timestamp(new Date().getTime()));
74+
em.persist(ubm);
75+
em.flush();
76+
77+
}
78+
79+
}

0 commit comments

Comments
 (0)