Ajouté la gestion de password Corrigé le slug des users à la créationmaster
@@ -9,10 +9,10 @@ from .models import DBSession, get_user | |||
from .security import EntryFactory, groupfinder | |||
import locale | |||
def main(global_config, **settings): | |||
""" This function returns a Pyramid WSGI application. | |||
""" | |||
locale.setlocale(locale.LC_ALL, "fr_FR.UTF-8") | |||
engine = engine_from_config(settings, 'sqlalchemy.') | |||
DBSession.configure(bind=engine) | |||
@@ -82,6 +82,7 @@ def main(global_config, **settings): | |||
config.add_route('edit_entity_cat', '/categorie/entity') | |||
## Users | |||
config.add_route('pict_user', '/user_picture') | |||
config.add_route('show_user', '/user/{user_slug:([\w-]+)?}') | |||
# HTML Routes - Logged | |||
@@ -1,5 +1,6 @@ | |||
# -*- coding: utf8 -*- | |||
from wtforms import Form, BooleanField, TextField, TextAreaField, SelectField, SubmitField, validators, FieldList | |||
from wtforms import Form, BooleanField, TextField, TextAreaField, SelectField | |||
from wtforms import SubmitField, validators, FieldList, PasswordField | |||
#import .ExtWforms | |||
from .ExtWtforms import MySelectField | |||
from wtforms import HiddenField, DecimalField, DateTimeField, FormField, FileField, DateField | |||
@@ -181,8 +182,15 @@ def captcha_check(form, field): | |||
if form.meta.csrf_context.get('Captcha')!=field.data: | |||
raise ValidationError(u"la vérification captcha est invalide.") | |||
class UserPasswordForm(MyBaseForm): | |||
uid = HiddenField() | |||
password = PasswordField("Mot de passe",[ | |||
validators.Length(max=128, message=u"128 car. maximum"), | |||
validators.required(message=u"Ce champ est obligatoire"), | |||
validators.EqualTo('confirm', message=u'Les password ne sont pas équivalents') ], | |||
filters=[strip_filter] | |||
) | |||
confirm = PasswordField('Confirmez') | |||
class UserRegisterForm(MyBaseForm): | |||
nom = TextField(u'Nom', [ | |||
@@ -44,13 +44,13 @@ a { | |||
height:100px; | |||
} | |||
.invalid { | |||
background:url(../images/invalid.png) no-repeat 0 50%; | |||
background:url(/img/invalid.png) no-repeat 0 50%; | |||
padding-left:22px; | |||
line-height:24px; | |||
color:#ec3f41; | |||
} | |||
.valid { | |||
background:url(../images/valid.png) no-repeat 0 50%; | |||
background:url(/img/valid.png) no-repeat 0 50%; | |||
padding-left:22px; | |||
line-height:24px; | |||
color:#3aba34; | |||
@@ -84,7 +84,8 @@ a { | |||
opacity: 0.5; | |||
position: absolute; | |||
text-align: center; | |||
width: 15px; | |||
width: 15px; | |||
top: -20px; | |||
} | |||
.Ucarousel-control.left { | |||
right: auto; | |||
@@ -1,4 +1,3 @@ | |||
function DoPost(TargetURL) { | |||
var Datas=$('#ModalForm').serialize(); | |||
$.ajax({ | |||
@@ -83,7 +82,6 @@ $(document).ready(function() { | |||
}); | |||
$('#AjaxModal').on('hidden', function(bla){ | |||
//$(this).data('modal', null); | |||
if (bla.target.id.endsWith('-help')) | |||
return; | |||
if (bla.target.id=='AjaxModal') { | |||
@@ -98,7 +96,6 @@ $(document).ready(function() { | |||
$('#AjaxPlaceModal').on('hidden', function(bla){ | |||
$("#place_type").select2("destroy"); | |||
//$(this).data('modal', null); | |||
if (bla.target.id.endsWith('-help')) | |||
return; | |||
if ($(this).children().length) | |||
@@ -152,20 +149,6 @@ $(document).ready(function() { | |||
$('a[href="' + SavHash + '"]').tab('show'); | |||
} | |||
} | |||
if (0) { | |||
var editor = CKEDITOR.replace( 'bio', { | |||
saveSubmitURL:'/SaveFrontPage/?part=bio', | |||
on : { blur: function( event ) { event.editor.getCommand( 'save' ).enable(); } | |||
} | |||
} ); | |||
} else { | |||
//CKEDITOR.disableAutoInline = true; | |||
//var editor = CKEDITOR.inline( 'bio' ); | |||
//var editor = CKEDITOR.replace( 'bio' ); | |||
//var editor = CKEDITOR.replace( 'bio' ); | |||
}; | |||
jQuery(function() { | |||
jQuery('.repeat').each(function() { | |||
@@ -22,3 +22,40 @@ | |||
}()); | |||
// Place any jQuery/helper plugins in here. | |||
function HandleControls() { | |||
// Trig some javascript to handle New Dialog content | |||
$.each( $('.fileupload'), | |||
function( NumCtrl, Ctrl ) { | |||
$("#"+Ctrl.id).fileupload({ | |||
// Uncomment the following to send cross-domain cookies: | |||
//xhrFields: {withCredentials: true}, | |||
//url: '/uploader/proceed/' | |||
url: this.action | |||
}); | |||
// Enable iframe cross-domain access via redirect option: | |||
$("#"+Ctrl.id).fileupload( | |||
'option', | |||
'redirect', | |||
window.location.href.replace( | |||
/\/[^\/]*$/, | |||
'/cors/result.html?%s' | |||
) | |||
); | |||
$("#"+Ctrl.id).addClass('fileupload-processing'); | |||
$.ajax({ | |||
// Uncomment the following to send cross-domain cookies: | |||
//xhrFields: {withCredentials: true}, | |||
//url: this.action, | |||
url: $("#"+Ctrl.id).fileupload('option', 'url'), | |||
//url: "uploader/proceed/", | |||
dataType: 'json', | |||
context: $("#"+Ctrl.id)[0] | |||
}).always(function () { | |||
$(this).removeClass('fileupload-processing'); | |||
}).done(function (result) { | |||
$(this).fileupload('option', 'done') | |||
.call(this, $.Event('done'), {result: result}); //$(this)}); | |||
}); | |||
} | |||
); | |||
} |
@@ -1,40 +1,9 @@ | |||
<%namespace name="Modals" file="jm2l:templates/modals.mako"/> | |||
<%namespace name="helpers" file="jm2l:templates/helpers.mako"/> | |||
<%def name="profil_wrapper(uprofil, profil_form)"> | |||
<div class="profile-icon" style="float:right;height:250px;width:250px;"> | |||
<% photos = uprofil.PhotosLinks %> | |||
<div id="MyPictureCarousel" class="carousel slide"> | |||
<div style="text-align: center;line-height:20px;"> | |||
<a data-target="#AjaxModal" Myhref="/2015/modal/Password/1" role="button" handle="modal">Changer mon mot de passe</a> | |||
</div> | |||
% if len(photos)>1: | |||
<!-- Carousel nav --> | |||
<a class="Ucarousel-control left" href="#MyPictureCarousel" data-slide="prev">‹</a> | |||
<a class="Ucarousel-control right" href="#MyPictureCarousel" data-slide="next">›</a> | |||
% endif | |||
<div style="text-align: center;line-height:20px;"> | |||
<a data-target="#AjaxModal" Myhref="/2015/modal/UserPicture/${uprofil.uid}" handle="modal">Changer ma photo</a> | |||
</div> | |||
<!-- Carousel items --> | |||
<div class="carousel-inner" style="height: 220px;"> | |||
% if len(photos): | |||
% for num, link in enumerate(photos): | |||
<div class="${['','active '][num==0]}item" id="UserPic${num}"> | |||
<div style="margin:auto;"> | |||
<img src="${link}" class="img-polaroid" style="max-height:205px;max-width:235px;" alt="Photo ${uprofil.slug}" /> | |||
</div> | |||
</div> | |||
% endfor | |||
% else: | |||
<div class="active item" id="UserPic0"> | |||
<div style="margin:auto;width:170px;"> | |||
<img src="/img/default-user.png" class="img-polaroid" alt="Photo ${uprofil.slug}" style="max-height:205px;" /> | |||
</div> | |||
</div> | |||
% endif | |||
</div> | |||
</div> | |||
</div> | |||
<div id="Photos"> | |||
${helpers.show_my_pictures(uprofil)} | |||
</div> | |||
<a href="/sign/jm2l/${uprofil.my_hash}">Mon lien</a> | |||
<h3>${profil_form.prenom.data} ${profil_form.nom.data}</h3> | |||
@@ -159,7 +159,7 @@ TabJs = {'select':[], 'desc':[]} | |||
<div class="fileupload-progress fade" style="float:right;"> | |||
<!-- The global progress bar --> | |||
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100"> | |||
<div class="progress-bar progress-bar-success" style="width:0%;"></div> | |||
<div class="bar progress-bar progress-bar-success" style="width:0%;"></div> | |||
</div> | |||
<!-- The extended global progress state --> | |||
<div class="progress-extended"> </div> | |||
@@ -184,7 +184,7 @@ TabJs = {'select':[], 'desc':[]} | |||
<p class="name">{%=file.name%}</p> | |||
<strong class="error text-danger"></strong> | |||
<p class="size">Processing...</p> | |||
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="progress-bar progress-bar-success" style="width:0%;"></div></div> | |||
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="bar progress-bar progress-bar-success" style="width:0%;"></div></div> | |||
</td> | |||
<td style="width: 85px;"> | |||
{% if (!i && !o.options.autoUpload) { %} | |||
@@ -395,6 +395,43 @@ plop | |||
## -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= | |||
## Wrapper pour les photos | |||
## -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= | |||
<%def name="show_my_pictures(uprofil)"> \ | |||
<div class="profile-icon" style="float:right;height:250px;width:250px;"> | |||
<% photos = uprofil.PhotosLinks %> | |||
<div style="text-align: center;line-height:20px;"> | |||
<a data-target="#AjaxModal" Myhref="/2015/modal/Password/1" role="button" handle="modal">Changer mon mot de passe</a> | |||
</div> | |||
<div style="text-align: center;line-height:20px;"> | |||
<a data-target="#AjaxModal" Myhref="/2015/modal/UserPicture/${uprofil.uid}" handle="modal">Changer ma photo</a> | |||
</div> | |||
<div id="MyPictureCarousel" class="carousel slide"> | |||
% if len(photos)>1: | |||
<!-- Carousel nav --> | |||
<a class="Ucarousel-control left" href="#MyPictureCarousel" data-slide="prev">‹</a> | |||
<a class="Ucarousel-control right" href="#MyPictureCarousel" data-slide="next">›</a> | |||
% endif | |||
<!-- Carousel items --> | |||
<div class="carousel-inner" style="height: 220px;"> | |||
% if len(photos): | |||
% for num, link in enumerate(photos): | |||
<div class="${['','active '][num==0]}item" id="UserPic${num}"> | |||
<div style="margin:auto;"> | |||
<img src="${link}" class="img-polaroid" style="max-height:205px;max-width:235px;" alt="Photo ${uprofil.slug}" /> | |||
</div> | |||
</div> | |||
% endfor | |||
% else: | |||
<div class="active item" id="UserPic0"> | |||
<div style="margin:auto;width:170px;"> | |||
<img src="/img/default-user.png" class="img-polaroid" alt="Photo ${uprofil.slug}" style="max-height:205px;" /> | |||
</div> | |||
</div> | |||
% endif | |||
</div> | |||
</div> | |||
</div> | |||
</%def> \ | |||
## -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= | |||
<%def name="show_pictures(uprofil)"> \ | |||
<div class="profile-icon pull-right"> | |||
<% photos = uprofil.PhotosLinks %> | |||
@@ -113,46 +113,15 @@ ${helpers.uploader_js()} | |||
<script src="/vendor/bootstrap.min.js"></script> | |||
<script src="/vendor/fileupload/js/jquery-uploader.min.js"></script> | |||
<script src="/vendor/ckeditor/ckeditor.js"></script> | |||
<script src="/js/plugins.js"></script> | |||
${self.jsAddOn()} | |||
## Then Handle Javascript | |||
<script> | |||
% for jsitem in context._kwargs['postpone_js']: | |||
${jsitem | n} | |||
% endfor | |||
$.each( $('.fileupload'), | |||
function( NumCtrl, Ctrl ) { | |||
$("#"+Ctrl.id).fileupload({ | |||
// Uncomment the following to send cross-domain cookies: | |||
//xhrFields: {withCredentials: true}, | |||
//url: '/uploader/proceed/' | |||
url: this.action | |||
}); | |||
// Enable iframe cross-domain access via redirect option: | |||
$("#"+Ctrl.id).fileupload( | |||
'option', | |||
'redirect', | |||
window.location.href.replace( | |||
/\/[^\/]*$/, | |||
'/cors/result.html?%s' | |||
) | |||
); | |||
$("#"+Ctrl.id).addClass('fileupload-processing'); | |||
$.ajax({ | |||
// Uncomment the following to send cross-domain cookies: | |||
//xhrFields: {withCredentials: true}, | |||
//url: this.action, | |||
url: $("#"+Ctrl.id).fileupload('option', 'url'), | |||
//url: "uploader/proceed/", | |||
dataType: 'json', | |||
context: $("#"+Ctrl.id)[0] | |||
}).always(function () { | |||
$(this).removeClass('fileupload-processing'); | |||
}).done(function (result) { | |||
$(this).fileupload('option', 'done') | |||
.call(this, $.Event('done'), {result: result}); //$(this)}); | |||
}); | |||
} | |||
); | |||
## Call Control Handler | |||
HandleControls(); | |||
</script> | |||
<!-- Piwik --> | |||
@@ -150,11 +150,10 @@ | |||
Les images de taille supérieure à 300x300 pixels seront redimensionnés. | |||
</div> | |||
${helpers.uploader("users", uid, "une Photo")} | |||
##${helpers.uploader_js()} | |||
</div> | |||
<div class="modal-footer"> | |||
<button class="btn" data-dismiss="modal" aria-hidden="true">Annuler</button> | |||
<button class="btn btn-primary">Enregistrer les modifications</button> | |||
<button class="btn btn-primary" onclick="javascript:DoPost('/2015/modal/UserPicture/${uid}');">Enregistrer les modifications</button> | |||
</div> | |||
</div> | |||
</%def> \ | |||
@@ -166,33 +165,12 @@ | |||
<h3>Changer mon mot de passe</h3> | |||
</div> | |||
<div class="modal-body"> | |||
<form id="ModalForm" action="javascript:DoPost('/2015/modal/Password/${uid}');" style='margin:0;'> | |||
<div class="description">Pour modifier le mot de passe actuel, | |||
entrez un nouveau mot de passe dans chacune des deux zones de texte. | |||
</div> | |||
<div class="password-strength" style="float:right;"> | |||
<div class="password-strength-text" aria-live="assertive">Faible</div> | |||
<div class="password-strength-title">Sécurité du mot de passe :</div> | |||
<div class="password-indicator"> | |||
<div style="width: 0%;" class="indicator"></div> | |||
</div> | |||
</div> | |||
<div class="form-item form-type-password-confirm form-item-pass"> | |||
<label for="edit-pass-pass1">Mot de passe </label> | |||
<input | |||
id="edit-pass-pass1" name="pass" size="25" maxlength="128" type="password"> | |||
</div> | |||
<div class="form-item form-type-password form-item-pass-pass2 confirm-parent"> | |||
<div style="visibility: hidden;" class="password-confirm"> | |||
Concordance des mots de passe : <span></span> | |||
</div> | |||
<label for="edit-pass-pass2">Confirmer le mot de passe </label> | |||
<input class="password-confirm form-text" | |||
id="edit-pass-pass2" name="pass2" size="25" maxlength="128" type="password"> | |||
</div> | |||
${ helpers.DisplayForm(form, {}) } | |||
<div id="pswd_info" style="display: block;"> | |||
Pour renforcer la sécurité de votre mot de passe : | |||
@@ -204,6 +182,7 @@ | |||
<li id="ponctu" class="invalid">Ajoutez des caractères de ponctuation</li> | |||
</ul> | |||
</div> | |||
</form> | |||
<script> | |||
$('input[type=password]').keyup(function() { | |||
// set password variable | |||
@@ -240,13 +219,13 @@ | |||
$('#ponctu').removeClass('invalid').addClass('valid'); | |||
} else { | |||
$('#ponctu').removeClass('valid').addClass('invalid'); | |||
} | |||
} | |||
}); | |||
</script> | |||
</div> | |||
<div class="modal-footer"> | |||
<button class="btn" data-dismiss="modal" aria-hidden="true">Annuler</button> | |||
<button class="btn btn-primary">Changer</button> | |||
<button class="btn btn-primary" onclick="javascript:document.forms['ModalForm'].submit();">Changer</button> | |||
</div> | |||
</div> | |||
</%def> \ | |||
@@ -284,4 +263,5 @@ context._kwargs['postpone_js']=[] | |||
% for jsitem in context._kwargs['postpone_js']: | |||
${jsitem | n} | |||
% endfor | |||
HandleControls(); | |||
</script> |
@@ -63,4 +63,15 @@ $.ajax({ | |||
alert(error); | |||
}, | |||
}); | |||
% elif modtype=='UserPicture': | |||
$.ajax({ | |||
url:'/user_picture', | |||
success:function(result, status, jqXHR){ | |||
var pictureresult = $('<div />').append(result).find('#MyPictureCarousel').html(); | |||
$('#MyPictureCarousel').html(pictureresult); | |||
}, | |||
error:function(result, error){ | |||
alert(error); | |||
}, | |||
}); | |||
% endif |
@@ -348,7 +348,6 @@ def action_task(request): | |||
## =-=- Here, We handle HTTP requests - User Logged Part -=-= | |||
@view_config(route_name='exchange', renderer="jm2l:templates/Logistique/Logistique.mako") | |||
def exchange(request): | |||
modtype = request.matchdict.get('modtype', None) | |||
@@ -454,8 +453,22 @@ def Modal(request): | |||
modtype = request.matchdict.get('modtype', None) | |||
uid = int(request.matchdict.get('id', -1)) | |||
session = request.session | |||
if modtype=='Password': | |||
form = UserPasswordForm(request.POST, request.user, meta={'csrf_context': request.session}) | |||
if request.method == 'POST' and form.validate(): | |||
response = render_to_response('jm2l:templates/modals_js.mako', | |||
{'modtype':modtype}, | |||
request=request) | |||
response.content_type = 'text/javascript' | |||
return response | |||
if modtype=='UserPicture': | |||
form = None | |||
if request.method == 'POST': | |||
response = render_to_response('jm2l:templates/modals_js.mako', | |||
{'modtype':modtype}, | |||
request=request) | |||
response.content_type = 'text/javascript' | |||
return response | |||
if modtype=='Place': | |||
if uid>0: | |||
place = Place.by_id(uid) | |||
@@ -622,7 +635,7 @@ def participer(request): | |||
form.populate_obj(TmpUsr) | |||
TmpUsr.nom = TmpUsr.nom.capitalize() | |||
TmpUsr.prenom = TmpUsr.prenom.capitalize() | |||
TmpUsr.slug = slugify(remove_accents('%s %s' % (form.prenom, form.nom)).lower().strip()) | |||
TmpUsr.slug = slugify(remove_accents('%s %s' % (form.prenom.data, form.nom.data)).lower().strip()) | |||
TmpUsr.password = TmpUsr.my_hash | |||
if len(TmpUsr.slug): | |||
CheckExist = DBSession.query(User)\ | |||
@@ -650,6 +663,10 @@ def change_year(request): | |||
return HTTPFound(location='/%s/le-programme' % year) | |||
return HTTPFound(location=request.route_url('home')) | |||
@view_config(route_name='pict_user', renderer="jm2l:templates/Profil/pict_user.mako") | |||
def pict_user(request): | |||
return {"uprofil":request.user} | |||
@view_config(route_name='event', renderer="jm2l:templates/view_event.mako") | |||
def show_event(request): | |||
year = int(request.matchdict.get('year', -1)) | |||