Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions core/src/main/java/dev/vml/es/acm/core/acl/Acl.java
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,12 @@ private void deleteAuthorizable(AclAuthorizable authorizable, String id) {
if (authorizable == null) {
context.getLogger().info("Skipped deleting authorizable '{}' (already deleted or never existed)", id);
return;
}
}
if (context.getAuthorizableManager().getAuthorizable(id) == null) {
context.getLogger().info("Skipped deleting authorizable '{}' (already deleted)", id);
return;
}

purge(authorizable);
context.getAuthorizableManager().deleteAuthorizable(authorizable.get());
}
Expand Down Expand Up @@ -259,7 +259,10 @@ public void addToGroup(GroupOptions options) {
String authorizableId = context.determineId(options.getAuthorizable(), options.getAuthorizableId());
String groupId = context.determineId(options.getGroup(), options.getGroupId());
context.getLogger()
.info("Skipped adding authorizable '{}' to group '{}' (authorizable not found)", authorizableId, groupId);
.info(
"Skipped adding authorizable '{}' to group '{}' (authorizable not found)",
authorizableId,
groupId);
return;
}
authorizable.addToGroup(options);
Expand Down Expand Up @@ -300,7 +303,10 @@ public void removeFromGroup(GroupOptions options) {
String authorizableId = context.determineId(options.getAuthorizable(), options.getAuthorizableId());
String groupId = context.determineId(options.getGroup(), options.getGroupId());
context.getLogger()
.info("Skipped removing authorizable '{}' from group '{}' (authorizable not found)", authorizableId, groupId);
.info(
"Skipped removing authorizable '{}' from group '{}' (authorizable not found)",
authorizableId,
groupId);
return;
}
authorizable.removeFromGroup(options);
Expand Down Expand Up @@ -340,7 +346,9 @@ public void removeFromAllGroups(AuthorizableOptions options) {
if (authorizable == null) {
String authorizableId = context.determineId(options.getAuthorizable(), options.getAuthorizableId());
context.getLogger()
.info("Skipped removing authorizable '{}' from all groups (authorizable not found)", authorizableId);
.info(
"Skipped removing authorizable '{}' from all groups (authorizable not found)",
authorizableId);
return;
}
authorizable.removeFromAllGroups();
Expand Down Expand Up @@ -402,7 +410,8 @@ public void removeMember(MemberOptions options) {
if (group == null) {
String memberId = context.determineId(options.getMember(), options.getMemberId());
String groupId = context.determineId(options.getGroup(), options.getGroupId());
context.getLogger().info("Skipped removing member '{}' from group '{}' (group not found)", memberId, groupId);
context.getLogger()
.info("Skipped removing member '{}' from group '{}' (group not found)", memberId, groupId);
return;
}
group.removeMember(options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ public void removeProperty(Closure<RemovePropertyOptions> closure) {
public void addToGroup(GroupOptions options) {
AclGroup group = context.determineGroup(options.getGroup(), options.getGroupId());
String groupId = context.determineId(options.getGroup(), options.getGroupId());

if (group == null) {
context.getLogger().info("Skipped adding authorizable '{}' to group '{}' (group not found)", id, groupId);
return;
}

boolean changed = context.getAuthorizableManager().addMember(group.get(), authorizable);
if (changed) {
context.getLogger().info("Added authorizable '{}' to group '{}'", id, groupId);
Expand All @@ -92,12 +92,13 @@ public void addToGroup(AclGroup group) {
public void removeFromGroup(GroupOptions options) {
AclGroup group = context.determineGroup(options.getGroup(), options.getGroupId());
String groupId = context.determineId(options.getGroup(), options.getGroupId());

if (group == null) {
context.getLogger().info("Skipped removing authorizable '{}' from group '{}' (group not found)", id, groupId);
context.getLogger()
.info("Skipped removing authorizable '{}' from group '{}' (group not found)", id, groupId);
return;
}

boolean changed = context.getAuthorizableManager().removeMember(group.get(), authorizable);
if (changed) {
context.getLogger().info("Removed authorizable '{}' from group '{}'", id, groupId);
Expand Down Expand Up @@ -132,7 +133,8 @@ public void removeFromAllGroups() {
if (anyChanged) {
context.getLogger().info("Removed authorizable '{}' from all groups", id);
} else {
context.getLogger().info("Skipped removing authorizable '{}' from all groups (not a member of any group)", id);
context.getLogger()
.info("Skipped removing authorizable '{}' from all groups (not a member of any group)", id);
}
} catch (RepositoryException e) {
throw new AclException(String.format("Cannot remove authorizable '%s' from all groups!", id), e);
Expand All @@ -145,18 +147,27 @@ public void clear(ClearOptions options) {

public void clear(String path, boolean strict) {
if (context.isCompositeNodeStore() && isAppsOrLibsPath(path)) {
context.getLogger().info("Skipped clearing permissions for authorizable '{}' at path '{}' (composite node store)", id, path);
context.getLogger()
.info(
"Skipped clearing permissions for authorizable '{}' at path '{}' (composite node store)",
id,
path);
return;
}
if (context.getResourceResolver().getResource(path) == null) {
context.getLogger().info("Skipped clearing permissions for authorizable '{}' at path '{}' (path not found)", id, path);
context.getLogger()
.info("Skipped clearing permissions for authorizable '{}' at path '{}' (path not found)", id, path);
return;
}
boolean changed = context.getPermissionsManager().clear(authorizable, path, strict);
if (changed) {
context.getLogger().info("Cleared permissions for authorizable '{}' at path '{}'", id, path);
} else {
context.getLogger().info("Skipped clearing permissions for authorizable '{}' at path '{}' (no permissions to clear)", id, path);
context.getLogger()
.info(
"Skipped clearing permissions for authorizable '{}' at path '{}' (no permissions to clear)",
id,
path);
}
}

Expand All @@ -173,25 +184,41 @@ private void apply(PermissionsOptions options, boolean allow) {
List<String> permissions = options.determineAllPermissions();
Map<String, Object> restrictions = options.determineAllRestrictions();
PermissionsOptions.Mode mode = options.getMode();

if (context.isCompositeNodeStore() && isAppsOrLibsPath(path)) {
String actionDescription = allow ? "allow permissions" : "deny permissions";
context.getLogger().info("Skipped setting {} for authorizable '{}' at path '{}' (composite node store)", actionDescription, id, path);
context.getLogger()
.info(
"Skipped setting {} for authorizable '{}' at path '{}' (composite node store)",
actionDescription,
id,
path);
return;
}

if (context.getResourceResolver().getResource(path) == null) {
if (mode == PermissionsOptions.Mode.FAIL) {
throw new AclException(String.format("Cannot apply permissions for authorizable '%s' at path '%s'! (path not found)", id, path));
throw new AclException(String.format(
"Cannot apply permissions for authorizable '%s' at path '%s'! (path not found)", id, path));
}
String actionDescription = allow ? "allow permissions" : "deny permissions";
context.getLogger().info("Skipped setting {} for authorizable '{}' at path '{}' (path not found)", actionDescription, id, path);
context.getLogger()
.info(
"Skipped setting {} for authorizable '{}' at path '{}' (path not found)",
actionDescription,
id,
path);
return;
}

if (context.getPermissionsManager().check(authorizable, path, permissions, restrictions, allow)) {
String actionDescription = allow ? "allow permissions" : "deny permissions";
context.getLogger().info("Skipped setting {} for authorizable '{}' at path '{}' (already set)", actionDescription, id, path);
context.getLogger()
.info(
"Skipped setting {} for authorizable '{}' at path '{}' (already set)",
actionDescription,
id,
path);
} else {
context.getPermissionsManager().apply(authorizable, path, permissions, restrictions, allow);
String actionDescription = allow ? "allow permissions" : "deny permissions";
Expand Down Expand Up @@ -230,7 +257,8 @@ public void removeProperty(String relPath) {
if (changed) {
context.getLogger().info("Removed property '{}' for authorizable '{}'", relPath, id);
} else {
context.getLogger().info("Skipped removing property '{}' for authorizable '{}' (property not set)", relPath, id);
context.getLogger()
.info("Skipped removing property '{}' for authorizable '{}' (property not set)", relPath, id);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ public void removeMember(Closure<MemberOptions> closure) {
public void addMember(MemberOptions options) {
AclAuthorizable member = context.determineAuthorizable(options.getMember(), options.getMemberId());
String memberId = context.determineId(options.getMember(), options.getMemberId());

if (member == null) {
context.getLogger().info("Skipped adding member '{}' to group '{}' (member not found)", memberId, getId());
return;
}

boolean changed = context.getAuthorizableManager().addMember(group, member.get());
if (changed) {
context.getLogger().info("Added member '{}' to group '{}'", memberId, getId());
Expand All @@ -65,12 +65,13 @@ public void addMember(AclAuthorizable member) {
public void removeMember(MemberOptions options) {
AclAuthorizable member = context.determineAuthorizable(options.getMember(), options.getMemberId());
String memberId = context.determineId(options.getMember(), options.getMemberId());

if (member == null) {
context.getLogger().info("Skipped removing member '{}' from group '{}' (member not found)", memberId, getId());
context.getLogger()
.info("Skipped removing member '{}' from group '{}' (member not found)", memberId, getId());
return;
}

boolean changed = context.getAuthorizableManager().removeMember(group, member.get());
if (changed) {
context.getLogger().info("Removed member '{}' from group '{}'", memberId, getId());
Expand Down Expand Up @@ -102,7 +103,8 @@ public void removeAllMembers() {
if (anyChanged) {
context.getLogger().info("Removed all members from group '{}'", getId());
} else {
context.getLogger().info("Skipped removing all members from group '{}' (no members to remove)", getId());
context.getLogger()
.info("Skipped removing all members from group '{}' (no members to remove)", getId());
}
} catch (RepositoryException e) {
throw new AclException(String.format("Cannot remove all members from group '%s'!", getId()), e);
Expand Down
24 changes: 24 additions & 0 deletions core/src/main/java/dev/vml/es/acm/core/script/ScriptSchedule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package dev.vml.es.acm.core.script;

import java.io.Serializable;
import java.util.Date;

public class ScriptSchedule implements Serializable {

private final String path;

private final Date nextExecution;

public ScriptSchedule(String path, Date nextExecution) {
this.path = path;
this.nextExecution = nextExecution;
}

public String getPath() {
return path;
}

public Date getNextExecution() {
return nextExecution;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
import org.slf4j.LoggerFactory;

@Component(
service = {ResourceChangeListener.class, EventListener.class, JobConsumer.class},
service = {ScriptScheduler.class, ResourceChangeListener.class, EventListener.class, JobConsumer.class},
immediate = true,
property = {
ResourceChangeListener.PATHS + "=glob:" + ScriptRepository.ROOT + "/automatic/**/*.groovy",
Expand Down Expand Up @@ -458,4 +458,22 @@ private boolean awaitInstanceHealthy(String operation, long retryMaxCount, long
}
return true;
}

public Optional<ScriptSchedule> findScriptSchedule(String path) {
Map<String, Object> filterProps = new HashMap<>();
filterProps.put(ScriptScheduler.JOB_PROP_TYPE, ScriptScheduler.JobType.CRON.name());
filterProps.put(ScriptScheduler.JOB_PROP_SCRIPT_PATH, path);

@SuppressWarnings("unchecked")
Collection<ScheduledJobInfo> jobInfos = jobManager.getScheduledJobs(ScriptScheduler.JOB_TOPIC, -1, filterProps);

if (jobInfos.isEmpty()) {
return Optional.empty();
}

ScheduledJobInfo jobInfo = jobInfos.iterator().next();
Date nextExecution = jobInfo.getNextScheduledExecution();

return Optional.of(new ScriptSchedule(path, nextExecution));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import dev.vml.es.acm.core.replication.Activator;
import dev.vml.es.acm.core.script.Script;
import dev.vml.es.acm.core.script.ScriptRepository;
import dev.vml.es.acm.core.script.ScriptSchedule;
import dev.vml.es.acm.core.script.ScriptScheduler;
import dev.vml.es.acm.core.script.ScriptStats;
import dev.vml.es.acm.core.script.ScriptType;
import dev.vml.es.acm.core.servlet.input.ScriptInput;
Expand Down Expand Up @@ -70,6 +72,9 @@ public static Optional<Action> of(String name) {
@Reference
private transient SpaSettings spaSettings;

@Reference
private transient ScriptScheduler scriptScheduler;

@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
long statsLimit =
Expand Down Expand Up @@ -101,8 +106,14 @@ protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse r
.map(Script::getPath)
.map(path -> ScriptStats.forCompletedByPath(request.getResourceResolver(), path, statsLimit))
.collect(Collectors.toList());
List<ScriptSchedule> schedules = scripts.stream()
.map(Script::getPath)
.map(path -> scriptScheduler.findScriptSchedule(path))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());

ScriptListOutput output = new ScriptListOutput(scripts, stats);
ScriptListOutput output = new ScriptListOutput(scripts, stats, schedules);
respondJson(response, ok("Scripts listed successfully", output));
} catch (Exception e) {
LOG.error("Scripts cannot be read!", e);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.vml.es.acm.core.servlet.output;

import dev.vml.es.acm.core.script.Script;
import dev.vml.es.acm.core.script.ScriptSchedule;
import dev.vml.es.acm.core.script.ScriptStats;
import java.io.Serializable;
import java.util.List;
Expand All @@ -11,9 +12,12 @@ public class ScriptListOutput implements Serializable {

private final List<ScriptStats> stats;

public ScriptListOutput(List<Script> scripts, List<ScriptStats> stats) {
private final List<ScriptSchedule> schedules;

public ScriptListOutput(List<Script> scripts, List<ScriptStats> stats, List<ScriptSchedule> schedules) {
this.list = scripts;
this.stats = stats;
this.schedules = schedules;
}

public List<Script> getList() {
Expand All @@ -23,4 +27,8 @@ public List<Script> getList() {
public List<ScriptStats> getStats() {
return stats;
}

public List<ScriptSchedule> getSchedules() {
return schedules;
}
}
6 changes: 5 additions & 1 deletion ui.frontend/src/components/DateExplained.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ const DateExplained: React.FC<DateExplainedProps> = ({ value }) => {
}

if (formatter.isTimezoneDifference()) {
const date = value instanceof Date ? value : new Date(value);
const isFuture = date.getTime() > Date.now();
const relativeText = isFuture ? 'This will be' : 'This was';

return (
<>
<Text>{formatter.dateAtInstance(value)}</Text>
Expand All @@ -26,7 +30,7 @@ const DateExplained: React.FC<DateExplainedProps> = ({ value }) => {
<p>
In your local timezone ({formatter.userTimezone()}), the date and time are {formatter.dateAtUser(value)}.
</p>
<p>This was {formatter.dateRelative(value)}.</p>
<p>{relativeText} {formatter.dateRelative(value)}.</p>
</Text>
</Content>
</ContextualHelp>
Expand Down
Loading