diff --git a/WebContent/WEB-INF/jsp/events.jsp b/WebContent/WEB-INF/jsp/events.jsp
index 919977eb39..59361b56f3 100644
--- a/WebContent/WEB-INF/jsp/events.jsp
+++ b/WebContent/WEB-INF/jsp/events.jsp
@@ -225,6 +225,7 @@
+
diff --git a/WebContent/WEB-INF/jsp/include/customEditor.jsp b/WebContent/WEB-INF/jsp/include/customEditor.jsp
index 41910679d4..12d5b2b90a 100644
--- a/WebContent/WEB-INF/jsp/include/customEditor.jsp
+++ b/WebContent/WEB-INF/jsp/include/customEditor.jsp
@@ -66,6 +66,12 @@
|
|
+
+
+ |
+ |
+
+
@@ -103,6 +109,10 @@
$set("customEditorAlarmListInactivityColumn",comp.hideInactivityColumn);
$set("customEditorAlarmListAckColumn",comp.hideAckColumn);
+ if('${isEventAssignEnabled}' !== '') {
+ $set("customEditorAlarmListAssigneeColumn",comp.hideAssigneeColumn);
+ }
+
} else if(comp.typeName == "yourCustomComponent") {
}
@@ -120,13 +130,14 @@
this.save = function() {
//hideContextualMessages("graphicRendererEditorPopup");
+ let customEditorAlarmListAssigneeColumn = '${isEventAssignEnabled}' !== '' ? $get("customEditorAlarmListAssigneeColumn") : false;
if (customEditor.typeName == "alarmlist")
ViewDwr.saveAlarmListComponent(customEditor.componentId,
$get("customEditorAlarmListMinAlarmLevel"), $get("customEditorAlarmListMaxListSize"),
$get("customEditorAlarmListWidth"),$get("customEditorAlarmListIdColumn"),
$get("customEditorAlarmListAlarmLevelColumn"),$get("customEditorAlarmListTimestampColumn"),
$get("customEditorAlarmListInactivityColumn"),$get("customEditorAlarmListAckColumn"),
- viewId, customEditor.saveCB);
+ viewId, customEditorAlarmListAssigneeColumn, customEditor.saveCB);
else if (customEditor.typeName == "yourCustomComponent")
alert('save your custom component component!');
diff --git a/WebContent/WEB-INF/jsp/systemSettings.jsp b/WebContent/WEB-INF/jsp/systemSettings.jsp
index 0f61a006c9..53d4de2016 100644
--- a/WebContent/WEB-INF/jsp/systemSettings.jsp
+++ b/WebContent/WEB-INF/jsp/systemSettings.jsp
@@ -112,6 +112,7 @@
setDisabled($(""), !settings.);
setDisabled($(""), !settings. || !settings.);
+ $set("", settings.);
var sel = $("");
sel.options[sel.options.length] = new Option("${lang.value}", "${lang.key}");
@@ -308,6 +309,7 @@
$get(""),
$get(""),
$get(""),
+ $get(""),
function(response) {
stopImageFader("saveMiscSettingsImg");
if (response.hasMessages)
@@ -961,6 +963,12 @@
|
+
+ |
+
+ "/>" type="checkbox" />
+ |
+
|
diff --git a/WebContent/WEB-INF/snippet/alarmList.jsp b/WebContent/WEB-INF/snippet/alarmList.jsp
index 122b4e8527..099653184f 100644
--- a/WebContent/WEB-INF/snippet/alarmList.jsp
+++ b/WebContent/WEB-INF/snippet/alarmList.jsp
@@ -24,6 +24,7 @@
|
|
|
+ |
|
|
@@ -33,7 +34,8 @@
|
${sst:time(event.activeTimestamp)} |
-
|
+
+
@@ -48,6 +50,14 @@
|
+
+
+
+ ${sst:time(event.assigneeTimestamp)}
+
+
+ |
+
|
diff --git a/WebContent/WEB-INF/snippet/eventList.jsp b/WebContent/WEB-INF/snippet/eventList.jsp
index ffc358ac05..c0525036b8 100644
--- a/WebContent/WEB-INF/snippet/eventList.jsp
+++ b/WebContent/WEB-INF/snippet/eventList.jsp
@@ -63,6 +63,7 @@
|
|
|
+ |
|
|
@@ -103,71 +104,16 @@
+
+
+
+ ${sst:time(event.assigneeTimestamp)}
+
+
+ |
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- (unknown event source id ${event.eventType.eventSourceId})
-
|
diff --git a/WebContent/WEB-INF/spring-security.xml b/WebContent/WEB-INF/spring-security.xml
index 43b2e159d6..557a6c77b0 100644
--- a/WebContent/WEB-INF/spring-security.xml
+++ b/WebContent/WEB-INF/spring-security.xml
@@ -181,6 +181,8 @@
+
+
@@ -392,6 +394,9 @@
+
+
+
diff --git a/WebContent/WEB-INF/tags/alarmAck.tag b/WebContent/WEB-INF/tags/alarmAck.tag
index 4216d3ed2b..c036ee8e80 100644
--- a/WebContent/WEB-INF/tags/alarmAck.tag
+++ b/WebContent/WEB-INF/tags/alarmAck.tag
@@ -23,6 +23,8 @@
+
+
@@ -33,4 +35,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (unknown event source id ${event.eventType.eventSourceId})
+
+
\ No newline at end of file
diff --git a/WebContent/resources/common.js b/WebContent/resources/common.js
index dd839b02e6..2d48f8c7a3 100644
--- a/WebContent/resources/common.js
+++ b/WebContent/resources/common.js
@@ -1261,6 +1261,28 @@ function OnListWebsocketStats() {
} );
}
+function assignEvent(eventId) {
+ MiscDwr.assignEvent(eventId, function(response) {
+ if(response) {
+ hide("assigneeImg"+ eventId);
+ var imgNode = $("assigneeImg"+ eventId);
+ updateImg(imgNode, "images/user_delete.png", mango.i18n["events.unassign"], true, "inline");
+ imgNode.onclick = function() {};
+ }
+ });
+}
+
+function unassignEvent(eventId) {
+ MiscDwr.unassignEvent(eventId, function(response) {
+ if(response) {
+ hide("unassigneeImg"+ eventId);
+ var imgNode = $("unassigneeImg"+ eventId);
+ updateImg(imgNode, "images/user_add.png", mango.i18n["events.assign"], true, "inline");
+ imgNode.onclick = function() {};
+ }
+ });
+}
+
function isEmpty(value) {
return !value || (typeof value === "string" && value.trim() === "");
}
\ No newline at end of file
diff --git a/scadalts-ui/src/locales/en.json b/scadalts-ui/src/locales/en.json
index 226ab01998..dc0451867f 100644
--- a/scadalts-ui/src/locales/en.json
+++ b/scadalts-ui/src/locales/en.json
@@ -1054,6 +1054,17 @@
"userDetails.view.enableFullScreen": "Enable full screen mode",
"userDetails.view.hideShortcutDisableFullScreen": "Hide shortcut to disable full screen",
"script.runScript": "Run script",
+ "systemsettings.event.pendingLimit": "Event Pending Limit",
+ "systemsettings.event.pendingCacheEnabled": "Enabled Event Pending Cache",
+ "systemsettings.workitems.reporting.enabled": "Work items reporting enabled",
+ "systemsettings.workitems.reporting.itemspersecond.enabled": "Items per second reporting enabled",
+ "systemsettings.workitems.reporting.itemspersecond.limit": "Items per second reporting limit",
+ "systemsettings.threads.name.additional.length": "Thread name length",
+ "systemsettings.webresource.uploads.path": "Uploaded images save path",
+ "systemsettings.webresource.graphics.path": "Custom Graphics images path",
+ "systemsettings.webresource.uploads.path.wrong":"Uploaded images save path must end with 'uploads' or 'uploads{0}' ",
+ "systemsettings.webresource.graphics.path.wrong": "Custom Graphics images path must end with 'graphics' or 'graphics{0}' ",
+ "systemsettings.misc.eventAssignEnabled": "Event Assign enabled",
"systemsettings.misc.eventPendingCacheEnabled": "Event Pending Limit",
"systemsettings.misc.eventPendingLimit": "Enabled Event Pending Cache",
"systemsettings.misc.workItemsReportingEnabled": "Work items reporting enabled",
diff --git a/scadalts-ui/src/views/System/SystemSettings/MiscSettingsComponent.vue b/scadalts-ui/src/views/System/SystemSettings/MiscSettingsComponent.vue
index 97b422e213..c43e1f6321 100644
--- a/scadalts-ui/src/views/System/SystemSettings/MiscSettingsComponent.vue
+++ b/scadalts-ui/src/views/System/SystemSettings/MiscSettingsComponent.vue
@@ -109,6 +109,13 @@
:rules="[validateUploadsPath]"
>
+
+
+
diff --git a/src/br/org/scadabr/api/dao/MangoDaoImpl.java b/src/br/org/scadabr/api/dao/MangoDaoImpl.java
index 2e79b56767..065dddef6d 100644
--- a/src/br/org/scadabr/api/dao/MangoDaoImpl.java
+++ b/src/br/org/scadabr/api/dao/MangoDaoImpl.java
@@ -567,7 +567,7 @@ public EventNotification ackEvent(int eventId) throws ScadaBRAPIException {
if (eventInstance != null) {
// alternateAckSource? - REM
- eventService.ackEvent(eventId, 1, 0, 0);
+ eventService.ackEvent(eventInstance, 1, this.user, 0);
// new EventDao().ackEvent(eventId, 1);
return APIUtils.toEventNotification(eventInstance);
} else {
diff --git a/src/br/org/scadabr/view/component/AlarmListComponent.java b/src/br/org/scadabr/view/component/AlarmListComponent.java
index b60cb78fc8..7ba5fddb6c 100644
--- a/src/br/org/scadabr/view/component/AlarmListComponent.java
+++ b/src/br/org/scadabr/view/component/AlarmListComponent.java
@@ -18,6 +18,7 @@
import com.serotonin.mango.view.ImplDefinition;
import com.serotonin.mango.web.dwr.BaseDwr;
import org.scada_lts.mango.service.EventService;
+import org.scada_lts.mango.service.SystemSettingsService;
@JsonRemoteEntity
public class AlarmListComponent extends CustomComponent {
@@ -37,6 +38,7 @@ public class AlarmListComponent extends CustomComponent {
private boolean hideTimestampColumn = false;
private boolean hideInactivityColumn = true;
private boolean hideAckColumn = false;
+ private boolean hideAssigneeColumn = false;
public AlarmListComponent() {}
@@ -50,15 +52,18 @@ private AlarmListComponent(AlarmListComponent alarmListComponent) {
this.hideTimestampColumn = alarmListComponent.isHideTimestampColumn();
this.hideInactivityColumn = alarmListComponent.isHideInactivityColumn();
this.hideAckColumn = alarmListComponent.isHideAckColumn();
+ this.hideAssigneeColumn = alarmListComponent.isHideAssigneeColumn();
}
@Override
public String generateContent() {
+ SystemSettingsService systemSettingsService = new SystemSettingsService();
Map model = new HashMap();
WebContext webContext = WebContextFactory.get();
HttpServletRequest request = webContext.getHttpServletRequest();
List toViewEvents = new EventService().getPendingEventsAlarmLevelMin(Common
.getUser().getId(), minAlarmLevel, maxListSize);
+ boolean eventAssignEnabled = systemSettingsService.isEventAssignEnabled();
model.put("nome", "marlon");
model.put("events",toViewEvents);
@@ -68,6 +73,8 @@ public String generateContent() {
model.put("hideTimestampColumn", hideTimestampColumn);
model.put("hideInactivityColumn", hideInactivityColumn);
model.put("hideAckColumn", hideAckColumn);
+ model.put("hideAssigneeColumn", hideAssigneeColumn);
+ model.put("isEventAssignEnabled", eventAssignEnabled);
String content = BaseDwr.generateContent(request, "alarmList.jsp",
model);
@@ -137,13 +144,21 @@ public void setHideInactivityColumn(boolean hideInactivityColumn) {
this.hideInactivityColumn = hideInactivityColumn;
}
+ public boolean isHideAssigneeColumn() {
+ return hideAssigneeColumn;
+ }
+
+ public void setHideAssigneeColumn(boolean hideAssigneeColumn) {
+ this.hideAssigneeColumn = hideAssigneeColumn;
+ }
+
@Override
public ViewComponent copy() {
return new AlarmListComponent(this);
}
private static final long serialVersionUID = -1;
- private static final int version = 1;
+ private static final int version = 2;
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeInt(version);
@@ -155,6 +170,7 @@ private void writeObject(ObjectOutputStream out) throws IOException {
out.writeBoolean(hideTimestampColumn);
out.writeBoolean(hideInactivityColumn);
out.writeBoolean(hideAckColumn);
+ out.writeBoolean(hideAssigneeColumn);
}
@@ -171,6 +187,16 @@ private void readObject(ObjectInputStream in) throws IOException {
hideTimestampColumn = in.readBoolean();
hideInactivityColumn = in.readBoolean();
hideAckColumn = in.readBoolean();
+ } else if (ver == 2) {
+ minAlarmLevel = in.readInt();
+ maxListSize = in.readInt();
+ width = in.readInt();
+ hideIdColumn = in.readBoolean();
+ hideAlarmLevelColumn = in.readBoolean();
+ hideTimestampColumn = in.readBoolean();
+ hideInactivityColumn = in.readBoolean();
+ hideAckColumn = in.readBoolean();
+ hideAssigneeColumn = in.readBoolean();
}
}
@@ -197,12 +223,12 @@ public boolean equals(Object o) {
if (!(o instanceof AlarmListComponent)) return false;
if (!super.equals(o)) return false;
AlarmListComponent that = (AlarmListComponent) o;
- return getMinAlarmLevel() == that.getMinAlarmLevel() && getMaxListSize() == that.getMaxListSize() && getWidth() == that.getWidth() && isHideIdColumn() == that.isHideIdColumn() && isHideAlarmLevelColumn() == that.isHideAlarmLevelColumn() && isHideTimestampColumn() == that.isHideTimestampColumn() && isHideInactivityColumn() == that.isHideInactivityColumn() && isHideAckColumn() == that.isHideAckColumn();
+ return getMinAlarmLevel() == that.getMinAlarmLevel() && getMaxListSize() == that.getMaxListSize() && getWidth() == that.getWidth() && isHideIdColumn() == that.isHideIdColumn() && isHideAlarmLevelColumn() == that.isHideAlarmLevelColumn() && isHideTimestampColumn() == that.isHideTimestampColumn() && isHideInactivityColumn() == that.isHideInactivityColumn() && isHideAckColumn() == that.isHideAckColumn() && isHideAssigneeColumn() == that.isHideAssigneeColumn();
}
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), getMinAlarmLevel(), getMaxListSize(), getWidth(), isHideIdColumn(), isHideAlarmLevelColumn(), isHideTimestampColumn(), isHideInactivityColumn(), isHideAckColumn());
+ return Objects.hash(super.hashCode(), getMinAlarmLevel(), getMaxListSize(), getWidth(), isHideIdColumn(), isHideAlarmLevelColumn(), isHideTimestampColumn(), isHideInactivityColumn(), isHideAckColumn(), isHideAssigneeColumn());
}
@@ -217,6 +243,7 @@ public String toString() {
", hideTimestampColumn=" + hideTimestampColumn +
", hideInactivityColumn=" + hideInactivityColumn +
", hideAckColumn=" + hideAckColumn +
- "} " + super.toString();
+ ", hideAssigneeColumn=" + hideAssigneeColumn +
+ '}';
}
}
diff --git a/src/com/serotonin/mango/MangoContextListener.java b/src/com/serotonin/mango/MangoContextListener.java
index ed8bf66eeb..fd44341f76 100644
--- a/src/com/serotonin/mango/MangoContextListener.java
+++ b/src/com/serotonin/mango/MangoContextListener.java
@@ -388,6 +388,14 @@ private void constantsInitialize(ServletContext ctx) {
SystemEventType.TYPE_POINT_LINK_FAILURE);
ctx.setAttribute("constants.SystemEventType.TYPE_PROCESS_FAILURE",
SystemEventType.TYPE_PROCESS_FAILURE);
+ ctx.setAttribute("constants.SystemEventType.TYPE_SMS_SEND_FAILURE",
+ SystemEventType.TYPE_SMS_SEND_FAILURE);
+ ctx.setAttribute("constants.SystemEventType.TYPE_SCRIPT_HANDLER_FAILURE",
+ SystemEventType.TYPE_SCRIPT_HANDLER_FAILURE);
+ ctx.setAttribute("constants.SystemEventType.TYPE_ASSIGNED_EVENT",
+ SystemEventType.TYPE_ASSIGNED_EVENT);
+ ctx.setAttribute("constants.SystemEventType.TYPE_UNASSIGNED_EVENT",
+ SystemEventType.TYPE_UNASSIGNED_EVENT);
ctx.setAttribute("constants.AuditEventType.TYPE_DATA_SOURCE",
AuditEventType.TYPE_DATA_SOURCE);
diff --git a/src/com/serotonin/mango/rt/EventManager.java b/src/com/serotonin/mango/rt/EventManager.java
index 27392e49ee..77d74fdf40 100644
--- a/src/com/serotonin/mango/rt/EventManager.java
+++ b/src/com/serotonin/mango/rt/EventManager.java
@@ -42,7 +42,6 @@
import org.scada_lts.mango.service.UserService;
import org.scada_lts.service.IHighestAlarmLevelService;
import org.scada_lts.web.beans.ApplicationBeans;
-import org.scada_lts.web.ws.model.WsEventMessage;
import org.scada_lts.web.ws.services.UserEventServiceWebSocket;
import java.util.*;
@@ -139,7 +138,7 @@ public void raiseEvent(EventType type, long time, boolean rtnApplicable,
eventConfirmForUsers.add(user);
if(evt.getAlarmLevel() > AlarmLevels.NONE)
- notifyEventUpdate(user, WsEventMessage.create(evt));
+ notifyEventCreate(user, evt);
}
}
@@ -158,9 +157,9 @@ public void raiseEvent(EventType type, long time, boolean rtnApplicable,
User admin = userService.getUser("admin");
if(admin != null) {
eventService.ackEvent(
- evt.getId(),
+ evt,
time,
- admin.getId(),
+ admin,
EventInstance.AlternateAcknowledgementSources.MAINTENANCE_MODE,
false); // no signaling of AlarmLevel change
for(User user: eventConfirmForUsers) {
@@ -450,14 +449,15 @@ public void notifyAlarmTimestampChange(long alarmTimestamp) {
}
- public void resetHighestAlarmLevels() {
- NotifyEventUtils.resetHighestAlarmLevels(highestAlarmLevelService, userService, userEventServiceWebSocket);
+ public void notifyEventReset() {
+ NotifyEventUtils.notifyEventReset(highestAlarmLevelService, userEventServiceWebSocket);
}
public int getHighestAlarmLevel(int userId) {
return highestAlarmLevelService.getAlarmLevel(User.onlyId(userId));
}
+ @Deprecated(since = "2.8.0")
public void notifyEventRaise(int eventId, int userId) {
if(eventId != Common.NEW_ID) {
EventInstance evt = eventService.getEvent(eventId);
@@ -466,6 +466,15 @@ public void notifyEventRaise(int eventId, int userId) {
}
}
+ @Deprecated(since = "2.8.0")
+ public void notifyEventRaise(int eventId) {
+ if(eventId != Common.NEW_ID) {
+ for(int userId: ApplicationBeans.getLoggedUsersBean().getUserIds()) {
+ notifyEventRaise(eventId, userId);
+ }
+ }
+ }
+
public void notifyEventRaise(EventInstance evt, User user) {
NotifyEventUtils.notifyEventRaise(highestAlarmLevelService, evt, user, userEventServiceWebSocket);
}
@@ -474,6 +483,7 @@ public void notifyEventAck(EventInstance evt, User user) {
NotifyEventUtils.notifyEventAck(highestAlarmLevelService, evt, user, userEventServiceWebSocket);
}
+ @Deprecated(since = "2.8.0")
public void notifyEventAck(int eventId, User user) {
if(eventId != Common.NEW_ID) {
EventInstance evt = eventService.getEvent(eventId);
@@ -481,10 +491,19 @@ public void notifyEventAck(int eventId, User user) {
}
}
+ @Deprecated(since = "2.8.0")
public void notifyEventAck(int eventId) {
if(eventId != Common.NEW_ID) {
- for (User user : userService.getActiveUsers())
- notifyEventAck(eventId, user);
+ for (int userId : ApplicationBeans.getLoggedUsersBean().getUserIds())
+ notifyEventAck(eventId, userService.getUser(userId));
+ }
+ }
+
+ @Deprecated(since = "2.8.0")
+ public void notifyEventAssignee(int eventId) {
+ if(eventId != Common.NEW_ID) {
+ for (int userId : ApplicationBeans.getLoggedUsersBean().getUserIds())
+ notifyEventAck(eventId, userService.getUser(userId));
}
}
@@ -494,8 +513,9 @@ public void notifyEventRtn(EventInstance evt, User user) {
public void notifyEventRtn(EventInstance event) {
if(event.getId() != Common.NEW_ID) {
- for (User user : userService.getActiveUsers())
+ for (User user : ApplicationBeans.getLoggedUsersBean().getUsers()) {
notifyEventRtn(event, user);
+ }
}
}
@@ -503,6 +523,7 @@ public void notifyEventToggle(EventInstance evt, User user) {
NotifyEventUtils.notifyEventToggle(highestAlarmLevelService, evt, user, userEventServiceWebSocket);
}
+ @Deprecated(since = "2.8.0")
public void notifyEventToggle(int eventId, int userId) {
if(eventId != Common.NEW_ID) {
EventInstance evt = eventService.getEvent(eventId);
@@ -511,7 +532,31 @@ public void notifyEventToggle(int eventId, int userId) {
}
}
- public void notifyEventUpdate(User user, WsEventMessage message) {
- NotifyEventUtils.notifyEventUpdate(user, message, userEventServiceWebSocket);
+ public void notifyEventCreate(User user, EventInstance event) {
+ NotifyEventUtils.notifyEventCreate(event, user, userEventServiceWebSocket);
+ }
+
+ public void notifyEventRaise(EventInstance event) {
+ if(event.getId() != Common.NEW_ID) {
+ for (User user : ApplicationBeans.getLoggedUsersBean().getUsers()) {
+ notifyEventRaise(event, user);
+ }
+ }
+ }
+
+ public void notifyEventAck(EventInstance event) {
+ if(event.getId() != Common.NEW_ID) {
+ for (User user : ApplicationBeans.getLoggedUsersBean().getUsers()) {
+ notifyEventAck(event, user);
+ }
+ }
+ }
+
+ public void notifyEventAssignee(EventInstance event) {
+ if(event.getId() != Common.NEW_ID) {
+ for (User user : ApplicationBeans.getLoggedUsersBean().getUsers()) {
+ notifyEventToggle(event, user);
+ }
+ }
}
}
diff --git a/src/com/serotonin/mango/rt/event/EventInstance.java b/src/com/serotonin/mango/rt/event/EventInstance.java
index a8cb1bda4b..c1c9650ec0 100644
--- a/src/com/serotonin/mango/rt/event/EventInstance.java
+++ b/src/com/serotonin/mango/rt/event/EventInstance.java
@@ -97,6 +97,9 @@ public interface AlternateAcknowledgementSources {
private String acknowledgedByUsername;
private int alternateAckSource;
+ private long assigneeTimestamp;
+ private String assigneeUsername;
+
//
//
// These fields are used only in the context of access by a particular user, providing state filled in from
@@ -185,6 +188,14 @@ public LocalizableMessage getAckMessage() {
return new LocalizableMessage("event.auto.acknowledge");
}
+ public LocalizableMessage getAssigneeMessage() {
+ if (isAssignee()) {
+ if (!StringUtils.isEmpty(assigneeUsername))
+ return new LocalizableMessage("events.assigneeByUser", assigneeUsername);
+ }
+ return new LocalizableMessage("common.noMessage");
+ }
+
public LocalizableMessage getExportAckMessage() {
if (isAcknowledged()) {
if (acknowledgedByUserId != 0 || !StringUtils.isEmpty(acknowledgedByUsername))
@@ -246,6 +257,10 @@ public boolean isAcknowledged() {
return acknowledgedTimestamp > 0;
}
+ public boolean isAssignee() {
+ return assigneeTimestamp > 0;
+ }
+
public long getActiveTimestamp() {
return activeTimestamp;
}
@@ -350,6 +365,22 @@ public void setAlternateAckSource(int alternateAckSource) {
this.alternateAckSource = alternateAckSource;
}
+ public long getAssigneeTimestamp() {
+ return assigneeTimestamp;
+ }
+
+ public void setAssigneeTimestamp(long assigneeTimestamp) {
+ this.assigneeTimestamp = assigneeTimestamp;
+ }
+
+ public String getAssigneeUsername() {
+ return assigneeUsername;
+ }
+
+ public void setAssigneeUsername(String assigneeUsername) {
+ this.assigneeUsername = assigneeUsername;
+ }
+
public Map getContext() {
return context;
}
@@ -459,6 +490,8 @@ public EventInstance copyWithContext(Map context) {
eventInstance.setHandlers(handlers);
eventInstance.setSilenced(silenced);
eventInstance.setUserNotified(userNotified);
+ eventInstance.setAssigneeTimestamp(assigneeTimestamp);
+ eventInstance.setAssigneeUsername(assigneeUsername);
return eventInstance;
}
diff --git a/src/com/serotonin/mango/rt/event/type/SystemEventType.java b/src/com/serotonin/mango/rt/event/type/SystemEventType.java
index 39f4019a58..754ea64dd5 100644
--- a/src/com/serotonin/mango/rt/event/type/SystemEventType.java
+++ b/src/com/serotonin/mango/rt/event/type/SystemEventType.java
@@ -60,6 +60,8 @@ public class SystemEventType extends EventType {
public static final int TYPE_PROCESS_FAILURE = 10;
public static final int TYPE_SCRIPT_HANDLER_FAILURE = 11;
public static final int TYPE_SMS_SEND_FAILURE = 12;
+ public static final int TYPE_ASSIGNED_EVENT = 13;
+ public static final int TYPE_UNASSIGNED_EVENT = 14;
public static final ExportCodes TYPE_CODES = new ExportCodes();
static {
@@ -78,6 +80,8 @@ public class SystemEventType extends EventType {
TYPE_CODES.addElement(TYPE_PROCESS_FAILURE, "PROCESS_FAILURE");
TYPE_CODES.addElement(TYPE_SCRIPT_HANDLER_FAILURE, "SCRIPT_HANDLER_FAILURE");
TYPE_CODES.addElement(TYPE_SMS_SEND_FAILURE, "SMS_SEND_FAILURE");
+ TYPE_CODES.addElement(TYPE_ASSIGNED_EVENT, "ASSIGNED_EVENT");
+ TYPE_CODES.addElement(TYPE_UNASSIGNED_EVENT, "UNASSIGNED_EVENT");
}
private static List systemEventTypes;
@@ -109,7 +113,11 @@ public static List getSystemEventTypes() {
addEventTypeVO(TYPE_SCRIPT_HANDLER_FAILURE, "event.system.script",
AlarmLevels.URGENT);
addEventTypeVO(TYPE_SMS_SEND_FAILURE, "event.system.sms",
- AlarmLevels.URGENT);
+ AlarmLevels.INFORMATION);
+ addEventTypeVO(TYPE_ASSIGNED_EVENT, "event.system.assigned",
+ AlarmLevels.INFORMATION);
+ addEventTypeVO(TYPE_UNASSIGNED_EVENT, "event.system.unassigned",
+ AlarmLevels.INFORMATION);
}
return systemEventTypes;
}
diff --git a/src/com/serotonin/mango/util/NotifyEventUtils.java b/src/com/serotonin/mango/util/NotifyEventUtils.java
index 41f49c02c8..027f2d2eab 100644
--- a/src/com/serotonin/mango/util/NotifyEventUtils.java
+++ b/src/com/serotonin/mango/util/NotifyEventUtils.java
@@ -3,8 +3,8 @@
import com.serotonin.mango.rt.event.AlarmLevels;
import com.serotonin.mango.rt.event.EventInstance;
import com.serotonin.mango.vo.User;
-import org.scada_lts.mango.adapter.MangoUser;
import org.scada_lts.service.IHighestAlarmLevelService;
+import org.scada_lts.web.beans.ApplicationBeans;
import org.scada_lts.web.ws.model.WsEventMessage;
import org.scada_lts.web.ws.services.UserEventServiceWebSocket;
@@ -12,9 +12,12 @@ public final class NotifyEventUtils {
private NotifyEventUtils() {}
- public static void resetHighestAlarmLevels(IHighestAlarmLevelService highestAlarmLevelService, MangoUser userService, UserEventServiceWebSocket userEventService) {
+ public static void notifyEventReset(IHighestAlarmLevelService highestAlarmLevelService, UserEventServiceWebSocket userEventService) {
highestAlarmLevelService.doResetAlarmLevels(userEventService::sendAlarmLevel);
- notifyEventReset(userService, userEventService);
+ ApplicationBeans.Lazy.getLoggedUsersBean().ifPresent(loggedUsers -> {
+ for(User user: loggedUsers.getUsers())
+ notifyEventUpdate(user, WsEventMessage.reset(), userEventService);
+ });
}
public static void notifyEventRaise(IHighestAlarmLevelService highestAlarmLevelService, EventInstance evt, User user, UserEventServiceWebSocket userEventService) {
@@ -44,12 +47,13 @@ public static void notifyEventAck(IHighestAlarmLevelService highestAlarmLevelSer
}
}
- public static void notifyEventReset(MangoUser userService, UserEventServiceWebSocket userEventService) {
- for(User user: userService.getActiveUsers())
- userEventService.sendEventUpdate(user, WsEventMessage.reset());
+ public static void notifyEventCreate(EventInstance evt, User user, UserEventServiceWebSocket userEventService) {
+ if(evt.getAlarmLevel() > AlarmLevels.NONE) {
+ notifyEventUpdate(user, WsEventMessage.create(evt), userEventService);
+ }
}
- public static void notifyEventUpdate(User user, WsEventMessage message, UserEventServiceWebSocket userEventService) {
+ private static void notifyEventUpdate(User user, WsEventMessage message, UserEventServiceWebSocket userEventService) {
userEventService.sendEventUpdate(user, message);
}
}
diff --git a/src/com/serotonin/mango/vo/User.java b/src/com/serotonin/mango/vo/User.java
index 9aa16e2b50..97416496f2 100644
--- a/src/com/serotonin/mango/vo/User.java
+++ b/src/com/serotonin/mango/vo/User.java
@@ -224,11 +224,13 @@ public void raiseRecursionFailureEvent() {
@Override
public void valueBound(HttpSessionBindingEvent event) {
ApplicationBeans.Lazy.getLoggedUsersBean().ifPresent(loggedUsers -> loggedUsers.addUser(this, event.getSession()));
+ ApplicationBeans.Lazy.getHighestAlarmLevelServiceBean().ifPresent(highestAlarmLevelService -> highestAlarmLevelService.doResetAlarmLevels((a, b) -> {}));
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
ApplicationBeans.Lazy.getLoggedUsersBean().ifPresent(loggedUsers -> loggedUsers.removeUser(this, event.getSession()));
+ ApplicationBeans.Lazy.getHighestAlarmLevelServiceBean().ifPresent(highestAlarmLevelService -> highestAlarmLevelService.doResetAlarmLevels((a, b) -> {}));
}
// Convenience method for JSPs
diff --git a/src/com/serotonin/mango/web/dwr/BaseDwr.java b/src/com/serotonin/mango/web/dwr/BaseDwr.java
index f7e7bad1d3..8c3e1bb8b1 100644
--- a/src/com/serotonin/mango/web/dwr/BaseDwr.java
+++ b/src/com/serotonin/mango/web/dwr/BaseDwr.java
@@ -21,11 +21,6 @@
import java.util.*;
import javax.servlet.http.HttpServletRequest;
-import javax.servlet.jsp.jstl.core.Config;
-import javax.servlet.jsp.jstl.fmt.LocalizationContext;
-
-import org.directwebremoting.WebContext;
-import org.directwebremoting.WebContextFactory;
import org.joda.time.DateTime;
import org.joda.time.IllegalFieldValueException;
@@ -54,9 +49,9 @@
import com.serotonin.web.content.ContentGenerator;
import com.serotonin.web.i18n.I18NUtils;
import com.serotonin.web.i18n.LocalizableMessage;
-import org.scada_lts.dao.pointvalues.PointValueAdnnotationsDAO;
import org.scada_lts.mango.adapter.MangoEvent;
import org.scada_lts.mango.service.EventService;
+import org.scada_lts.mango.service.SystemSettingsService;
abstract public class BaseDwr {
public static final String MODEL_ATTR_EVENTS = "events";
@@ -100,6 +95,10 @@ protected PointValueTime prepareBasePointState(String componentId, BasePointStat
model.put("pointValue", pointValue);
}
+ User user = Common.getUser();
+ if(user != null)
+ model.put(Common.SESSION_USER, user);
+
return pointValue;
}
@@ -170,6 +169,8 @@ protected void setChart(DataPointVO point, BasePointState state, HttpServletRequ
protected void setMessages(BasePointState state, HttpServletRequest request, String snippet,
Map model) {
+ SystemSettingsService systemSettingsService = new SystemSettingsService();
+ model.put("isEventAssignEnabled", systemSettingsService.isEventAssignEnabled());
state.setMessages(generateContent(request, snippet + ".jsp", model).trim());
}
diff --git a/src/com/serotonin/mango/web/dwr/EventsDwr.java b/src/com/serotonin/mango/web/dwr/EventsDwr.java
index f3fb0269e1..91a0ad487f 100644
--- a/src/com/serotonin/mango/web/dwr/EventsDwr.java
+++ b/src/com/serotonin/mango/web/dwr/EventsDwr.java
@@ -40,6 +40,7 @@
import com.serotonin.web.i18n.LocalizableMessage;
import org.scada_lts.mango.adapter.MangoEvent;
import org.scada_lts.mango.service.EventService;
+import org.scada_lts.mango.service.SystemSettingsService;
public class EventsDwr extends BaseDwr {
private static final int PAGE_SIZE = 50;
@@ -49,6 +50,7 @@ public class EventsDwr extends BaseDwr {
public static final String STATUS_ACTIVE = "A";
public static final String STATUS_RTN = "R";
public static final String STATUS_NORTN = "N";
+ public static final String STATUS_ASSIGNEE = "U";
public static final int DATE_RANGE_TYPE_NONE = 1;
public static final int DATE_RANGE_TYPE_RELATIVE = 2;
@@ -88,6 +90,9 @@ public DwrResponseI18n searchOld(int eventId, int eventSourceType,
model.put("events", results);
model.put("showControls", false);
+ SystemSettingsService systemSettingsService = new SystemSettingsService();
+ model.put("isEventAssignEnabled", systemSettingsService.isEventAssignEnabled());
+
response.addData("content",
generateContent(request, "eventList.jsp", model));
response.addData("resultCount", new LocalizableMessage(
@@ -182,6 +187,9 @@ status, alarmLevel, getKeywords(keywordStr), dateRange.getL1(),
model.put("page", page);
model.put("pendingEvents", false);
+ SystemSettingsService systemSettingsService = new SystemSettingsService();
+ model.put("isEventAssignEnabled", systemSettingsService.isEventAssignEnabled());
+
response.addData("content",
generateContent(request, "eventList.jsp", model));
response.addData("resultCount", new LocalizableMessage(
diff --git a/src/com/serotonin/mango/web/dwr/MiscDwr.java b/src/com/serotonin/mango/web/dwr/MiscDwr.java
index 31ea7a737b..92b8e741dd 100644
--- a/src/com/serotonin/mango/web/dwr/MiscDwr.java
+++ b/src/com/serotonin/mango/web/dwr/MiscDwr.java
@@ -42,9 +42,7 @@
import org.directwebremoting.WebContextFactory;
import org.scada_lts.dao.SystemSettingsDAO;
import org.scada_lts.mango.adapter.MangoEvent;
-import org.scada_lts.mango.service.EventService;
-import org.scada_lts.mango.service.UserService;
-import org.scada_lts.mango.service.ViewService;
+import org.scada_lts.mango.service.*;
import com.serotonin.io.StreamUtils;
import com.serotonin.mango.Common;
@@ -88,8 +86,9 @@ public DwrResponseI18n toggleSilence(int eventId) {
User user = Common.getUser();
if (user != null) {
- boolean result = new EventService()
- .toggleSilence(eventId, user.getId());
+ EventService eventService = new EventService();
+ EventInstance event = eventService.getEvent(eventId);
+ boolean result = eventService.toggleSilence(event, user);
resetLastAlarmLevelChange();
response.addData("silenced", result);
} else
@@ -100,14 +99,11 @@ public DwrResponseI18n toggleSilence(int eventId) {
public DwrResponseI18n silenceAll() {
- List silenced = new ArrayList();
+ List silenced = new ArrayList<>();
User user = Common.getUser();
- MangoEvent eventService = new EventService();
- for (EventInstance evt : eventService.getPendingEvents(user.getId())) {
- if (!evt.isSilenced()) {
- eventService.toggleSilence(evt.getId(), user.getId());
- silenced.add(evt.getId());
- }
+ if (user != null) {
+ MangoEvent eventService = new EventService();
+ silenced = eventService.silenceEvents(user);
}
resetLastAlarmLevelChange();
@@ -123,23 +119,46 @@ public int acknowledgeEvent(int eventId) {
if (user != null) {
EventInstance evt = eventService.getEvent(eventId);
if(evt != null && !evt.isActive()) {
- eventService.ackEvent(evt.getId(), System.currentTimeMillis(),
- user.getId(), 0);
+ eventService.ackEvent(evt, System.currentTimeMillis(), user, 0);
resetLastAlarmLevelChange();
}
}
return eventId;
}
+ public boolean assignEvent(int eventId) {
+ User user = Common.getUser();
+ MangoEvent eventService = new EventService();
+ boolean result = false;
+ if (user != null) {
+ EventInstance evt = eventService.getEvent(eventId);
+ if(evt != null) {
+ result = eventService.assignEvent(evt, user);
+ resetLastAlarmLevelChange();
+ }
+ }
+ return result;
+ }
+
+ public boolean unassignEvent(int eventId) {
+ User user = Common.getUser();
+ MangoEvent eventService = new EventService();
+ boolean result = false;
+ if (user != null) {
+ EventInstance evt = eventService.getEvent(eventId);
+ if(evt != null) {
+ result = eventService.unassignEvent(evt, user);
+ resetLastAlarmLevelChange();
+ }
+ }
+ return result;
+ }
+
public void acknowledgeAllPendingEvents() {
User user = Common.getUser();
if (user != null) {
MangoEvent eventService = new EventService();
- long now = System.currentTimeMillis();
- for (EventInstance evt : eventService.getPendingEvents(user.getId())) {
- if(!evt.isActive())
- eventService.ackEvent(evt.getId(), now, user.getId(), 0);
- }
+ eventService.ackEvents(user);
resetLastAlarmLevelChange();
}
}
@@ -438,6 +457,9 @@ public Map doLongPoll(int pollSessionId) {
model.put("events", eventService.getPendingEvents(user.getId()));
model.put("pendingEvents", true);
model.put("noContentWhenEmpty", true);
+ SystemSettingsService service = new SystemSettingsService();
+ model.put("isEventAssignEnabled", service.isEventAssignEnabled());
+
String currentContent = generateContent(httpRequest,
"eventList.jsp", model);
currentContent = StringUtils.trimWhitespace(currentContent);
diff --git a/src/com/serotonin/mango/web/dwr/SystemSettingsDwr.java b/src/com/serotonin/mango/web/dwr/SystemSettingsDwr.java
index a87f8b82bd..6aa6f9a802 100644
--- a/src/com/serotonin/mango/web/dwr/SystemSettingsDwr.java
+++ b/src/com/serotonin/mango/web/dwr/SystemSettingsDwr.java
@@ -177,6 +177,8 @@ public Map getSettings() {
systemSettingsService.getMiscSettings().getWebResourceGraphicsPath());
settings.put(SystemSettingsDAO.WEB_RESOURCE_UPLOADS_PATH,
systemSettingsService.getMiscSettings().getWebResourceUploadsPath());
+ settings.put(SystemSettingsDAO.EVENT_ASSIGN_ENABLED,
+ systemSettingsService.getMiscSettings().isEventAssignEnabled());
return settings;
}
@@ -329,7 +331,8 @@ public DwrResponseI18n saveMiscSettings(int uiPerformance, String dataPointRtVal
int eventPendingLimit, boolean eventPendingCacheEnabled,
boolean workItemsReportingEnabled, boolean workItemsReportingItemsPerSecondEnabled,
int workItemsReportingItemsPerSecondLimit, int threadsNameAdditionalLength,
- String webResourceGraphicsPath, String webResourceUploadsPath) {
+ String webResourceGraphicsPath, String webResourceUploadsPath,
+ boolean eventAssignEnabled) {
Permissions.ensureAdmin();
SystemSettingsDAO systemSettingsDAO = new SystemSettingsDAO();
DwrResponseI18n response = new DwrResponseI18n();
@@ -387,7 +390,8 @@ public DwrResponseI18n saveMiscSettings(int uiPerformance, String dataPointRtVal
else {
response.addContextualMessage(SystemSettingsDAO.WEB_RESOURCE_UPLOADS_PATH, "systemsettings.webresource.uploads.path.wrong", File.separator);
}
-
+ SystemSettingsService systemSettingsService = new SystemSettingsService();
+ systemSettingsService.saveEventAssignEnabled(eventAssignEnabled);
return response;
}
diff --git a/src/com/serotonin/mango/web/dwr/ViewDwr.java b/src/com/serotonin/mango/web/dwr/ViewDwr.java
index f1dd722052..cb93dbe5bb 100644
--- a/src/com/serotonin/mango/web/dwr/ViewDwr.java
+++ b/src/com/serotonin/mango/web/dwr/ViewDwr.java
@@ -897,7 +897,10 @@ public DwrResponseI18n saveFlexComponent(String viewComponentId, int width, int
}
- public DwrResponseI18n saveAlarmListComponent(String viewComponentId, int minAlarmLevel, int maxListSize, int width, boolean hideIdColumn, boolean hideAlarmLevelColumn, boolean hideTimestampColumn, boolean hideInactivityColumn, boolean hideAckColumn, int viewId) {
+ public DwrResponseI18n saveAlarmListComponent(String viewComponentId, int minAlarmLevel, int maxListSize, int width,
+ boolean hideIdColumn, boolean hideAlarmLevelColumn, boolean hideTimestampColumn,
+ boolean hideInactivityColumn, boolean hideAckColumn, int viewId,
+ boolean hideAssigneeColumn) {
DwrResponseI18n response = new DwrResponseI18n();
// Validate
@@ -916,6 +919,7 @@ public DwrResponseI18n saveAlarmListComponent(String viewComponentId, int minAla
c.setHideTimestampColumn(hideTimestampColumn);
c.setHideInactivityColumn(hideInactivityColumn);
c.setHideAckColumn(hideAckColumn);
+ c.setHideAssigneeColumn(hideAssigneeColumn);
// resetPointComponent(c);
}
diff --git a/src/org/scada_lts/dao/HighestAlarmLevelDAO.java b/src/org/scada_lts/dao/HighestAlarmLevelDAO.java
index e06b7b56d1..f88434f51a 100644
--- a/src/org/scada_lts/dao/HighestAlarmLevelDAO.java
+++ b/src/org/scada_lts/dao/HighestAlarmLevelDAO.java
@@ -23,6 +23,7 @@ public class HighestAlarmLevelDAO implements IHighestAlarmLevelDAO {
+ "join events e on u.eventId=e.id "
+ "where "
+ "(e.ackTs is null or e.ackTs = 0) "
+ + "and (e.assigneeTs is null or e.assigneeTs = 0) "
+ "and u.silenced='N' and " + COLUMN_NAME_USERID + "=? "
+ "and (e.rtnCause is null or e.rtnCause = 0) "
+ "and e.rtnApplicable = 'Y'";
@@ -37,6 +38,7 @@ public class HighestAlarmLevelDAO implements IHighestAlarmLevelDAO {
+ "join events e on u.eventId=e.id "
+ "where "
+ "(e.ackTs is null or e.ackTs = 0) "
+ + "and (e.assigneeTs is null or e.assigneeTs = 0) "
+ "and u.silenced='N' "
+ "and (e.rtnCause is null or e.rtnCause = 0) "
+ "and e.rtnApplicable = 'Y' "
diff --git a/src/org/scada_lts/dao/PendingEventsDAO.java b/src/org/scada_lts/dao/PendingEventsDAO.java
index 14f19b659c..6cebd167eb 100644
--- a/src/org/scada_lts/dao/PendingEventsDAO.java
+++ b/src/org/scada_lts/dao/PendingEventsDAO.java
@@ -61,6 +61,8 @@ public class PendingEventsDAO {
private final static String COLUMN_NAME_EVENT_USERNAME = "username";
private final static String COLUMN_NAME_EVENT_ALTERNATE_ACK_SOURCE = "alternateAckSource";
private final static String COLUMN_NAME_EVENT_SILENCED = "silenced";
+ private final static String COLUMN_NAME_EVENT_ASSIGNEE_TS = "assigneeTs";
+ private final static String COLUMN_NAME_EVENT_ASSIGNEE_USERNAME = "assigneeUsername";
// @formatter:off
private static final String SQL_EVENTS = ""
@@ -80,7 +82,9 @@ public class PendingEventsDAO {
+ "e.ackUserId, "
+ "u.username, "
+ "e.alternateAckSource, "
- + "ue.silenced "
+ + "ue.silenced, "
+ + "e.assigneeTs, "
+ + "e.assigneeUsername "
+ "from "
+ "events e "
+ "left join users u on e.ackUserId=u.id "
@@ -163,6 +167,12 @@ private EventInstance mapToEvent(Map> comments, Resul
}
event.setEventComments(comments.get(event.getId()));
+
+ long assigneeTs = rs.getLong(COLUMN_NAME_EVENT_ASSIGNEE_TS);
+ if (!rs.wasNull()) {
+ event.setAssigneeTimestamp(assigneeTs);
+ event.setAssigneeUsername(rs.getString(COLUMN_NAME_EVENT_ASSIGNEE_USERNAME));
+ }
return event;
}
diff --git a/src/org/scada_lts/dao/SystemSettingsDAO.java b/src/org/scada_lts/dao/SystemSettingsDAO.java
index 9a6ff52fdd..8afb2748d8 100644
--- a/src/org/scada_lts/dao/SystemSettingsDAO.java
+++ b/src/org/scada_lts/dao/SystemSettingsDAO.java
@@ -20,7 +20,6 @@
import com.serotonin.InvalidArgumentException;
import com.serotonin.ShouldNeverHappenException;
import com.serotonin.mango.Common;
-import com.serotonin.mango.rt.maint.work.WorkItemPriority;
import com.serotonin.mango.vo.DataPointVO;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -164,6 +163,7 @@ public class SystemSettingsDAO {
public static final String THREADS_NAME_ADDITIONAL_LENGTH = "threadsNameAdditionalLength";
public static final String WEB_RESOURCE_GRAPHICS_PATH = "webResourceGraphicsPath";
public static final String WEB_RESOURCE_UPLOADS_PATH = "webResourceUploadsPath";
+ public static final String EVENT_ASSIGN_ENABLED = "eventAssignEnabled";
// @formatter:off
private static final String SELECT_SETTING_VALUE_WHERE = ""
@@ -413,6 +413,7 @@ public String getDatabaseSchemaVersion(String key, String defaultValue) {
DEFAULT_VALUES.put(THREADS_NAME_ADDITIONAL_LENGTH, SystemSettingsUtils.getThreadsNameAdditionalLength());
DEFAULT_VALUES.put(WEB_RESOURCE_GRAPHICS_PATH, SystemSettingsUtils.getWebResourceGraphicsPath());
DEFAULT_VALUES.put(WEB_RESOURCE_UPLOADS_PATH, SystemSettingsUtils.getWebResourceUploadsPath());
+ DEFAULT_VALUES.put(EVENT_ASSIGN_ENABLED, SystemSettingsUtils.isEventAssignEnabled());
}
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED, rollbackFor = SQLException.class)
diff --git a/src/org/scada_lts/dao/event/EventDAO.java b/src/org/scada_lts/dao/event/EventDAO.java
index 49f34a3707..9fd0d19578 100644
--- a/src/org/scada_lts/dao/event/EventDAO.java
+++ b/src/org/scada_lts/dao/event/EventDAO.java
@@ -29,10 +29,7 @@
import com.serotonin.mango.vo.User;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.scada_lts.dao.DAO;
-import org.scada_lts.dao.GenericDaoCR;
-import org.scada_lts.dao.IUserCommentDAO;
-import org.scada_lts.dao.SerializationData;
+import org.scada_lts.dao.*;
import com.serotonin.mango.rt.event.type.AuditEventUtils;
import org.scada_lts.utils.QueryUtils;
import org.scada_lts.utils.SQLPageWithTotal;
@@ -92,6 +89,9 @@ public class EventDAO implements GenericDaoCR {
private static final String COLUMN_NAME_USER_COMMENT_COUNT = "comments";
private static final String COLUMN_NAME_EVENT_ID = "eventId";
private static final String COLUMN_NAME_USER_ID = "userId";
+
+ private static final String COLUMN_NAME_ASSIGNEE_TS = "assigneeTs";
+ private static final String COLUMN_NAME_ASSIGNEE_USERNAME = "assigneeUsername";
//------------- User comments
//TODO rewrite to another class
@@ -135,7 +135,8 @@ public class EventDAO implements GenericDaoCR {
"e." + COLUMN_NAME_ACT_TS + ", " +
"e." + COLUMN_NAME_ALTERNATE_ACK_SOURCE + ", " +
"dp."+ COLUMN_NAME_DATAPOINT_XID + ", " +
- "ue."+ COLUMN_NAME_SILENCED + " ";
+ "ue."+ COLUMN_NAME_SILENCED + ", " +
+ "e."+ COLUMN_NAME_ASSIGNEE_TS +" ";
// @formatter:off
private static final String BASIC_EVENT_SELECT = ""
@@ -154,7 +155,9 @@ public class EventDAO implements GenericDaoCR {
+ "e."+COLUMN_NAME_ACT_TS+", "
+ "e."+COLUMN_NAME_ACT_USER_ID+", "
+ "u."+COLUMN_NAME_USER_NAME+","
- + "e."+COLUMN_NAME_ALTERNATE_ACK_SOURCE+" "
+ + "e."+COLUMN_NAME_ALTERNATE_ACK_SOURCE+", "
+ + "e."+ COLUMN_NAME_ASSIGNEE_TS +", "
+ + "e."+ COLUMN_NAME_ASSIGNEE_USERNAME +" "
+ "from "
+ "events e "
+ "left join users u on e."+COLUMN_NAME_ACT_USER_ID+"=u.id ";
@@ -174,7 +177,9 @@ public class EventDAO implements GenericDaoCR {
+ "e."+COLUMN_NAME_SHORT_MESSAGE+", "
+ "e."+COLUMN_NAME_ACT_TS+", "
+ "e."+COLUMN_NAME_ACT_USER_ID+", "
- + "e."+COLUMN_NAME_ALTERNATE_ACK_SOURCE+" "
+ + "e."+COLUMN_NAME_ALTERNATE_ACK_SOURCE+", "
+ + "e."+ COLUMN_NAME_ASSIGNEE_TS +", "
+ + "e."+ COLUMN_NAME_ASSIGNEE_USERNAME +" "
+ "from "
+ "events e where "
+ COLUMN_NAME_ID + " "
@@ -211,11 +216,11 @@ public class EventDAO implements GenericDaoCR {
private static final String EVENT_UPDATE = ""
+ "update "
- + "events set "
- + COLUMN_NAME_RTN_TS+"=?,"
- + COLUMN_NAME_RTN_CAUSE+"=? "
+ + "events e set "
+ + "e."+COLUMN_NAME_RTN_TS+"=?,"
+ + "e."+COLUMN_NAME_RTN_CAUSE+"=? "
+ "where "
- + COLUMN_NAME_ID+"=?";
+ + "e."+COLUMN_NAME_ID+"=?";
private static final String EVENT_SELECT_BASE_ON_ID = ""+
@@ -225,38 +230,55 @@ public class EventDAO implements GenericDaoCR {
private static final String EVENT_ACT ="" +
"update "
- +"events set "
- + COLUMN_NAME_ACT_TS+"=?, "
- + COLUMN_NAME_ACT_USER_ID+"=?, "
- + COLUMN_NAME_ALTERNATE_ACK_SOURCE+"=? "
+ +"events e set "
+ + "e."+COLUMN_NAME_ACT_TS+"=?, "
+ + "e."+COLUMN_NAME_ACT_USER_ID+"=?, "
+ + "e."+COLUMN_NAME_ALTERNATE_ACK_SOURCE+"=? "
+ "where "
- + COLUMN_NAME_ID+"=? and "
- + "("+COLUMN_NAME_ACT_TS+" is null or "+COLUMN_NAME_ACT_TS+" = 0) ";
+ + "e."+COLUMN_NAME_ID+"=? and "
+ + "("+"e."+COLUMN_NAME_ACT_TS+" is null or "+"e."+COLUMN_NAME_ACT_TS+" = 0) ";
+
+ private static final String EVENT_ASSIGN_EVENT ="" +
+ "update "
+ +"events e set "
+ + "e."+COLUMN_NAME_ASSIGNEE_TS +"=?, "
+ + "e."+COLUMN_NAME_ASSIGNEE_USERNAME +"=? "
+ + "where "
+ + "e."+COLUMN_NAME_ID+"=? and "
+ + "("+ "e."+COLUMN_NAME_ASSIGNEE_TS +" is null or "+ "e."+COLUMN_NAME_ASSIGNEE_TS +" = 0) ";
+
+ private static final String EVENT_UNASSIGN_EVENT ="" +
+ "update "
+ +"events e set "
+ + "e."+COLUMN_NAME_ASSIGNEE_TS +"=null, "
+ + "e."+COLUMN_NAME_ASSIGNEE_USERNAME +"=null "
+ + "where "
+ + "e."+COLUMN_NAME_ID+"=? ";
private static final String EVENT_ACT_ALL ="" +
"update "
- +" events set "
- + COLUMN_NAME_ACT_TS+"=?, "
- + COLUMN_NAME_ACT_USER_ID+"=?, "
- + COLUMN_NAME_ALTERNATE_ACK_SOURCE+"=? "
+ +" events e set "
+ + "e."+COLUMN_NAME_ACT_TS+"=?, "
+ + "e."+COLUMN_NAME_ACT_USER_ID+"=?, "
+ + "e."+COLUMN_NAME_ALTERNATE_ACK_SOURCE+"=? "
+ "where "
- + "("+COLUMN_NAME_ACT_TS+" is null or "+COLUMN_NAME_ACT_TS+" = 0) ";
+ + "("+"e."+COLUMN_NAME_ACT_TS+" is null or "+"e."+COLUMN_NAME_ACT_TS+" = 0) ";
private static final String EVENT_SILENCE_ALL ="" +
"UPDATE "
- + "userEvents SET "
- + COLUMN_NAME_ALARM_SILENCED+"='Y' "
- + "WHERE userId=? ";
+ + "userEvents ue SET "
+ + "ue."+COLUMN_NAME_ALARM_SILENCED+"='Y' "
+ + "WHERE ue." + COLUMN_NAME_USER_ID + "=? ";
private static final String EVENT_ACT_IDS ="" +
"update "
- +"events set "
- + COLUMN_NAME_ACT_TS+"=?, "
- + COLUMN_NAME_ACT_USER_ID+"=?, "
- + COLUMN_NAME_ALTERNATE_ACK_SOURCE+"=? "
+ +"events e set "
+ + "e."+COLUMN_NAME_ACT_TS+"=?, "
+ + "e."+COLUMN_NAME_ACT_USER_ID+"=?, "
+ + "e."+COLUMN_NAME_ALTERNATE_ACK_SOURCE+"=? "
+ "where "
- + COLUMN_NAME_ID+" rlike ? and "
- + "("+COLUMN_NAME_ACT_TS+" is null or "+COLUMN_NAME_ACT_TS+" = 0) ";
+ + "e."+COLUMN_NAME_ID+" rlike ? and "
+ + "("+"e."+COLUMN_NAME_ACT_TS+" is null or "+"e."+COLUMN_NAME_ACT_TS+" = 0) ";
public static final String EVENT_FILTER_ACTIVE=" "
+"e."+ COLUMN_NAME_RTN_APPLICABLE+"=? and (e."+ COLUMN_NAME_RTN_TS+" is null or e."+COLUMN_NAME_RTN_TS+"=0)";
@@ -278,7 +300,9 @@ public class EventDAO implements GenericDaoCR {
+ "e."+COLUMN_NAME_ACT_USER_ID+", "
+ "u."+COLUMN_NAME_USER_NAME+","
+ "e."+COLUMN_NAME_ALTERNATE_ACK_SOURCE+", "
- + "ue."+COLUMN_NAME_SILENCED+" "
+ + "ue."+COLUMN_NAME_SILENCED+", "
+ + "e."+ COLUMN_NAME_ASSIGNEE_TS +", "
+ + "e."+ COLUMN_NAME_ASSIGNEE_USERNAME +" "
+ "from "
+ "events e "
+ "left join users u on e."+COLUMN_NAME_ACT_USER_ID+"=u.id "
@@ -328,10 +352,10 @@ public class EventDAO implements GenericDaoCR {
+"order by uc."+COLUMN_NAME_TIME_STAMP;
private static final String EVENT_DELETE_BEFORE= ""
- +"delete from events "
- + "where "+COLUMN_NAME_ACTIVE_TS+" "
- + " and "+COLUMN_NAME_ACT_TS+" is not null "
- + " and ("+COLUMN_NAME_RTN_APPLICABLE+"=? or ("+COLUMN_NAME_RTN_APPLICABLE+"=? and "+COLUMN_NAME_ACT_TS+" is not null))";
+ +"delete from events e "
+ + "where "+"e."+COLUMN_NAME_ACTIVE_TS+" "
+ + " and "+"e."+COLUMN_NAME_ACT_TS+" is not null "
+ + " and ("+"e."+COLUMN_NAME_RTN_APPLICABLE+"=? or ("+"e."+COLUMN_NAME_RTN_APPLICABLE+"=? and "+"e."+COLUMN_NAME_ACT_TS+" is not null))";
private static final String COUNT_EVENT=""
+"select "
@@ -474,7 +498,8 @@ public class EventDAO implements GenericDaoCR {
"e." + COLUMN_NAME_MESSAGE + ", " +
"e." + COLUMN_NAME_ACT_TS + ", " +
"u." + COLUMN_NAME_USER_NAME + ", " +
- "e." + COLUMN_NAME_ALTERNATE_ACK_SOURCE + " " +
+ "e." + COLUMN_NAME_ALTERNATE_ACK_SOURCE+", " +
+ "e."+ COLUMN_NAME_ASSIGNEE_TS +" "+
"FROM events e " +
"LEFT JOIN users u ON u.id=e.ackUserId " +
"WHERE typeId=? AND typeRef1=? " +
@@ -495,7 +520,8 @@ public class EventDAO implements GenericDaoCR {
"e." + COLUMN_NAME_MESSAGE + ", " +
"e." + COLUMN_NAME_ACT_TS + ", " +
"u." + COLUMN_NAME_USER_NAME + ", " +
- "e." + COLUMN_NAME_ALTERNATE_ACK_SOURCE + " " +
+ "e." + COLUMN_NAME_ALTERNATE_ACK_SOURCE + ", " +
+ "e." + COLUMN_NAME_ASSIGNEE_TS + " " +
"FROM events e " +
"LEFT JOIN users u ON u.id=e.ackUserId " +
"WHERE typeId=? AND typeRef1=? " +
@@ -516,6 +542,17 @@ public class EventDAO implements GenericDaoCR {
private static final String STATUS_ACTIVE_CONDITION_SQL = "e.rtnApplicable='Y' and (e.rtnTs is null or e.rtnTs = 0)";
private static final String STATUS_RTN_CONDITION_SQL = "e.rtnApplicable='Y' and (e.rtnTs is not null and e.rtnTs <> 0)";
private static final String STATUS_NORTN_CONDITION_SQL = "e.rtnApplicable='N'";
+ private static final String STATUS_ASSIGNEE_CONDITION_SQL = "(e."+ COLUMN_NAME_ASSIGNEE_TS+" is not null and e."+COLUMN_NAME_ASSIGNEE_TS+" <> 0)";
+
+ private static final String STATUS_NO_ACTIVE_CONDITION_SQL = "(e.rtnApplicable='N' or (e.rtnTs is not null and e.rtnTs <> 0))";
+
+ private static final String UNASSIGN_EVENT_ALL ="" +
+ "update "
+ +"events e set "
+ + "e." + COLUMN_NAME_ASSIGNEE_TS +"=null, "
+ + "e." + COLUMN_NAME_ASSIGNEE_USERNAME +"=null "
+ + "where "
+ + STATUS_ACTIVE_CONDITION_SQL;
// @formatter:on
@@ -595,6 +632,12 @@ public EventInstance mapRow(ResultSet rs, int rowNum) throws SQLException {
event.setAcknowledgedByUsername(rs.getString(COLUMN_NAME_USER_NAME));
event.setAlternateAckSource(rs.getInt(COLUMN_NAME_ALTERNATE_ACK_SOURCE));
}
+ long assigneeTs = rs.getLong(COLUMN_NAME_ASSIGNEE_TS);
+
+ if (!rs.wasNull()) {
+ event.setAssigneeTimestamp(assigneeTs);
+ event.setAssigneeUsername(rs.getString(COLUMN_NAME_ASSIGNEE_USERNAME));
+ }
return event;
@@ -809,6 +852,8 @@ public SQLPageWithTotal findEvents(
filterCondtions.add("e.rtnTs > 0");
} else if (EventsDwr.STATUS_NORTN.equals(query.getStatus())) {
filterCondtions.add("e.rtnApplicable='N'");
+ } else if (EventsDwr.STATUS_ASSIGNEE.equals(query.getStatus())) {
+ filterCondtions.add(STATUS_ASSIGNEE_CONDITION_SQL);
}
List userCommentKeywordConditions = new ArrayList();
@@ -965,22 +1010,27 @@ public void updateAck(long actTS, long userId, int alternateAckSource, long even
}
- public void ackAllPending(long actTS, long userId, int alternateAckSource) {
+ public void ackEvents(long actTS, long userId, int alternateAckSource) {
if (LOG.isTraceEnabled()) {
LOG.trace("actTS:"+actTS+" userId:"+userId+" alternateAckSource:"+alternateAckSource);
}
- DAO.getInstance().getJdbcTemp().update( EVENT_ACT_ALL, new Object[] { actTS, userId, alternateAckSource } );
+ DAO.getInstance().getJdbcTemp().update( EVENT_ACT_ALL + "and " + STATUS_NO_ACTIVE_CONDITION_SQL, new Object[] { actTS, userId, alternateAckSource } );
}
- public void silenceAll(long userId) {
+ public void silenceEvents(long userId) {
if (LOG.isTraceEnabled()) {
LOG.trace(" userId:"+userId);
}
DAO.getInstance().getJdbcTemp().update( EVENT_SILENCE_ALL, new Object[] { userId } );
}
-
+ public void unassignEvents() {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace(" unassignEvents");
+ }
+ DAO.getInstance().getJdbcTemp().update(UNASSIGN_EVENT_ALL, new Object[] {} );
+ }
public void ackAllPendingSelected(long actTS, long userId, int alternateAckSource, List ids) {
if (LOG.isTraceEnabled()) {
@@ -1090,6 +1140,8 @@ public List searchOld(int eventId, int eventSourceType, String st
where.add(STATUS_RTN_CONDITION_SQL);
} else if (EventsDwr.STATUS_NORTN.equals(status)) {
where.add(STATUS_NORTN_CONDITION_SQL);
+ } else if (EventsDwr.STATUS_ASSIGNEE.equals(status)) {
+ where.add(STATUS_ASSIGNEE_CONDITION_SQL);
}
if (alarmLevel != -1) {
@@ -1194,6 +1246,8 @@ public List search(int eventId, int eventSourceType,
where.add(STATUS_RTN_CONDITION_SQL);
} else if (EventsDwr.STATUS_NORTN.equals(status)) {
where.add(STATUS_NORTN_CONDITION_SQL);
+ } else if (EventsDwr.STATUS_ASSIGNEE.equals(status)) {
+ where.add(STATUS_ASSIGNEE_CONDITION_SQL);
}
if (alarmLevel != -1) {
@@ -1481,4 +1535,38 @@ public String joinOr(List conditions) {
}
return result.toString();
}
+
+ public boolean isSilence(int eventId, int userId) {
+ String result = null;
+ try {
+ result = DAO.getInstance().getJdbcTemp().queryForObject(SILENCED_SELECT, new Object[]{eventId, userId}, String.class);
+ } catch (Exception ex) {
+ LOG.warn(ex);
+ }
+ if (result == null) {
+ return true;
+ } else {
+ return DAO.charToBool(result);
+ }
+ }
+
+ public boolean assign(long eventId, long acceptTs, User user) {
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("acceptTs:"+acceptTs+" username:"+user.getUsername()+" eventId:"+eventId);
+ }
+
+ int updates = DAO.getInstance().getJdbcTemp().update(EVENT_ASSIGN_EVENT, new Object[] { acceptTs, user.getUsername(), eventId } );
+ return updates > 0;
+ }
+
+ public boolean unassign(long eventId) {
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("eventId:"+eventId);
+ }
+
+ int updates = DAO.getInstance().getJdbcTemp().update(EVENT_UNASSIGN_EVENT, new Object[] { eventId } );
+ return updates > 0;
+ }
}
diff --git a/src/org/scada_lts/dao/migration/mysql/V2_8_0__AddAssigneeColumnsToEvents.java b/src/org/scada_lts/dao/migration/mysql/V2_8_0__AddAssigneeColumnsToEvents.java
new file mode 100644
index 0000000000..74c5412114
--- /dev/null
+++ b/src/org/scada_lts/dao/migration/mysql/V2_8_0__AddAssigneeColumnsToEvents.java
@@ -0,0 +1,71 @@
+package org.scada_lts.dao.migration.mysql;
+
+import com.serotonin.mango.view.View;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.flywaydb.core.api.migration.BaseJavaMigration;
+import org.flywaydb.core.api.migration.Context;
+import org.scada_lts.dao.DAO;
+import org.scada_lts.dao.SerializationData;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.util.List;
+import java.util.Objects;
+
+public class V2_8_0__AddAssigneeColumnsToEvents extends BaseJavaMigration {
+
+ private static final Log LOG = LogFactory.getLog(V2_8_0__AddAssigneeColumnsToEvents.class);
+
+ @Override
+ public void migrate(Context context) throws Exception {
+
+ final JdbcTemplate jdbcTmp = DAO.getInstance().getJdbcTemp();
+
+ try {
+ addAssigneeColumn(jdbcTmp);
+ updateViewComponents(jdbcTmp);
+ } catch (Exception ex) {
+ LOG.error(ex.getMessage(), ex);
+ throw ex;
+ }
+ }
+
+ private void addAssigneeColumn(JdbcTemplate jdbcTmp) {
+
+ boolean existsAssigneeTsColumn = jdbcTmp.queryForObject("SELECT (SELECT `TABLE_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA`= DATABASE() AND `TABLE_NAME`='events' AND `COLUMN_NAME`='assigneeTs') IS NOT NULL;", boolean.class);
+ boolean existsAssigneeUsernameColumn = jdbcTmp.queryForObject("SELECT (SELECT `TABLE_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA`= DATABASE() AND `TABLE_NAME`='events' AND `COLUMN_NAME`='assigneeUsername') IS NOT NULL;", boolean.class);
+
+ if(!existsAssigneeTsColumn)
+ jdbcTmp.update("ALTER TABLE events ADD COLUMN assigneeTs bigint DEFAULT NULL;");
+
+ if(!existsAssigneeUsernameColumn)
+ jdbcTmp.update("ALTER TABLE events ADD COLUMN assigneeUsername VARCHAR(40) DEFAULT NULL;");
+ }
+
+ private void updateViewComponents(JdbcTemplate jdbcTmp) {
+ List views = jdbcTmp.query("SELECT id, data FROM mangoViews", (resultSet, i) -> {
+ try (InputStream inputStream = resultSet.getBinaryStream("data");
+ ObjectInputStream objectInputStream = new ObjectInputStream(inputStream)) {
+ View view = (View) objectInputStream.readObject();
+ view.setId(resultSet.getInt("id"));
+ return view;
+ } catch (IOException | ClassNotFoundException ex) {
+ LOG.error(ex.getMessage(), ex);
+ return null;
+ }
+ });
+
+ boolean isNull = views.stream().anyMatch(Objects::isNull);
+ if (isNull) {
+ throw new IllegalStateException("View is null!");
+ }
+
+ for (View view : views) {
+ jdbcTmp.update("UPDATE mangoViews set data = ? WHERE id = ?",
+ new SerializationData().writeObject(view), view.getId());
+ }
+ }
+}
diff --git a/src/org/scada_lts/login/LoggedUsers.java b/src/org/scada_lts/login/LoggedUsers.java
index 6f67fe10c8..71b8913652 100644
--- a/src/org/scada_lts/login/LoggedUsers.java
+++ b/src/org/scada_lts/login/LoggedUsers.java
@@ -19,21 +19,16 @@ public class LoggedUsers implements ILoggedUsers {
private static final Log LOG = LogFactory.getLog(LoggedUsers.class);
- public LoggedUsers() {}
-
private final Map loggedUsers = new ConcurrentHashMap<>();
private final Map> loggedSessions = new ConcurrentHashMap<>();
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
- private final ThreadLocal blocked = new ThreadLocal<>();
+
+ public LoggedUsers() {}
@Override
public User addUser(User user, HttpSession session) {
lock.writeLock().lock();
try {
- if("setAttribute".equals(blocked.get())) {
- LOG.warn("blocked addUser: " + LoggingUtils.userInfo(user) + ", thread: " + Thread.currentThread().getName());
- return null;
- }
loggedSessions.putIfAbsent(user.getId(), new CopyOnWriteArrayList<>());
if(!loggedSessions.get(user.getId()).contains(session)) {
loggedSessions.get(user.getId()).add(session);
@@ -50,7 +45,7 @@ public User addUser(User user, HttpSession session) {
public void updateUser(User user) {
lock.writeLock().lock();
try {
- update(user, loggedUsers, loggedSessions, blocked);
+ update(user, loggedUsers, loggedSessions);
} finally {
lock.writeLock().unlock();
}
@@ -63,7 +58,7 @@ public void updateUsers(UsersProfileVO profile) {
for(User user: new ArrayList<>(loggedUsers.values())) {
if(user.getUserProfile() == profile.getId()) {
profile.apply(user);
- update(user, loggedUsers, loggedSessions, blocked);
+ update(user, loggedUsers, loggedSessions);
}
}
} finally {
@@ -75,10 +70,6 @@ public void updateUsers(UsersProfileVO profile) {
public User removeUser(User user, HttpSession session) {
lock.writeLock().lock();
try {
- if("setAttribute".equals(blocked.get())) {
- LOG.warn("blocked removeUser: " + LoggingUtils.userInfo(user) + ", thread: " + Thread.currentThread().getName());
- return null;
- }
if (loggedSessions.get(user.getId()) == null || (loggedSessions.get(user.getId()).remove(session)
&& loggedSessions.get(user.getId()).isEmpty())) {
loggedSessions.remove(user.getId());
@@ -121,8 +112,7 @@ public User getUser(int id) {
}
private static void update(User user, Map loggedUsers,
- Map> loggedSessions,
- ThreadLocal blocked) {
+ Map> loggedSessions) {
User loggedUser = loggedUsers.get(user.getId());
if(loggedUser == null) {
LOG.warn("not logged user: " + LoggingUtils.userInfo(user) + ", thread: " + Thread.currentThread().getName());
@@ -133,9 +123,7 @@ private static void update(User user, Map loggedUsers,
user.setAttribute("roles", roles);
loggedSessions.putIfAbsent(user.getId(), new CopyOnWriteArrayList<>());
for(HttpSession session : loggedSessions.get(user.getId())) {
- blocked.set("setAttribute");
session.setAttribute(SESSION_USER, user);
- blocked.set("");
}
loggedUsers.put(user.getId(), user);
}
diff --git a/src/org/scada_lts/mango/adapter/MangoEvent.java b/src/org/scada_lts/mango/adapter/MangoEvent.java
index cab5948e6e..253c35b240 100644
--- a/src/org/scada_lts/mango/adapter/MangoEvent.java
+++ b/src/org/scada_lts/mango/adapter/MangoEvent.java
@@ -24,6 +24,7 @@
import com.serotonin.mango.rt.event.EventInstance;
import com.serotonin.mango.rt.event.type.EventType;
+import com.serotonin.mango.vo.User;
import com.serotonin.mango.vo.UserComment;
import com.serotonin.mango.vo.event.EventHandlerVO;
import com.serotonin.mango.vo.event.EventTypeVO;
@@ -37,9 +38,11 @@
public interface MangoEvent {
void saveEvent(EventInstance event);
-
+
+ @Deprecated(since = "2.8.0")
void ackEvent(int eventId, long time, int userId, int alternateAckSource, boolean signalAlarmLevelChange);
-
+
+ @Deprecated(since = "2.8.0")
void ackEvent(int eventId, long time, int userId, int alternateAckSource);
void silenceEvent(int eventId, int userId);
@@ -50,8 +53,10 @@ public interface MangoEvent {
void unsilenceEvents(List eventIds, int userId);
+ @Deprecated(since = "2.8.0")
void ackAllPending(long time, int userId, int alternateAckSource);
+ @Deprecated(since = "2.8.0")
void silenceAll(int userId);
void ackSelected(long time, int userId, int alternateAckSource, List ids);
@@ -116,9 +121,10 @@ public interface MangoEvent {
void updateEventHandler(EventHandlerVO handler);
void deleteEventHandler(final int handlerId);
-
+
+ @Deprecated(since = "2.8.0")
boolean toggleSilence(int eventId, int userId);
-
+
int getHighestUnsilencedAlarmLevel(int userId);
EventInstance getEvent(int eventId);
@@ -128,4 +134,15 @@ public interface MangoEvent {
boolean isXidUnique(String xid, int excludeId);
List getPendingEventsAlarmLevelMin(int userId, int alarmLevelMin, int limit);
+
+ boolean toggleSilence(EventInstance event, User user);
+
+ boolean assignEvent(EventInstance event, User user);
+ boolean unassignEvent(EventInstance event, User user);
+
+ void ackEvent(EventInstance event, long time, User user, int alternateAckSource, boolean signalAlarmLevelChange);
+ void ackEvent(EventInstance event, long time, User user, int alternateAckSource);
+ void unassignEvents();
+ void ackEvents(User user);
+ List silenceEvents(User user);
}
diff --git a/src/org/scada_lts/mango/service/EventService.java b/src/org/scada_lts/mango/service/EventService.java
index 25b53c9222..306b4e795d 100644
--- a/src/org/scada_lts/mango/service/EventService.java
+++ b/src/org/scada_lts/mango/service/EventService.java
@@ -24,12 +24,15 @@
import com.serotonin.mango.rt.event.type.AuditEventType;
import com.serotonin.mango.rt.event.type.AuditEventUtils;
import com.serotonin.mango.rt.event.type.EventType;
+import com.serotonin.mango.rt.event.type.SystemEventType;
import com.serotonin.mango.rt.maint.work.AbstractBeforeAfterWorkItem;
import com.serotonin.mango.rt.maint.work.WorkItemPriority;
+import com.serotonin.mango.util.LoggingUtils;
import com.serotonin.mango.vo.User;
import com.serotonin.mango.vo.UserComment;
import com.serotonin.mango.vo.event.EventHandlerVO;
import com.serotonin.mango.vo.event.EventTypeVO;
+import com.serotonin.web.i18n.LocalizableMessage;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.scada_lts.cache.PendingEventsCache;
@@ -135,13 +138,15 @@ public void saveEvent(EventInstance event) {
updateCache(event);
}
}
-
+
+ @Deprecated(since = "2.8.0")
@Transactional(readOnly = false,propagation= Propagation.REQUIRES_NEW,isolation= Isolation.READ_COMMITTED,rollbackFor=SQLException.class)
@Override
public void ackEvent(int eventId, long time, int userId, int alternateAckSource, boolean signalAlarmLevelChange) {
_ackEvent(eventId, time, userId, alternateAckSource, signalAlarmLevelChange);
}
+ @Deprecated(since = "2.8.0")
@Transactional(readOnly = false,propagation= Propagation.REQUIRES_NEW,isolation= Isolation.READ_COMMITTED,rollbackFor=SQLException.class)
@Override
public void ackEvent(int eventId, long time, int userId, int alternateAckSource) {
@@ -170,12 +175,18 @@ public void unsilenceEvents(List eventIds, int userId) {
@Override
public void ackAllPending(long time, int userId, int alternateAckSource) {
- eventDAO.ackAllPending(time, userId, alternateAckSource);
+ MangoEvent eventService = new EventService();
+ UserService userEvent = new UserService();
+ User user = userEvent.getUser(userId);
+ for (EventInstance evt : eventService.getPendingEvents(user.getId())) {
+ if(!evt.isActive())
+ eventService.ackEvent(evt, time, user, alternateAckSource);
+ }
}
@Override
public void silenceAll(int userId) {
- eventDAO.silenceAll(userId);
+ eventDAO.silenceEvents(userId);
}
@Override
@@ -310,7 +321,7 @@ public EventInstance insertEventComment(int eventId, UserComment comment) {
@Override
public int purgeEventsBefore(long time) {
int result = eventDAO.purgeEventsBefore(time);
- Common.ctx.getEventManager().resetHighestAlarmLevels();
+ Common.ctx.getEventManager().notifyEventReset();
return result;
}
@@ -424,6 +435,7 @@ public void deleteEventHandler(final String handlerXid) {
}
@Override
+ @Deprecated(since = "2.8.0")
public boolean toggleSilence(int eventId, int userId) {
boolean updated = eventDAO.toggleSilence(eventId, userId, false);
if (updated) {
@@ -550,6 +562,7 @@ public SQLPageWithTotal getEventsWithLimit(JsonEventSearch query, User
return eventDAO.findEvents(query, user);
}
+ @Deprecated(since = "2.8.0")
private void notifyEventAck(int eventId) {
Common.ctx.getEventManager().notifyEventAck(eventId);
}
@@ -568,6 +581,7 @@ public boolean isXidUnique(String xid, int excludeId) {
return DAO.getInstance().isXidUnique(xid, excludeId, "eventHandlers");
}
+ @Deprecated(since = "2.8.0")
private void _ackEvent(int eventId, long time, int userId, int alternateAckSource, boolean signalAlarmLevelChange) {
eventDAO.updateAck(time, userId, alternateAckSource, eventId);
// true silenced
@@ -576,4 +590,128 @@ private void _ackEvent(int eventId, long time, int userId, int alternateAckSourc
clearCache();
notifyEventAck(eventId);
}
+
+ @Override
+ public boolean toggleSilence(EventInstance event, User user) {
+ boolean updated = eventDAO.toggleSilence(event.getId(), user.getId(), true);
+ if (updated) {
+ Common.ctx.getEventManager().setLastAlarmTimestamp(System.currentTimeMillis());
+ Common.ctx.getEventManager().notifyEventToggle(event, user);
+ } else if(!event.isAssignee()) {
+ Common.ctx.getEventManager().notifyEventRaise(event, user);
+ }
+ return updated;
+ }
+
+ @Transactional(readOnly = false,propagation= Propagation.REQUIRES_NEW,isolation= Isolation.READ_COMMITTED,rollbackFor=SQLException.class)
+ @Override
+ public void ackEvent(EventInstance event, long time, User user, int alternateAckSource, boolean signalAlarmLevelChange) {
+ _ackEvent(event, time, user, alternateAckSource, signalAlarmLevelChange);
+ }
+
+ @Transactional(readOnly = false,propagation= Propagation.REQUIRES_NEW,isolation= Isolation.READ_COMMITTED,rollbackFor=SQLException.class)
+ @Override
+ public void ackEvent(EventInstance event, long time, User user, int alternateAckSource) {
+ _ackEvent(event, time, user, alternateAckSource, true);
+ }
+
+ @Override
+ public boolean assignEvent(EventInstance event, User user) {
+ if(!isAssignPermission(event, user)) {
+ return false;
+ }
+ long time = System.currentTimeMillis();
+ boolean updated = eventDAO.assign(event.getId(), time, user);
+ if (updated) {
+ Common.ctx.getEventManager().setLastAlarmTimestamp(time);
+ Common.ctx.getEventManager().notifyEventAssignee(event);
+ removeUserIdFromCache(user.getId());
+ SystemEventType.raiseEvent(new SystemEventType(SystemEventType.TYPE_ASSIGNED_EVENT), time, false,
+ new LocalizableMessage("events.assignedBy", LoggingUtils.userInfo(user), LoggingUtils.eventInfo(event)));
+ } else {
+ Common.ctx.getEventManager().notifyEventRaise(event);
+ }
+ return updated;
+ }
+
+ @Override
+ public boolean unassignEvent(EventInstance event, User user) {
+ if(!isAssignPermission(event, user)) {
+ return false;
+ }
+ long time = System.currentTimeMillis();
+ boolean updated = eventDAO.unassign(event.getId());
+ if (updated) {
+ Common.ctx.getEventManager().setLastAlarmTimestamp(time);
+ removeUserIdFromCache(user.getId());
+ SystemEventType.raiseEvent(new SystemEventType(SystemEventType.TYPE_UNASSIGNED_EVENT), time, false,
+ new LocalizableMessage("events.unassignedBy", event.getAssigneeUsername(), LoggingUtils.userInfo(user),
+ LoggingUtils.eventInfo(event)));
+ }
+ boolean silence = eventDAO.isSilence(event.getId(), user.getId());
+ if(!silence) {
+ Common.ctx.getEventManager().notifyEventRaise(event);
+ }
+ return updated;
+ }
+
+ @Override
+ public void unassignEvents() {
+ eventDAO.unassignEvents();
+ Common.ctx.getEventManager().notifyEventReset();
+ }
+
+ @Override
+ public void ackEvents(User user) {
+ long now = System.currentTimeMillis();
+ if(user.isAdmin()) {
+ eventDAO.ackEvents(now, user.getId(), 0);
+ clearCache();
+ Common.ctx.getEventManager().notifyEventReset();
+ } else {
+ for (EventInstance evt : getPendingEvents(user.getId())) {
+ if(!evt.isActive())
+ ackEvent(evt, now, user, 0);
+ }
+ }
+ }
+
+ @Override
+ public List silenceEvents(User user) {
+ List silenced = new ArrayList<>();
+ if(user.isAdmin()) {
+ eventDAO.silenceEvents(user.getId());
+ clearCache();
+ Common.ctx.getEventManager().notifyEventReset();
+ } else {
+ for (EventInstance evt : getPendingEvents(user.getId())) {
+ if (!evt.isSilenced()) {
+ toggleSilence(evt, user);
+ silenced.add(evt.getId());
+ }
+ }
+ }
+ return silenced;
+ }
+
+ private static boolean isAssignPermission(EventInstance event, User user) {
+ return !event.isAssignee() || (user.isAdmin() || Objects.equals(user.getUsername(), event.getAssigneeUsername()));
+ }
+
+ private void notifyEventAck(EventInstance event) {
+ Common.ctx.getEventManager().notifyEventAck(event);
+ }
+
+ private void _ackEvent(EventInstance event, long time, User user, int alternateAckSource, boolean signalAlarmLevelChange) {
+ if(event.isActive()) {
+ LOG.warn("Event is active! This event cannot be acknowledged.");
+ return;
+ }
+ eventDAO.updateAck(time, user.getId(), alternateAckSource, event.getId());
+ // true silenced
+ userEventDAO.updateAck(event.getId(), true);
+
+ clearCache();
+ notifyEventAck(event);
+ }
}
diff --git a/src/org/scada_lts/mango/service/PendingEventService.java b/src/org/scada_lts/mango/service/PendingEventService.java
index ea9557399e..cecbf8308b 100644
--- a/src/org/scada_lts/mango/service/PendingEventService.java
+++ b/src/org/scada_lts/mango/service/PendingEventService.java
@@ -20,7 +20,6 @@
import com.serotonin.mango.rt.event.type.AlarmLevelType;
import com.serotonin.mango.rt.event.EventInstance;
-import org.scada_lts.login.ILoggedUsers;
import com.serotonin.mango.vo.User;
import com.serotonin.mango.vo.UserComment;
import org.apache.commons.logging.Log;
@@ -48,45 +47,44 @@ public class PendingEventService {
private final SystemSettingsService systemSettingsService;
private final IHighestAlarmLevelService highestAlarmLevelService;
- private final ILoggedUsers loggedUsers;
public PendingEventService() {
userCommentDAO = ApplicationBeans.getUserCommentDaoBean();
highestAlarmLevelService = ApplicationBeans.getHighestAlarmLevelServiceBean();
- loggedUsers = ApplicationBeans.getLoggedUsersBean();
pendingEventsDAO = new PendingEventsDAO();
systemSettingsService = new SystemSettingsService();
}
public Map> getPendingEvents() {
-
- Set users = loggedUsers.getUserIds();
- Map> comments = getCacheUserComments(userCommentDAO.getEventComments());
- int limit = systemSettingsService.getMiscSettings().getEventPendingLimit();
-
- Map> cacheEvents = new ConcurrentHashMap<>();
- for (int userId: users) {
- Set events = pendingEventsDAO.getPendingEvents(userId, comments, AlarmLevelType.NONE,
- SystemSettingsUtils.getEventPendingUpdateLimit(), 0).stream()
- .map(EventInstanceEqualsById::new)
- .collect(Collectors.toSet());
- if(!events.isEmpty()) {
- int highestAlarmLevelForUser = highestAlarmLevelService.getAlarmLevel(User.onlyId(userId));
- for (AlarmLevelType alarmLevelType : AlarmLevelType.getAlarmLevelsWithoutNone()) {
- if(alarmLevelType.getCode() <= highestAlarmLevelForUser) {
- long count = events.stream()
- .filter(a -> a.getEventInstance().getAlarmLevel() >= alarmLevelType.getCode())
- .count();
- if (count < limit) {
- events.addAll(pendingEventsDAO.getPendingEvents(userId, comments, alarmLevelType, limit, 0).stream()
- .map(EventInstanceEqualsById::new)
- .collect(Collectors.toSet()));
+ Map> cacheEvents = new ConcurrentHashMap<>();
+ ApplicationBeans.Lazy.getLoggedUsersBean().ifPresent(loggedUsers -> {
+ Set users = loggedUsers.getUserIds();
+ Map> comments = getCacheUserComments(userCommentDAO.getEventComments());
+ int limit = systemSettingsService.getMiscSettings().getEventPendingLimit();
+ for (int userId: users) {
+ Set events = pendingEventsDAO.getPendingEvents(userId, comments, AlarmLevelType.NONE,
+ SystemSettingsUtils.getEventPendingUpdateLimit(), 0).stream()
+ .map(EventInstanceEqualsById::new)
+ .collect(Collectors.toSet());
+ if(!events.isEmpty()) {
+ int highestAlarmLevelForUser = highestAlarmLevelService.getAlarmLevel(User.onlyId(userId));
+ for (AlarmLevelType alarmLevelType : AlarmLevelType.getAlarmLevelsWithoutNone()) {
+ if(alarmLevelType.getCode() <= highestAlarmLevelForUser) {
+ long count = events.stream()
+ .filter(a -> a.getEventInstance().getAlarmLevel() >= alarmLevelType.getCode())
+ .count();
+ if (count < limit) {
+ events.addAll(pendingEventsDAO.getPendingEvents(userId, comments, alarmLevelType, limit, 0).stream()
+ .map(EventInstanceEqualsById::new)
+ .collect(Collectors.toSet()));
+ }
}
}
}
+ cacheEvents.put(userId, events.stream().map(EventInstanceEqualsById::getEventInstance).collect(Collectors.toList()));
}
- cacheEvents.put(userId, events.stream().map(EventInstanceEqualsById::getEventInstance).collect(Collectors.toList()));
- }
+ });
+
return cacheEvents;
}
diff --git a/src/org/scada_lts/mango/service/SystemSettingsService.java b/src/org/scada_lts/mango/service/SystemSettingsService.java
index 8498b0dac6..ad1530bbc2 100644
--- a/src/org/scada_lts/mango/service/SystemSettingsService.java
+++ b/src/org/scada_lts/mango/service/SystemSettingsService.java
@@ -24,6 +24,7 @@
import org.scada_lts.utils.SystemSettingsUtils;
import org.scada_lts.web.mvc.api.AggregateSettings;
import org.scada_lts.web.mvc.api.json.*;
+import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
@@ -38,6 +39,7 @@
*
* @author Radoslaw Jajko
*/
+@Service
public class SystemSettingsService {
private static final org.apache.commons.logging.Log LOG = LogFactory.getLog(SystemSettingsService.class);
@@ -142,6 +144,7 @@ public JsonSettingsMisc getMiscSettings() {
json.setWorkItemsReportingItemsPerSecondLimit(SystemSettingsDAO.getIntValue(SystemSettingsDAO.WORK_ITEMS_REPORTING_ITEMS_PER_SECOND_LIMIT));
json.setWebResourceGraphicsPath(SystemSettingsDAO.getValue(SystemSettingsDAO.WEB_RESOURCE_GRAPHICS_PATH));
json.setWebResourceUploadsPath(SystemSettingsDAO.getValue(SystemSettingsDAO.WEB_RESOURCE_UPLOADS_PATH));
+ json.setEventAssignEnabled(SystemSettingsDAO.getBooleanValue(SystemSettingsDAO.EVENT_ASSIGN_ENABLED));
return json;
}
@@ -158,6 +161,7 @@ public void saveMiscSettings(JsonSettingsMisc json) {
systemSettingsDAO.setIntValue(SystemSettingsDAO.WORK_ITEMS_REPORTING_ITEMS_PER_SECOND_LIMIT, json.getWorkItemsReportingItemsPerSecondLimit());
systemSettingsDAO.setValue(SystemSettingsDAO.WEB_RESOURCE_GRAPHICS_PATH, json.getWebResourceGraphicsPath());
systemSettingsDAO.setValue(SystemSettingsDAO.WEB_RESOURCE_UPLOADS_PATH, json.getWebResourceUploadsPath());
+ saveEventAssignEnabled(json.isEventAssignEnabled());
}
public SettingsDataRetention getDataRetentionSettings() {
@@ -382,6 +386,14 @@ public void saveAggregateSettings(AggregateSettings aggregateSettings) {
systemSettingsDAO.setValue(SystemSettingsDAO.AGGREGATION_ENABLED, String.valueOf(aggregateSettings.isEnabled()));
}
+ public void saveEventAssignEnabled(boolean eventAssignEnabled) {
+ systemSettingsDAO.setBooleanValue(SystemSettingsDAO.EVENT_ASSIGN_ENABLED, eventAssignEnabled);
+ if(!eventAssignEnabled) {
+ EventService eventService = new EventService();
+ eventService.unassignEvents();
+ }
+ }
+
public DataPointSyncMode getDataPointRtValueSynchronized() {
return SystemSettingsDAO.getObject(SystemSettingsDAO.DATAPOINT_RUNTIME_VALUE_SYNCHRONIZED, DataPointSyncMode::typeOf);
}
@@ -455,6 +467,16 @@ public int getThreadsNameAdditionalLength() {
}
}
+ public boolean isEventAssignEnabled() {
+ boolean defaultValue = SystemSettingsUtils.isEventAssignEnabled();
+ try {
+ return SystemSettingsDAO.getBooleanValue(SystemSettingsDAO.EVENT_ASSIGN_ENABLED, defaultValue);
+ } catch (Exception e) {
+ LOG.error(e.getMessage());
+ return defaultValue;
+ }
+ }
+
private static String getHttpResponseHeaders(JsonSettingsHttp json) {
try {
String httpResponseHeaders = json.getHttpResponseHeaders();
diff --git a/src/org/scada_lts/quartz/ResetCacheHighestAlarmLevel.java b/src/org/scada_lts/quartz/ResetCacheHighestAlarmLevel.java
index ae55f27914..64103ee264 100644
--- a/src/org/scada_lts/quartz/ResetCacheHighestAlarmLevel.java
+++ b/src/org/scada_lts/quartz/ResetCacheHighestAlarmLevel.java
@@ -24,7 +24,6 @@
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.StatefulJob;
-import org.scada_lts.mango.service.UserService;
import org.scada_lts.service.IHighestAlarmLevelService;
import org.scada_lts.web.beans.ApplicationBeans;
import org.scada_lts.web.ws.services.UserEventServiceWebSocket;
@@ -42,18 +41,16 @@ public class ResetCacheHighestAlarmLevel implements StatefulJob {
private final IHighestAlarmLevelService highestAlarmLevelService;
private final UserEventServiceWebSocket userEventServiceWebSocket;
- private final UserService userService;
public ResetCacheHighestAlarmLevel() {
this.highestAlarmLevelService = ApplicationBeans.getHighestAlarmLevelServiceBean();
- this.userService = new UserService();
this.userEventServiceWebSocket = ApplicationBeans.getUserEventServiceWebsocketBean();
}
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
long time = System.currentTimeMillis();
- NotifyEventUtils.resetHighestAlarmLevels(highestAlarmLevelService, userService, userEventServiceWebSocket);
+ NotifyEventUtils.notifyEventReset(highestAlarmLevelService, userEventServiceWebSocket);
LOG.info(ResetCacheHighestAlarmLevel.class.getSimpleName() + " executed in [" + (System.currentTimeMillis() - time)+ "] ms");
}
}
diff --git a/src/org/scada_lts/service/HighestAlarmLevelService.java b/src/org/scada_lts/service/HighestAlarmLevelService.java
index ee3a86459b..0fc8ab55fb 100644
--- a/src/org/scada_lts/service/HighestAlarmLevelService.java
+++ b/src/org/scada_lts/service/HighestAlarmLevelService.java
@@ -4,8 +4,7 @@
import com.serotonin.mango.vo.User;
import org.scada_lts.dao.IHighestAlarmLevelDAO;
import org.scada_lts.dao.model.UserAlarmLevel;
-import org.scada_lts.mango.adapter.MangoUser;
-import org.scada_lts.mango.service.UserService;
+import org.scada_lts.web.beans.ApplicationBeans;
import org.scada_lts.web.ws.model.WsAlarmLevelMessage;
import java.util.function.BiConsumer;
@@ -13,11 +12,9 @@
public class HighestAlarmLevelService implements IHighestAlarmLevelService {
private final IHighestAlarmLevelDAO highestAlarmLevelDAO;
- private final MangoUser userService;
public HighestAlarmLevelService(IHighestAlarmLevelDAO highestAlarmLevelDAO) {
this.highestAlarmLevelDAO = highestAlarmLevelDAO;
- this.userService = new UserService();
}
@Override
@@ -57,8 +54,10 @@ public boolean doRemoveAlarmLevel(User user, EventInstance event, BiConsumer