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

io.imunity.upman.rest.RestProjectService Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2018 Bixbit - Krzysztof Benedyczak. All rights reserved.
 * See LICENCE.txt file for licensing information.
 */

package io.imunity.upman.rest;

import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.NotFoundException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import pl.edu.icm.unity.base.entity.EntityParam;
import pl.edu.icm.unity.base.exceptions.EngineException;
import pl.edu.icm.unity.base.group.Group;
import pl.edu.icm.unity.base.group.GroupContents;
import pl.edu.icm.unity.base.group.GroupDelegationConfiguration;
import pl.edu.icm.unity.base.i18n.I18nString;
import pl.edu.icm.unity.base.identity.IdentityTaV;
import pl.edu.icm.unity.base.tx.Transactional;
import pl.edu.icm.unity.engine.api.EnquiryManagement;
import pl.edu.icm.unity.engine.api.EntityManagement;
import pl.edu.icm.unity.engine.api.GroupsManagement;
import pl.edu.icm.unity.engine.api.RegistrationsManagement;
import pl.edu.icm.unity.engine.api.authn.AuthorizationException;
import pl.edu.icm.unity.engine.api.entity.EntityWithContactInfo;
import pl.edu.icm.unity.engine.api.group.GroupNotFoundException;
import pl.edu.icm.unity.engine.api.group.IllegalGroupValueException;
import pl.edu.icm.unity.engine.api.identity.UnknownEmailException;
import pl.edu.icm.unity.engine.api.identity.UnknownIdentityException;
import pl.edu.icm.unity.engine.api.project.DelegatedGroupManagement;
import pl.edu.icm.unity.engine.api.project.DelegatedGroupMember;
import pl.edu.icm.unity.engine.api.project.GroupAuthorizationRole;
import pl.edu.icm.unity.engine.api.utils.CodeGenerator;
import pl.edu.icm.unity.engine.api.utils.PrototypeComponent;
import pl.edu.icm.unity.stdext.identity.EmailIdentity;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static java.util.Optional.ofNullable;

@PrototypeComponent
class RestProjectService
{
	private DelegatedGroupManagement delGroupMan;
	private GroupsManagement groupMan;
	private UpmanRestAuthorizationManager authz;
	private EntityManagement idsMan;
	private ProjectGroupProvider projectGroupProvider;
	private RegistrationsManagement registrationsManagement;
	private EnquiryManagement enquiryManagement;
	private String rootGroup;
	private String authorizationGroup;

	//for spring
	@SuppressWarnings("unused")
	private RestProjectService()
	{
	}

	RestProjectService(DelegatedGroupManagement delGroupMan,
	                          GroupsManagement groupMan,
	                          UpmanRestAuthorizationManager authz,
	                          EntityManagement idsMan,
	                          RegistrationsManagement registrationsManagement,
	                          EnquiryManagement enquiryManagement,
	                          String rootGroup,
	                          String authorizationGroup)
	{
		init(delGroupMan, groupMan, authz, idsMan, registrationsManagement, enquiryManagement, rootGroup,
				authorizationGroup);
	}

	void init(DelegatedGroupManagement delGroupMan, GroupsManagement groupMan,
			UpmanRestAuthorizationManager authz, EntityManagement idsMan,
			RegistrationsManagement registrationsManagement, EnquiryManagement enquiryManagement, String rootGroup,
			String authorizationGroup)
	{
		this.delGroupMan = delGroupMan;
		this.groupMan = groupMan;
		this.projectGroupProvider = new ProjectGroupProvider(groupMan);
		this.authz = authz;
		this.rootGroup = rootGroup;
		this.authorizationGroup = authorizationGroup;
		this.idsMan = idsMan;
		this.registrationsManagement = registrationsManagement;
		this.enquiryManagement = enquiryManagement;
	}

	@Transactional
	public RestProjectId addProject(RestProjectCreateRequest project) throws EngineException
	{
		assertAuthorization();

		String projectId;
		if(project.projectId == null)
		{
			GroupContents groupContent = groupMan.getContents(rootGroup, GroupContents.GROUPS);
			List subGroups = groupContent.getSubGroups();
			projectId = generateName(subGroups);
		}
		else
			projectId = project.projectId;

		String projectPath = ProjectPathProvider.getProjectPath(projectId, rootGroup);
		if (project.displayedName == null || project.displayedName.isEmpty())
			throw new IllegalArgumentException();

		Group toAdd = new Group(projectPath);
		toAdd.setPublic(project.isPublic);
		toAdd.setDisplayedName(convertToI18nString(project.displayedName));
		toAdd.setDescription(convertToI18nString(project.description));

		toAdd.setDelegationConfiguration(new GroupDelegationConfiguration(true,
				project.enableSubprojects,
				project.logoUrl,
				null, null, null,
				project.readOnlyAttributes, List.of())
			);
		
		groupMan.addGroup(toAdd);

		return new RestProjectId(projectId);
	}

	@Transactional
	public void updateProject(String projectId, RestProjectUpdateRequest project) throws EngineException
	{
		assertAuthorization();

		if (project.displayedName == null || project.displayedName.isEmpty())
			throw new IllegalArgumentException("Displayed name have to be set");

		String projectPath = ProjectPathProvider.getProjectPath(projectId, rootGroup);
		Group toUpdate = projectGroupProvider.getProjectGroup(projectId, projectPath);
		toUpdate.setPublic(project.isPublic);
		toUpdate.setDisplayedName(convertToI18nString(project.displayedName));
		toUpdate.setDescription(convertToI18nString(project.description));

		try
		{
			toUpdate.setDelegationConfiguration(new GroupDelegationConfiguration(true, project.enableSubprojects,
					project.logoUrl, null, null, null, project.readOnlyAttributes, List.of()));
			groupMan.updateGroup(projectPath, toUpdate);
		} catch (GroupNotFoundException e)
		{
			throw new NotFoundException(e);
		}
	}

	private I18nString convertToI18nString(Map map)
	{
		I18nString i18nString = new I18nString();
		i18nString.addAllValues(map);
		ofNullable(map.get("")).ifPresent(i18nString::setDefaultValue);
		return i18nString;
	}

	private static String generateName(List subGroups)
	{
		String name;
		do
		{
			name = CodeGenerator.generateMixedCharCode(5);
		} while (subGroups.contains(name));
		return name;
	}

	@Transactional
	public void removeProject(String projectId) throws EngineException
	{
		assertAuthorization();
		String projectPath = ProjectPathProvider.getProjectPath(projectId, rootGroup);
		Group projectGroup = projectGroupProvider.getProjectGroup(projectId, projectPath);
		try
		{
			unsetAndRemoveProjectForms(projectGroup);
			groupMan.removeGroup(projectGroup.toString(), true);		
		}
		catch (GroupNotFoundException e)
		{
			throw new NotFoundException(e);
		}
	}

	private void unsetAndRemoveProjectForms(Group projectGroup) throws EngineException
	{
		GroupDelegationConfiguration orgGroupDelegationConfiguration = projectGroup.getDelegationConfiguration();
		GroupDelegationConfiguration newGroupDelegationConfiguration = GroupDelegationConfiguration.builder()
				.copy(projectGroup.getDelegationConfiguration())
				.withRegistrationForm(null)
				.withSignupEnquiryForm(null)
				.withMembershipUpdateEnquiryForm(null)
				.build();
		projectGroup.setDelegationConfiguration(newGroupDelegationConfiguration);
		groupMan.updateGroup(projectGroup.toString(), projectGroup);

		if (orgGroupDelegationConfiguration.registrationForm != null
				&& !orgGroupDelegationConfiguration.registrationForm.isEmpty())
		{
			registrationsManagement.removeForm(orgGroupDelegationConfiguration.registrationForm, true);
		}

		if (orgGroupDelegationConfiguration.signupEnquiryForm != null
				&& !orgGroupDelegationConfiguration.signupEnquiryForm.isEmpty())
		{
			enquiryManagement.removeEnquiry(orgGroupDelegationConfiguration.signupEnquiryForm, true);
		}

		if (orgGroupDelegationConfiguration.membershipUpdateEnquiryForm != null
				&& !orgGroupDelegationConfiguration.membershipUpdateEnquiryForm.isEmpty())
		{
			enquiryManagement.removeEnquiry(orgGroupDelegationConfiguration.membershipUpdateEnquiryForm, true);
		}
	}
	
	
	@Transactional
	public RestProject getProject(String projectId) throws EngineException
	{
		assertAuthorization();
		String projectPath = ProjectPathProvider.getProjectPath(projectId, rootGroup);
		Group projectGroup = projectGroupProvider.getProjectGroup(projectId, projectPath);
		return map(projectId, projectGroup);
	}

	@Transactional
	public List getProjects() throws EngineException
	{
		assertAuthorization();
		List groups = groupMan.getGroupsByWildcard(rootGroup + "/**");
		return groups.stream()
			.filter(group -> !group.getName().equals(rootGroup))
			.filter(group -> group.getDelegationConfiguration().enabled)
			.map(group -> map(group.getName().replace(rootGroup + "/", ""), group))
			.collect(Collectors.toList());
	}

	@Transactional
	public void addProjectMember(String projectId, String email) throws EngineException
	{
		assertAuthorization();
		String projectPath = ProjectPathProvider.getProjectPath(projectId, rootGroup);
		projectGroupProvider.getProjectGroup(projectId, projectPath);
		Long id = getId(email);
		delGroupMan.addMemberToGroup(projectPath, projectPath, id);
	}

	private void validateRole(RestAuthorizationRole role)
	{
		if (Arrays.stream(GroupAuthorizationRole.values()).noneMatch(authzRole -> authzRole.name().equals(role.role)))
			throw new IllegalArgumentException(String.format("Invalid role: %s, allowed values: manager, " +
				"projectsAdmin, regular", role.role));
	}

	@Transactional
	public void removeProjectMember(String projectId, String email) throws EngineException
	{
		assertAuthorization();
		String projectPath = ProjectPathProvider.getProjectPath(projectId, rootGroup);
		projectGroupProvider.getProjectGroup(projectId, projectPath);
		try
		{
			groupMan.removeMember(ProjectPathProvider.getProjectPath(projectId, rootGroup), new EntityParam(new IdentityTaV(EmailIdentity.ID, email)));
		}
		catch (UnknownIdentityException e)
		{
			throw new NotFoundException(String.format("Email %s not found", email));
		}
	}

	@Transactional
	public List getProjectMembers(String projectId) throws EngineException
	{
		assertAuthorization();
		String projectPath = ProjectPathProvider.getProjectPath(projectId, rootGroup);
		projectGroupProvider.getProjectGroup(projectId, projectPath);
		return delGroupMan.getDelegatedGroupMembers(projectPath, projectPath).stream()
			.map(RestProjectService::map)
			.collect(Collectors.toList());
	}

	@Transactional
	public RestProjectMembership getProjectMember(String projectId, String email) throws EngineException
	{
		assertAuthorization();
		String projectPath = ProjectPathProvider.getProjectPath(projectId, rootGroup);
		projectGroupProvider.getProjectGroup(projectId, projectPath);
		return delGroupMan.getDelegatedGroupMembers(projectPath, projectPath).stream()
			.filter(member -> member.email.getValue().equals(email))
			.map(RestProjectService::map)
			.findFirst()
			.orElseThrow(() -> new NotFoundException("There is no member"));
	}

	@Transactional
	public RestAuthorizationRole getProjectAuthorizationRole(String projectId, String email) throws EngineException
	{
		return new RestAuthorizationRole(getProjectMember(projectId, email).role);
	}

	@Transactional
	public void setProjectAuthorizationRole(String projectId, String email,
	                                                         RestAuthorizationRole role) throws EngineException
	{
		assertAuthorization();
		String projectPath = ProjectPathProvider.getProjectPath(projectId, rootGroup);
		projectGroupProvider.getProjectGroup(projectId, projectPath);
		validateRole(role);
		Long id = getId(email);
		try
		{
			delGroupMan.setGroupAuthorizationRole(projectPath, projectPath, id,
				GroupAuthorizationRole.valueOf(role.role));
		}
		catch (IllegalGroupValueException e)
		{
			throw new NotFoundException("Entity is not a member of the project");
		}
	}

	private Long getId(String email) throws EngineException
	{
		Set entities;
		try
		{
			entities = idsMan.getAllEntitiesWithContactEmails(Set.of(email));
		}
		catch (UnknownEmailException e)
		{
			throw new NotFoundException(String.format("Email %s not found", email));
		}

		if(entities.size() > 1)
			throw new BadRequestException("Ambiguous user");
		if(entities.size() == 0)
			throw new NotFoundException(String.format("Email %s not found", email));
		return entities.iterator().next().entity.getId();
	}

	private void assertAuthorization() throws AuthorizationException
	{
		authz.assertManagerAuthorization(authorizationGroup);
	}

	private static RestProject map(String projectId, Group group)
	{
		return RestProject.builder()
			.withProjectId(projectId)
			.withPublic(group.isPublic())
			.withDisplayedName(group.getDisplayedName().getMap())
			.withDescription(group.getDescription().getMap())
			.withLogoUrl(group.getDelegationConfiguration().logoUrl)
			.withEnableSubprojects(group.getDelegationConfiguration().enableSubprojects)
			.withReadOnlyAttributes(group.getDelegationConfiguration().attributes)
			.withRegistrationForm(group.getDelegationConfiguration().registrationForm)
			.withSignUpEnquiry(group.getDelegationConfiguration().signupEnquiryForm)
			.withMembershipUpdateEnquiry(group.getDelegationConfiguration().membershipUpdateEnquiryForm)
			.build();
	}

	private static RestProjectMembership map(DelegatedGroupMember member)
	{
		return RestProjectMembership.builder()
			.withEmail(member.email.getValue())
			.withRole(member.role.name())
			.withAttributes(
				member.attributes.stream()
					.map(attr -> new RestAttribute(attr.getName(), List.copyOf(attr.getValues())))
					.collect(Collectors.toList())
			)
			.build();
	}
	
	@Component
	public static class RestProjectServiceFactory
	{
		private final DelegatedGroupManagement delGroupMan;
		private final GroupsManagement groupMan;
		private final UpmanRestAuthorizationManager authz;
		private final EntityManagement idsMan;
		private final RegistrationsManagement registrationsManagement;
		private final EnquiryManagement enquiryManagement;
		private final ObjectFactory factory;

		@Autowired
		RestProjectServiceFactory(@Qualifier("insecure") DelegatedGroupManagement delGroupMan,
				@Qualifier("insecure") GroupsManagement groupMan, UpmanRestAuthorizationManager authz,
				@Qualifier("insecure") EntityManagement idsMan,
				@Qualifier("insecure") RegistrationsManagement registrationsManagement,
				@Qualifier("insecure") EnquiryManagement enquiryManagement,
				ObjectFactory factory)
		{
			this.delGroupMan = delGroupMan;
			this.groupMan = groupMan;
			this.authz = authz;
			this.idsMan = idsMan;
			this.registrationsManagement = registrationsManagement;
			this.enquiryManagement = enquiryManagement;
			this.factory = factory;
		}

		RestProjectService newInstance(String rootGroup, String authorizeGroup)
		{
			RestProjectService bean = factory.getObject();
			bean.init(delGroupMan, groupMan, authz, idsMan,
					registrationsManagement, enquiryManagement, rootGroup, authorizeGroup);
			return bean;
		}
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy