Commit 299d0f0a authored by Marcel Rieger's avatar Marcel Rieger
Browse files

Update login, register, and password recovery pages.

parent 65354fb8
......@@ -17,10 +17,10 @@ dev_mode = True
client_log_level = all
client_log_ignore = []
welcome_text = <center>Welcome to VISPA!</center>
welcome_phrase = Welcome to VISPA!
#login_text = Information for Login
#registration_text = Information for Registration
forgot_text = A mail with further instructions will be sent to your mail account!
#forgot_text = Check your spam folder and uncheck no-reply@vispa.physik.rwth-aachen.de
use_forgot = False
[websockets]
......
......@@ -11,6 +11,7 @@ from vispa.models.workspace import Workspace, WorkspaceState
from vispa.models.preference import VispaPreference, ExtensionPreference
from vispa.models.shortcuts import VispaShortcuts, ExtensionShortcuts
from vispa import browser
from vispa import MessageException
import vispa
import vispa.workspace
import logging
......@@ -48,43 +49,37 @@ class AjaxController(AbstractController):
@cherrypy.expose
@cherrypy.tools.user(on=False)
@cherrypy.tools.workspace(on=False)
def register(self, username, email, password):
@cherrypy.tools.ajax()
def register(self, username, email):
db = cherrypy.request.db
user = User.register(db, username, email, password)
if isinstance(user, User):
if User.is_active(cherrypy.request.db, user.id):
cherrypy.session["user_id"] = unicode(user.id)
if "user.registration.hook" in cherrypy.config:
cmd = []
for arg in cherrypy.config["user.registration.hook"]:
cmd.append(Template(arg).substitute(username=user.name, userid=user.id))
call(cmd)
return success(encode_json=True)
user = User.register(db, username, email)
if vispa.config("user", "registration.sendmail", False):
User.send_registration_mail(user.name, user.email, user.hash)
else:
return fail(msg=user, encode_json=True)
return {"hash": user.hash}
return {"hash": None}
@cherrypy.expose
@cherrypy.tools.user(on=False)
@cherrypy.tools.workspace(on=False)
@cherrypy.tools.json_out()
def forgot(self, username):
@cherrypy.tools.ajax()
def forgotpassword(self, username):
User.forgot_password(cherrypy.request.db, username)
return {"msg": "Further instructions have been sent to your mail address!"}
@cherrypy.expose
@cherrypy.tools.user(on=False)
@cherrypy.tools.workspace(on=False)
@cherrypy.tools.json_out()
def resetpassword(self, userhash, password, *args, **kwargs):
user = User.get_by_hash(cherrypy.request.db, userhash)
if not user:
return fail()
@cherrypy.tools.ajax()
def setpassword(self, hash, password):
user = User.get_by_hash(cherrypy.request.db, hash)
if not isinstance(user, User):
raise MessageException("Invalid hash")
user.hash = None
user.password = password
if User.is_active(cherrypy.request.db, user.id):
cherrypy.session["user_id"] = unicode(user.id)
cherrypy.session["user_name"] = user.name
return success()
@cherrypy.expose
@cherrypy.tools.workspace(on=False)
......
......@@ -91,39 +91,6 @@ class RootController(AbstractController):
workspace_data[int(workspace.id)] = data
return workspace_data
@cherrypy.expose
@cherrypy.tools.allow(methods=["GET"])
@cherrypy.tools.stats(page="index")
@cherrypy.tools.render(template="html/sites/index.html")
def index2(self, *args, **kwargs):
db = cherrypy.request.db
username = cherrypy.request.user.name
devmode = vispa.config("web", "devmode", True)
use_websockets = vispa.config("websockets", "enabled", False)
secure_websockets = vispa.config("websockets", "secure", False)
preferences = self.get_preferences(db, cherrypy.request.user.id, parse_json=True)
client_logging_enabled = vispa.config("web", "client_logging_enabled", True)
client_logging_level = vispa.config("web", "client_logging_level", "info")
client_logging_ignore = vispa.config("web", "client_logging_ignore", [])
workspace_ids = self.get("workspace_ids")
workspace_data = self.workspace_data()
workspace_data = JSON.dumps(workspace_data)
add_workspaces = vispa.config("workspace", "allow_new_workspaces", True)
data = {"devmode" : devmode,
"username" : username,
"common_js" : self.common_js,
"common_css" : self.common_css,
"use_websockets" : use_websockets,
"secure_websockets": secure_websockets,
"workspace_ids" : self.convert(workspace_ids, int),
"workspace_data" : workspace_data,
"add_workspaces" : add_workspaces,
"logging_enabled" : client_logging_enabled,
"logging_level" : client_logging_level,
"logging_ignore" : client_logging_ignore}
data.update(preferences)
return data
@cherrypy.expose
@cherrypy.tools.workspace(on=False)
@cherrypy.tools.allow(methods=["GET"])
......@@ -162,20 +129,22 @@ class RootController(AbstractController):
@cherrypy.tools.user(reverse=True, path="/")
@cherrypy.tools.allow(methods=["GET"])
@cherrypy.tools.stats(page="login")
@cherrypy.tools.render(template="html/sites/login.html")
@cherrypy.tools.render(template="sites/login.mako")
def login(self, *args, **kwargs):
path = self.requested_path()
welcome_text = vispa.config("web", "welcome_text", "")
welcome_phrase = vispa.config("web", "welcome_phrase", "")
login_text = vispa.config("web", "login_text", "")
registration_text = vispa.config("web", "registration_text", "")
forgot_text = vispa.config("web", "forgot_text", "")
use_forgot = vispa.config("web", "use_forgot", False)
return {"requested_path" : path,
"welcome_text" : welcome_text,
"login_text" : login_text,
"registration_text": registration_text,
"forgot_text" : forgot_text,
"use_forgot" : use_forgot}
return {
"requested_path" : path,
"welcome_phrase" : welcome_phrase,
"login_text" : login_text,
"registration_text": registration_text,
"forgot_text" : forgot_text,
"use_forgot" : use_forgot
}
@cherrypy.expose
@cherrypy.tools.user()
......@@ -187,13 +156,19 @@ class RootController(AbstractController):
@cherrypy.expose
@cherrypy.tools.user(reverse=True)
@cherrypy.tools.render(template="html/sites/activate.html")
def activate(self, hash, *args, **kwargs):
user = User.activate(cherrypy.request.db, hash)
if not isinstance(user, User):
return self.success()
else:
return self.fail()
@cherrypy.tools.workspace(on=False)
@cherrypy.tools.render(template="sites/password.mako")
def password(self, hash, *args, **kwargs):
user = User.get_by_hash(cherrypy.request.db, hash)
welcome_phrase = vispa.config("web", "welcome_phrase", "")
data = {
"welcome_phrase": welcome_phrase,
"username": None,
"hash": hash
}
if isinstance(user, User):
data["username"] = user.name
return data
@cherrypy.expose
@cherrypy.tools.user(reverse=True)
......
......@@ -74,10 +74,10 @@ class User(Base):
if user is None:
user = User.get_by_email(session, username)
if user is None:
raise MessageException('Unknown user')
raise MessageException('Wrong username or password')
if user.password != password:
raise MessageException('Wrong password')
raise MessageException('Wrong username or password')
if user.status != User.ACTIVE:
raise MessageException("Account is not active")
......@@ -87,24 +87,20 @@ class User(Base):
return user
@staticmethod
def register(session, name, email, password):
# name exists?
def register(session, name, email):
# check by name
if User.get_by_name(session, name) is not None:
return 'This username already exists!'
raise MessageException('Username or mail address already exists!')
# check the email
# check by email
if User.get_by_email(session, email) is not None:
return 'Your mail address already exists!'
raise MessageException('User or mail address already exists!')
# Max Users ?
# max users?
count = session.query(User).count()
if count >= User.MAX_USERS:
return 'The maximum number of registered users is reached!'
# check the passwd's
if len(password) < User.PW_LENGTH[0] or len(password) > User.PW_LENGTH[1]:
return 'The length of your password should be between %d and %d chars!' % tuple(User.PW_LENGTH)
# email valid?
email = email.lower()
valid_hosts = vispa.config('user', 'registration.mail_hosts', [])
......@@ -117,41 +113,26 @@ class User(Base):
if len(valid_hosts) and host not in valid_hosts:
emailvalid = False
if not emailvalid:
return 'This is not a valid mail address!'
raise MessageException('Please use a valid email address!')
# check the name
# => length
if len(name) < User.NAME_LENGTH[0] or len(name) > User.NAME_LENGTH[1]:
return 'The length of the username should be between %d and %d chars!' % tuple(User.NAME_LENGTH)
raise MessageException('The length of the username should be between %d and %d chars!' % tuple(User.NAME_LENGTH))
# => chars
for char in name:
if char not in User.NAME_CHARS:
return 'The char \'%s\' is not allowed!' % char
# name forbidden?
raise MessageException('The char \'%s\' is not allowed!' % char)
# => forbidden?
if name.lower() in User.FORBIDDEN_NAMES:
return 'This username is forbidden!'
raise MessageException('This username is forbidden!')
# ## The userdata passed all checks
# The userdata passed all checks
# create a hash
hash = User.generate_hash(32)
# => register the user
autoactive = vispa.config('user', 'registration.autoactive', True)
status = User.ACTIVE if autoactive else User.INACTIVE
user = User(name=name, password=password, email=email, hash=hash, status=status)
# register the user?
user = User(name=name, password=User.generate_hash(64), email=email,
hash=User.generate_hash(32), status=User.ACTIVE)
session.add(user)
# send the registration mail?
if vispa.config('user', 'registration.sendmail', False):
User.send_registration_mail(name, email, hash)
# we need a commit this time
# because we need the id which is
# generated after the commit
session.commit()
vispa.fire_callback("user.register", user)
......@@ -165,9 +146,15 @@ class User(Base):
to_addr = email
subject = "Your Vispa Registration"
response_host = vispa.config('user', 'registration.activation', 'http://localhost')
link = os.path.join(response_host, "?hash=%s" % hash)
msg = "Hi %s!\n\nTo finish your registration for Vispa, click on the link below:\n\n%s\n\nYour Vispa-Team!" % (name, link)
response_host = vispa.config('user', 'registration.activation', 'http://localhost/password')
link = os.path.join(response_host, hash)
msg = """Thanks for your registration, %s!
\n\n
To finish your registration, click on the link below:
\n\n
%s
\n\n
Your Vispa-Team!""" % (name, link)
User.send_mail(from_addr, to_addr, subject, msg)
......@@ -200,9 +187,15 @@ class User(Base):
to_addr = user.email
subject = "Your Vispa Password"
response_host = vispa.config('user', 'registration.forgot', 'http://localhost')
link = os.path.join(response_host, "?hash=%s" % hash)
msg = "Hi %s!\n\nYou requested a password change.\nClick on the link below to select a new one:\n\n%s\n\nYour Vispa-Team!" % (user.name, link)
response_host = vispa.config('user', 'registration.forgot', 'http://localhost/password')
link = os.path.join(response_host, hash)
msg = """Hi %s!
\n\n
You requested a password change. To set a new one, click on the link below:
\n\n
%s
\n\n
Your Vispa-Team!""" % (user.name, link)
try:
User.send_mail(from_addr, to_addr, subject, msg)
......
/* bootstrap adjustments */
nav a > b.caret:last-child {
margin-left: 6px;
}
li a > i.glyphicon:first-child,
li button > i.glyphicon:first-child {
margin-right: 6px;
vertical-align: text-top;
}
.modal-header i.glyphicon {
margin-right: 6px;
}
/* basic classes */
.vispa-absolute (@top: 0px, @right: 0px, @bottom: 0px, @left: 0px) {
position: absolute;
top: @top;
right: @right;
bottom: @bottom;
left: @left;
}
.vispa-hidden {
display: hidden;
}
.vispa-blur {
-webkit-filter: blur(1px);
-webkit-transition: -webkit-filter 300ms;
}
.vispa-modal {
.vispa-absolute;
background-color: rgba(0, 0, 0, 0.4);
cursor: default;
z-index: 2;
}
.vispa-table-outer {
display: table;
height: 100%;
width: 100%;
}
.vispa-table-inner {
display: table-cell;
vertical-align: middle;
}
.vispa-rtl-fix {
color: transparent;
font-size: 0px;
}
.vispa-rtl-fix-hidden {
.vispa-rtl-fix;
display: none;
}
/* imports */
@import "../../base/base.less";
/* variables */
@header-height: 50px;
@tab-bar-height: 40px;
@border-offset: 5px;
......@@ -11,67 +15,6 @@
@tab-color-active: #000;
/* bootstrap adjustments */
nav a > b.caret:last-child {
margin-left: 6px;
}
li a > i.glyphicon:first-child,
li button > i.glyphicon:first-child {
margin-right: 6px;
vertical-align: text-top;
}
.modal-header i.glyphicon {
margin-right: 6px;
}
/* basic classes */
.vispa-absolute (@top: 0px, @right: 0px, @bottom: 0px, @left: 0px) {
position: absolute;
top: @top;
right: @right;
bottom: @bottom;
left: @left;
}
.vispa-hidden {
display: hidden;
}
.vispa-blur {
-webkit-filter: blur(1px);
-webkit-transition: -webkit-filter 300ms;
}
.vispa-modal {
.vispa-absolute;
background-color: rgba(0, 0, 0, 0.4);
cursor: default;
z-index: 2;
}
.vispa-table-outer {
display: table;
height: 100%;
width: 100%;
}
.vispa-table-inner {
display: table-cell;
vertical-align: middle;
}
.vispa-rtl-fix {
color: transparent;
font-size: 0px;
}
.vispa-rtl-fix-hidden {
.vispa-rtl-fix;
display: none;
}
/* vispa styles */
.vispa-nav {
......
body {
background-image: url(../../../img/maingui/grey.png);
}
.startup-overlay {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
z-index: 10;
background-color: #303030;
}
.content-outer {
margin: 20px auto;
width: 640px;
min-width: 640px;
}
.content-logo {
text-align: center;
margin-bottom: 20px;
}
.content-top {
font-family: "Trebuchet MS", Helvetica, Arial, sans-serif;
color: #505050;
margin-bottom: 20px;
}
#accordion > div {
overflow: hidden;
}
.input {
height: 20px;
width: 220px;
padding: 1px 2px 0px 2px;
color: #3383bb;
}
.table {
margin-bottom: 10px;
}
.table td {
padding: 5px 5px;
}
.table button {
float: right;
}
\ No newline at end of file
/* imports */
@import "../../base/base.less";
body {
padding-top: 20px;
padding-bottom: 20px;
}
.vispa-header-logo {
margin-right: 15px;
}
.tab-content {
margin-top: 20px;
}
.space {
margin: 0px 10px;
}
form {
margin-bottom: 20px;
}
.form-control {
position: relative;
font-size: 16px;
height: auto;
padding: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.form-control:focus {
z-index: 2;
}
.side_text {
padding-top: 30px;
}
#login-name, #register-name {
margin-bottom: -1px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
#login-password, #register-email {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
#register-email {
margin-bottom: 20px;
}
#forgot-name {
margin: 20px 0px;
}
\ No newline at end of file
/* imports */
@import "../../base/base.less";
body {
padding-top: 20px;
padding-bottom: 20px;
}
.vispa-header-logo {
margin-right: 15px;
}
.tab-content {
margin-top: 20px;
}
.space {
margin: 0px 10px;
}
.form-control {
position: relative;
font-size: 16px;
height: auto;
padding: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.form-control:focus {
z-index: 2;
}
#password1 {
margin-bottom: -1px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
#password2 {
border-top-left-radius: 0;
border-top-right-radius: 0;
margin-bottom: 20px;
}