Skip to content

Commit 769e9ee

Browse files
Merge pull request #198 from appirio-tech/tuxing1986-dev_verify_email_fix_20181031
add the success url and fail url for verify email
2 parents 71dbcb9 + 5773af7 commit 769e9ee

File tree

6 files changed

+156
-60
lines changed

6 files changed

+156
-60
lines changed

docs/postman/Member Service.postman_collection.json

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,27 @@
2424
],
2525
"body": {
2626
"mode": "raw",
27-
"raw": "{\r\n \"param\": {\r\n\r\n \"maxRating\": null,\r\n \"userId\": 132456,\r\n \"firstName\": \"F_NAME\",\r\n \"lastName\": \"L_NAME\",\r\n \"description\": null,\r\n \"otherLangName\": \"NIAL\",\r\n \"handle\": \"heffan\",\r\n \"handleLower\": \"heffan\",\r\n \"status\": \"ACTIVE\",\r\n \"email\": \"heffanNew@email.com\",\r\n \"addresses\": [],\r\n \"homeCountryCode\": null,\r\n \"competitionCountryCode\": \"USA\",\r\n \"photoURL\": \"http://img.picturequotes.com/2/9/8712/dont-panic-quote-1.jpg\",\r\n \"tracks\": [\r\n \"DEVELOP\",\r\n \"DATA_SCIENCE\"\r\n ],\r\n \"updatedAt\": \"2015-10-19T11:33Z\",\r\n \"createdAt\": \"2014-04-10T10:55Z\",\r\n \"createdBy\": \"40011578\",\r\n \"updatedBy\": \"40011578\"\r\n }\r\n}"
27+
"raw": "{\r\n \"param\": {\r\n\r\n \"maxRating\": null,\r\n \"userId\": 132456,\r\n \"firstName\": \"F_NAME\",\r\n \"lastName\": \"L_NAME\",\r\n \"description\": null,\r\n \"otherLangName\": \"NIAL\",\r\n \"handle\": \"heffan\",\r\n \"handleLower\": \"heffan\",\r\n \"status\": \"ACTIVE\",\r\n \"email\": \"heffanNew111222@email.com\",\r\n \"addresses\": [],\r\n \"homeCountryCode\": null,\r\n \"competitionCountryCode\": \"USA\",\r\n \"photoURL\": \"https://topcoder-prod-media.s3.amazonaws.com/member/profile/heffan-12345.jpeg\",\r\n \"tracks\": [\r\n \"DEVELOP\",\r\n \"DATA_SCIENCE\"\r\n ],\r\n \"updatedAt\": \"2015-10-19T11:33Z\",\r\n \"createdAt\": \"2014-04-10T10:55Z\",\r\n \"createdBy\": \"40011578\",\r\n \"updatedBy\": \"40011578\"\r\n }\r\n}"
2828
},
2929
"url": {
30-
"raw": "{{apiUrl}}/v3/members/heffan",
30+
"raw": "{{apiUrl}}/v3/members/heffan?successUrl=http://www.topcoder.com&failUrl=http://www.yahoo.com",
3131
"host": [
3232
"{{apiUrl}}"
3333
],
3434
"path": [
3535
"v3",
3636
"members",
3737
"heffan"
38+
],
39+
"query": [
40+
{
41+
"key": "successUrl",
42+
"value": "http://www.topcoder.com"
43+
},
44+
{
45+
"key": "failUrl",
46+
"value": "http://www.yahoo.com"
47+
}
3848
]
3949
}
4050
},
@@ -43,7 +53,7 @@
4353
{
4454
"name": "Verify User Email",
4555
"request": {
46-
"method": "POST",
56+
"method": "GET",
4757
"header": [
4858
{
4959
"key": "Content-Type",
@@ -59,7 +69,7 @@
5969
"raw": ""
6070
},
6171
"url": {
62-
"raw": "{{apiUrl}}/v3/members/heffan/verify?oldEmail=heffan@email.com&newEmail=heffanNew@email.com&token=qL9UH8k3YOjvyOTR",
72+
"raw": "{{apiUrl}}/v3/members/heffan/verify?oldEmail=heffanNew@email.com&newEmail=heffanNew111222@email.com&token=DgLz5uJ1CjZAY0iV&successUrl=http://www.topcoder.com&failUrl=http://www.yahoo.com",
6373
"host": [
6474
"{{apiUrl}}"
6575
],
@@ -72,15 +82,23 @@
7282
"query": [
7383
{
7484
"key": "oldEmail",
75-
"value": "heffan@email.com"
85+
"value": "heffanNew@email.com"
7686
},
7787
{
7888
"key": "newEmail",
79-
"value": "heffanNew@email.com"
89+
"value": "heffanNew111222@email.com"
8090
},
8191
{
8292
"key": "token",
83-
"value": "qL9UH8k3YOjvyOTR"
93+
"value": "DgLz5uJ1CjZAY0iV"
94+
},
95+
{
96+
"key": "successUrl",
97+
"value": "http://www.topcoder.com"
98+
},
99+
{
100+
"key": "failUrl",
101+
"value": "http://www.yahoo.com"
84102
}
85103
]
86104
}

service/src/main/java/com/appirio/service/member/manager/MemberProfileManager.java

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535

3636
import java.io.UnsupportedEncodingException;
3737
import java.lang.reflect.InvocationTargetException;
38+
import java.net.URI;
39+
import java.net.URISyntaxException;
3840
import java.net.URLEncoder;
3941
import java.text.SimpleDateFormat;
4042
import java.util.ArrayList;
@@ -61,24 +63,24 @@
6163
* Version 1.2 - Topcoder Member Settings Profile - Email Verification v1.0
6264
* - use core api 4.3.1, change to use M2M token
6365
* </p>
64-
*
66+
*
6567
* <p>
6668
* Version 1.3 - Topcoder Member Processor ES Response Fixes Code Challenge v1.0
6769
* - change the event message structure for update profile/photo
6870
* </p>
69-
*
71+
*
7072
* <p>
7173
* Version 1.4 - Topcoder Member Service - Update the Members Endpoint version 1.0
7274
* - get more profile properties from informix db
7375
* </p>
74-
*
76+
*
7577
* <p>
7678
* Version 1.5 - Topcoder Member Service - Update endpoints to read from ES v1.0
7779
* - get the profile from elasticsearch if exists
7880
* </p>
7981
*
8082
* @author TCCoder
81-
* @version 1.5
83+
* @version 1.5
8284
*
8385
*/
8486
public class MemberProfileManager {
@@ -127,22 +129,22 @@ public class MemberProfileManager {
127129
* The email verification config field
128130
*/
129131
private final EmailVerificationConfiguration emailVerificationConfig;
130-
132+
131133
/**
132-
* The jestClient field
134+
* The jestClient field
133135
*/
134136
private JestClient jestClient;
135-
137+
136138
/**
137-
* The membersIndexName field
139+
* The membersIndexName field
138140
*/
139141
private final String membersIndexName;
140-
142+
141143
/**
142-
* The membersTypeName field
144+
* The membersTypeName field
143145
*/
144146
private final String membersTypeName;
145-
147+
146148
/**
147149
* The informixDAO field
148150
*/
@@ -167,9 +169,9 @@ public class MemberProfileManager {
167169
* @param m2mAuthConfiguration the m2mAuthConfiguration to use
168170
* @param emailVerificationConfig the emailVerificationConfig to use
169171
*/
170-
public MemberProfileManager(MemberProfileDAO memberProfileDAO, MemberStatsDAO memberStatsDAO,
172+
public MemberProfileManager(MemberProfileDAO memberProfileDAO, MemberStatsDAO memberStatsDAO,
171173
MemberProfileInformixDAO informixDAO, MemberProfileInformixDwDAO informixDwDAO, String photoURLDomain, FileInvocationHandler fileInvocationHandler,
172-
EventBusServiceClient eventBusServiceClient, M2mAuthConfiguration m2mAuthConfiguration, EmailVerificationConfiguration emailVerificationConfig,
174+
EventBusServiceClient eventBusServiceClient, M2mAuthConfiguration m2mAuthConfiguration, EmailVerificationConfiguration emailVerificationConfig,
173175
JestClient jestClient, String membersIndexName, String membersTypeName) {
174176
this.memberProfileDAO = memberProfileDAO;
175177
this.memberStatsDAO = memberStatsDAO;
@@ -203,7 +205,7 @@ public MemberProfile getMemberProfile(String handle, String data, AuthUser authU
203205
if (fields.isEmpty()) {
204206
fields.addAll(Helper.PROFILE_FIELDS);
205207
}
206-
208+
207209
MemberProfile memberProfile = SearchHelper.getMemberProfile(handle, jestClient, this.membersIndexName, this.membersTypeName);
208210
if (memberProfile != null) {
209211
logger.info("Get the member profile from the elasticsearch for the user: " + handle);
@@ -218,7 +220,7 @@ public MemberProfile getMemberProfile(String handle, String data, AuthUser authU
218220
memberProfile.setMaxRating(memberStats.getMaxRating());
219221
}
220222
}
221-
223+
222224
Helper.addMoreProperties(handle, memberProfile, fields, informixDAO, informixDwDAO);
223225

224226
// if user is not logged in
@@ -241,25 +243,46 @@ public MemberProfile getMemberProfile(String handle, String data, AuthUser authU
241243
/**
242244
* Update member profile
243245
*
244-
* @param handle Handle of the user
245-
* @param authUser Authentication user
246-
* @param memberProfile Member profile
247-
* @return MemberProfile Member profile
246+
* @param handle the handle to use
247+
* @param successUrl the successUrl to use
248+
* @param failUrl the failUrl to use
249+
* @param authUser the authUser to use
250+
* @param memberProfile the memberProfile to use
248251
* @throws SupplyException if any error occurs
249252
* @throws IllegalAccessException if any error occurs
250-
* @throws InvocationTargetException if any error occurs
251-
* @throws InstantiationException if any error occurs
252253
* @throws NoSuchMethodException if any error occurs
254+
* @throws InstantiationException if any error occurs
255+
* @throws SupplyException if any error occurs
256+
* @throws InvocationTargetException if any error occurs
257+
* @throws JsonProcessingException if any error occurs
258+
* @return the MemberProfile result
253259
*/
254-
public MemberProfile updateMemberProfile(String handle, AuthUser authUser, MemberProfile memberProfile) throws
255-
IllegalAccessException, NoSuchMethodException, InstantiationException, SupplyException,
260+
public MemberProfile updateMemberProfile(String handle, String successUrl, String failUrl, AuthUser authUser, MemberProfile memberProfile)
261+
throws IllegalAccessException, NoSuchMethodException, InstantiationException, SupplyException,
256262
InvocationTargetException, JsonProcessingException {
257263

258264
MemberProfile existingMemberProfile = memberProfileDAO.validateHandle(handle, authUser, false);
259265

260266
boolean verifyEmail = false;
261267
if (!existingMemberProfile.getEmail().equals(memberProfile.getEmail())) {
262268
verifyEmail = true;
269+
if (successUrl == null || successUrl.trim().length() == 0) {
270+
throw new SupplyException("The success redirect url should be provided for the verification of email", HttpServletResponse.SC_BAD_REQUEST);
271+
}
272+
if (failUrl == null || failUrl.trim().length() == 0) {
273+
throw new SupplyException("The failUrl redirect url should be provided for the verification of email", HttpServletResponse.SC_BAD_REQUEST);
274+
}
275+
try {
276+
new URI(successUrl);
277+
} catch (URISyntaxException e) {
278+
throw new SupplyException("The successUrl is syntax invalid", HttpServletResponse.SC_BAD_REQUEST);
279+
}
280+
try {
281+
new URI(failUrl);
282+
} catch (URISyntaxException e) {
283+
throw new SupplyException("The failUrl is syntax invalid", HttpServletResponse.SC_BAD_REQUEST);
284+
}
285+
263286
if (!EmailValidator.getInstance().isValid((String) memberProfile.getEmail())) {
264287
throw new SupplyException("The email is invalid:" + memberProfile.getEmail(), HttpServletResponse.SC_BAD_REQUEST);
265288
} else {
@@ -284,11 +307,11 @@ public MemberProfile updateMemberProfile(String handle, AuthUser authUser, Membe
284307
// fire event on to the event bus to update member profile
285308
logger.info("publish member-profile-update-event");
286309
Helper.publishEventMessage(eventBusServiceClient, m2mAuthConfiguration,
287-
memberProfile.getUserId(),
310+
memberProfile.getUserId(),
288311
"member.action.profile.update", existingMemberProfile, memberProfile, logger);
289312

290313
if (verifyEmail) {
291-
this.fireEmailVerificationEvent(authUser, memberProfile);
314+
this.fireEmailVerificationEvent(authUser, memberProfile, successUrl, failUrl);
292315
}
293316

294317
MemberProfile result = memberProfileDAO.getMemberProfile(handle);
@@ -352,9 +375,12 @@ public void verifyUserEmail(String handle, AuthUser authUser, String newEmail, S
352375
* Fire email verification event
353376
*
354377
* @param authUser the authUser to use
355-
* @param profile the member profile to use
378+
* @param profile the profile to use
379+
* @param successUrl the successUrl to use
380+
* @param failUrl the failUrl to use
381+
* @throws SupplyException if any error occurs
356382
*/
357-
private void fireEmailVerificationEvent(AuthUser authUser, MemberProfile profile) throws SupplyException {
383+
private void fireEmailVerificationEvent(AuthUser authUser, MemberProfile profile, String successUrl, String failUrl) throws SupplyException {
358384
EventMessage msg = new EventMessage();
359385
msg.setTopic("member.action.email.profile.emailchange.verification").setMimeType("application/json").setOriginator("tc-member-profile").setTimestamp(new Date());
360386
Map<String, String> data = new LinkedHashMap<String, String>();
@@ -366,9 +392,16 @@ private void fireEmailVerificationEvent(AuthUser authUser, MemberProfile profile
366392
.replace("{token}", profile.getEmailVerifyToken())
367393
.replace("{newEmail}", profile.getNewEmail())
368394
.replace("{oldEmail}", profile.getEmail())
369-
.replace("{jwtToken}", authUser.getToken());
395+
.replace("{jwtToken}", authUser.getToken())
396+
.replace("{redirectTo}", successUrl);
370397
String verificationDisagreeUrl = this.emailVerificationConfig.getVerificationDisagreeUrl()
371-
.replace("{baseUrl}", this.emailVerificationConfig.getBaseUrl());
398+
.replace("{baseUrl}", this.emailVerificationConfig.getBaseUrl())
399+
.replace("{handle}", profile.getHandle())
400+
.replace("{token}", profile.getEmailVerifyToken())
401+
.replace("{newEmail}", profile.getNewEmail())
402+
.replace("{oldEmail}", profile.getEmail())
403+
.replace("{jwtToken}", authUser.getToken())
404+
.replace("{redirectTo}", failUrl);
372405
data.put("verificationAgreeUrl", verificationAgreeUrl);
373406
data.put("verificationDisagreeUrl", verificationDisagreeUrl);
374407
data.put("verificationToken", profile.getEmailVerifyToken());
@@ -480,7 +513,7 @@ public String updatePhoto(String handle, AuthUser authUser, PhotoTokenContentTyp
480513

481514
logger.info("publish member-profile-photo-update-event");
482515
Helper.publishProfilePhotoEvent(eventBusServiceClient, m2mAuthConfiguration, "member.action.profile.photo.update", eventObj, logger);
483-
516+
484517
return photoURL;
485518
}
486519

service/src/main/java/com/appirio/service/member/resources/MemberProfileResource.java

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.appirio.service.member.api.PhotoTokenContentType;
66
import com.appirio.service.member.manager.MemberProfileManager;
77
import com.appirio.supply.ErrorHandler;
8+
import com.appirio.supply.SupplyException;
89
import com.appirio.tech.core.api.v3.request.FieldSelector;
910
import com.appirio.tech.core.api.v3.request.PostPutRequest;
1011
import com.appirio.tech.core.api.v3.request.annotation.APIFieldParam;
@@ -17,6 +18,10 @@
1718
import org.slf4j.Logger;
1819
import org.slf4j.LoggerFactory;
1920

21+
import java.net.URI;
22+
import java.net.URISyntaxException;
23+
24+
import javax.servlet.http.HttpServletResponse;
2025
import javax.validation.Valid;
2126
import javax.ws.rs.Consumes;
2227
import javax.ws.rs.GET;
@@ -28,6 +33,7 @@
2833
import javax.ws.rs.QueryParam;
2934
import javax.ws.rs.core.Context;
3035
import javax.ws.rs.core.MediaType;
36+
import javax.ws.rs.core.Response;
3137
import javax.ws.rs.core.SecurityContext;
3238

3339
/**
@@ -113,20 +119,24 @@ public ApiResponse getMemberProfile(@PathParam("handle") String handle,
113119
}
114120

115121
/**
116-
* Update profile
117-
* @param handle Handle of the user
118-
* @param authUser Authentication user
119-
* @param putRequest Put request
120-
* @return ApiResponse Api response
122+
* Update member profile
123+
*
124+
* @param handle the handle to use
125+
* @param successUrl the successUrl to use
126+
* @param failUrl the failUrl to use
127+
* @param authUser the authUser to use
128+
* @param putRequest the putRequest to use
129+
* @return the ApiResponse result
121130
*/
122131
@PUT
123132
@Timed
124-
public ApiResponse updateMemberProfile(@PathParam("handle") String handle, @Auth AuthUser authUser,
125-
@Valid PostPutRequest<MemberProfile> putRequest) {
133+
public ApiResponse updateMemberProfile(@PathParam("handle") String handle, @QueryParam("successUrl") String successUrl,
134+
@QueryParam("failUrl") String failUrl, @Auth AuthUser authUser,
135+
@Valid PostPutRequest<MemberProfile> putRequest) {
126136
try {
127137
logger.debug("updateMemberProfile, handle : " + handle + " auth : " + authUser);
128138
MemberProfile memberProfile = putRequest.getParam();
129-
MemberProfile resultMemberProfile = memberProfileManager.updateMemberProfile(handle, authUser, memberProfile);
139+
MemberProfile resultMemberProfile = memberProfileManager.updateMemberProfile(handle, successUrl, failUrl, authUser, memberProfile);
130140
return ApiResponseFactory.createResponse(resultMemberProfile);
131141
} catch (Throwable ex) {
132142
return ErrorHandler.handle(ex, logger);
@@ -140,21 +150,42 @@ public ApiResponse updateMemberProfile(@PathParam("handle") String handle, @Auth
140150
* @param newEmail the newEmail to use
141151
* @param oldEmail the oldEmail to use
142152
* @param token the token to use
153+
* @param successUrl the successUrl to use
154+
* @param failUrl the failUrl to use
143155
* @param authUser the authUser to use
144-
* @return the ApiResponse result
156+
* @throws SupplyException if any error occurs
157+
* @return the Response result
145158
*/
146-
@POST
159+
@GET
147160
@Path("/verify")
148161
@Timed
149-
public ApiResponse verifyUserEmail(@PathParam("handle") String handle, @QueryParam("newEmail") String newEmail, @QueryParam("oldEmail") String oldEmail,
150-
@QueryParam("token") String token, @Auth AuthUser authUser) {
162+
public Response verifyUserEmail(@PathParam("handle") String handle, @QueryParam("newEmail") String newEmail, @QueryParam("oldEmail") String oldEmail,
163+
@QueryParam("token") String token, @QueryParam("successUrl") String successUrl, @QueryParam("failUrl") String failUrl,
164+
@Auth AuthUser authUser) throws SupplyException {
165+
151166
try {
152167
logger.debug("verifyUserEmail, handle : " + handle + ", newEmail : " + newEmail + ", oldEmail : " +
153168
oldEmail + ", token : " + token + " auth : " + authUser);
169+
if (successUrl == null || successUrl.trim().length() == 0) {
170+
throw new SupplyException("The success redirect rl should be provided for the verification of email", HttpServletResponse.SC_BAD_REQUEST);
171+
}
172+
if (failUrl == null || failUrl.trim().length() == 0) {
173+
throw new SupplyException("The fail redirect url should be provided for the verification of email", HttpServletResponse.SC_BAD_REQUEST);
174+
}
175+
154176
memberProfileManager.verifyUserEmail(handle, authUser, newEmail, oldEmail, token);
155-
return ApiResponseFactory.createResponse(null);
177+
return Response.temporaryRedirect( new URI(successUrl)).build();
178+
} catch (SupplyException se) {
179+
throw se;
180+
} catch (URISyntaxException use) {
181+
throw new SupplyException("The successUrl is syntax invalid", HttpServletResponse.SC_BAD_REQUEST);
156182
} catch (Throwable ex) {
157-
return ErrorHandler.handle(ex, logger);
183+
logger.error(ex.getMessage(), ex);
184+
try {
185+
return Response.temporaryRedirect(new URI(failUrl)).build();
186+
} catch (URISyntaxException e) {
187+
throw new SupplyException("The failUrl is syntax invalid", HttpServletResponse.SC_BAD_REQUEST);
188+
}
158189
}
159190
}
160191

0 commit comments

Comments
 (0)