2016/05/10
10 May, 2016

[Tutorial] How To Implement Terms & Conditions Approval for WSO2 API Manager

  • Praminda Jayawardana
  • Software Engineer - WSO2

Table of contents


Applies to

WSO2 API Manager Version 1.10 or above


Introduction

Terms and conditions (T&C) is a common method used in modern web applications to get users’ approval to certain set of usage conditions and use of data. WSO2 API Manager 1.10.0 also has several use cases where T&C approval can be used, such as subscription and user signup. This tutorial will provide a guide on how to implement T&C in API Store user signup using the subtheme approach.


What is a sub theme

A sub theme in WSO2 API Manager is a set of modifications to a main theme. By applying a sub theme you can override parts of a main theme and customize it to your needs without creating a whole new theme or changing the original one. This approach gives you the flexibility to try new UI changes without affecting the original theme. Implementation of a sub theme resides inside the main theme under the subthemes sub directory. Sub themes only contain the files you want to override from the main theme.


Creating the sub theme

First you need to take a copy of the original theme you want extend by a sub theme. Themes are located inside the repository/deployment/server/jaggeryapps/store/site/themes/ directory in API manager distribution. Moreover, you can download the default theme from this link. Name the copy of your theme with a preferred sub theme name. In this guide, let’s call it tnc. Then we have to customize the template file for signup and add the T&C component. Open the file templates/user/sign-up/template.jag in sub theme directory. Replace div class called form-actions at the bottom with the following code snippet.

<div class="form-actions">
   			 <span>
   				 <label>
   					 <input type="checkbox" id="terms" name="terms" value="false"/>
   					 I agree to <a href="https://wso2.com">terms and conditions</a> of WSO2 API Mananger 1.10.0
   				 </label>
   			 </span>
    	<input id="submit-user" class="submit btn btn-primary" type="submit" value="<%=i18n.localize("submit")%>" disabled/>
	</div>

This will add a checkbox before the submit button and disable the submit button.

Now we have to add the logic to enable/disable the submit button when the checkbox is checked/unchecked. To do that we need to update Javascript file for the above template file. Open templates/user/sign-up/js/sign-up.js file. Add the following jquery event listener inside document.ready function.

$("#terms").change(function() {
  var isAgreed = $("#submit-user").prop("disabled");
  if(isAgreed) {
	$("#submit-user").prop("disabled", false);
  } else {
	$("#submit-user").prop("disabled", true);
  }
});

This will enable/disable the submit button depending on the checkbox value. Finally the above files should look like what’s shown below.


template.jag

<% jagg.template("user/sign-up", function(inputs, outputs, jagg) { %>
    <%
    var fields = outputs.fields, length = fields.length;
    var user = session.get("logged.user");
    var mod = jagg.module("manager");
    var httpsUrl= mod.getHTTPsURL();
    if(user){ %>
   	 <script>
   	 location.href = "<%= jagg.getSiteContext()%>";
   	 </script>
   	 <% } %>
   	 <script>
   	 var context= "<%=jagg.getSiteContext()%>";
   	 </script>
   	 <div class="title-section"><h2><%=i18n.localize("signupTitle")%></h2></div>
   	 <div class="content-section shadow-up">
   		 <div class="content-data">
   			 <form class="form-horizontal" id="sign-up" autocomplete="off">
   				 <fieldset>
   					 <div class="control-group">
   						 <label class="control-label"  for="newUsername"><%=i18n.localize("username")%>:<span class="requiredAstrix">*</span></label>
   						 <div class="controls">
   							 <input id="newUsername" name="newUsername" maxlength="30" minlength="5" type="text" class="required validName input-medium noSpace" />
   							 <%
   							 if(request_tenant != null) { %>
   								 <label class="lblTenantDomainName"  for="newUsername"> @<%=request_tenant%></label>
   								 <%	}
   								 %>
   								 
   								 <input id="hiddenTenantDomain" type="hidden" value="<%=request_tenant%>">
   							 </div>
   						 </div>
   						 
   						 <div class="control-group">
   							 <label class="control-label" for="newPassword"><%=i18n.localize("password")%>:<span class="requiredAstrix">*</span></label>
   							 <div class="controls">
   								 <div class="row-fluid">
   									 <div class="span6">
   										 <input type="password" class="input-large password validPassword" id="newPassword" name="newPassword" />
   										 
   										 <div class="help-block" id="password-help" style="display:none">
   											 <%=i18n.localize("pwHelpMsgLine1")%>
   											 <ul>
   												 <li><%=i18n.localize("pwHelpMsgLine2")%></li>
   												 <li><%=i18n.localize("pwHelpMsgLine3")%></li>
   												 <li><%=i18n.localize("pwHelpMsgLine4")%></li>
   												 <li><%=i18n.localize("pwHelpMsgLine5")%></li>
   											 </ul>
   											 
   										 </div>
   									 </div>
   									 <div class="span6">
   										 <div class="password-meter" style="display:none;">
   											 <div class="password-meter-message"></div>
   											 <div class="password-meter-bg">
   												 <div class="password-meter-bar"></div>
   											 </div>
   										 </div>
   									 </div>
   								 </div>
   							 </div>
   						 </div>
   						 
   						 
   						 
   						 <div class="control-group">
   							 <label class="control-label" for="newPasswordConfirm"><%=i18n.localize("retypePassword")%>:<span class="requiredAstrix">*</span></label>
   							 <div class="controls"><input type="password" class="matchPasswords input-large" id="newPasswordConfirm" /></div>
   						 </div>
   						 
   						 <%
   						 var i, field, inputClass;
   						 for(i = 0; i < length; i++) {
   							 field = fields[i];
   							 var required = field.required;
   							 var claimUri = field.claimUri;
   							 if (required == true) {
   								 inputClass = "required input-large";
   							 } else {
   								 inputClass = "input-xlarge";
   							 }
   							 if (claimUri.indexOf("name") !== -1) {
   								 inputClass = "required validName input-large noSpace";
   							 } else if (claimUri.indexOf("email") !== -1) {
   								 inputClass = "required validEmail input-large noSpace";
   							 }
   							 %>
   							 <%if (required == true) {%>
   								 <div class="control-group">
   									 <label class="control-label" for="<%=i%>cliamUri"><%=i18n.localize(field.name, field.name)%>:
   										 <span class="requiredAstrix">*</span>
   									 </label>
   									 <div class="controls"><input type="text" id="<%=i%>cliamUri" name="<%=i%>cliamUri" class="<%=inputClass%>"/></div>
   								 </div>
   								 <%} %>
   								 <% } %>
   								 <div class="controls" style="padding-bottom:10px;" id="moreFieldsLink"><a onclick="showMoreFields()"><i class="icon-plus-sign"></i>More Details</a></div>
   								 <div class="controls" id="hideFieldsLink" style="display:none;padding-bottom:10px;">
   									 <a onclick="hideMoreFields()">
   										 <i class="icon-minus-sign"></i>More Details</a>
   									 </div>
   									 <div id="moreFields" style="display:none">
   										 <%
   										 for(i = 0; i < length; i++) {
   											 field = fields[i];
   											 var required = field.required;
   											 var claimUri = field.claimUri;
   											 if(field.name == "Home Phone" || field.name == "Telephone") {
   												 field.name = "Land Phone";
   											 } else if (field.name == "Mobile") {
   												 field.name = "Mobile Phone";
   											 }
   											 if (claimUri.indexOf("address") !== -1) {
   												 inputClass = "input-address";
   											 } else if (claimUri.indexOf("country") !== -1) {
   												 inputClass = "input-medium";
   											 } else if (claimUri.indexOf("role") !== -1) {
   												 inputClass = "input-small";
   											 } else {
   												 inputClass = "input-large";
   											 }
   											 %>
   											 <%if (required != true) {%>
   												 <div class="control-group">
   													 <label class="control-label" for="<%=i%>cliamUri"><%=i18n.localize(field.name, field.name)%>:
   													 </label>
   													 <div class="controls"><input type="text" id="<%=i%>cliamUri" name="<%=i%>cliamUri" class="<%=inputClass%>"/></div>
   												 </div>
   												 <%} %>
   												 <% } %>
   											 </div>
   											 <input type="hidden" id="fieldCount" name="fieldCount" value="<%=length%>"/>
   											 
   											 <div class="form-actions">
   												 <span>
   													 <label>
   														 <input type="checkbox" id="terms" name="terms" value="false"/>
   														 I agree to <a href="https://wso2.com">terms and conditions</a> of WSO2 API Mananger 1.10.0
   													 </label>
   												 </span>
   												 <input id="submit-user" class="submit btn btn-primary" type="submit" value="<%=i18n.localize("submit")%>" disabled/>
   											 </div>
   											 
   										 </fieldset>
   									 </form>
   								 </div>
   							 </div>
   							 <form id="signUpRedirectForm" method="post" action="<%=jagg.getAbsoluteUrl(jagg.getThemeFile("templates/user/sign-up/redirector.jag"))%>">
   								 <input type="hidden" name="redirectToHome" id="redirectToHome" value="<%= jagg.getSiteContext() %>" />
   							 </form>
   							 
   							 
   							 <% }); %>


sign-up.js

$(document).ready(function() {
	$.validator.addMethod("matchPasswords", function(value) {
   	 return value == $("#newPassword").val();
    }, "The passwords you entered do not match.");
 
	$.validator.addMethod('noSpace', function(value, element) {
        	return !/\s/g.test(value);
	}, 'The Name contains white spaces.');
 
 
	$("#sign-up").validate({
 	submitHandler: function(form) {
   	 var fieldCount = document.getElementById('fieldCount').value;
    var allFieldsValues;
	 for(var i = 0; i 

Now we have completed the customizations required for new sub theme. Next we need to enable the sub theme we created in WSO2 API Manager. To do that, copy the theme we customized (tnc directory) to repository/deployment/server/jaggeryapps/store/site/themes/<main_theme_name>/subthemes/. Open repository/deployment/server/jaggeryapps/store/site/conf/site.json and change the theme configuration as follows.

"theme" : {
        "base" : "fancy",
        "subtheme" : "tnc"
}

Now if you visit the signup page in the API Store you will notice that the changes have now been applied.

Figure 1


Conclusion

In this guide we looked at how you can enable T&C in WSO2 API Manager 1.10.0 API Store user signup, using the subtheme approach. This implementation will allow you to get your users to agree to your privacy and T&C statements before they sign up as API Store user.


References

 

About Author

  • Praminda Jayawardana
  • Software Engineer
  • WSO2 Inc.