Skip to content

Commit

Permalink
Merge pull request #3110 from Vojtech-Sassmann/addSponsoredUsersToGroups
Browse files Browse the repository at this point in the history
Core - createSponsoredMembersFromCsv, groups
  • Loading branch information
zlamalp authored Mar 5, 2021
2 parents 3cd4c3a + 13a4e06 commit 07287af
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 15 deletions.
7 changes: 7 additions & 0 deletions perun-base/src/main/resources/perun-roles.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2614,6 +2614,13 @@ perun_policies:
include_policies:
- default_policy

group-createSponsoredMembersFromCSV_Vo_String_List<String>_User_policy:
policy_roles:
- GROUPADMIN: Group
- VOADMIN: Vo
include_policies:
- default_policy

createSponsoredMembers_Vo_String_List<String>_User_policy:
policy_roles:
- SPONSOR: Vo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import cz.metacentrum.perun.core.api.exceptions.AttributeNotExistsException;
import cz.metacentrum.perun.core.api.exceptions.ExtSourceNotExistsException;
import cz.metacentrum.perun.core.api.exceptions.ExtendMembershipException;
import cz.metacentrum.perun.core.api.exceptions.GroupExistsException;
import cz.metacentrum.perun.core.api.exceptions.GroupNotExistsException;
import cz.metacentrum.perun.core.api.exceptions.GroupResourceMismatchException;
import cz.metacentrum.perun.core.api.exceptions.InternalErrorException;
Expand Down Expand Up @@ -1228,13 +1229,14 @@ public interface MembersManager {
* @param sendActivationLink if true link for manual activation of every created sponsored member account will be send
* to email which was set for him, be careful when using no-reply emails
* @param url base URL of Perun Instance
* @param groups groups, to which will be the created users assigned
* @return map of names to map of status, login and password
* @throws PrivilegeException insufficient permissions
*/
Map<String, Map<String, String>> createSponsoredMembersFromCSV(PerunSession sess, Vo vo, String namespace,
List<String> data, String header, User sponsor,
LocalDate validityTo, boolean sendActivationLink,
String url) throws PrivilegeException;
String url, List<Group> groups) throws PrivilegeException;

/**
* Creates new sponsored Members (with random generated passwords).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1545,12 +1545,13 @@ Member setSponsoredMember(PerunSession session, SponsoredUserData data, Vo vo, U
* to email which was set for him, be careful when using no-reply emails
* @param url base URL of Perun Instance
* @param validation Type of members validation, when ASYNC do not call this method in a cycle!
* @param groups groups, to which will be the created users assigned
* @return map of names to map of status, login, password, user and member
*/
Map<String, Map<String, String>> createSponsoredMembersFromCSV(PerunSession sess, Vo vo, String namespace,
List<String> data, String header, User sponsor,
LocalDate validityTo, boolean sendActivationLink,
String url, Validation validation);
String url, Validation validation, List<Group> groups);

/**
* Creates new sponsored members.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,8 @@ public boolean isDirectGroupMember(PerunSession sess, Group group, Member member

@Override
public void addMember(PerunSession sess, List<Group> groups, Member member) throws WrongReferenceAttributeValueException, AlreadyMemberException, WrongAttributeValueException, GroupNotExistsException {
Collections.sort(groups, Collections.reverseOrder());
groups = new ArrayList<>(groups);
groups.sort(Collections.reverseOrder());
for (Group group : groups) {
// Check if the group is NOT members or administrators group
if (group.getName().equals(VosManager.MEMBERS_GROUP)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ public class MembersManagerBlImpl implements MembersManagerBl {
private static final String LOGIN = "login";
private static final String PASSWORD = "password";
private static final String STATUS = "status";
private static final String GROUP_ADDING_ERRORS = "group_adding_errors";
private static final String MEMBER = "member";

public static final List<String> SPONSORED_MEMBER_REQUIRED_FIELDS = Arrays.asList(
Expand Down Expand Up @@ -2444,7 +2445,8 @@ public Member setSponsoredMember(PerunSession session, SponsoredUserData data, V

@Override
public Map<String, Map<String, String>> createSponsoredMembersFromCSV(PerunSession sess, Vo vo, String namespace,
List<String> data, String header, User sponsor, LocalDate validityTo, boolean sendActivationLink, String url, Validation validation) {
List<String> data, String header, User sponsor, LocalDate validityTo, boolean sendActivationLink,
String url, Validation validation, List<Group> groups) {

Map<String, Map<String, String>> totalResult = new HashMap<>();
Set<Member> createdMembers = new HashSet<>();
Expand Down Expand Up @@ -2472,7 +2474,7 @@ public Map<String, Map<String, String>> createSponsoredMembersFromCSV(PerunSessi
// async validation must be performed at the end, not directly during member creation
Validation localValidation = (Objects.equals(Validation.ASYNC, validation)) ? Validation.NONE : validation;
Map<String, Object> originalResult = createSingleSponsoredMemberFromCSV(sess, vo, namespace, singleRow,
sponsor, validityTo, sendActivationLink, url, localValidation);
sponsor, validityTo, sendActivationLink, url, localValidation, groups);

// convert result to expected "type" for outer API
Map<String, String> newResult = new HashMap<>();
Expand Down Expand Up @@ -3119,12 +3121,13 @@ private void processMemberAfterRemovingLastSponsor(PerunSession sess, Member spo
* @param validityTo validity of the sponsorship. If null, the sponsorship will not be automatically canceled.
* @param url base URL of Perun Instance
* @param validation Which type of validation to perform. If you are using ASYNC, do not call this method in a cycle!
* @param groups groups, to which will be the created users assigned
* @return result of the procedure
*/
private Map<String, Object> createSingleSponsoredMemberFromCSV(PerunSession sess, Vo vo, String namespace,
Map<String, String> data, User sponsor,
LocalDate validityTo, boolean sendActivationLink,
String url, Validation validation) {
String url, Validation validation, List<Group> groups) {
for (String requiredField : SPONSORED_MEMBER_REQUIRED_FIELDS) {
if (!data.containsKey(requiredField)) {
log.error("Invalid data passed, missing required value: {}", requiredField);
Expand Down Expand Up @@ -3167,8 +3170,9 @@ private Map<String, Object> createSingleSponsoredMemberFromCSV(PerunSession sess

// create sponsored member
Map<String, Object> status = new HashMap<>();
Member member = null;
try {
Member member = createSponsoredMember(sess, input, vo, sponsor, validityTo, sendActivationLink, url, validation);
member = createSponsoredMember(sess, input, vo, sponsor, validityTo, sendActivationLink, url, validation);
User user = perunBl.getUsersManagerBl().getUserByMember(sess, member);
// get login to return
String login = null;
Expand All @@ -3183,12 +3187,28 @@ private Map<String, Object> createSingleSponsoredMemberFromCSV(PerunSession sess

// we must pass member back for the purpose of validation
status.put(MEMBER, member);

status.put(STATUS, OK);
} catch (Exception e) {
log.error("Failed to create a sponsored user.", e);
status.put(STATUS, e.getMessage());
}

if (groups != null && !groups.isEmpty()) {
Map<Integer, String> groupAssignmentErrors = new HashMap<>();
if (member != null) {
for (Group group : groups) {
try {
perunBl.getGroupsManagerBl().addMember(sess, group, member);
} catch (Exception e) {
groupAssignmentErrors.put(group.getId(), e.getMessage());
log.error("Failed to add a member to a group. Member: {}, Group: {}", member, group, e);
}
}
}
status.put(GROUP_ADDING_ERRORS, groupAssignmentErrors);
}


return status;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import cz.metacentrum.perun.core.api.exceptions.AttributeNotExistsException;
import cz.metacentrum.perun.core.api.exceptions.ExtSourceNotExistsException;
import cz.metacentrum.perun.core.api.exceptions.ExtendMembershipException;
import cz.metacentrum.perun.core.api.exceptions.GroupExistsException;
import cz.metacentrum.perun.core.api.exceptions.GroupNotExistsException;
import cz.metacentrum.perun.core.api.exceptions.GroupResourceMismatchException;
import cz.metacentrum.perun.core.api.exceptions.InternalErrorException;
Expand Down Expand Up @@ -1286,7 +1287,8 @@ public RichMember setSponsoredMember(PerunSession session, Vo vo, User userToBeS

@Override
public Map<String, Map<String, String>> createSponsoredMembersFromCSV(PerunSession sess, Vo vo, String namespace,
List<String> data, String header, User sponsor, LocalDate validityTo, boolean sendActivationLink, String url) throws PrivilegeException {
List<String> data, String header, User sponsor, LocalDate validityTo, boolean sendActivationLink,
String url, List<Group> groups) throws PrivilegeException {
Utils.checkPerunSession(sess);
Utils.notNull(vo, "vo");
Utils.notNull(data, "names");
Expand All @@ -1298,13 +1300,20 @@ public Map<String, Map<String, String>> createSponsoredMembersFromCSV(PerunSessi
} else {
//Authorization
if (!AuthzResolver.authorizedInternal(sess,
"createSponsoredMembersFromCSV_Vo_String_List<String>_User_policy", Arrays.asList(vo, sponsor))) {
throw new PrivilegeException(sess, "createSponsoredMembers");
"createSponsoredMembersFromCSV_Vo_String_List<String>_User_policy", vo, sponsor)) {
throw new PrivilegeException(sess, "createSponsoredMembersFromCSV");
}
}

for (Group group : groups) {
if (!AuthzResolver.authorizedInternal(sess,
"group-createSponsoredMembersFromCSV_Vo_String_List<String>_User_policy", vo, group)) {
throw new PrivilegeException(sess, "createSponsoredMembersFromCSV");
}
}

return membersManagerBl
.createSponsoredMembersFromCSV(sess, vo, namespace, data, header, sponsor, validityTo, sendActivationLink, url, Validation.ASYNC);
.createSponsoredMembersFromCSV(sess, vo, namespace, data, header, sponsor, validityTo, sendActivationLink, url, Validation.ASYNC, groups);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cz.metacentrum.perun.core.impl.modules.attributes.urn_perun_vo_attribute_def_def_membershipExpirationRules.VO_EXPIRATION_RULES_ATTR;
import static cz.metacentrum.perun.core.impl.modules.attributes.urn_perun_vo_attribute_def_def_membershipExpirationRules.expireSponsoredMembers;
Expand Down Expand Up @@ -1653,7 +1654,7 @@ public void createSponsoredMembersFromCSV() throws Exception {
"Obi-wan;Kenobi;[email protected];\"He has the high ground\""
);
Map<String, Map<String, String>> allResults = perun.getMembersManagerBl().createSponsoredMembersFromCSV(
sess, createdVo, "dummy", data, header, sponsorUser, null, false, null, Validation.SYNC);
sess, createdVo, "dummy", data, header, sponsorUser, null, false, null, Validation.SYNC, null);
assertThat(allResults).hasSize(2);

Map<String, String> user1Data = allResults.get("Darth;Vader;[email protected];\"Best dad ever\"");
Expand Down Expand Up @@ -1690,10 +1691,36 @@ public void createSponsoredMembersFromCSVNotAllowedAttrFails() throws Exception
);
assertThatExceptionOfType(InternalErrorException.class)
.isThrownBy(() -> perun.getMembersManagerBl().createSponsoredMembersFromCSV(sess, createdVo, "dummy",
data, header, sponsorUser, null, false, null, Validation.SYNC))
data, header, sponsorUser, null, false, null, Validation.SYNC, null))
.withMessageContaining("Not allowed additional value passed, value: ");
}

@Test
public void createSponsoredMembersFromCSVAssignToGroups() throws Exception {
System.out.println(CLASS_NAME + "createSponsoredMembersFromCSVAssignToGroups");
//create user in group sponsors with role SPONSOR
Member sponsorMember = setUpSponsor(createdVo);
User sponsorUser = perun.getUsersManagerBl().getUserByMember(sess, sponsorMember);
AuthzResolverBlImpl.setRole(sess, sponsorUser, createdVo, Role.SPONSOR);

//create guests
String header = "firstname;lastname;" + A_U_PREFERRED_MAIL + ";" + A_U_NOTE;
List<String> data = List.of(
"Darth;Vader;[email protected];\"Best dad ever\""
);
Map<String, Map<String, String>> allResults = perun.getMembersManagerBl().createSponsoredMembersFromCSV(
sess, createdVo, "dummy", data, header, sponsorUser, null, false, null,
Validation.SYNC, List.of(createdGroup));

Map<String, String> user1Data = allResults.get("Darth;Vader;[email protected];\"Best dad ever\"");
User createdUser = getUserByDummyLogin(user1Data.get("login"));
Member member = perun.getMembersManager().getMemberByUser(sess, createdVo, createdUser);

var groupMembers = perun.getGroupsManagerBl().getGroupMembers(sess, createdGroup);

assertThat(groupMembers).contains(member);
}

@Test
public void createSponsoredMembers() throws Exception {
System.out.println(CLASS_NAME + "createSponsoredMembers");
Expand Down
1 change: 1 addition & 0 deletions perun-openapi/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8427,6 +8427,7 @@ paths:
namespace: { type: string }
validityTo: { type: string }
sendActivationLink: { type: boolean }
groups: { type: array, items: { type: integer }, description: "groups to which should be the created users assigned" }

/json/membersManager/createSponsoredMembers:
post:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ public RichMember call(ApiCaller ac, Deserializer params) throws PerunException
* @param sendActivationLink (optional) boolean if true link for manual activation of every created sponsored member
* account will be send to the email (can't be used with empty email parameter), default is false
* If set to true, a non-empty namespace has to be provided.
* @param groups int[] group ids, to which will be the created users assigned (has to be from the given vo)
* @return Map<String, Map<String, String> newly created sponsored member, their password and status of creation
*/
createSponsoredMembersFromCSV {
Expand Down Expand Up @@ -376,8 +377,22 @@ public Map<String, Map<String, String>> call(ApiCaller ac, Deserializer params)

List<String> data = new ArrayList<>(params.readList("data", String.class));

List<Group> groups = new ArrayList<>();

if (params.contains("groups")) {
int[] groupIds = params.readArrayOfInts("groups");
for (int groupId : groupIds) {
var group = ac.getGroupById(groupId);
if (group.getVoId() != vo.getId()) {
throw new RpcException(RpcException.Type.WRONG_PARAMETER, "Given groups must be from the given vo.");
}
groups.add(group);
}
}

return ac.getMembersManager()
.createSponsoredMembersFromCSV(ac.getSession(), vo, namespace, data, header, sponsor, validityTo, sendActivationLink, params.getServletRequest().getRequestURL().toString());
.createSponsoredMembersFromCSV(ac.getSession(), vo, namespace, data, header, sponsor, validityTo,
sendActivationLink, params.getServletRequest().getRequestURL().toString(), groups);
}
},

Expand Down

0 comments on commit 07287af

Please sign in to comment.