mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2024-12-04 19:15:30 +00:00
Adjustment in user_profile template. Add avatar uploading support
This commit is contained in:
parent
28882b57b1
commit
5d06195795
1
.gitignore
vendored
1
.gitignore
vendored
@ -25,4 +25,5 @@ config.py
|
||||
logfile.log
|
||||
|
||||
db_repository/*
|
||||
upload/avatar/*
|
||||
tmp/*
|
||||
|
@ -35,9 +35,10 @@ class User(db.Model):
|
||||
firstname = db.Column(db.String(64))
|
||||
lastname = db.Column(db.String(64))
|
||||
email = db.Column(db.String(128))
|
||||
avatar = db.Column(db.String(128))
|
||||
role_id = db.Column(db.Integer, db.ForeignKey('role.id'))
|
||||
|
||||
def __init__(self, id=None, username=None, password=None, plain_text_password=None, firstname=None, lastname=None, role_id=None, email=None, reload_info=True):
|
||||
def __init__(self, id=None, username=None, password=None, plain_text_password=None, firstname=None, lastname=None, role_id=None, email=None, avatar=None, reload_info=True):
|
||||
self.id = id
|
||||
self.username = username
|
||||
self.password = password
|
||||
@ -46,6 +47,7 @@ class User(db.Model):
|
||||
self.lastname = lastname
|
||||
self.role_id = role_id
|
||||
self.email = email
|
||||
self.avatar = avatar
|
||||
|
||||
if reload_info:
|
||||
user_info = self.get_user_info_by_id() if id else self.get_user_info_by_username()
|
||||
@ -238,6 +240,8 @@ class User(db.Model):
|
||||
user.email = self.email
|
||||
if self.plain_text_password:
|
||||
user.password = self.get_hashed_password(self.plain_text_password)
|
||||
if self.avatar:
|
||||
user.avatar = self.avatar
|
||||
|
||||
try:
|
||||
db.session.commit()
|
||||
|
54
app/static/admin/pages/scripts/user_profile.js
Normal file
54
app/static/admin/pages/scripts/user_profile.js
Normal file
@ -0,0 +1,54 @@
|
||||
var UserProfile = function() {
|
||||
var handleUpdatePassword = function() {
|
||||
$('.password-form').validate({
|
||||
errorElement: 'span', //default input error message container
|
||||
errorClass: 'help-block', // default input error message class
|
||||
focusInvalid: false, // do not focus the last invalid input
|
||||
ignore: "",
|
||||
rules: {
|
||||
password: {
|
||||
required: true
|
||||
},
|
||||
rpassword: {
|
||||
equalTo: "#newpassword"
|
||||
},
|
||||
},
|
||||
|
||||
invalidHandler: function(event, validator) { //display error alert on form submit
|
||||
|
||||
},
|
||||
|
||||
highlight: function(element) { // hightlight error inputs
|
||||
$(element)
|
||||
.closest('.form-group').addClass('has-error'); // set error class to the control group
|
||||
},
|
||||
|
||||
success: function(label) {
|
||||
label.closest('.form-group').removeClass('has-error');
|
||||
label.remove();
|
||||
},
|
||||
|
||||
submitHandler: function(form) {
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
|
||||
$('.password-form input').keypress(function(e) {
|
||||
if (e.which == 13) {
|
||||
if ($('.password-form').validate().form()) {
|
||||
$('.password-form').submit();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
//main function to initiate the module
|
||||
init: function() {
|
||||
handleUpdatePassword();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}();
|
@ -98,7 +98,11 @@
|
||||
<!-- DOC: Apply "dropdown-dark" class after below "dropdown-extended" to change the dropdown styte -->
|
||||
<li class="dropdown dropdown-user">
|
||||
<a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown" data-hover="dropdown" data-close-others="true">
|
||||
{% if current_user.avatar %}
|
||||
<img alt="" class="img-circle" src="{{ url_for('user_avatar', filename=current_user.avatar) }}"/>
|
||||
{% else %}
|
||||
<img alt="" class="img-circle" src="{{ url_for('static', filename='admin/layout2/img/avatar.png') }}"/>
|
||||
{% endif %}
|
||||
<span class="username username-hide-on-mobile">
|
||||
{% if current_user.is_authenticated() %} {{ current_user.firstname }} {% endif %}</span>
|
||||
<i class="fa fa-angle-down"></i>
|
||||
|
@ -91,13 +91,15 @@
|
||||
<!-- END PERSONAL INFO TAB -->
|
||||
<!-- CHANGE AVATAR TAB -->
|
||||
<div class="tab-pane" id="tab_1_2">
|
||||
<form action="{{ user_profile }}" role="form">
|
||||
<form action="{{ user_profile }}" method="POST" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<div class="fileinput fileinput-new" data-provides="fileinput">
|
||||
<div class="fileinput-new thumbnail" style="width: 200px; height: 150px;">
|
||||
<img src="http://www.placehold.it/200x150/EFEFEF/AAAAAA&text=no+image" alt=""/>
|
||||
</div>
|
||||
<div class="fileinput-preview fileinput-exists thumbnail" style="max-width: 200px; max-height: 150px;">
|
||||
<div class="fileinput-new thumbnail" style="width: 200px; height: 210px;">
|
||||
{% if current_user.avatar %}
|
||||
<img src="{{ url_for('user_avatar', filename=current_user.avatar) }}" alt=""/ style="width:200px;height:200px;">
|
||||
{% else %}
|
||||
<img src="http://www.placehold.it/200x200/EFEFEF/AAAAAA&text=no+image" alt=""/>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div>
|
||||
<span class="btn default btn-file">
|
||||
@ -105,7 +107,7 @@
|
||||
Select image </span>
|
||||
<span class="fileinput-exists">
|
||||
Change </span>
|
||||
<input type="file" name="...">
|
||||
<input type="file" name="file">
|
||||
</span>
|
||||
<a href="javascript:;" class="btn default fileinput-exists" data-dismiss="fileinput">
|
||||
Remove </a>
|
||||
@ -113,14 +115,11 @@
|
||||
</div>
|
||||
<div class="clearfix margin-top-10">
|
||||
<span class="label label-danger">NOTE! </span>
|
||||
<span>Attached image thumbnail is supported in Latest Firefox, Chrome, Opera, Safari and Internet Explorer 10 only </span>
|
||||
<span> Only support <strong>.PNG, .JPG, .JPEG</strong>. Best size is <strong>200x200</strong>. </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="margin-top-10">
|
||||
<a href="javascript:;" class="btn green-haze">
|
||||
Submit </a>
|
||||
<a href="javascript:;" class="btn default">
|
||||
Cancel </a>
|
||||
<button type="submit" class="btn green-haze"> Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -130,23 +129,17 @@
|
||||
{% if not current_user.password %}
|
||||
Your account password is managed via LDAP which isn't supported to change here.
|
||||
{% else %}
|
||||
<form action="{{ user_profile }}" method="POST">
|
||||
<div class="form-group">
|
||||
<label class="control-label">Current Password</label>
|
||||
<input type="password" class="form-control"/>
|
||||
</div>
|
||||
<form class="password-form" action="{{ user_profile }}" method="POST">
|
||||
<div class="form-group">
|
||||
<label class="control-label">New Password</label>
|
||||
<input type="password" class="form-control"/>
|
||||
<input name="password" id="newpassword" type="password" class="form-control"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">Re-type New Password</label>
|
||||
<input name="newpassword" type="password" class="form-control"/>
|
||||
<input name="rpassword" type="password" class="form-control"/>
|
||||
</div>
|
||||
<div class="margin-top-10">
|
||||
<button type="submit" class="btn green-haze"> Change Password</button>
|
||||
<a href="javascript:;" class="btn default">
|
||||
Cancel </a>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
@ -167,18 +160,19 @@
|
||||
{{ super() }}
|
||||
<!-- BEGIN PAGE LEVEL PLUGINS -->
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='global/plugins/bootstrap-select/bootstrap-select.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='global/plugins/select2/select2.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='global/plugins/jquery-multi-select/js/jquery.multi-select.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='global/plugins/jquery-validation/js/jquery.validate.min.js') }}" type="text/javascript"></script>
|
||||
<!-- END PAGE LEVEL PLUGINS -->
|
||||
|
||||
<!-- BEGIN PAGE LEVEL SCRIPTS -->
|
||||
<script src="{{ url_for('static', filename='global/scripts/metronic.js') }}" type="text/javascript"></script>
|
||||
<script src="{{ url_for('static', filename='admin/layout2/scripts/layout.js') }}" type="text/javascript"></script>
|
||||
<script src="{{ url_for('static', filename='admin/pages/scripts/user_profile.js') }}" type="text/javascript"></script>
|
||||
<!-- END PAGE LEVEL SCRIPTS -->
|
||||
<script>
|
||||
jQuery(document).ready(function() {
|
||||
Metronic.init(); // init metronic core componets
|
||||
Layout.init(); // init layout
|
||||
UserProfile.init();
|
||||
});
|
||||
</script>
|
||||
<!-- END JAVASCRIPTS -->
|
||||
|
30
app/views.py
30
app/views.py
@ -1,10 +1,12 @@
|
||||
import os
|
||||
import json
|
||||
import jinja2
|
||||
import traceback
|
||||
|
||||
from functools import wraps
|
||||
from flask.ext.login import login_user, logout_user, current_user, login_required
|
||||
from flask import Flask, g, request, make_response, jsonify, render_template, session, redirect, url_for, flash
|
||||
from flask import Flask, g, request, make_response, jsonify, render_template, session, redirect, url_for, send_from_directory
|
||||
from werkzeug import secure_filename
|
||||
|
||||
from lib import utils
|
||||
from app import app, login_manager
|
||||
@ -403,15 +405,37 @@ def user_profile():
|
||||
if request.method == 'GET':
|
||||
return render_template('user_profile.html')
|
||||
if request.method == 'POST':
|
||||
# get new profile info
|
||||
firstname = request.form['firstname'] if 'firstname' in request.form else ''
|
||||
lastname = request.form['lastname'] if 'lastname' in request.form else ''
|
||||
email = request.form['email'] if 'email' in request.form else ''
|
||||
new_password = request.form['newpassword'] if 'newpassword' in request.form else ''
|
||||
new_password = request.form['password'] if 'password' in request.form else ''
|
||||
|
||||
user = User(username=current_user.username, plain_text_password=new_password, firstname=firstname, lastname=lastname, email=email, reload_info=False)
|
||||
# get new avatar
|
||||
save_file_name = None
|
||||
if 'file' in request.files:
|
||||
file = request.files['file']
|
||||
if file:
|
||||
filename = secure_filename(file.filename)
|
||||
file_extension = filename.rsplit('.', 1)[1]
|
||||
|
||||
if file_extension.lower() in ['jpg', 'jpeg', 'png']:
|
||||
save_file_name = current_user.username + '.' + file_extension
|
||||
file.save(os.path.join(app.config['UPLOAD_DIR'], 'avatar', save_file_name))
|
||||
|
||||
|
||||
# update user profile
|
||||
user = User(username=current_user.username, plain_text_password=new_password, firstname=firstname, lastname=lastname, email=email, avatar=save_file_name, reload_info=False)
|
||||
user.update_profile()
|
||||
|
||||
return render_template('user_profile.html')
|
||||
|
||||
|
||||
@app.route('/user/avatar/<string:filename>')
|
||||
def user_avatar(filename):
|
||||
return send_from_directory(os.path.join(app.config['UPLOAD_DIR'], 'avatar'), filename)
|
||||
|
||||
|
||||
@app.route('/', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def index():
|
||||
|
@ -10,6 +10,9 @@ PORT = 9393
|
||||
LOG_LEVEL = 'DEBUG'
|
||||
LOG_FILE = 'logfile.log'
|
||||
|
||||
# Upload
|
||||
UPLOAD_DIR = os.path.join(basedir, 'upload')
|
||||
|
||||
# DATABASE CONFIG
|
||||
SQLALCHEMY_DATABASE_URI = 'mysql://root:123456@192.168.59.103/pdns'
|
||||
SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository')
|
||||
|
4
upload/avatar/.gitignore
vendored
Normal file
4
upload/avatar/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
Loading…
Reference in New Issue
Block a user