Skip to content
This repository was archived by the owner on Jan 23, 2025. It is now read-only.

user_activation_email_api #367

Merged
merged 2 commits into from
Oct 8, 2014
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
130 changes: 127 additions & 3 deletions actions/user.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/*
* Copyright (C) 2014 TopCoder Inc., All Rights Reserved.
*
* @version 1.0
* @author muzehyun
* @version 1.1
* @author muzehyun, Ghost_141
* Changes in 1.1:
* - Implement user activation email api.
*/
'use strict';
var async = require('async');
Expand All @@ -12,6 +14,18 @@ var ForbiddenError = require('../errors/ForbiddenError');
var UnauthorizedError = require('../errors/UnauthorizedError');
var IllegalArgumentError = require('../errors/IllegalArgumentError');

/**
* The activation email subject.
* @since 1.1
*/
var activationEmailSubject = "Topcoder User Registration Activation";

/**
* The activation email sender name.
* @since 1.1
*/
var activationEmailSenderName = "Topcoder API";

/**
* It validates activation code and retrieves user id from activation code
* @param {String} activationCode - activation code string
Expand All @@ -27,6 +41,16 @@ function getCoderId(activationCode, helper) {
return 0;
}

/**
* Get cache key for user resend times in cache.
* @param {String} handle - The handle of user.
* @returns {string} The cache key.
* @since 1.1
*/
function getCacheKeyForResendTimes(handle) {
return 'user-activation-' + handle;
}

/**
* The API for activate user
*/
Expand Down Expand Up @@ -121,8 +145,12 @@ exports.activateUser = {
};
// send email
api.tasks.enqueue("sendEmail", emailParams, 'default');

result = { success: true };
cb();
// Remove cache from resend times from server.
api.cache.destroy(getCacheKeyForResendTimes(handle), function () {
cb();
});
}
], function (err) {
if (err) {
Expand All @@ -134,3 +162,99 @@ exports.activateUser = {
});
}
};

/**
* Handle user activation email here.
* @param {Object} api - The api object.
* @param {Object} connection - The database connection object map.
* @param {Function} next - The callback function.
* @since 1.1
*/
function userActivationEmail(api, connection, next) {
var helper = api.helper, caller = connection.caller, currentResendTimes, activationCode,
dbConnectionMap = connection.dbConnectionMap,
cacheKey = 'user-activation-' + caller.handle;

async.waterfall([
function (cb) {
cb(helper.checkMember(connection, 'You must login for this endpoint.'));
},
function (cb) {
api.dataAccess.executeQuery('check_user_activated', { handle: caller.handle }, dbConnectionMap, cb);
},
function (rs, cb) {
if (rs[0].status === 'A') {
cb(new BadRequestError("You're already activated."));
return;
}
helper.getCachedValue(cacheKey, cb);
},
function (resendTimes, cb) {
if (_.isUndefined(resendTimes)) {
// We need to send the activation email and store the resend times.
currentResendTimes = 0;
} else {
if (resendTimes >= api.config.tcConfig.userActivationResendLimit) {
cb(new BadRequestError('Sorry, you already reached the limit of resend times. Please contact for support.'));
return;
}
currentResendTimes = resendTimes;
}
api.dataAccess.executeQuery('get_user_email_and_handle', { userId: caller.userId }, dbConnectionMap, cb);
},
function (rs, cb) {
activationCode = helper.generateActivationCode(caller.userId);
api.tasks.enqueue("sendEmail",
{
subject : activationEmailSubject,
activationCode : activationCode,
template : 'activation_email',
toAddress : rs[0].email,
fromAddress : process.env.TC_EMAIL_ACCOUNT,
senderName : activationEmailSenderName,
url : process.env.TC_ACTIVATION_SERVER_NAME + '/reg2/activate.action?code=' + activationCode,
userHandle : rs[0].handle
}, 'default');
api.cache.save(cacheKey, currentResendTimes + 1, api.config.tcConfig.userActivationCacheLifeTime,
function (err) {
cb(err);
});
}
], function (err) {
if (err) {
helper.handleError(api, connection, err);
} else {
connection.response = {
success: true
};
}
next(connection, true);
});
}

/**
* The API for activate user email.
* @since 1.1
*/
exports.userActivationEmail = {
name: 'userActivationEmail',
description: 'Trigger sending user activation email.',
inputs: {
required: [],
optional: []
},
blockedConnectionTypes: [],
outputExample: {},
version: 'v2',
transaction: 'read',
databases: ['common_oltp'],
cacheEnabled: false,
run: function (api, connection, next) {
if (connection.dbConnectionMap) {
api.log('Execute userActivationEmail#run', 'debug');
userActivationEmail(api, connection, next);
} else {
api.helper.handleNoConnection(api, connection, next);
}
}
};
57 changes: 57 additions & 0 deletions apiary.apib
Original file line number Diff line number Diff line change
Expand Up @@ -2083,6 +2083,63 @@ Register a new user.
"description":"Servers are up but overloaded. Try again later."
}

## My Profile [/user/activation-email]
### My Profile [GET]
+ Request

+ Headers

Authorization : Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZHwxMzI0NTYiLCJleHAiOjEzOTI4MTc4ODQsImF1ZCI6InRvcGNvZGVyIiwiaWF0IjoxMzkyNzU3ODg0fQ.7X2IKkiyyI1ExSM5GNpdhJ8fGGK5-oAjzccX6YL_BKY

+ Response 200 (application/json)

{
success: true
}

+ Response 400 (application/json)

{
"name":"Bad Request",
"value":"400",
"description":"This message will explain why the request is invalid or cannot be served."
"details:":"You're already activated."
}

+ Response 400 (application/json)

{
"name":"Bad Request",
"value":"400",
"description":"This message will explain why the request is invalid or cannot be served."
"details:":"Sorry, you already reached the limit of resend times. Please contact for support."
}

+ Response 401 (application/json)

{
"name":"Unauthorized",
"value":"401",
"description":"This message will explain why the request is invalid or cannot be served."
"details:":"You must login for this endpoint."
}

+ Response 500 (application/json)

{
"name":"Internal Server Error",
"value":"500",
"description":"Unknown server error. Please contact support."
}

+ Response 503 (application/json)

{
"name":"Service Unavailable",
"value":"503",
"description":"Servers are up but overloaded. Try again later."
}

## Search My Challenges [/user/challenges?type={type}&pageIndex={pageIndex}&pageSize={pageSize}&sortColumn={sortColumn}&sortOrder={sortOrder}&communityId={communityId}&submissionEndFrom={submissionEndFrom}&submissionEndTo={submissionEndTo}&challengeType={challengeType}&platforms={platforms}&technologies={technologies}&prizeLowerBound={prizeLowerBound}&prizeUpperBound={prizeUpperBound}]
### Search My Challenges [GET]

Expand Down
8 changes: 6 additions & 2 deletions config/tc-config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/*
* Copyright (C) 2013 - 2014 TopCoder Inc., All Rights Reserved.
*
* @author vangavroche, Ghost_141, kurtrips, Sky_, isv, bugbuka, flytoj2ee
* @version 1.26
* @author vangavroche, Ghost_141, kurtrips, Sky_, isv, bugbuka, flytoj2ee, TCSASSEMBLER
* @version 1.27
* changes in 1.1:
* - add defaultCacheLifetime parameter
* changes in 1.2:
Expand Down Expand Up @@ -62,12 +62,16 @@
* - Move configuration contents in tc-config.js
* Changes in 1.26:
* - Add studioReview object for get studio review opportunities api.
* Changes in 1.27:
* Add userActivationResendLimit and userActivationCacheLifeTime for user activation email api.
*/

"use strict";

var config = {
defaultUserCacheLifetime: process.env.USER_CACHE_EXPIRY || 1000 * 60 * 60 * 24, //24 hours default
userActivationResendLimit: 5,
userActivationCacheLifeTime: 1000 * 60 * 60 * 23 * 30,
pastChallengesCacheLifetime: 24 * 60 * 60 * 1000,
resetTokenPrefix: 'tokens-',
resetTokenSuffix: '-reset-token',
Expand Down
8 changes: 7 additions & 1 deletion queries/get_user_email_and_handle
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
SELECT handle, email FROM email_user WHERE user_id = @userId@
SELECT
u.handle
, e.address
FROM user u
, email e
WHERE u.user_id = @userId@
AND u.user_id = e.user_id
5 changes: 4 additions & 1 deletion routes.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2013 - 2014 TopCoder Inc., All Rights Reserved.
*
* @version 1.58
* @version 1.59
* @author vangavroche, Sky_, muzehyun, kurtrips, Ghost_141, ecnu_haozi, hesibo, LazyChild, isv, flytoj2ee,
* @author panoptimum, bugbuka, Easyhard
*
Expand Down Expand Up @@ -136,6 +136,8 @@
* - Added route for Active / Upcoming Data Science Challenges API.
* Changes in 1.58:
* - Add routes for SRM practice problems API.
* Changes in 1.59:
* - Add route for user activation email api.
*/
/*jslint node:true, nomen: true */
"use strict";
Expand Down Expand Up @@ -251,6 +253,7 @@ exports.routes = {
{ path: "/:apiVersion/design/download/:submissionId", action: "downloadDesignSubmission" },

{ path: "/:apiVersion/user/challenges", action: "getMyChallenges" },
{ path: "/:apiVersion/user/activation-email", action: "userActivationEmail" },

{ path: "/:apiVersion/users/tops/:trackType", action: "getTopTrackMembers" },
{ path: "/:apiVersion/users/resetToken", action: "generateResetToken" },
Expand Down
2 changes: 2 additions & 0 deletions test/sqls/userActivationEmail/common_oltp__clean
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DELETE FROM email WHERE email_id IN (100326, 100325);
DELETE FROM user WHERE user_id IN (100326, 100325);
8 changes: 8 additions & 0 deletions test/sqls/userActivationEmail/common_oltp__insert_test_data
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
INSERT INTO user (user_id, handle, status) VALUES(100326, 'promise', 'U');
INSERT INTO user (user_id, handle, status) VALUES(100325, 'callback', 'U');

INSERT INTO email(user_id, email_id, email_type_id, address, create_date, modify_date, primary_ind, status_id)
VALUES(100326, 100326, 1, 'promise@fakeserver.com', CURRENT, CURRENT, 1, 1);

INSERT INTO email(user_id, email_id, email_type_id, address, create_date, modify_date, primary_ind, status_id)
VALUES(100325, 100325, 1, 'callback@fakeserver.com', CURRENT, CURRENT, 1, 1);
Loading