Skip to content

Commit a5fe671

Browse files
Merge 25.7 to develop
2 parents 7f061fc + c4d5b64 commit a5fe671

File tree

2 files changed

+95
-28
lines changed

2 files changed

+95
-28
lines changed

LDK/src/org/labkey/ldk/LDKController.java

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,20 @@
2121
import org.apache.commons.lang3.StringUtils;
2222
import org.apache.logging.log4j.LogManager;
2323
import org.apache.logging.log4j.Logger;
24-
import org.jetbrains.annotations.NotNull;
2524
import org.json.JSONArray;
2625
import org.json.JSONObject;
2726
import org.labkey.api.action.ApiResponse;
2827
import org.labkey.api.action.ApiSimpleResponse;
29-
import org.labkey.api.action.ConfirmAction;
3028
import org.labkey.api.action.ExportAction;
3129
import org.labkey.api.action.HasAllowBindParameter;
3230
import org.labkey.api.action.MutatingApiAction;
3331
import org.labkey.api.action.ReadOnlyApiAction;
34-
import org.labkey.api.action.SimpleErrorView;
3532
import org.labkey.api.action.SimpleViewAction;
3633
import org.labkey.api.action.SpringActionController;
3734
import org.labkey.api.data.Container;
3835
import org.labkey.api.data.ContainerManager;
39-
import org.labkey.api.data.CoreSchema;
40-
import org.labkey.api.data.DbSequenceManager;
4136
import org.labkey.api.data.PropertyManager;
4237
import org.labkey.api.data.PropertyManager.WritablePropertyMap;
43-
import org.labkey.api.data.SqlExecutor;
4438
import org.labkey.api.data.SqlScriptRunner;
4539
import org.labkey.api.data.TableInfo;
4640
import org.labkey.api.ldk.LDKService;
@@ -70,7 +64,7 @@
7064
import org.labkey.api.settings.AppProps;
7165
import org.labkey.api.settings.LookAndFeelProperties;
7266
import org.labkey.api.util.ConfigurationException;
73-
import org.labkey.api.util.GUID;
67+
import org.labkey.api.util.HtmlString;
7468
import org.labkey.api.util.PageFlowUtil;
7569
import org.labkey.api.util.Path;
7670
import org.labkey.api.util.StringUtilsLabKey;
@@ -86,7 +80,6 @@
8680
import org.labkey.ldk.notification.NotificationServiceImpl;
8781
import org.labkey.ldk.sql.LDKNaturalizeInstallationManager;
8882
import org.springframework.validation.BindException;
89-
import org.springframework.validation.Errors;
9083
import org.springframework.web.servlet.ModelAndView;
9184

9285
import java.net.URISyntaxException;
@@ -371,7 +364,7 @@ public ModelAndView getView(RunNotificationForm form, BindException errors) thro
371364

372365
if (!n.isAvailable(getContainer()))
373366
{
374-
return new HtmlView("The notification " + form.getKey() + " is not available in this container");
367+
return new HtmlView(HtmlString.of("The notification " + form.getKey() + " is not available in this container"));
375368
}
376369

377370
_title = n.getName();
@@ -392,7 +385,7 @@ public ModelAndView getView(RunNotificationForm form, BindException errors) thro
392385
sb.append(msg == null ? "The notification did not produce a message" : msg);
393386
}
394387

395-
return new HtmlView(sb.toString());
388+
return new HtmlView(HtmlString.unsafe(sb.toString()));
396389
}
397390

398391
@Override
@@ -448,7 +441,7 @@ public ModelAndView getView(Object form, BindException errors) throws Exception
448441
String sb = "This page is designed to inspect all registered container scoped tables and report any tables with duplicate keys in the same container. This should be enforced by the user schema; however, direct DB inserts will bypass this check.<p>" +
449442
StringUtils.join(messages, "<br>");
450443

451-
return new HtmlView(sb);
444+
return new HtmlView(HtmlString.of(sb));
452445
}
453446

454447
@Override
@@ -520,7 +513,7 @@ public ApiResponse execute(NotificationSettingsForm form, BindException errors)
520513
{
521514
if (form.getEnabled() != null)
522515
{
523-
NotificationServiceImpl.get().setServiceEnabled(form.getEnabled());
516+
NotificationServiceImpl.get().setServiceEnabled(getUser(), form.getEnabled());
524517
}
525518
}
526519

@@ -529,7 +522,7 @@ public ApiResponse execute(NotificationSettingsForm form, BindException errors)
529522
try
530523
{
531524
ValidEmail e = new ValidEmail(form.getReplyEmail());
532-
NotificationServiceImpl.get().setReturnEmail(getContainer(), e.getEmailAddress());
525+
NotificationServiceImpl.get().setReturnEmail(getContainer(), getUser(), e.getEmailAddress());
533526
}
534527
catch (ValidEmail.InvalidEmailException e)
535528
{
@@ -555,7 +548,7 @@ public ApiResponse execute(NotificationSettingsForm form, BindException errors)
555548
return null;
556549
}
557550

558-
NotificationServiceImpl.get().setUser(getContainer(), u.getUserId());
551+
NotificationServiceImpl.get().setUser(getContainer(), getUser(), u.getUserId());
559552
}
560553
catch (ValidEmail.InvalidEmailException e)
561554
{
@@ -576,7 +569,7 @@ public ApiResponse execute(NotificationSettingsForm form, BindException errors)
576569
return null;
577570
}
578571

579-
NotificationServiceImpl.get().setActive(n, getContainer(), notifications.getBoolean(key));
572+
NotificationServiceImpl.get().setActive(n, getContainer(), getUser(), notifications.getBoolean(key));
580573
}
581574
}
582575
}
@@ -904,7 +897,7 @@ public ModelAndView getView(Object form, BindException errors) throws Exception
904897
String urlString = PropertyManager.getProperties(getContainer(), REDIRECT_URL_DOMAIN).get(REDIRECT_URL_PROP);
905898
if (urlString == null)
906899
{
907-
return new HtmlView("This folder is only visible to admins");
900+
return new HtmlView(HtmlString.of("This folder is only visible to admins"));
908901
}
909902
else
910903
{
@@ -919,7 +912,7 @@ public ModelAndView getView(Object form, BindException errors) throws Exception
919912
}
920913
catch (URISyntaxException e)
921914
{
922-
return new HtmlView("Invalid redirect URL set: " + urlString);
915+
return new HtmlView(HtmlString.unsafe("Invalid redirect URL set: " + urlString));
923916
}
924917
}
925918
}

LDK/src/org/labkey/ldk/notification/NotificationServiceImpl.java

Lines changed: 85 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import org.jetbrains.annotations.NotNull;
2727
import org.jetbrains.annotations.Nullable;
2828
import org.json.JSONObject;
29+
import org.labkey.api.audit.AuditLogService;
30+
import org.labkey.api.audit.provider.SiteSettingsAuditProvider.SiteSettingsAuditEvent;
2931
import org.labkey.api.data.CompareType;
3032
import org.labkey.api.data.Container;
3133
import org.labkey.api.data.ContainerManager;
@@ -168,11 +170,19 @@ public boolean isServiceEnabled()
168170
return Boolean.parseBoolean(prop);
169171
}
170172

171-
public void setServiceEnabled(Boolean status)
173+
public void setServiceEnabled(User u, Boolean status)
172174
{
175+
boolean oldStatus = isServiceEnabled();
173176
WritablePropertyMap pm = PropertyManager.getWritableProperties(ContainerManager.getRoot(), NotificationServiceImpl.CONFIG_PROPERTY_DOMAIN, true);
174177
pm.put(ENABLED_PROP, status.toString());
175178
pm.save();
179+
180+
if (status != oldStatus)
181+
{
182+
SiteSettingsAuditEvent event = new SiteSettingsAuditEvent(ContainerManager.getRoot(),
183+
"Notification service has been " + (status ? "enabled" : "disabled") + ".");
184+
AuditLogService.get().addEvent(u, event);
185+
}
176186
}
177187

178188
@Override
@@ -219,17 +229,28 @@ public Address getReturnEmail(Container c)
219229
return email == null ? null : getAddress(email);
220230
}
221231

222-
public void setReturnEmail(Container c, String returnEmail)
232+
public void setReturnEmail(Container c, User u, String returnEmail)
223233
{
224234
try
225235
{
226236
if(returnEmail != null)
227237
{
228238
ValidEmail email = new ValidEmail(returnEmail);
239+
String previous = getConfigProperty(c, RETURN_EMAIL);
229240

230241
WritablePropertyMap pm = PropertyManager.getWritableProperties(c, NotificationServiceImpl.CONFIG_PROPERTY_DOMAIN, true);
231242
pm.put(RETURN_EMAIL, email.getEmailAddress());
232243
pm.save();
244+
245+
if(!returnEmail.equals(previous))
246+
{
247+
SiteSettingsAuditEvent event = new SiteSettingsAuditEvent(c, "Notification reply-to email updated.");
248+
String before = previous == null ? "" : previous;
249+
String after = email.getEmailAddress();
250+
String html = "<table><tr><td class='labkey-form-label'>Reply-to email</td><td>" + PageFlowUtil.filter(before) + "&nbsp;&raquo;&nbsp;" + PageFlowUtil.filter(after) + "</td></tr></table>";
251+
event.setChanges(html);
252+
AuditLogService.get().addEvent(u, event);
253+
}
233254
}
234255
}
235256
catch (ValidEmail.InvalidEmailException e)
@@ -247,13 +268,25 @@ public User getUser(Container c)
247268
return UserManager.getUser(Integer.parseInt(user));
248269
}
249270

250-
public void setUser(Container c, Integer userId)
271+
public void setUser(Container c, User u, Integer userId)
251272
{
252273
if(userId != null)
253274
{
275+
User previousUser = getUser(c);
254276
WritablePropertyMap pm = PropertyManager.getWritableProperties(c, NotificationServiceImpl.CONFIG_PROPERTY_DOMAIN, true);
255277
pm.put(USER_PROP, String.valueOf(userId));
256278
pm.save();
279+
280+
if (previousUser == null || (previousUser.getUserId() != userId))
281+
{
282+
User newUser = UserManager.getUser(userId);
283+
String before = previousUser == null ? "" : previousUser.getEmail();
284+
String after = newUser == null ? "" : newUser.getEmail();
285+
SiteSettingsAuditEvent event = new SiteSettingsAuditEvent(c, "Notification service user updated.");
286+
String html = "<table><tr><td class='labkey-form-label'>Service user</td><td>" + PageFlowUtil.filter(before) + "&nbsp;&raquo;&nbsp;" + PageFlowUtil.filter(after) + "</td></tr></table>";
287+
event.setChanges(html);
288+
AuditLogService.get().addEvent(u, event);
289+
}
257290
}
258291
}
259292

@@ -362,11 +395,20 @@ public boolean isActive(Notification n, Container c)
362395
return false;
363396
}
364397

365-
public void setActive(Notification n, Container c, boolean active)
398+
public void setActive(Notification n, Container c, User u, boolean active)
366399
{
400+
boolean old = isActive(n, c);
367401
WritablePropertyMap pm = PropertyManager.getWritableProperties(c, NotificationServiceImpl.STATUS_PROPERTY_DOMAIN, true);
368402
pm.put(getKey(n), active ? String.valueOf(active) : null);
369403
pm.save();
404+
405+
if (old != active)
406+
{
407+
String action = active ? "enabled" : "disabled";
408+
String comment = "Notification '" + n.getName() + "' has been " + action + ".";
409+
SiteSettingsAuditEvent event = new SiteSettingsAuditEvent(c, comment);
410+
AuditLogService.get().addEvent(u, event);
411+
}
370412
}
371413

372414
@Override
@@ -530,6 +572,9 @@ public void updateSubscriptions(Container c, User u, Notification n, @Nullable L
530572
{
531573
TableInfo ti = LDKSchema.getTable(LDKSchema.TABLE_NOTIFICATION_RECIPIENTS);
532574

575+
List<UserPrincipal> actuallyAdded = new ArrayList<>();
576+
List<UserPrincipal> actuallyRemoved = new ArrayList<>();
577+
533578
if (toAdd != null)
534579
{
535580
for (UserPrincipal up : toAdd)
@@ -548,20 +593,49 @@ public void updateSubscriptions(Container c, User u, Notification n, @Nullable L
548593
row.put("createdby", u.getUserId());
549594
row.put("created", new Date());
550595
Table.insert(u, ti, row);
596+
actuallyAdded.add(up);
551597
}
552598
}
599+
}
553600

554-
if (toRemove != null)
601+
if (toRemove != null)
602+
{
603+
for (UserPrincipal up : toRemove)
555604
{
556-
for (UserPrincipal up : toRemove)
557-
{
558-
SimpleFilter filter = new SimpleFilter(FieldKey.fromString("container"), c.getId(), CompareType.EQUAL);
559-
filter.addCondition(FieldKey.fromString("recipient"), up.getUserId());
560-
filter.addCondition(FieldKey.fromString("notificationtype"), n.getName());
605+
SimpleFilter filter = new SimpleFilter(FieldKey.fromString("container"), c.getId(), CompareType.EQUAL);
606+
filter.addCondition(FieldKey.fromString("recipient"), up.getUserId());
607+
filter.addCondition(FieldKey.fromString("notificationtype"), n.getName());
608+
609+
Table.delete(ti, filter);
610+
actuallyRemoved.add(up);
611+
}
612+
}
561613

562-
Table.delete(ti, filter);
614+
// Audit event
615+
if ((!actuallyAdded.isEmpty() || !actuallyRemoved.isEmpty()) && u != null)
616+
{
617+
StringBuilder html = new StringBuilder();
618+
if (!actuallyAdded.isEmpty())
619+
{
620+
html.append("<div class='labkey-form-label'>Added recipients</div><ul>");
621+
for (UserPrincipal up : actuallyAdded)
622+
{
623+
html.append("<li>").append(PageFlowUtil.filter(up.getName())).append(" (ID: ").append(up.getUserId()).append(")</li>");
624+
}
625+
html.append("</ul>");
626+
}
627+
if (!actuallyRemoved.isEmpty())
628+
{
629+
html.append("<div class='labkey-form-label'>Removed recipients</div><ul>");
630+
for (UserPrincipal up : actuallyRemoved)
631+
{
632+
html.append("<li>").append(PageFlowUtil.filter(up.getName())).append(" (ID: ").append(up.getUserId()).append(")</li>");
563633
}
634+
html.append("</ul>");
564635
}
636+
SiteSettingsAuditEvent event = new SiteSettingsAuditEvent(c, "Updated notification subscriptions for '" + n.getName() + "'.");
637+
event.setChanges(html.toString());
638+
AuditLogService.get().addEvent(u, event);
565639
}
566640
}
567641

0 commit comments

Comments
 (0)