DtoMapper.java

package jasper.service.dto;

import com.fasterxml.jackson.databind.ObjectMapper;
import jasper.component.Storage;
import jasper.domain.Ext;
import jasper.domain.External;
import jasper.domain.Metadata;
import jasper.domain.Plugin;
import jasper.domain.Ref;
import jasper.domain.Template;
import jasper.domain.User;
import jasper.domain.proj.HasTags;
import jasper.security.Auth;
import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static jasper.domain.proj.Tag.publicTag;

/**
 * Filtering mapper. Removes fields hidden to the user.
 */
@Mapper(componentModel = "spring")
public abstract class DtoMapper {

	@Autowired
	Auth auth;

	@Autowired
	ObjectMapper objectMapper;

	@Mapping(target = "metadata.userUrls", ignore = true)
	public abstract RefDto domainToDto(Ref ref);

	@Mapping(target = "responses", source = "metadata.responses")
	@Mapping(target = "metadata.userUrls", ignore = true)
	public abstract RefNodeDto domainToNodeDto(Ref ref);

	public abstract RefReplDto dtoToRepl(RefDto ref);

	public abstract ExtDto domainToDto(Ext ext);

	public abstract UserDto domainToDto(User user);
	public abstract ExternalDto domainToDto(External external);

	public abstract PluginDto domainToDto(Plugin plugin);

	public abstract TemplateDto domainToDto(Template plugin);

	public abstract BackupDto domainToDto(Storage.StorageRef plugin);

	@AfterMapping
	protected void filterTags(@MappingTarget HasTags ref) {
		if (ref.getTags() == null) return;
		ref.setTags(new ArrayList<>(auth.filterTags(ref.getTags())));
	}

	@AfterMapping
	protected void filterPlugins(@MappingTarget HasTags ref) {
		if (ref.getPlugins() == null) return;
		var filteredPlugins = objectMapper.createObjectNode();
		ref.getPlugins().fieldNames().forEachRemaining(tag -> {
			if (auth.canReadTag(tag + auth.getOrigin())) filteredPlugins.set(tag, ref.getPlugins().get(tag));
		});
		if (filteredPlugins.isEmpty()) {
			ref.setPlugins(null);
		} else {
			ref.setPlugins(filteredPlugins);
		}
	}

	@AfterMapping
	protected void filterMetadata(@MappingTarget MetadataDto metadata) {
		if (metadata.getPlugins() == null) return;
		var filteredPlugins = new HashMap<String, Integer>();
		metadata.getPlugins().entrySet().iterator().forEachRemaining(e -> {
			if (auth.canReadTag(e.getKey() + auth.getOrigin())) {
				filteredPlugins.put(e.getKey(), e.getValue());
			}
		});
		if (filteredPlugins.isEmpty()) {
			metadata.setPlugins(null);
		} else {
			metadata.setPlugins(filteredPlugins);
		}
	}

	@AfterMapping
	protected void filterTags(@MappingTarget UserDto userDto) {
		userDto.setReadAccess(auth.filterTags(userDto.getReadAccess()));
		userDto.setWriteAccess(auth.filterTags(userDto.getWriteAccess()));
	}

	@AfterMapping
	protected void userUrlsMetadata(Metadata source, @MappingTarget MetadataDto target) {
		if (source.getUserUrls() == null) return;
		if (auth.getUserTag() == null) return;
		var prefix = "tag:/" + publicTag(auth.getUserTag().tag) + "?url=";
		target.setUserUrls(source.getUserUrls().entrySet().stream()
			// TODO: how is null getting in here
			.filter(e -> e.getValue().stream().anyMatch(url -> url != null && url.startsWith(prefix)))
			.map(Map.Entry::getKey)
			.toList()
		);
	}

	public int countMetadata(List<String> responses) {
		if (responses == null) return 0;
		return responses.size();
	}
}