Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport 4.2.x] Register user / allow to select the group where the user wants to register #8195

Merged
merged 3 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions core/src/test/resources/org/fao/geonet/api/Messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ register_email_admin_message=Dear Admin,\n\
Newly registered user %s has requested %s access for %s.\n\
Yours sincerely,\n\
The %s team.
register_email_group_admin_message=Dear Admin,\n\
Newly registered user %s has requested %s access in group %s for %s.\n\
Yours sincerely,\n\
The %s team.
register_email_subject=%s / Your account as %s
register_email_message=Dear User,\n\
Your registration at %s was successful.\n\
Expand All @@ -77,6 +81,21 @@ register_email_message=Dear User,\n\
\n\
Yours sincerely,\n\
The %s team.
register_email_group_message=Dear User,\n\
Your registration at %s was successful.\n\
Your account is: \n\
* username: %s\n\
* password: %s\n\
* profile: %s\n\
\n\
We have sent your request for %s to the group %s administrator. You will be contacted shortly.\n\
To log in and access your account, please click on the link below.\n\
%s\n\
\n\
Thanks for your registration.\n\
\n\
Yours sincerely,\n\
The %s team.
new_user_rating=%s / New user rating on %s
new_user_rating_text=See record %s
user_feedback_title=%s / User feedback on %s / %s
Expand Down
16 changes: 16 additions & 0 deletions core/src/test/resources/org/fao/geonet/api/Messages_fre.properties
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ register_email_admin_message=Cher administrateur,\n\
L'utilisateur %s vient de demander une cr\u00E9ation de compte pour %s.\n\
Salutation,\n\
L'\u00E9quipe %s.
register_email_group_admin_message=Cher administrateur,\n\
L'utilisateur %s vient de demander une cr\u00E9ation de compte pour %s en groupe %s.\n\
Salutation,\n\
L'\u00E9quipe %s.
register_email_subject=%s / Votre compte %s
register_email_message=Cher utilisateur,\n\
Votre compte a \u00E9t\u00E9 cr\u00E9\u00E9 avec succ\u00E9s pour %s.\n\
Expand All @@ -65,6 +69,18 @@ register_email_message=Cher utilisateur,\n\
\n\
Salutations,\n\
L'\u00E9quipe %s.
register_email_group_message=Cher utilisateur,\n\
Votre compte a \u00E9t\u00E9 cr\u00E9\u00E9 avec succ\u00E9s pour %s.\n\
* Nom d'utilisateur : %s\n\
* Mot de passe : %s\n\
* Profil : %s\n\
\n\
Nous avons envoy\u00E9 votre demande de %s \u00E0 l'administrateur du groupe %s. Vous serez contact\u00E9 rapidement.\n\
Vous pouvez d\u00E9s \u00E0 pr\u00E9sent vous connecter.\n\
%s\n\
\n\
Salutations,\n\
L'\u00E9quipe %s.
new_user_rating=%s / Nouvelle \u00E9valuation faite pour %s
new_user_rating_text=Consulter la fiche %s
user_feedback_title=%s / Nouveau commentaire sur %s / %s
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ Click the `Create an account` button and fill out the registration form:
The fields in this form are self-explanatory except for the following:

- **Email**: The user's email address. This is mandatory and will be used as the username.
- **Profile**: By default, self-registered users are given the `Registered User` profile (see previous section). If any other profile is selected:
- **Requested profile**: By default, self-registered users are given the `Registered User` profile (see previous section). If any other profile is selected:
- the user will still be given the `Registered User` profile
- an email will be sent to the Email address nominated in the Feedback section of the 'System Administration' menu, informing them of the request for a more privileged profile
- **Requested group**: By default, self-registered users are not assigned to any group. If a group is selected:
- the user will still not be assigned to any group
- an email will be sent to the Email address nominated in the Feedback section of the 'System Administration' menu, informing them of the requested group.

## What happens when a user self-registers?

Expand Down
19 changes: 19 additions & 0 deletions services/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@
<scope>test</scope>
</dependency>


<dependency>
<groupId>org.jvnet.mock-javamail</groupId>
<artifactId>mock-javamail</artifactId>
<version>1.9</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
Expand Down Expand Up @@ -386,6 +394,17 @@
</execution>
</executions>
</plugin>

<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<mail.smtp.class>org.jvnet.mock_javamail.MockTransport</mail.smtp.class>
<mail.pop3.class>org.jvnet.mock_javamail.MockStore</mail.pop3.class>
<mail.imap.class>org.jvnet.mock_javamail.MockStore</mail.imap.class>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
Expand Down
151 changes: 106 additions & 45 deletions services/src/main/java/org/fao/geonet/api/users/RegisterApi.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//=============================================================================
//=== Copyright (C) 2001-2021 Food and Agriculture Organization of the
//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the
//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
//=== and United Nations Environment Programme (UNEP)
//===
Expand All @@ -26,7 +26,6 @@
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jeeves.server.context.ServiceContext;
import org.fao.geonet.api.API;
import org.fao.geonet.api.ApiUtils;
import org.fao.geonet.api.tools.i18n.LanguageUtils;
import org.fao.geonet.api.users.model.UserRegisterDto;
Expand All @@ -45,17 +44,14 @@
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import javax.servlet.http.HttpServletRequest;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.*;

@EnableWebMvc
@Service
Expand All @@ -72,12 +68,20 @@ public class RegisterApi {
@Autowired(required=false)
SecurityProviderConfiguration securityProviderConfiguration;

@Autowired
GroupRepository groupRepository;

@Autowired
UserGroupRepository userGroupRepository;

@Autowired
SettingManager settingManager;

@io.swagger.v3.oas.annotations.Operation(summary = "Create user account",
description = "User is created with a registered user profile. username field is ignored and the email is used as " +
"username. Password is sent by email. Catalog administrator is also notified.")
@RequestMapping(
@PutMapping(
value = "/actions/register",
method = RequestMethod.PUT,
produces = MediaType.TEXT_PLAIN_VALUE)
@ResponseStatus(value = HttpStatus.CREATED)
@ResponseBody
Expand All @@ -101,19 +105,18 @@ public ResponseEntity<String> registerUser(

ServiceContext context = ApiUtils.createServiceContext(request);

SettingManager sm = context.getBean(SettingManager.class);
boolean selfRegistrationEnabled = sm.getValueAsBool(Settings.SYSTEM_USERSELFREGISTRATION_ENABLE);
boolean selfRegistrationEnabled = settingManager.getValueAsBool(Settings.SYSTEM_USERSELFREGISTRATION_ENABLE);
if (!selfRegistrationEnabled) {
return new ResponseEntity<>(String.format(
messages.getString("self_registration_disabled")
), HttpStatus.PRECONDITION_FAILED);
}

boolean recaptchaEnabled = sm.getValueAsBool(Settings.SYSTEM_USERSELFREGISTRATION_RECAPTCHA_ENABLE);
boolean recaptchaEnabled = settingManager.getValueAsBool(Settings.SYSTEM_USERSELFREGISTRATION_RECAPTCHA_ENABLE);

if (recaptchaEnabled) {
boolean validRecaptcha = RecaptchaChecker.verify(userRegisterDto.getCaptcha(),
sm.getValue(Settings.SYSTEM_USERSELFREGISTRATION_RECAPTCHA_SECRETKEY));
settingManager.getValue(Settings.SYSTEM_USERSELFREGISTRATION_RECAPTCHA_SECRETKEY));
if (!validRecaptcha) {
return new ResponseEntity<>(
messages.getString("recaptcha_not_valid"), HttpStatus.PRECONDITION_FAILED);
Expand Down Expand Up @@ -144,7 +147,7 @@ public ResponseEntity<String> registerUser(
), HttpStatus.PRECONDITION_FAILED);
}

if (userRepository.findByUsernameIgnoreCase(userRegisterDto.getEmail()).size() != 0) {
if (!userRepository.findByUsernameIgnoreCase(userRegisterDto.getEmail()).isEmpty()) {
// username is ignored and the email is used as username in selfregister
return new ResponseEntity<>(String.format(
messages.getString("user_with_that_username_found"),
Expand All @@ -153,16 +156,13 @@ public ResponseEntity<String> registerUser(
}

User user = new User();

// user.setUsername(userRegisterDto.getUsername());
user.setName(userRegisterDto.getName());
user.setSurname(userRegisterDto.getSurname());
user.setOrganisation(userRegisterDto.getOrganisation());
user.setProfile(Profile.findProfileIgnoreCase(userRegisterDto.getProfile()));
user.getAddresses().add(userRegisterDto.getAddress());
user.getEmailAddresses().add(userRegisterDto.getEmail());


String password = User.getRandomPassword();
user.getSecurity().setPassword(
PasswordUtil.encode(context, password)
Expand All @@ -172,48 +172,78 @@ public ResponseEntity<String> registerUser(
user.setProfile(Profile.RegisteredUser);
user = userRepository.save(user);

Group targetGroup = getGroup(context);
Group targetGroup = getGroup();

if (targetGroup != null) {
UserGroup userGroup = new UserGroup().setUser(user).setGroup(targetGroup).setProfile(Profile.RegisteredUser);
context.getBean(UserGroupRepository.class).save(userGroup);
userGroupRepository.save(userGroup);
}


String catalogAdminEmail = sm.getValue(Settings.SYSTEM_FEEDBACK_EMAIL);
String catalogAdminEmail = settingManager.getValue(Settings.SYSTEM_FEEDBACK_EMAIL);
String subject = String.format(
messages.getString("register_email_admin_subject"),
sm.getSiteName(),
settingManager.getSiteName(),
user.getEmail(),
requestedProfile
);
String message = String.format(
messages.getString("register_email_admin_message"),
user.getEmail(),
requestedProfile,
sm.getNodeURL(),
sm.getSiteName()
);
if (!MailUtil.sendMail(catalogAdminEmail, subject, message, null, sm)) {
Group requestedGroup = getRequestedGroup(userRegisterDto.getGroup());
String message;
if (requestedGroup != null) {
message = String.format(
messages.getString("register_email_group_admin_message"),
user.getEmail(),
requestedProfile,
requestedGroup.getLabelTranslations().get(context.getLanguage()),
settingManager.getNodeURL(),
settingManager.getSiteName()
);
} else {
message = String.format(
messages.getString("register_email_admin_message"),
user.getEmail(),
requestedProfile,
settingManager.getNodeURL(),
settingManager.getSiteName()
);

}

if (Boolean.FALSE.equals(MailUtil.sendMail(catalogAdminEmail, subject, message, null, settingManager))) {
return new ResponseEntity<>(String.format(
messages.getString("mail_error")), HttpStatus.PRECONDITION_FAILED);
}

subject = String.format(
messages.getString("register_email_subject"),
sm.getSiteName(),
settingManager.getSiteName(),
user.getProfile()
);
message = String.format(
messages.getString("register_email_message"),
sm.getSiteName(),
user.getUsername(),
password,
Profile.RegisteredUser,
requestedProfile,
sm.getNodeURL(),
sm.getSiteName()
);
if (!MailUtil.sendMail(user.getEmail(), subject, message, null, sm)) {
if (requestedGroup != null) {
message = String.format(
messages.getString("register_email_group_message"),
settingManager.getSiteName(),
user.getUsername(),
password,
Profile.RegisteredUser,
requestedProfile,
requestedGroup.getLabelTranslations().get(context.getLanguage()),
settingManager.getNodeURL(),
settingManager.getSiteName()
);
} else {
message = String.format(
messages.getString("register_email_message"),
settingManager.getSiteName(),
user.getUsername(),
password,
Profile.RegisteredUser,
requestedProfile,
settingManager.getNodeURL(),
settingManager.getSiteName()
);
}

if (Boolean.FALSE.equals(MailUtil.sendMail(user.getEmail(), subject, message, null, settingManager))) {
return new ResponseEntity<>(String.format(
messages.getString("mail_error")), HttpStatus.PRECONDITION_FAILED);
}
Expand All @@ -224,8 +254,39 @@ public ResponseEntity<String> registerUser(
), HttpStatus.CREATED);
}

Group getGroup(ServiceContext context) throws SQLException {
final GroupRepository bean = context.getBean(GroupRepository.class);
return bean.findById(ReservedGroup.guest.getId()).get();
/**
* Returns the group (GUEST) to assign to the registered user.
*
* @return
*/
private Group getGroup() {
Optional<Group> targetGroupOpt = groupRepository.findById(ReservedGroup.guest.getId());

if (targetGroupOpt.isPresent()) {
return targetGroupOpt.get();
}

return null;
}

/**
* Returns the group requested by the registered user.
*
* @param requestedGroup Requested group identifier for the user.
* @return
*/
private Group getRequestedGroup(String requestedGroup) {
Group targetGroup = null;

if (StringUtils.hasLength(requestedGroup)) {
Optional<Group> targetGroupOpt = groupRepository.findById(Integer.parseInt(requestedGroup));

// Don't allow reserved groups
if (targetGroupOpt.isPresent() && !targetGroupOpt.get().isReserved()) {
targetGroup = targetGroupOpt.get();
}
}

return targetGroup;
}
}
Loading
Loading