Skip to content

Commit

Permalink
SAK-29422 Initial release of NYU's "Public Announcement System"
Browse files Browse the repository at this point in the history
Adds the following capabilities to Sakai:

  * The ability to display a banner message to users. These can be
    limited to particular servers and given different severity
    levels. Use cases include allowing administrators to alert users
    to upcoming system downtime, weather warnings and informational
    messages.

  * Popup messages on login. These can be used to show larger amounts
    of information in a modal dialog, and users can dismiss each
    message either temporarily (in which case it will be shown 24
    hours later), or permanently.

  * Timezone checks, which alert the user if the timezone set in their
    Sakai preferences doesn't match the timezone of their local
    machine. This warning is displayed as a banner alert and links the
    user to the page where they can set their timezone.

This commit includes the management tool, entity providers for
creating and deleting banners and popups programmatically and a new
service implementation that underpins it all.
  • Loading branch information
marktriggs committed Jun 23, 2015
1 parent 3a7207e commit dd25a53
Show file tree
Hide file tree
Showing 69 changed files with 5,968 additions and 0 deletions.
6 changes: 6 additions & 0 deletions master/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1420,6 +1420,12 @@
<version>${sakai.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sakaiproject.pasystem</groupId>
<artifactId>pasystem-api</artifactId>
<version>${sakai.version}</version>
<scope>provided</scope>
</dependency>
<!-- UI dependencies; our glue packages, not the raw libraries, -->
<!-- and only where we have duplication in dependencyManagement sections. -->
<dependency>
Expand Down
44 changes: 44 additions & 0 deletions pasystem/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
## What it does

The Public Announcement system provides:

* The ability to display a banner message to users. These can be
limited to particular servers and given different severity
levels. Use cases include allowing administrators to alert users
to upcoming system downtime, weather warnings and informational
messages.

* Popup messages on login. These can be used to show larger amounts
of information in a modal dialog, and users can dismiss each
message either temporarily (in which case it will be shown 24
hours later), or permanently.

* Timezone checks, which alert the user if the timezone set in their
Sakai preferences doesn't match the timezone of their local
machine. This warning is displayed as a banner alert and links the
user to the page where they can set their timezone.


## Configuration

You can control the Public Announcement system with the following
properties:

* pasystem.enabled (default: false) -- Whether or not to show popups
and banners to users.

* pasystem.auto.ddl (default: false) -- Whether to automatically
create/upgrade the PA System's database tables on startup. This
is required for the first time you start the PA System, but
there's no harm in leaving it enabled.

* pasystem.banner.temporary-timeout-ms (default: 86400000) -- The
number of milliseconds to hide a medium priority banner once it
has been dismissed.

* pasystem.popup.temporary-timeout-ms (default: 86400000) -- The
"later" in "Remind me later" when a popup is dismissed.

* pasystem.timezone-check (default: false) -- Whether to warn users
via banner if their computer's timezone doesn't match their Sakai
profile timezone.
31 changes: 31 additions & 0 deletions pasystem/pasystem-api/api/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<name>pasystem-api</name>
<groupId>org.sakaiproject.pasystem</groupId>
<artifactId>pasystem-api</artifactId>

<packaging>jar</packaging>

<parent>
<artifactId>pasystem-base</artifactId>
<groupId>org.sakaiproject.pasystem</groupId>
<version>11-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>

<properties>
<deploy.target>shared</deploy.target>
</properties>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**********************************************************************************
*
* Copyright (c) 2015 The Sakai Foundation
*
* Original developers:
*
* New York University
* Payten Giles
* Mark Triggs
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.osedu.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/

package org.sakaiproject.pasystem.api;

/**
* Methods implemented by things that can be marked as acknowledged (popups and banners).
*/
public interface Acknowledger {

public final String TEMPORARY = "temporary";
public final String PERMANENT = "permanent";

/**
* Mark an item as acknowledged with a type-appropriate acknowledgement type.
*/
public void acknowledge(final String uuid, final String userEid);

/**
* Mark an item as acknowledged with a specific acknowledgement type.
*/
public void acknowledge(final String uuid, final String userEid, final String acknowledgementType);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/**********************************************************************************
*
* Copyright (c) 2015 The Sakai Foundation
*
* Original developers:
*
* New York University
* Payten Giles
* Mark Triggs
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.osedu.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/

package org.sakaiproject.pasystem.api;

import java.util.Arrays;
import java.util.Date;
import lombok.Getter;

import static org.sakaiproject.pasystem.api.ValidationHelper.*;

/**
* A data object representing a banner.
*/
public class Banner implements Comparable<Banner> {
@Getter
private final String uuid;
@Getter
private final String message;
@Getter
private final long startTime;
@Getter
private final long endTime;
@Getter
private final String hosts;
private final BannerType type;
@Getter
private final boolean isActive;

@Getter
private final boolean isDismissed;

enum BannerType {
HIGH,
MEDIUM,
LOW
}

public Banner(String message, String hosts, boolean active, long startTime, long endTime, String type) {
this(null, message, hosts, active, startTime, endTime, type, false);
}

public Banner(String uuid, String message, String hosts, boolean active, long startTime, long endTime, String type) {
this(uuid, message, hosts, active, startTime, endTime, type, false);
}

public Banner(String uuid, String message, String hosts, boolean active, long startTime, long endTime, String type, boolean isDismissed) {
this.uuid = uuid;
this.message = message;
this.hosts = hosts;
this.isActive = active;
this.startTime = startTime;
this.endTime = endTime;
this.type = BannerType.valueOf(type.toUpperCase());
this.isDismissed = isDismissed;
}

/**
* The type of this banner (high, medium, low).
*/
public String getType() {
return this.type.toString().toLowerCase();
}

/**
* Determine the default acknowledgement type for this banner.
*/
public String calculateAcknowledgementType() {
if (type.equals(BannerType.MEDIUM)) {
return Acknowledger.TEMPORARY;
} else {
return Acknowledger.PERMANENT;
}
}

@Override
public int compareTo(Banner other) {
return getSeverityScore() - other.getSeverityScore();
}

public boolean equals(Object obj) {
if (!(obj instanceof Banner)) {
return false;
}

return uuid.equals(((Banner)obj).getUuid());
}

public int hashCode() {
return uuid.hashCode();
}

/**
* A numeric type representing this banner's importance (higher number = more important)
*/
public int getSeverityScore() {
return type.ordinal();
}

/**
* Whether or not this banner should be displayed at this moment in time.
*/
public boolean isActiveNow() {
if (!isActive()) {
return false;
}

if (startTime == 0 && endTime == 0) {
return isActive();
}

Date now = new Date();

return (now.after(new Date(startTime))
&& (endTime == 0 || now.before(new Date(endTime))));
}

/**
* Whether or not this banner type can be dismissed by a user.
*/
public boolean isDismissible() {
return !BannerType.HIGH.equals(type);
}

/**
* True if this banner is active now and assigned to the current server.
*/
public boolean isActiveForHost(String hostname) {
// are we active?
if (!isActiveNow()) {
return false;
}

// if no hosts then assume active for any host
if (hosts == null || hosts.isEmpty()) {
return true;
}

// we have some hosts defined, so check if the current is listed
return Arrays.asList(hosts.split(",")).contains(hostname);
}

/**
* Check that the values we've been given make sense.
*/
public Errors validate() {
Errors errors = new Errors();

if (!startTimeBeforeEndTime(startTime, endTime)) {
errors.addError("start_time", "start_time_after_end_time");
errors.addError("end_time", "start_time_after_end_time");
}

return errors;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**********************************************************************************
*
* Copyright (c) 2015 The Sakai Foundation
*
* Original developers:
*
* New York University
* Payten Giles
* Mark Triggs
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.osedu.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/

package org.sakaiproject.pasystem.api;

import java.util.List;
import java.util.Optional;

/**
* The interface for the banners sub-service.
*/
public interface Banners extends Acknowledger {

/**
* A list of banners that should be shown for a given server and user.
*/
public List<Banner> getRelevantBanners(String serverId, String userEid);

public String createBanner(Banner banner);

public void updateBanner(Banner banner);

public void deleteBanner(String uuid);

public List<Banner> getAll();

/**
* Forget all acknowledgements for the current user.
*/
public void clearTemporaryDismissedForUser(String userEid);

public Optional<Banner> getForId(String uuid);
}

Loading

0 comments on commit dd25a53

Please sign in to comment.