Commit 699777af authored by Alain Takoudjou's avatar Alain Takoudjou

slaprunner: remove create user at first launch

It's not needed anymore to create a user at first launch of webrunner. Credential can be created from slapos recipe directly.
Webrunner can also clone default repository at first launch.

/reviewed-on nexedi/slapos.toolbox!7
parent 69a41bc8
...@@ -43,6 +43,7 @@ setup(name=name, ...@@ -43,6 +43,7 @@ setup(name=name,
'slapos.core', # as it provides library for slap 'slapos.core', # as it provides library for slap
'xml_marshaller', # needed to dump information 'xml_marshaller', # needed to dump information
'GitPython', #needed for git manipulation into slaprunner 'GitPython', #needed for git manipulation into slaprunner
'passlib',
'netifaces', 'netifaces',
] + additional_install_requires, ] + additional_install_requires,
extras_require = { extras_require = {
......
...@@ -11,79 +11,68 @@ from git import Repo ...@@ -11,79 +11,68 @@ from git import Repo
from flask import jsonify from flask import jsonify
def cloneRepo(data): def cloneRepo(url, workDir, user="", email=""):
"""Clone a repository """Clone a repository
Args: Args:
data: a dictionary of parameters to use: workDir is the path of the new project
data['path'] is the path of the new project url is the url of the repository to be cloned
data['repo'] is the url of the repository to be cloned email is the user's email
data['email'] is the user's email user is the name of the user"""
data['user'] is the name of the user
Returns:
a jsonify data"""
workDir = data['path']
if not workDir: if not workDir:
return jsonify(code=0, return jsonify(code=0,
result="Can not create project folder.") result="Can not create project folder.")
code = 0
json = ""
try:
if os.path.exists(workDir) and len(os.listdir(workDir)) < 2:
shutil.rmtree(workDir) # delete useless files
repo = Repo.clone_from(data["repo"], workDir)
config_writer = repo.config_writer()
config_writer.add_section("user")
if data["user"] != "":
config_writer.set_value("user", "name", data["user"].encode("utf-8"))
if data["email"] != "":
config_writer.set_value("user", "email", data["email"])
code = 1
except Exception as e:
json = safeResult(str(e))
return jsonify(code=code, result=json)
if os.path.exists(workDir) and len(os.listdir(workDir)) < 2:
shutil.rmtree(workDir) # delete useless files
repo = Repo.clone_from(url, workDir)
config_writer = repo.config_writer()
config_writer.add_section("user")
if user != "":
config_writer.set_value("user", "name", user.encode("utf-8"))
if email != "":
config_writer.set_value("user", "email", email)
def updateGitConfig(repository, user, email):
if not os.path.exists(repository):
return
repo = Repo(repository)
config_writer = repo.config_writer()
if user != "":
config_writer.set_value("user", "name", user.encode("utf-8"))
if email != "":
config_writer.set_value("user", "email", email)
config_writer.release()
def gitStatus(project): def gitStatus(project):
"""Run git status and return status of specified project folder """Run git status and return status of specified project folder
Args: Args:
project: path of the projet to get status project: path of the projet to get status
Returns: Returns:
a parsed string that contains the result of git status""" a list with (result of git status, current branch, isdirty)"""
code = 0
json = "" repo = Repo(project)
try: git = repo.git
repo = Repo(project) result = git.status().replace('#', '')
git = repo.git branch = git.branch().replace(' ', '').split('\n')
json = git.status().replace('#', '') isdirty = repo.is_dirty(untracked_files=True)
branch = git.branch().replace(' ', '').split('\n') return (result, branch, isdirty)
isdirty = repo.is_dirty(untracked_files=True)
code = 1
except Exception as e:
json = safeResult(str(e))
return jsonify(code=code, result=json, branch=branch, dirty=isdirty)
def switchBranch(project, name): def switchBranch(project, branch):
"""Switch a git branch """Switch a git branch
Args: Args:
project: directory of the local git repository project: directory of the local git repository
name: switch from current branch to `name` branch name: switch from current branch to `name` branch"""
Returns:
a jsonify data""" repo = Repo(project)
code = 0 current_branch = repo.active_branch.name
json = "" if branch == current_branch:
try: return False
repo = Repo(project) else:
current_branch = repo.active_branch.name git = repo.git
if name == current_branch: git.checkout(branch)
json = "This is already your active branch for this project" return True
else:
git = repo.git
git.checkout(name)
code = 1
except Exception as e:
json = safeResult(str(e))
return jsonify(code=code, result=json)
def addBranch(project, name, onlyCheckout=False): def addBranch(project, name, onlyCheckout=False):
...@@ -93,20 +82,17 @@ def addBranch(project, name, onlyCheckout=False): ...@@ -93,20 +82,17 @@ def addBranch(project, name, onlyCheckout=False):
name: name of the new branch name: name of the new branch
onlyCheckout: if True then the branch `name` is created before checkout onlyCheckout: if True then the branch `name` is created before checkout
Returns: Returns:
a jsonify data""" True or False"""
code = 0
json = "" if not os.path.exists(project):
try: return False
repo = Repo(project) repo = Repo(project)
git = repo.git git = repo.git
if not onlyCheckout: if not onlyCheckout:
git.checkout('-b', name) git.checkout('-b', name)
else: else:
git.checkout(name) git.checkout(name)
code = 1 return True
except Exception as e:
json = safeResult(str(e))
return jsonify(code=code, result=json)
def getDiff(project): def getDiff(project):
......
...@@ -8,12 +8,16 @@ import flask ...@@ -8,12 +8,16 @@ import flask
import logging import logging
import logging.handlers import logging.handlers
import os import os
import urlparse
from slapos.htpasswd import HtpasswdFile from slapos.htpasswd import HtpasswdFile
from slapos.runner.process import setHandler from slapos.runner.process import setHandler
import sys import sys
from slapos.runner.utils import runInstanceWithLock from slapos.runner.utils import runInstanceWithLock
from slapos.runner.views import * from slapos.runner.views import *
from slapos.runner.gittools import cloneRepo, switchBranch
from git import GitCommandError
import time import time
import traceback
TRUE_VALUES = (1, '1', True, 'true', 'True') TRUE_VALUES = (1, '1', True, 'true', 'True')
...@@ -129,6 +133,20 @@ def serve(config): ...@@ -129,6 +133,20 @@ def serve(config):
os.mkdir(software_link) os.mkdir(software_link)
setHandler() setHandler()
app.logger.addHandler(config.logger) app.logger.addHandler(config.logger)
repo_url = app.config['default_repository']
branch_name = app.config.get('default_repository_branch', '')
repo_name = os.path.basename(repo_url.replace('.git', ''))
try:
repository_path = os.path.join(workdir, repo_name)
app.config.update(default_repository_path=repository_path)
if len(os.listdir(workdir)) == 0 or not os.path.exists(repository_path):
app.logger.info('cloning repository %s...' % repo_url)
result = cloneRepo(repo_url, repository_path)
if branch_name:
switchBranch(repository_path, branch_name)
except GitCommandError, e:
app.logger.warning('Error while cloning default repository: %s' % str(e))
traceback.print_exc()
app.logger.info('Running slapgrid...') app.logger.info('Running slapgrid...')
if app.config['auto_deploy_instance'] in TRUE_VALUES: if app.config['auto_deploy_instance'] in TRUE_VALUES:
import thread import thread
......
...@@ -707,7 +707,7 @@ a.lshare img{ ...@@ -707,7 +707,7 @@ a.lshare img{
} }
.form{padding:10px; padding-left:20px;} .form{padding:10px; padding-left:20px;}
.form label{display:block; float:left; width:150px; padding-top:10px;} .form label{display:block; float:left; width:150px; padding-top:10px;}
.form input[type=text] ,.form input[type=password] {float:left; width:190px;margin:5px;} .form input[type=text] ,.form input[type=password], .form select {float:left; width:190px;margin:5px;}
.hiddendiv {display: none;white-space: pre-wrap;min-height: 18px;font-size: 13px; .hiddendiv {display: none;white-space: pre-wrap;min-height: 18px;font-size: 13px;
padding:3px;word-wrap: break-word;width:430px; max-height:120px;font-family: 'Helvetica Neue',Tahoma,Helvetica,Arial,sans-serif;} padding:3px;word-wrap: break-word;width:430px; max-height:120px;font-family: 'Helvetica Neue',Tahoma,Helvetica,Arial,sans-serif;}
.list{display: block;padding: 5px;background: #E7E7E7; margin-bottom:7px;} .list{display: block;padding: 5px;background: #E7E7E7; margin-bottom:7px;}
......
...@@ -8,59 +8,56 @@ $(document).ready(function () { ...@@ -8,59 +8,56 @@ $(document).ready(function () {
$("#information").Tooltip(); $("#information").Tooltip();
$("#update").click(function () { $("#update").click(function () {
var haspwd = false, var haspwd = false;
hasAccount = ($("input#hasAccount").val() !== ""); if ($("select#username").val() === "" || !$("select#username").val().match(/^[\w\d\._\-]+$/)) {
if ($("input#username").val() === "" || !$("input#username").val().match(/^[\w\d\._\-]+$/)) {
$("#error").Popup("Invalid user name. Please check it!", {type: 'alert', duration: 3000}); $("#error").Popup("Invalid user name. Please check it!", {type: 'alert', duration: 3000});
return false; return false;
} }
if ($("input#name").val() === "") { if ($("input#name").val() === "") {
$("#error").Popup("Please enter your name and surname!", {type: 'alert', duration: 3000}); $("#error").Popup("Please enter your full name for git configuration!", {type: 'alert', duration: 3000});
return false; return false;
} }
if (!$("input#email").val().match(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/)) { if (!$("input#email").val().match(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/)) {
$("#error").Popup("Please enter a valid email address!", {type: 'alert', duration: 3000}); $("#error").Popup("Please enter a valid email address!", {type: 'alert', duration: 3000});
return false; return false;
} }
if (!hasAccount && !$("input#password").val()) {
$("#error").Popup("Please enter your new password!", {type: 'alert', duration: 3000});
return false;
}
if ($("input#password").val() !== "") { if ($("input#password").val() !== "") {
if ($("input#password").val() === "" || !$("input#password").val()) { if ($("input#password").val() === "" || !$("input#password").val()) {
$("#error").Popup("Please enter your current password!", {type: 'alert', duration: 3000});
return false;
}
if ($("input#npassword").val() === "" || !$("input#npassword").val()) {
$("#error").Popup("Please enter your new password!", {type: 'alert', duration: 3000}); $("#error").Popup("Please enter your new password!", {type: 'alert', duration: 3000});
return false; return false;
} }
if ($("input#password").val() !== $("input#cpassword").val()) { if ($("input#npassword").val() !== $("input#cpassword").val()) {
$("#error").Popup("your password does not match!", {type: 'alert', duration: 3000}); $("#error").Popup("your new password does not match!", {type: 'alert', duration: 3000});
return false; return false;
} }
haspwd = true; haspwd = true;
} }
if (!$("input#rcode").val().match(/^[\w\d]+$/)) {
$("#error").Popup("Please enter your password recovery code.", {type: 'alert', duration: 3000});
return false;
}
if (send) { if (send) {
return false; return false;
} }
send = true; send = true;
var base_url = 'https://' + $("input#username").val() + ':'
+ $("input#password").val() + '@' + location.host
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: $SCRIPT_ROOT + ((hasAccount) ? '/updateAccount' : '/configAccount'), url: $SCRIPT_ROOT + '/updateAccount',
data: { data: {
name: $("input#name").val(), name: $("input#name").val(),
username: $("input#username").val(), username: $("select#username").val(),
email: $("input#email").val(), email: $("input#email").val(),
password: ((haspwd) ? $("input#password").val() : ""), password: ((haspwd) ? $("input#password").val() : ""),
rcode: $("input#rcode").val() new_password: ((haspwd) ? $("input#npassword").val() : "")
}, },
success: function (data) { success: function (data) {
if (data.code === 1) { if (data.code === 1) {
var url = 'https://' + $("input#username").val() + ':' + $("input#password").val() + '@' + location.host + $SCRIPT_ROOT + '/'; if ($("input#npassword").val() !== "") {
window.location.href = url; var url = 'https://' + $("select#username").val() + ':' + $("input#npassword").val() + '@' + location.host + $SCRIPT_ROOT + '/';
window.location.href = url;
} else {
$("#error").Popup("Account information saved successfully!", {type: 'info', duration: 5000});
}
} else { } else {
$("#error").Popup(data.result, {type: 'error', duration: 5000}); $("#error").Popup(data.result, {type: 'error', duration: 5000});
} }
...@@ -101,10 +98,6 @@ $(document).ready(function () { ...@@ -101,10 +98,6 @@ $(document).ready(function () {
$("#error").Popup("Invalid user name. Please check it!", {type: 'alert', duration: 3000}); $("#error").Popup("Invalid user name. Please check it!", {type: 'alert', duration: 3000});
return false; return false;
} }
if (!$("input#new_rcode").val().match(/^[\w\d]+$/)) {
$("#error").Popup("Please enter your password recovery code.", {type: 'alert', duration: 3000});
return false;
}
if (send) { if (send) {
return false; return false;
} }
...@@ -114,21 +107,19 @@ $(document).ready(function () { ...@@ -114,21 +107,19 @@ $(document).ready(function () {
url: $SCRIPT_ROOT + '/addUser', url: $SCRIPT_ROOT + '/addUser',
data: { data: {
username: $("input#new_username").val(), username: $("input#new_username").val(),
password: $("input#new_password").val(), password: $("input#new_password").val()
rcode: $("input#new_rcode").val(),
}, },
success: function (data) { success: function (data) {
if (data.code === 1) { if (data.code === 1) {
$("#error").Popup(data.result, {type: 'info', duration: 5000}); $("#error").Popup(data.result, {type: 'info', duration: 5000});
} else if (data.code === 0) { } else if (data.code === 0) {
$("#error").Popup(data.result, {type: 'error', duration: 5000}); $("#error").Popup(data.result, {type: 'error', duration: 5000});
} else { } else {
$("#error").Popup(data.result, {type: 'alert', duration: 5000}); $("#error").Popup(data.result, {type: 'alert', duration: 5000});
} }
send = false; send = false;
$("input#new_username").val(''); $("input#new_username").val('');
$("input#new_password").val(''); $("input#new_password").val('');
$("input#new_rcode").val('');
}, },
error: function () { send = false; } error: function () { send = false; }
}); });
......
...@@ -33,7 +33,7 @@ $(document).ready(function () { ...@@ -33,7 +33,7 @@ $(document).ready(function () {
$("#repoEmpty").hide(); $("#repoEmpty").hide();
$("#repoContent").show(); $("#repoContent").show();
for (i = 0; i < result.length; i += 1) { for (i = 0; i < result.length; i += 1) {
$("#project").append("<option value='"+result[i]+"'>"+result[i]+"</option>") $("#project").append("<option value='"+result[i]+"'>"+result[i]+"</option>");
} }
$("#project").change(); $("#project").change();
} }
...@@ -144,11 +144,15 @@ $(document).ready(function () { ...@@ -144,11 +144,15 @@ $(document).ready(function () {
$("#clone").append("Clone"); $("#clone").append("Clone");
send = false; send = false;
}, },
error: function (request, error) { error: function (xhr, request, error) {
$("#error").Popup("unable to clone your project, please check your internet connection", {type: 'error', duration: 3000}); console.log(xhr.responseText);
$("#error").Popup("unable to clone your project, please check your internet connection.<br/>" + xhr.responseText, {type: 'error', duration: 5000});
$("#imgwaitting").hide(); $("#imgwaitting").hide();
$("#clone").empty(); $("#clone").empty();
$("#clone").append("Clone"); $("#clone").append("Clone");
},
always: function () {
send = false;
} }
}); });
return false; return false;
......
...@@ -29,8 +29,8 @@ $(document).ready(function () { ...@@ -29,8 +29,8 @@ $(document).ready(function () {
function gitStatus() { function gitStatus() {
var project = $("#project").val(), var project = $("#project").val(),
urldata = $("input#workdir").val() + "/" + project; urldata = $("input#workdir").val() + "/" + project;
$("#status").empty(); $("#status").empty();
$("#commit").hide();
$("#flash").empty(); $("#flash").empty();
if (project === "") { if (project === "") {
$("#status").append("<h2>Please select one project...</h2><br/><br/>"); $("#status").append("<h2>Please select one project...</h2><br/><br/>");
...@@ -55,11 +55,11 @@ $(document).ready(function () { ...@@ -55,11 +55,11 @@ $(document).ready(function () {
//alert(message); //alert(message);
$("#status").append("<p>" + message + "</p>"); $("#status").append("<p>" + message + "</p>");
if (data.dirty) { if (data.dirty) {
$("#commit").show(); $("#status").append(
$("#status").append("<br/><h2>Display Diff for current Project</h2>"); "<br/><p style='font-size:15px;color: #D62B2B;padding: 0;'" +
$("#status").append("<p style='font-size:15px;'>You have changes in your project." + ">You have changes in your project." +
" <a href='#' id='viewdiff'" " <a href='#' id='viewdiff'"
+ ">Watch the diff file</a></p>"); + ">Watch the diff</a></p>");
} }
$("#viewdiff").click(function () { $("#viewdiff").click(function () {
viewDiff(); viewDiff();
...@@ -89,7 +89,7 @@ $(document).ready(function () { ...@@ -89,7 +89,7 @@ $(document).ready(function () {
success: function (data) { success: function (data) {
if (data.code === 1) { if (data.code === 1) {
$("#inline_content").empty(); $("#inline_content").empty();
$("#inline_content").append('<div class="main_content"><pre id="editorViewer"></pre></div>'); $("#inline_content").append('<div class="main_content"><pre id="editorViewer"></pre></div>');
viewer = ace.edit("editorViewer"); viewer = ace.edit("editorViewer");
viewer.setTheme("ace/theme/crimson_editor"); viewer.setTheme("ace/theme/crimson_editor");
...@@ -98,10 +98,10 @@ $(document).ready(function () { ...@@ -98,10 +98,10 @@ $(document).ready(function () {
viewer.getSession().setUseSoftTabs(true); viewer.getSession().setUseSoftTabs(true);
viewer.renderer.setHScrollBarAlwaysVisible(false); viewer.renderer.setHScrollBarAlwaysVisible(false);
viewer.setReadOnly(true); viewer.setReadOnly(true);
$("#inlineViewer").colorbox({inline:true, width: "847px", onComplete:function(){ $("#inlineViewer").colorbox({inline:true, width: "847px", onComplete:function(){
viewer.getSession().setValue(data.result); viewer.getSession().setValue(data.result);
}, title: 'Git diff for project ' + project}); }, title: 'Git diff for project ' + project});
$("#inlineViewer").click(); $("#inlineViewer").click();
send = false; send = false;
} else { } else {
$("#error").Popup(data.result, {type: 'error'}); $("#error").Popup(data.result, {type: 'error'});
......
...@@ -9,45 +9,69 @@ ...@@ -9,45 +9,69 @@
{% block body %} {% block body %}
<div id="tabContainer"> <div id="tabContainer">
<ul> <ul>
<li><a href="#tab1" class="active">Your personal information</a></li> <li><a href="#tab1" class="active">Update Account information</a></li>
{% if params %} {% if params %}
<li><a href="#tab2">Build & Run configuration</a></li>
<li><a href="#tab3">Add user</a></li> <li><a href="#tab3">Add user</a></li>
<li><a href="#tab2">Build & Run configuration</a></li>
{% endif %} {% endif %}
</ul><!-- //Tab buttons --> </ul><!-- //Tab buttons -->
<div class="tabDetails"> <div class="tabDetails">
<div id="tab1" class="tabContents"> <div id="tab1" class="tabContents">
<form class="account"> <form class="account">
<div class='form'> <div class='form'>
<label for="name">Your name: </label> <fieldset>
<input type='text' name='name' id='name' value='{{name}}'/> <legend><b> User credentials </b> </legend>
<div class='clear'></div> <label for="username">Username: </label>
<label for="email">Your email address: </label> <select name="username" id="username">
<input type='text' name='email' id='email' value='{{email}}'/> {% for username in username_list -%}
<div class='clear'></div> <option value="{{username}}">{{username}}</option>
<label for="username">User name: </label> {% endfor -%}
<input type='text' name='username' id='username' value='{{username}}'/> </select>
<div class='clear'></div> <div class='clear'></div>
<label for="password">Password: </label> <label for="password">Password: </label>
<input type='password' name='password' id='password' value=''/> <input type='password' name='password' id='password' value=''/>
<div class='clear'></div> <div class='clear'></div>
<label for="cpassword">Confirm Password: </label> <label for="npassword">New Password: </label>
<input type='password' name='cpassword' id='cpassword' value=''/> <input type='password' name='npassword' id='npassword' value=''/>
<div class='clear'></div> <div class='clear'></div>
<label for="cpassword">Confirm New Password: </label>
<input type='password' name='cpassword' id='cpassword' value=''/>
<div class='clear'></div>
</fieldset>
<br/> <br/>
<label for="rcode">Password Recovery code:</label> <fieldset>
<input type='password' name='rcode' id='rcode' value=''/> <legend><b> Git user and email </b> </legend>
<span class="information"><a href="#" id="information" rel="tooltip">help ?</a></span> <label for="name">Your name: </label>
<div class='clear'></div> <input type='text' name='name' id='name' value='{{name}}'/>
<div class='clear'></div>
<label for="email">Your email address: </label>
<input type='text' name='email' id='email' value='{{email}}'/>
<div class='clear'></div>
</fieldset>
<br/> <br/>
<label></label> <label></label>
<input type="submit" name="update" id ="update" value="Update Account" class="button"/> <input type="submit" name="update" id ="update" value="Update Account" class="button"/>
<div class='clear'></div> <div class='clear'></div>
</div> </div>
<input type="hidden" name="hasAccount" id="hasAccount" value="{{name}}"/>
</form> </form>
</div> </div>
{% if params %} {% if params %}
<div id="tab3" class="tabContents">
<form class="slapgrid">
<div class='form'>
<label for="username">New user name :</label>
<input type='text' name='username' id='new_username'/>
<div class='clear'></div>
<label for="password">New password :</label>
<input type='password' name='password' id='new_password'/>
<div class='clear'></div>
<br/>
<label></label>
<input type="submit" name="add_user" id="add_user" value="Add new user" class="button"/>
<div class='clear'></div>
</div>
</form>
</div>
<div id="tab2" class="tabContents"> <div id="tab2" class="tabContents">
<form class="slapgrid"> <form class="slapgrid">
<div class='form'> <div class='form'>
...@@ -72,26 +96,6 @@ ...@@ -72,26 +96,6 @@
</div> </div>
</form> </form>
</div> </div>
<div id="tab3" class="tabContents">
<form class="slapgrid">
<div class='form'>
<label for="username">New user name :</label>
<input type='text' name='username' id='new_username'/>
<div class='clear'></div>
<label for="password">New password :</label>
<input type='password' name='password' id='new_password'/>
<div class='clear'></div>
<label for="new_rcode">Password Recovery code:</label>
<input type='password' name='new_rcode' id='new_rcode' value=''/>
<span class="information"><a href="#" id="information" rel="tooltip">help ?</a></span>
<div class='clear'></div>
<br/>
<label></label>
<input type="submit" name="add_user" id="add_user" value="Add new user" class="button"/>
<div class='clear'></div>
</div>
</form>
</div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
......
...@@ -83,45 +83,32 @@ ...@@ -83,45 +83,32 @@
Your repository folder is empty. <a id="switchtoclone">Click here</a> to create a new one! Your repository folder is empty. <a id="switchtoclone">Click here</a> to create a new one!
</h2> </h2>
<div id="repoContent" style="{% if not project %}display:none{% endif %}"> <div id="repoContent" style="{% if not project %}display:none{% endif %}">
<label for='project'>Current Repository: </label> <label for='project'>Current Repository: </label>
<select id="project" name="project"> <select id="project" name="project">
{% for folder in project%} {% for folder in project%}
<option value="{{folder}}">{{folder}}</option> <option value="{{folder}}">{{folder}}</option>
{% endfor %} {% endfor %}
</select> </select>
<a id="switchtoclone" class="lshare">&nbsp;New repository&nbsp;</a> <a id="switchtoclone" class="lshare">&nbsp;New repository&nbsp;</a>
<br/><br/> <br/><br/>
<div id="contentInfo"> <div id="contentInfo">
<div id="status" style="margin-bottom:20px;"> <div id="status" style="margin-bottom:20px;">
<h2>Please select one project...</h2> <h2>Please select one project...</h2>
</div> </div>
<div id="branchlist" style="margin-bottom:20px;"> <div id="branchlist" style="margin-bottom:20px;">
<h2>Your Repository Branches</h2> <h2>Your Repository Branches</h2>
<div style="margin-left:15px;"> <div style="margin-left:15px;">
<label for='activebranch'>Select your active Branch: </label> <label for='activebranch'>Select your active Branch: </label>
<select name="activebranch" id="activebranch"> <select name="activebranch" id="activebranch">
</select> </select>
&nbsp;&nbsp;<label for='branchname'>Branch Name: </label> &nbsp;&nbsp;<label for='branchname'>Branch Name: </label>
<input type="text" name="branchname" id="branchname" size='22' value="Enter the branch name..." /> <input type="text" name="branchname" id="branchname" size='22' value="Enter the branch name..." />
<input type="submit" name="addbranch" id ="addbranch" value="Add" class="button" title='add new branch: git checkout -b branch'/> <input type="submit" name="addbranch" id ="addbranch" value="Add" class="button" title='add new branch: git checkout -b branch'/>
<input type="submit" name="docheckout" id ="docheckout" value="Checkout" class="button" title='add existing branch: git checkout branch'/> <input type="submit" name="docheckout" id ="docheckout" value="Checkout" class="button" title='add existing branch: git checkout branch'/>
<br/> <br/>
<!--<label for='pullbranch'>Update your local repository: </label>--> </div>
<!--<input type="submit" name="pullbranch" id ="pullbranch" value="Pull" class="button"/>--> </div>
<!--<img class="waitting" id="pullimgwaitting" src="{{ url_for('static', filename='images/waiting.gif') }}" alt="" />--> </div>
</div>
</div>
<div id="commit" style="margin-bottom:20px;">
<h2>Commit All your changes (On active branch)</h2>
<div style="margin-left:15px;">
<label for='commitmsg'>Commit message: </label>
<input type="text" name="commitmsg" id="commitmsg" size='40' value="Enter message..." />
<input type="submit" name="commit" id ="commitbutton" value="Commit" class="button"/>
<img class="waitting" id="imgwaitting" src="{{ url_for('static', filename='images/waiting.gif') }}" alt="" />
</div>
</div>
<br/>
</div>
</div> </div>
</form> </form>
</div> </div>
......
...@@ -24,7 +24,8 @@ from flask import jsonify ...@@ -24,7 +24,8 @@ from flask import jsonify
from slapos.runner.gittools import cloneRepo from slapos.runner.gittools import cloneRepo
from slapos.runner.process import Popen from slapos.runner.process import Popen
from slapos.htpasswd import HtpasswdFile # from slapos.htpasswd import HtpasswdFile
from passlib.apache import HtpasswdFile
import slapos.slap import slapos.slap
from slapos.grid.utils import md5digest from slapos.grid.utils import md5digest
...@@ -60,61 +61,36 @@ def html_escape(text): ...@@ -60,61 +61,36 @@ def html_escape(text):
"""Produce entities within text.""" """Produce entities within text."""
return "".join(html_escape_table.get(c, c) for c in text) return "".join(html_escape_table.get(c, c) for c in text)
def getSession(config): def getSession(config):
""" """
Get the session data of current user. Get the session data of current user.
Returns: Returns:
a list of user information or None if the file does not exist. a list of user information or None if the file does not exist.
""" """
user_path = os.path.join(config['etc_dir'], '.users') user_path = os.path.join(config['etc_dir'], '.htpasswd')
if os.path.exists(user_path): if os.path.exists(user_path):
return open(user_path).read().split(';') return open(user_path).read().split(';')
def checkUserCredential(config, username, password):
htpasswdfile = os.path.join(config['etc_dir'], '.htpasswd')
if not os.path.exists(htpasswdfile):
return False
passwd = HtpasswdFile(htpasswdfile)
return passwd.check_password(username, password)
def saveSession(config, account): def updateUserCredential(config, username, password):
""" """
Save account information for the current user Save account information for the current user
Args:
config: Slaprunner configuration
session: Flask session
account: New session data to be save
Returns:
True if all goes well or str (error message) if fail
""" """
# XXX Cedric LN hardcoded path for files if username and password:
user = os.path.join(config['etc_dir'], '.users') htpasswdfile = os.path.join(config['etc_dir'], '.htpasswd')
htpasswdfile = os.path.join(config['etc_dir'], '.htpasswd') passwd = HtpasswdFile(htpasswdfile)
backup = False passwd.set_password(username, password)
try:
if os.path.exists(user):
#backup previous data
data = open(user).read()
open('%s.back' % user, 'w').write(data)
backup = True
if not account[1]:
account[1] = data.split(';')[1]
#save new account data
open(user, 'w').write((';'.join(account)).encode("utf-8"))
# Htpasswd file for cloud9
# XXX Cedric Le N order of account list values suppose to be fixed
# Remove former file to avoid outdated accounts
if os.path.exists(htpasswdfile):
os.remove(htpasswdfile)
passwd = HtpasswdFile(htpasswdfile, create=True)
passwd.update(account[0], account[1])
passwd.save() passwd.save()
return True return True
except Exception as e:
try: return False
if backup:
os.remove(user)
os.rename('%s.back' % user, user)
except:
pass
return str(e)
def getRcode(config): def getRcode(config):
...@@ -125,17 +101,23 @@ def getRcode(config): ...@@ -125,17 +101,23 @@ def getRcode(config):
except (ConfigParser.NoSectionError, IOError) as e: except (ConfigParser.NoSectionError, IOError) as e:
return None return None
def getUsernameList(config):
htpasswdfile = os.path.join(config['etc_dir'], '.htpasswd')
if os.path.exists(htpasswdfile):
passwd = HtpasswdFile(htpasswdfile)
return passwd.users()
return []
def createNewUser(config, name, passwd): def createNewUser(config, name, passwd):
htpasswdfile = os.path.join(config['etc_dir'], '.htpasswd') htpasswdfile = os.path.join(config['etc_dir'], '.htpasswd')
if os.path.exists(htpasswdfile): if os.path.exists(htpasswdfile):
htpasswd = HtpasswdFile(htpasswdfile) htpasswd = HtpasswdFile(htpasswdfile)
htpasswd.update(name, passwd) htpasswd.set_password(name, passwd)
htpasswd.save() htpasswd.save()
return True return True
return False return False
def getCurrentSoftwareReleaseProfile(config): def getCurrentSoftwareReleaseProfile(config):
""" """
Returns used Software Release profile as a string. Returns used Software Release profile as a string.
......
...@@ -15,27 +15,29 @@ from flask import (Flask, request, redirect, url_for, render_template, ...@@ -15,27 +15,29 @@ from flask import (Flask, request, redirect, url_for, render_template,
g, flash, jsonify, session, abort, send_file) g, flash, jsonify, session, abort, send_file)
import slapos import slapos
from slapos.runner.utils import (checkSoftwareFolder, configNewSR, from slapos.runner.utils import (checkSoftwareFolder, configNewSR, checkUserCredential,
createNewUser, getBuildAndRunParams, createNewUser, getBuildAndRunParams,
getProfilePath, getSlapgridResult, getProfilePath, getSlapgridResult,
listFolder, getBuildAndRunParams, listFolder, getBuildAndRunParams,
getProjectTitle, getRcode, getSession, getProjectTitle, getRcode, updateUserCredential,
getSlapStatus, getSvcStatus, getSlapStatus, getSvcStatus,
getSvcTailProcess, isInstanceRunning, getSvcTailProcess, getUsernameList, isInstanceRunning,
isSoftwareRunning, isSoftwareReleaseReady, isText, isSoftwareRunning, isSoftwareReleaseReady, isText,
loadSoftwareRList, md5sum, newSoftware, loadSoftwareRList, md5sum, newSoftware,
readFileFrom, readParameters, realpath, readFileFrom, readParameters, realpath,
removeInstanceRoot, removeProxyDb, removeInstanceRoot, removeProxyDb,
removeSoftwareByName, runSlapgridUntilSuccess, removeSoftwareByName, runSlapgridUntilSuccess,
saveSession, saveBuildAndRunParams, saveBuildAndRunParams,
setMiniShellHistory, setMiniShellHistory,
stopProxy, stopProxy,
svcStartStopProcess, svcStartAll, svcStopAll, tail, svcStartStopProcess, svcStartAll, svcStopAll, tail,
updateInstanceParameter) updateInstanceParameter)
from git import GitCommandError
from slapos.runner.fileBrowser import FileBrowser from slapos.runner.fileBrowser import FileBrowser
from slapos.runner.gittools import (cloneRepo, gitStatus, switchBranch, from slapos.runner.gittools import (cloneRepo, gitStatus, switchBranch,
addBranch, getDiff, gitCommit, gitPush, gitPull) addBranch, getDiff, gitCommit, gitPush,
gitPull, updateGitConfig, safeResult)
app = Flask(__name__) app = Flask(__name__)
...@@ -56,7 +58,7 @@ def before_request(): ...@@ -56,7 +58,7 @@ def before_request():
if request.path.startswith('/static') \ if request.path.startswith('/static') \
or request.path == '/isSRReady': or request.path == '/isSRReady':
return return
"""
account = getSession(app.config) account = getSession(app.config)
if account: if account:
session['title'] = getProjectTitle(app.config) session['title'] = getProjectTitle(app.config)
...@@ -64,7 +66,8 @@ def before_request(): ...@@ -64,7 +66,8 @@ def before_request():
session['title'] = "No account is defined" session['title'] = "No account is defined"
if request.path != "/setAccount" and request.path != "/configAccount": if request.path != "/setAccount" and request.path != "/configAccount":
return redirect(url_for('setAccount')) return redirect(url_for('setAccount'))
"""
session['title'] = getProjectTitle(app.config)
g.instance_monitoring_url = app.config['instance_monitoring_url'] g.instance_monitoring_url = app.config['instance_monitoring_url']
# general views # general views
...@@ -84,17 +87,25 @@ def login(): ...@@ -84,17 +87,25 @@ def login():
@app.route("/setAccount") @app.route("/setAccount")
def setAccount(): def setAccount():
account = getSession(app.config) """account = getSession(app.config)
if not account: if not account:
return render_template('account.html') return render_template('account.html')
return redirect(url_for('login')) return redirect(url_for('login'))"""
def myAccount(): def myAccount():
account = getSession(app.config) # account = getSession(app.config)
return render_template('account.html', username=account[0], git_user_path = os.path.join(app.config['etc_dir'], '.git_user')
email=account[2], name=account[3].decode('utf-8'), name = email = ""
params=getBuildAndRunParams(app.config)) if os.path.exists(git_user_path):
with open(git_user_path, 'r') as gfile:
name, email = gfile.read().split(';')
return render_template(
'account.html',
username_list=getUsernameList(app.config),
email=email,
name=name.decode('utf-8'),
params=getBuildAndRunParams(app.config))
def getSlapgridParameters(): def getSlapgridParameters():
...@@ -103,11 +114,16 @@ def getSlapgridParameters(): ...@@ -103,11 +114,16 @@ def getSlapgridParameters():
def manageRepository(): def manageRepository():
public_key = open(app.config['public_key']).read() public_key = open(app.config['public_key']).read()
account = getSession(app.config) account = [] #getSession(app.config)
git_user_path = os.path.join(app.config['etc_dir'], '.git_user')
name = email = ""
if os.path.exists(git_user_path):
with open(git_user_path, 'r') as gfile:
name, email = gfile.read().split(';')
return render_template('manageRepository.html', workDir='workspace', return render_template('manageRepository.html', workDir='workspace',
project=listFolder(app.config, 'workspace'), project=listFolder(app.config, 'workspace'),
public_key=public_key, name=account[3].decode('utf-8'), public_key=public_key, name=name.decode('utf-8'),
email=account[2]) email=email)
@app.route("/doLogin", methods=['POST']) @app.route("/doLogin", methods=['POST'])
...@@ -273,13 +289,13 @@ def openProject(method): ...@@ -273,13 +289,13 @@ def openProject(method):
def cloneRepository(): def cloneRepository():
path = realpath(app.config, request.form['name'], False) path = realpath(app.config, request.form['name'], False)
data = { if not path:
'repo': request.form['repo'], return jsonify(code=0, result="Can not access folder: Permission Denied")
'user': request.form['user'], try:
'email': request.form['email'], cloneRepo(request.form['repo'], path, request.form['user'], request.form['email'])
'path': path return jsonify(code=1, result="")
} except GitCommandError, e:
return cloneRepo(data) return jsonify(code=0, result=safeResult(str(e)))
def listDirectory(): def listDirectory():
...@@ -306,7 +322,11 @@ def setCurrentProject(): ...@@ -306,7 +322,11 @@ def setCurrentProject():
def getProjectStatus(): def getProjectStatus():
path = realpath(app.config, request.form['project']) path = realpath(app.config, request.form['project'])
if path: if path:
return gitStatus(path) try:
result, branch, isdirty = gitStatus(path)
return jsonify(code=1, result=result, branch=branch, dirty=isdirty)
except GitCommandError, e:
return jsonify(code=0, result=safeResult(str(e)))
else: else:
return jsonify(code=0, result="Can not read folder: Permission Denied") return jsonify(code=0, result="Can not read folder: Permission Denied")
...@@ -392,7 +412,14 @@ def saveFileContent(): ...@@ -392,7 +412,14 @@ def saveFileContent():
def changeBranch(): def changeBranch():
path = realpath(app.config, request.form['project']) path = realpath(app.config, request.form['project'])
if path: if path:
return switchBranch(path, request.form['name']) try:
if switchBranch(path, request.form['name']):
return jsonify(code=1, result="")
else:
json = "This is already your active branch for this project"
return jsonify(code=1, result=json)
except GitCommandError, e:
return jsonify(code=0, result=safeResult(str(e)))
else: else:
return jsonify(code=0, result="Can not read folder: Permission Denied") return jsonify(code=0, result="Can not read folder: Permission Denied")
...@@ -400,10 +427,17 @@ def changeBranch(): ...@@ -400,10 +427,17 @@ def changeBranch():
def newBranch(): def newBranch():
path = realpath(app.config, request.form['project']) path = realpath(app.config, request.form['project'])
if path: if path:
if request.form['create'] == '1': try:
return addBranch(path, request.form['name']) if request.form['create'] == '1':
else: result = addBranch(path, request.form['name'])
return addBranch(path, request.form['name'], True) else:
result = addBranch(path, request.form['name'], True)
if result:
return jsonify(code=1, result="")
else:
return jsonify(code=0, result="Failed to checkout to branch %s.")
except GitCommandError, e:
return jsonify(code=0, result=safeResult(str(e)))
else: else:
return jsonify(code=0, result="Can not read folder: Permission Denied") return jsonify(code=0, result="Can not read folder: Permission Denied")
...@@ -591,28 +625,34 @@ def updateBuildAndRunConfig(): ...@@ -591,28 +625,34 @@ def updateBuildAndRunConfig():
#update user account data #update user account data
def updateAccount(): def updateAccount():
code = request.form['rcode'].strip()
recovery_code = getRcode(app.config)
if code != recovery_code:
return jsonify(code=0, result="Your password recovery code is not valid!")
account = [ username = request.form['username'].strip()
request.form['username'].strip(), password = request.form['password'].strip()
request.form['password'].strip(), new_password = request.form['new_password'].strip()
request.form['email'].strip(), email = request.form['email'].strip()
request.form['name'].strip() name = request.form['name'].strip()
]
result = saveSession(app.config, account) if username and password and new_password:
if type(result) == type(""): if not checkUserCredential(app.config, username, password):
return jsonify(code=0, result=result) return jsonify(code=0, result="Username and password doesn't match for '%s'" % username)
else:
return jsonify(code=1, result="") result = updateUserCredential(app.config, username, new_password)
if not result:
return jsonify(code=0, result="Failed to update Credentials!")
try:
updateGitConfig(app.config['default_repository_path'], name, email)
except GitCommandError, e:
return jsonify(code=0, result=str(e))
with open(os.path.join(app.config['etc_dir'], '.git_user'), 'w') as gfile:
gfile.write('%s;%s' % (name, email))
return jsonify(code=1, result="")
#update user account data #update user account data
@app.route("/configAccount", methods=['POST']) @app.route("/configAccount", methods=['POST'])
def configAccount(): def configAccount():
last_account = getSession(app.config) """last_account = getSession(app.config)
if last_account: if last_account:
return jsonify(code=0, return jsonify(code=0,
result="Unable to respond to your request, permission denied.") result="Unable to respond to your request, permission denied.")
...@@ -630,13 +670,9 @@ def configAccount(): ...@@ -630,13 +670,9 @@ def configAccount():
if type(result) == type(""): if type(result) == type(""):
return jsonify(code=0, result=result) return jsonify(code=0, result=result)
else: else:
return jsonify(code=1, result="") return jsonify(code=1, result="")"""
def addUser(): def addUser():
code = request.form['rcode'].strip()
recovery_code = getRcode(app.config)
if code != recovery_code:
return jsonify(code=0, result="Your password recovery code is not valid!")
if createNewUser(app.config, request.form['username'], if createNewUser(app.config, request.form['username'],
request.form['password']): request.form['password']):
return jsonify(code=1, result="New user succesfully saved") return jsonify(code=1, result="New user succesfully saved")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment