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

io.imunity.scim.console.SCIMServiceEditorSchemaTab Maven / Gradle / Ivy

There is a newer version: 4.0.3
Show newest version
/*
 * Copyright (c) 2021 Bixbit - Krzysztof Benedyczak. All rights reserved.
 * See LICENCE.txt file for licensing information.
 */

package io.imunity.scim.console;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.combobox.MultiSelectComboBox;
import com.vaadin.flow.component.customfield.CustomField;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.html.Anchor;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.upload.Upload;
import com.vaadin.flow.component.upload.receivers.FileBuffer;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.server.StreamResource;
import io.imunity.scim.config.SchemaType;
import io.imunity.scim.console.EditSchemaSubView.EditSchemaSubViewFactory;
import io.imunity.scim.console.mapping.SchemaWithMappingBean;
import io.imunity.scim.schema.SchemaResourceDeserialaizer;
import io.imunity.vaadin.auth.services.ServiceEditorBase.EditorTab;
import io.imunity.vaadin.auth.services.ServiceEditorComponent;
import io.imunity.vaadin.elements.CustomValuesMultiSelectComboBox;
import io.imunity.vaadin.elements.NotificationPresenter;
import io.imunity.vaadin.elements.grid.GridWithActionColumn;
import io.imunity.vaadin.elements.grid.SingleActionHandler;
import io.imunity.vaadin.endpoint.common.api.SubViewSwitcher;
import pl.edu.icm.unity.base.Constants;
import pl.edu.icm.unity.base.exceptions.EngineException;
import pl.edu.icm.unity.base.message.MessageSource;
import pl.edu.icm.unity.engine.api.config.UnityServerConfiguration;
import pl.edu.icm.unity.engine.api.exceptions.RuntimeEngineException;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static io.imunity.vaadin.elements.CSSVars.TEXT_FIELD_BIG;
import static io.imunity.vaadin.elements.CssClassNames.MEDIUM_VAADIN_FORM_ITEM_LABEL;

class SCIMServiceEditorSchemaTab extends VerticalLayout implements EditorTab
{
	private final MessageSource msg;
	private final SubViewSwitcher subViewSwitcher;
	private final EditSchemaSubViewFactory editSchemaSubViewFactory;
	private final ConfigurationVaadinBeanMapper configurationVaadinBeanMapper;
	private final NotificationPresenter notificationPresenter;

	private SCIMServiceEditorSchemaTab(MessageSource msg, NotificationPresenter notificationPresenter, EditSchemaSubViewFactory editSchemaSubViewFactory,
			UnityServerConfiguration unityServerConfiguration, SubViewSwitcher subViewSwitcher,
			ConfigurationVaadinBeanMapper configurationVaadinBeanMapper)
	{
		this.msg = msg;
		this.notificationPresenter = notificationPresenter;
		this.subViewSwitcher = subViewSwitcher;
		this.editSchemaSubViewFactory = editSchemaSubViewFactory;
		this.configurationVaadinBeanMapper = configurationVaadinBeanMapper;
	}

	void initUI(Binder configBinder)
	{
		VerticalLayout mainL = new VerticalLayout();
		mainL.setSizeFull();
		
		FormLayout main = new FormLayout();
		main.setResponsiveSteps(new FormLayout.ResponsiveStep("0", 1));
		main.addClassName(MEDIUM_VAADIN_FORM_ITEM_LABEL.getName());
		MultiSelectComboBox membershipAttributes = new CustomValuesMultiSelectComboBox();
		membershipAttributes.setWidth(TEXT_FIELD_BIG.value());
		membershipAttributes.setPlaceholder(msg.getMessage("typeOrSelect"));
		main.addFormItem(membershipAttributes, msg.getMessage("SCIMServiceEditorSchemaTab.membershipAttributes"));
		configBinder.forField(membershipAttributes)
				.withConverter(List::copyOf, HashSet::new)
				.bind("membershipAttributes");
		mainL.add(main);
		
		SchemasComponent schemas = new SchemasComponent();
		configBinder.forField(schemas).bind("schemas");
		mainL.add(schemas);

		schemas.addValueChangeListener(e ->
		{
			Set attr = new HashSet<>();
			for (SchemaWithMappingBean schema : e.getValue())
			{
				if (schema == null)
					continue;
				schema.getAttributes().forEach(a -> attr.add(a.getAttributeDefinition().getName()));
			}
			membershipAttributes.setItems(attr);
		});
		add(mainL);
		setSizeFull();
		
	}

	@Override
	public String getType()
	{
		return ServiceEditorComponent.ServiceEditorTab.OTHER.toString();
	}

	@Override
	public Component getComponent()
	{
		return this;
	}

	private class SchemasComponent extends CustomField>
	{
		@Override
		protected List generateModelValue()
		{
			return schemasGrid.getElements();
		}

		@Override
		protected void setPresentationValue(List newPresentationValue)
		{
			schemasGrid.setItems(newPresentationValue);
			
		}
		private GridWithActionColumn schemasGrid;
		private VerticalLayout main;
		private FileBuffer fileBuffer;
		private Upload upload;
		public SchemasComponent()
		{
			initUI();
		}

		private void initUI()
		{
			main = new VerticalLayout();
			main.setSizeFull();
			main.setMargin(false);
			main.setPadding(false);		
			main.add(createHeaderActionLayout());
			schemasGrid = new GridWithActionColumn<>(msg::getMessage, getActionsHandlers());
			schemasGrid.addComponentColumn(
					p ->
					{
						Button button = new Button(p.getId(), e -> gotoEdit(p));
						button.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
						return button;
					})
							.setHeader(msg.getMessage("SCIMServiceEditorSchemaTab.schemaId"))
							.setAutoWidth(true);
			
			
			
			schemasGrid.addBooleanColumn(s -> s.isEnable()).setHeader(msg.getMessage("SCIMServiceEditorSchemaTab.enabled"));
			schemasGrid.addComponentColumn(
					s -> getMappingStatusLabel(!s.getType().equals(SchemaType.GROUP_CORE) && s.hasInvalidMappings())).setHeader(
					msg.getMessage("SCIMServiceEditorSchemaTab.mappingStatus")).setAutoWidth(true);
			schemasGrid.setWidthFull();
			main.add(schemasGrid);
			
			add(main);
			setSizeFull();
			setMargin(false);
			setPadding(false);
			
		}
		
		public HorizontalLayout createHeaderActionLayout()
		{
			HorizontalLayout headerLayout = new HorizontalLayout();
			headerLayout.setPadding(false);
			headerLayout.setMargin(false);
			headerLayout.setSpacing(true);
			headerLayout.setWidthFull();
			Button addButton = new Button(msg.getMessage("create"), e -> gotoNew());
			addButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
			addButton.setIcon(VaadinIcon.PLUS_CIRCLE_O.create());
			Button importButton = new Button(msg.getMessage("SCIMServiceEditorSchemaTab.import"));
			importButton.setIcon(VaadinIcon.DOWNLOAD.create());
			fileBuffer = new FileBuffer();
			upload = new Upload(fileBuffer);
			upload.setAcceptedFileTypes("application/json");
			upload.addFinishedListener(e -> importUserSchema());
			upload.getElement()
					.addEventListener("file-remove", e -> clear());
			upload.addFileRejectedListener(
					e -> notificationPresenter.showError(msg.getMessage("error"), e.getErrorMessage()));
			upload.setDropAllowed(false);
			upload.setVisible(true);
			upload.setUploadButton(importButton);
			headerLayout.add(upload);
			headerLayout.add(addButton);
			headerLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
			return headerLayout;
		}
		
		private Icon getMappingStatusLabel(boolean warn)
		{
			return new Icon(!warn ? VaadinIcon.CHECK_CIRCLE_O : VaadinIcon.EXCLAMATION_CIRCLE_O);
			
		}
		
		private void importUserSchema()
		{
			try
			{
				SchemaWithMappingBean schema;
				try
				{
					schema = configurationVaadinBeanMapper.mapFromConfigurationSchema(
							SchemaResourceDeserialaizer.deserializeUserSchemaFromFile(fileBuffer.getFileData().getFile()));
				} catch (EngineException | RuntimeEngineException e)
				{
					notificationPresenter.showError("", e.getMessage());
					upload.clearFileList();
					return;
				}
				upload.clearFileList();
				if (schemasGrid.getElements().stream().filter(s -> s.getId().equals(schema.getId())).findAny()
						.isPresent())
				{
					notificationPresenter.showError("", msg.getMessage("SCIMServiceEditorSchemaTab.schemaExistError", schema.getId()));
					upload.clearFileList();
					return;
				}

				schemasGrid.addElement(schema);
			} catch (IOException e)
			{
				upload.clearFileList();
				notificationPresenter.showError("Can not import schema", e.getMessage());
			}
		}

		private List> getActionsHandlers()
		{

			SingleActionHandler export = SingleActionHandler.builder(SchemaWithMappingBean.class)
					.withCaption(msg.getMessage("SCIMServiceEditorSchemaTab.exportAction"))
					.withIcon(VaadinIcon.UPLOAD).withHandler(r -> export(r.iterator().next())).build();

			SingleActionHandler edit = SingleActionHandler
					.builder4Edit(msg::getMessage, SchemaWithMappingBean.class).withHandler(r ->
					{
						SchemaWithMappingBean edited = r.iterator().next();
						gotoEdit(edited);
					}

					).build();

			SingleActionHandler remove = SingleActionHandler
					.builder4Delete(msg::getMessage, SchemaWithMappingBean.class).withHandler(r ->
					{

						SchemaWithMappingBean schema = r.iterator().next();
						schemasGrid.removeElement(schema);
					}).withDisabledPredicate(s -> !getEditMode(s).equals(AttributesEditMode.FULL_EDIT)).build();

			return Arrays.asList(export, edit, remove);
		}

		
		private void export(SchemaWithMappingBean mapping)
		{
			Anchor download = new Anchor(getStreamResource(mapping), "");
			download.getElement()
					.setAttribute("download", true);
			add(download);
			download.getElement()
					.executeJs("return new Promise(resolve =>{this.click(); setTimeout(() => resolve(true), 150)})",
							download.getElement())
					.then(j -> remove(download));
		}

		private StreamResource getStreamResource(SchemaWithMappingBean mapping)
		{
			return new StreamResource(getNewFilename(mapping), () ->
			{

				try
				{
					byte[] content = Constants.MAPPER.writerWithDefaultPrettyPrinter()
							.writeValueAsBytes(configurationVaadinBeanMapper.mapToConfigurationSchema(mapping));
					return new ByteArrayInputStream(content);
				} catch (Exception e)
				{
					throw new RuntimeException(e);
				}
			})
			{
				@Override
				public Map getHeaders()
				{
					Map headers = new HashMap<>(super.getHeaders());
					headers.put("Content-Disposition", "attachment; filename=\"" + getNewFilename(mapping) + "\"");
					return headers;
				}
			};
		}

		private String getNewFilename(SchemaWithMappingBean mapping)
		{
			return mapping.getName()  + ".json";
		}

		private void gotoNew()
		{
			gotoEditSubView(null, s ->
			{
				subViewSwitcher.exitSubViewAndShowUpdateInfo();
				schemasGrid.addElement(s);
			});

		}

		private void gotoEdit(SchemaWithMappingBean edited)
		{
			gotoEditSubView(edited, s ->
			{
				schemasGrid.replaceElement(edited, s);
				subViewSwitcher.exitSubViewAndShowUpdateInfo();
			});
		}

		private void gotoEditSubView(SchemaWithMappingBean edited, Consumer onConfirm)
		{
			EditSchemaSubView subView;
			try
			{
				subView = editSchemaSubViewFactory.getSubView(
						schemasGrid.getElements().stream().map(s -> s.getId()).collect(Collectors.toList()), edited,
						getEditMode(edited), s ->
						{
							onConfirm.accept(s);
						//	fireChange();
							schemasGrid.focus();
						}, () ->
						{
							subViewSwitcher.exitSubView();
							schemasGrid.focus();
						});
				subViewSwitcher.goToSubView(subView);
			} catch (EngineException e)
			{
				notificationPresenter.showError("Can not edit schema", e.getMessage());
			}
		}

		private AttributesEditMode getEditMode(SchemaWithMappingBean schema)
		{
			if (schema != null)
			{
				if (schema.getType().equals(SchemaType.USER_CORE))
					return AttributesEditMode.EDIT_MAPPING_ONLY;
				if (schema.getType().equals(SchemaType.GROUP_CORE))
					return AttributesEditMode.HIDE_MAPPING;
			}

			return AttributesEditMode.FULL_EDIT;

		}
	}

	@org.springframework.stereotype.Component
	static class SCIMServiceEditorSchemaTabFactory
	{
		private final EditSchemaSubViewFactory editSchemaSubViewFactory;
		private final MessageSource msg;
		private final UnityServerConfiguration configuration;
		private final ConfigurationVaadinBeanMapper configurationVaadinBeanMapper;
		private final NotificationPresenter notificationPresenter;

		SCIMServiceEditorSchemaTabFactory(NotificationPresenter notificationPresenter, EditSchemaSubViewFactory editSchemaSubViewFactory, MessageSource msg,
				ConfigurationVaadinBeanMapper configurationVaadinBeanMapper, UnityServerConfiguration configuration)
		{
			this.notificationPresenter = notificationPresenter;
			this.editSchemaSubViewFactory = editSchemaSubViewFactory;
			this.msg = msg;
			this.configuration = configuration;
			this.configurationVaadinBeanMapper = configurationVaadinBeanMapper;
		}

		SCIMServiceEditorSchemaTab getSCIMServiceEditorSchemaTab(SubViewSwitcher subViewSwitcher)
		{
			return new SCIMServiceEditorSchemaTab(msg, notificationPresenter, editSchemaSubViewFactory, configuration, subViewSwitcher,
					configurationVaadinBeanMapper);
		}

	}

	@Override
	public VaadinIcon getIcon()
	{
		return VaadinIcon.TAGS;
	}

	@Override
	public String getCaption()
	{
		return msg.getMessage("SCIMServiceEditorSchemaTab.schemas");
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy