All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.datarouter.clustersetting.service.ClusterSettingDailyDigest Maven / Gradle / Ivy

/*
 * Copyright © 2009 HotPads ([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.datarouter.clustersetting.service;

import static j2html.TagCreator.b;
import static j2html.TagCreator.div;
import static j2html.TagCreator.small;

import java.time.ZoneId;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Stream;

import io.datarouter.clustersetting.config.DatarouterClusterSettingPaths;
import io.datarouter.clustersetting.enums.ClusterSettingValidity;
import io.datarouter.clustersetting.storage.clustersetting.ClusterSetting;
import io.datarouter.clustersetting.web.ClusterSettingHtml;
import io.datarouter.clustersetting.web.browse.ClusterSettingBrowseHandler.ClusterSettingBrowseEmailLinks;
import io.datarouter.clustersetting.web.override.handler.ClusterSettingOverrideViewHandler.ClusterSettingOverrideEmailLinks;
import io.datarouter.email.html.J2HtmlEmailTable;
import io.datarouter.email.html.J2HtmlEmailTable.J2HtmlEmailTableColumn;
import io.datarouter.instrumentation.relay.rml.Rml;
import io.datarouter.instrumentation.relay.rml.RmlBlock;
import io.datarouter.scanner.Scanner;
import io.datarouter.web.digest.DailyDigest;
import io.datarouter.web.digest.DailyDigestGrouping;
import io.datarouter.web.digest.DailyDigestService;
import j2html.TagCreator;
import j2html.tags.specialized.DivTag;
import j2html.tags.specialized.TableTag;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;

@Singleton
public class ClusterSettingDailyDigest implements DailyDigest{

	@Inject
	private ClusterSettingService settingService;
	@Inject
	private DailyDigestService digestService;
	@Inject
	private DatarouterClusterSettingPaths paths;
	@Inject
	private ClusterSettingHtml clusterSettingHtml;
	@Inject
	private ClusterSettingOverrideEmailLinks overrideEmailLinks;
	@Inject
	private ClusterSettingBrowseEmailLinks browseEmailLinks;

	@Override
	public String getTitle(){
		return "Cluster Settings";
	}

	@Override
	public DailyDigestType getType(){
		return DailyDigestType.ACTIONABLE;
	}

	@Override
	public DailyDigestGrouping getGrouping(){
		return DailyDigestGrouping.MEDIUM;
	}

	@Override
	public Optional getEmailContent(ZoneId zoneId){
		return makeContent(
				new ClusterSettingDailyDigestPageFormatter(emailFormatter),
				new ClusterSettingDailyDigestPageFormatter(emailPrefixFormatter));
	}

	@Override
	public Optional getRelayContent(ZoneId zoneId){
		List tables = Scanner.of(
				makeHeaderAndRelayContent(ClusterSettingValidity.REDUNDANT, browseEmailLinks::fromEmail),
				makeHeaderAndRelayContent(ClusterSettingValidity.UNREFERENCED, overrideEmailLinks::view),
				makeHeaderAndRelayContent(ClusterSettingValidity.OLD, browseEmailLinks::fromEmail),
				makeHeaderAndRelayContent(ClusterSettingValidity.UNKNOWN, overrideEmailLinks::view))
				.concatOpt(Function.identity())
				.list();

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

		return Optional.of(Rml.paragraph(
				digestService.makeHeading("Settings", paths.datarouter.settings.overrides.view))
				.with(tables.stream()
						.flatMap(table -> Stream.of(
								Rml.heading(4, Rml.text(table.heading())),
								Rml.text(table.helper()).italic(),
								Rml.table()
										.with(table.settings().stream()
												.map(Rml::tableCell)
												.map(Rml::tableRow))))));
	}

	private Optional makeContent(
			ClusterSettingDailyDigestPageFormatter settingFormatter,
			ClusterSettingDailyDigestPageFormatter prefixFormatter){
		Optional redundantTable = settingService
				.scanWithValidity(ClusterSettingValidity.REDUNDANT)
				.listTo(settings -> settingFormatter.build(
						settings,
						"Redundant",
						Optional.of("Setting's value in database is the same as the code. Generally safe to delete "
								+ "through the Cluster Setting UI")));
		Optional unreferencedTable = settingService
				.scanWithValidity(ClusterSettingValidity.UNREFERENCED)
				.listTo(settings -> prefixFormatter.build(
						settings,
						"Unreferenced",
						Optional.of("Settings exist in the database but not in the code.")));
		Optional oldTable = settingService
				.scanWithValidity(ClusterSettingValidity.OLD)
				.listTo(settings -> settingFormatter.build(
						settings,
						"Old",
						Optional.of("Setting has lived in the database for over the threshold. Could update the "
								+ "defaults in the code.")));
		Optional unknownTable = settingService
				.scanWithValidity(ClusterSettingValidity.UNKNOWN)
				.listTo(settings -> prefixFormatter.build(settings, "Unknown", Optional.empty()));

		List tables = Scanner.of(redundantTable, unreferencedTable, oldTable, unknownTable)
				.concatOpt(Function.identity())
				.sort(Comparator.comparing(HeaderAndContent::header))
				.map(HeaderAndContent::content)
				.list();
		if(tables.isEmpty()){
			return Optional.empty();
		}
		var header = digestService.makeHeader("Settings", paths.datarouter.settings.overrides.view);
		var tablesDiv = div(header);
		Scanner.of(tables)
				.map(TagCreator::div)
				.forEach(tablesDiv::with);
		return Optional.of(tablesDiv);
	}

	private Optional makeHeaderAndRelayContent(
			ClusterSettingValidity validity,
			Function toLink){
		List settings = settingService.scanWithValidity(validity).list();

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

		return Optional.of(new HeaderAndRelayContent(
				validity.display,
				validity.description,
				settings.stream()
						.map(ClusterSetting::getName)
						.map(setting -> Rml.text(setting).link(toLink.apply(setting)))
						.toList()));
	}

	private interface ClusterSettingDailyDigestTableFormatter{
		TableTag makeTable(List settings);
	}

	private class ClusterSettingDailyDigestPageFormatter{

		private final ClusterSettingDailyDigestTableFormatter tableFormatter;

		public ClusterSettingDailyDigestPageFormatter(ClusterSettingDailyDigestTableFormatter tableFormatter){
			this.tableFormatter = tableFormatter;
		}

		public Optional build(
				List settings,
				String header,
				Optional caption){
			if(settings.isEmpty()){
				return Optional.empty();
			}
			return Optional.of(new HeaderAndContent(
					header,
					div(div(b(header)), small(caption.orElse("")), tableFormatter.makeTable(settings))));
		}

	}

	private record HeaderAndContent(
			String header,
			DivTag content){
	}

	private record HeaderAndRelayContent(
			String heading,
			String helper,
			List settings){
	}

	private final ClusterSettingDailyDigestTableFormatter emailFormatter = settings ->
			new J2HtmlEmailTable()
					.withColumn(new J2HtmlEmailTableColumn<>("Name",
							row -> clusterSettingHtml.makeBrowseSettingLink(row.getName())))
					// don't send values in an email
					.build(settings);

	private final ClusterSettingDailyDigestTableFormatter emailPrefixFormatter = settings ->
			new J2HtmlEmailTable()
					.withColumn(new J2HtmlEmailTableColumn<>("Name",
							row -> clusterSettingHtml.makeOverridePrefixSettingLink(row.getName())))
					// don't send values in an email
					.build(settings);

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy