Skip to content

Commit

Permalink
Added new user registration capability
Browse files Browse the repository at this point in the history
  • Loading branch information
rhinoman committed Mar 28, 2016
1 parent 674b382 commit 22c40f3
Show file tree
Hide file tree
Showing 15 changed files with 392 additions and 14 deletions.
18 changes: 12 additions & 6 deletions config/config_service/config_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,13 @@ import (
type ConfigController struct{}

type ConfigResponse struct {
Links HatLinks `json:"_links"`
ParamName string `json:"paramName"`
ParamValue string `json:"paramValue"`
Links HatLinks `json:"_links"`
Param ConfigParam `json:"configParam"`
}

type ConfigParam struct {
ParamName string `json:"paramName"`
ParamValue string `json:"paramValue"`
}

var configWebService *restful.WebService
Expand Down Expand Up @@ -98,8 +102,10 @@ func (cc ConfigController) genConfigResponse(paramName, paramValue string) Confi
uri := cc.configUri() + "/" + paramName
links.Self = &HatLink{Href: uri, Method: "GET"}
return ConfigResponse{
Links: links,
ParamName: paramName,
ParamValue: paramValue,
Links: links,
Param: ConfigParam{
ParamName: paramName,
ParamValue: paramValue,
},
}
}
1 change: 1 addition & 0 deletions frontend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ func main() {
config.InitEtcd()
config.FetchCommonConfig()
config.FetchServiceSection(config.FrontendService)
config.FetchServiceSection(config.AuthService)
// Load plugin ini
fserv.LoadPluginData(config.Frontend.PluginDir + "/plugins.ini")
database.InitDb()
Expand Down
15 changes: 15 additions & 0 deletions frontend/routing/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ func Start() {
r := mux.NewRouter()
// Serve the login page
r.HandleFunc("/login", getLogin).Methods("GET")
// Serve the new user registration page
r.HandleFunc("/register", getRegistration).Methods("GET")
// Serve the forgot password page
r.HandleFunc("/forgot_password", getForgotPassword).Methods("GET")
// Serve the rest password page
Expand Down Expand Up @@ -177,6 +179,19 @@ func getLogin(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, location)
}

// Serve up the registration page
func getRegistration(w http.ResponseWriter, r *http.Request) {
if config.Auth.AllowNewUserRegistration {
location := path.Join(webAppDir, "register.html")
LogRequest(r)
log.Printf("Serving registration page from %s", location)
http.ServeFile(w, r, location)
} else {
//New user registration isn't enabled
w.WriteHeader(http.StatusForbidden)
}
}

// Serve up the forgot password page
func getForgotPassword(w http.ResponseWriter, r *http.Request) {
location := path.Join(webAppDir, "forgot_password.html")
Expand Down
13 changes: 12 additions & 1 deletion frontend/web_app/app/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ <h2 class="form-signin-heading">Sign in</h2>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
<div class="link-box">
<a href="/forgot_password">Forgot Password?</a>
<a href="/forgot_password">Forgot Password</a>
</div>
</div>
</div>
Expand All @@ -43,6 +43,17 @@ <h2 class="form-signin-heading">Sign in</h2>
}

$("div#alertBox").css("display", "none");
// Should we display the reigstration link?
$.ajax({
type: "GET",
url: "api/v1/config/auth/allowNewUserRegistration",
dataType: "json"
}).done(function(param){
const paramValue = param.configParam.paramValue;
if(paramValue){
$("div.link-box").append('&bull;&nbsp;<a href="/register">Register</a>');
}
});
$("#loginForm").on("submit", function(event){
event.preventDefault();
var loginCredentials = {
Expand Down
121 changes: 120 additions & 1 deletion frontend/web_app/app/register.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,128 @@
<meta name="description" content="New user registration">
<title>Register</title>
<link href="/app/resource/scripts/vendor/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/app/resource/styles/register.css" rel="stylesheet">
<script type="text/javascript" src="/app/resource/scripts/vendor/jquery/dist/jquery.min.js"></script>
</head>
<body>

<div class="container">
<div class="register-box">
<form id="registerForm">
<h2 class="form-register-heading">Register</h2>
<p>Create a new account for this site</p>
<div id="alertBox" class="alert alert-danger" role="alert"></div>
<label for="inputUsername" class="sr-only">Username</label>
<div class="input-group">
<span class="input-group-addon glyphicon glyphicon-user" id="user-icon"></span>
<input type="text" id="inputUsername" class="form-control" placeholder="Enter username" required autofocus>
</div>
<label for="inputEmail" class="sr-only">Email</label>
<div class="input-group">
<span class="input-group-addon glyphicon glyphicon-envelope" id="email-icon"></span>
<input type="email" id="inputEmail" class="form-control" placeholder="Enter email address" required>
</div>
<label for="inputPassword" class="sr-only">Password</label>
<div class="input-group">
<span class="input-group-addon glyphicon glyphicon-lock" id="lock-icon"></span>
<input type="password" id="inputPassword" class="form-control" placeholder="Enter a Password" required>
</div>
<label for="verifyPassword" class="sr-only">Verify Password</label>
<div class="input-group">
<span class="input-group-addon glyphicon glyphicon-lock" id="veriy-icon"></span>
<input type="password" id="verifyPassword" class="form-control" placeholder="Verify Password" required>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Register</button>
</form>
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$("div#alertBox").hide();
});
function validateEmail(email) {
var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
function validateUser(user){
var errors = [];
if(user.name.length < 3 || user.name.length > 80){
errors.push("Username invalid");
}
if(user.password.length < 4){
errors.push("Password too short");
}
if(!validateEmail(user.userPublic.contactInfo.email)){
errors.push("Email address is invalid");
}
return errors;
}
function showError(errors){
var alertBox = $("div#alertBox");
var errorStr = "";
for(var i = 0; i < errors.length; i++){
errorStr += "<li>" + errors[i] + "</li>";
}
alertBox.html("<p>Couldn't complete registration</p><ul>" + errorStr + "</ul>");
alertBox.show();
}
function login(username, password){
const loginCredentials = {
name: username,
password: password
};
$.ajax({
type: "POST",
url: "api/v1/auth/session",
data: JSON.stringify(loginCredentials),
contentType: "application/json",
dataType: "json"
}).done(function(){
$("div#alertBox").hide();
window.location = "/app";
}).fail(function(){
$("div#alertBox").html("Could not log in. Please try again later").show();
});
}
$("#registerForm").on("submit", function(event){
event.preventDefault();
const userName = $("#inputUsername").val();
const password = $("#inputPassword").val();
const verifyPassword = $("#verifyPassword").val();
const email = $("#inputEmail").val();
if(password !== verifyPassword){
showError(["Password fields do not match"]);
return;
}
const newUser = {
name: userName,
password: password,
userPublic: {
contactInfo: {
email: email
}
}
};
var errors = validateUser(newUser);
if(errors.length > 0){
showError(errors);
} else {
$.ajax({
type: "POST",
url: "api/v1/users/register",
data: JSON.stringify(newUser),
contentType: "application/json"
}).done(function(){
$("div#alertBox").hide();
login(userName, password);
}).fail(function(jqXHR, reason){
if(jqXHR.status === 409){
$("div#alertBox").html("Username already exists.").show();
} else {
$("div#alertBox").html("Couldn't create user: " + reason).show();
}
})
}
});
</script>
</body>
</html>
60 changes: 60 additions & 0 deletions frontend/web_app/app/scripts/entities/config/config_manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Licensed to Wikifeat under one or more contributor license agreements.
* See the LICENSE.txt file distributed with this work for additional information
* regarding copyright ownership.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of Wikifeat nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

'use strict';

define([
'jquery',
'underscore',
'backbone',
'marionette',
'entities/base_manager',
'entities/config/config_param'
], function($,_,Backbone,Marionette,BaseManager,ConfigParamModel){

//Constructor
var ConfigManager = function(){
BaseManager.call(this, ConfigParamModel);
};

ConfigManager.prototype = Object.create(BaseManager.prototype);

ConfigManager.prototype.getConfigParam = function(section, param){
if (section !== "" && param !== ""){
var entity = new ConfigParamModel();
entity.url = entity.urlRoot + "/" + section + "/" + param;
return this.fetchDeferred(entity);
} else {
return null;
}
};

return ConfigManager;
});
54 changes: 54 additions & 0 deletions frontend/web_app/app/scripts/entities/config/config_param.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Licensed to Wikifeat under one or more contributor license agreements.
* See the LICENSE.txt file distributed with this work for additional information
* regarding copyright ownership.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of Wikifeat nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

'use strict';

define([
'jquery',
'underscore',
'backbone',
'entities/base_model'
], function($,_,Backbone, BaseModel){

//Constructor
function ConfigParamModel(data, options){
BaseModel.call(this, "configParam", data, options);
}

ConfigParamModel.prototype = Object.create(BaseModel.prototype);

ConfigParamModel.prototype.urlRoot = "/api/v1/config";
ConfigParamModel.prototype.defaults = {
paramName: "",
paramValue: ""
};

return ConfigParamModel;
});
13 changes: 11 additions & 2 deletions frontend/web_app/app/scripts/entities/entity_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ define([
'backbone',
'backbone.radio',
'entities/user/user_manager',
'entities/wiki/wiki_manager'
], function($,_,Backbone,Radio,UserManager,WikiManager){
'entities/wiki/wiki_manager',
'entities/config/config_manager'
], function($,_,Backbone,Radio,UserManager,WikiManager,ConfigManager){

var EntityManager = function(){
//Might add some stuff here, maybe.
Expand Down Expand Up @@ -191,5 +192,13 @@ define([

//-------End Wiki Manager Stuff

//-------Config Manager stuff
var configManager = new ConfigManager();
var configChannel = Radio.channel('configManager');

configChannel.reply("get:configParam", function(section, param){
return configManager.getConfigParam(section, param);
});

return EntityManager
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@
<span class="glyphicon glyphicon-log-in"></span>
Log In
</a>
<a href="/register" class="subMenuLink" id="registerLink">
<span class="glyphicon glyphicon-ok-circle"></span>
Register
</a>
</div>
Loading

0 comments on commit 22c40f3

Please sign in to comment.