Compare commits
56 Commits
0.1
...
8ca5e4a457
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ca5e4a457 | |||
| 15c0f4fd79 | |||
| c91fdad70b | |||
| 5ccf91701f | |||
| 722fc7062e | |||
| beccb99088 | |||
| f5901a2ed4 | |||
| abaa9c66ce | |||
| 450fe88faa | |||
| 54be4c878f | |||
| 1ce6020bff | |||
| 2eb2d7fe98 | |||
| 5cdd623e6a | |||
| 740c744fc1 | |||
| 5fdee1d5ae | |||
| 37600d8bf2 | |||
| cb49a4417d | |||
| 35c20b20e0 | |||
| 4e525f5d79 | |||
| 1ac275c415 | |||
| b8f03b77da | |||
| f10523e706 | |||
| c03142fe71 | |||
| 4bb19ff8a9 | |||
| f5cd7021c5 | |||
| bfb4cca7d3 | |||
|
|
2fee7bef88 | ||
| 5c1cc0a650 | |||
| 6ee1b4decb | |||
| 3c149711f5 | |||
| 8cb8806673 | |||
| 7c56207b4e | |||
| 0d36ba7dcb | |||
| ecb3d4ac50 | |||
| 101f363293 | |||
|
|
4f7afa21e8 | ||
|
|
9d71b83218 | ||
|
|
a5b4ee42ed | ||
|
|
dfebabe92d | ||
| 265e6d5f65 | |||
| f33e9f611a | |||
| 78227870bc | |||
|
|
3451259a57 | ||
|
|
aef308e3fd | ||
|
|
87a088f54d | ||
|
|
4a278699d9 | ||
|
|
73002b5fb3 | ||
|
|
9094654956 | ||
|
|
b34695a41b | ||
| 083a7147ff | |||
| d7a44c04a3 | |||
| e42fdfd83e | |||
| d923a5eb97 | |||
| beb1e65ca7 | |||
| 66375d272f | |||
| 6b264cd46b |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,4 +1,8 @@
|
||||
__pycache__/
|
||||
base.db
|
||||
log.txt
|
||||
config.py
|
||||
users/
|
||||
sys
|
||||
*~
|
||||
#*
|
||||
27
LICENSE
Normal file
27
LICENSE
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2015, Kitoy
|
||||
All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
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 HOLDER 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.
|
||||
52
README.md
52
README.md
@@ -1,27 +1,53 @@
|
||||
# Pywallter est un projet pour partager des fichiers avec ses potes.
|
||||
# Pywallter est un projet de portail communautaire pour les utilisateurs d'un serveur.
|
||||
Ça demande juste un identifiant et un mot de passe et voila.
|
||||
Si les serveurs Mail et/ou XMPP sont configurer pywallter peut à gerer les alias et le mot de passe pour son compte mail et XMPP
|
||||
On peut y importer des fichiers que l'on pourra rendre accèssible en public par la suite.
|
||||
Je voulais tester cette idée de post-it pour que les utilisateur puisse s'échanger des messages
|
||||
ou que les admins puisse faire des annonces...
|
||||
On verra
|
||||
on pourrait ajoute de la double authentification mais bon ...
|
||||
|
||||
|
||||
## Pour démarrer le programme
|
||||
## Installer le programme
|
||||
|
||||
### Sur OpenBSD (7.1)
|
||||
Il faut installé FLask et quelques dépendances
|
||||
pkg_add py3-werkzeug py3-jinja2 py3-Pillow py3-wtforms py3-flask-wtf py3-flask \
|
||||
py3-bcrypt py3-markdown
|
||||
Il faut installer FLask et quelques dépendances
|
||||
pkg_add py3-werkzeug py3-jinja2 py3-Pillow py3-wtforms py3-flask-wtf py3-flask \
|
||||
py3-bcrypt py3-markdown py3-gevent py3-zopeinterface
|
||||
|
||||
Il reste malheuresment une dépendances sur flask-bcrypt a installé avec pip:
|
||||
|
||||
pip install flask-bcrypt
|
||||
|
||||
### Sur Debian
|
||||
apt install python3-flask python3-flask-bcrypt python3-wtforms python3-pil python3-markdown
|
||||
### Ensuite dans le dossier du projet tu fais :
|
||||
apt install python3-flask python3-flask-bcrypt python3-wtforms python3-pil python3-markdown \
|
||||
python3-gevent python3-zope.interface
|
||||
|
||||
$ export FLASK_APP=pywallter.py
|
||||
$ flask run
|
||||
## Démarrer le programme :
|
||||
|
||||
# cp config.py.example config.py
|
||||
$ python3 pywallter.py
|
||||
|
||||
#### En serveur de production
|
||||
$ python3 wsgi.py
|
||||
|
||||
Et ça devrait démarrer sans soucis.
|
||||
|
||||
Au premier démarage il créé un dossier pour les données et la base de données sqlite puis il s'arrête,
|
||||
il faut donc le redémarrer (c'est un peu con faudra changer ça )
|
||||
## Support serveru MAIL et XMPP
|
||||
|
||||
$ flask run
|
||||
Le logiciel a besoin de opensmtpd et prosody pour fonctionner.
|
||||
Le serveur mail et xmmp se base sur le domaine de la machine.
|
||||
Les scripts dans le dossier scripts sont la à titre d'exemple et peuvent être copié dans /usr/local/bin
|
||||
Une configuration fonctionnelle de prosody et opensmtpd est disponible dans le wiki.
|
||||
|
||||
Suffit pour le faire redémarrer
|
||||
## Comment ça fonctionne ?
|
||||
Globalement le programme stocke les fichiers des utilisateurs dans un dossiers, les fichiers de tous types
|
||||
sont stocker dans le dossier files et les images sont mis dans le dossier images et son consultable dans le menu gallerie.
|
||||
Pour les comptes XMPP le programme fait un appel à prosodyctl.
|
||||
Pour les comptes mail vous devez avoir deux programmes set_mail_alias et set_mail_passwd.
|
||||
|
||||
Les appels pour le compte mail se font ainsi :
|
||||
set_mail_passwd example@votredomaine.fr 'le mot de passe'
|
||||
|
||||
set_mail_alias example@votredomaine.fr add monalias@votredomaine.fr
|
||||
set_mail_alias example@votredomaine.fr del monalias@votredomaine.fr
|
||||
|
||||
54
Todo
54
Todo
@@ -3,9 +3,9 @@ Bugs:
|
||||
|
||||
Liste d'améliorations à coder
|
||||
|
||||
- Vérifier et valider les requêtes envoyées via les formulaires avec WTForms
|
||||
|
||||
- Réorganiser le code en utilisant Blueprint
|
||||
|
||||
- Réorganiser le code en utilisant Blueprint (Fait)
|
||||
|
||||
- À l'inscription d'un membre, créer dossiers :
|
||||
|
||||
@@ -14,49 +14,15 @@ Liste d'améliorations à coder
|
||||
/<user>/files/
|
||||
/<user>/images/
|
||||
/<user>/posts/
|
||||
/<user>/public/image/
|
||||
/<user>/public/file/
|
||||
|
||||
Il faudrait aussi limiter la taille du dossier /<user>/ à 1 ou 2 Go maxi par exemple.
|
||||
- Faire un fichier de config. (Fait)
|
||||
|
||||
Mais du coup, si les fichiers, images, et posts sont stockés dans ces dossiers,
|
||||
il faut stocker leurs chemins respectifs dans la bdd ? Et la consulter quand on veut afficher
|
||||
ces fichiers dans des vues ?
|
||||
|
||||
|
||||
- Il faudrait aussi limiter la taille du dossier /<user>/ à 1 ou 2 Go maxi par exemple. (Plus tard)
|
||||
|
||||
|
||||
|
||||
Quand on aura fait ça déjà on sera pas mal.
|
||||
|
||||
- Faciliter l'intégration d'un certificat let's encrypt (ça serait vraiment bon ça)
|
||||
|
||||
|
||||
# Architecture future en construction/réflexion
|
||||
#######################
|
||||
|
||||
pywallter/
|
||||
__init__.py
|
||||
views/
|
||||
inscription.py
|
||||
login.py
|
||||
blog.py
|
||||
upload.py
|
||||
filelist.py
|
||||
gallery.py
|
||||
templates/
|
||||
accueil.html
|
||||
inscription.html
|
||||
login.html
|
||||
squelette.html
|
||||
fileupload.html
|
||||
blog.html
|
||||
postedit.html
|
||||
privateblog.html
|
||||
publicblog.html
|
||||
filelist.html
|
||||
gallery.html
|
||||
logs.html
|
||||
parametres.html
|
||||
profil.html
|
||||
static/
|
||||
js/
|
||||
css/
|
||||
fonts/
|
||||
|
||||
#######################
|
||||
Un truc dans le genre ça pourrait le faire ?
|
||||
|
||||
31
config.py.example
Normal file
31
config.py.example
Normal file
@@ -0,0 +1,31 @@
|
||||
# L'adresse de base de votre site.
|
||||
# example BASE_URL="https://example.com"
|
||||
# BASE_URL="http://localhost:8000/" # si vous lancez pywallter avec flask run"
|
||||
|
||||
|
||||
BASE_URL="https://example.com/"
|
||||
# Essentiels pour les cookies
|
||||
SECRET_KEY="CHANGE-ME"
|
||||
|
||||
# Dossier où seront stocker les fichiers
|
||||
DOSSIER_APP = "./users/"
|
||||
|
||||
# Fichiers sqlite
|
||||
DATABASE = "./base.db"
|
||||
|
||||
# Extension des images accepter
|
||||
EXT_IMG= {'.jpg', '.JPG', '.png', '.PNG', '.gif', '.GIF', '.bmp', '.BMP', '.jpeg', '.JPEG' }
|
||||
|
||||
# Service
|
||||
# XMPP = True => Le service est installé et lancer
|
||||
# XMMP = False => Le service est désactivé
|
||||
XMPP_SERVER = False
|
||||
|
||||
# Service Mail
|
||||
# MAIL_SERVER = True => Le service est installé et lancer
|
||||
# MAIL_SERVER = False => Le service est désactivé
|
||||
MAIL_SERVER = False
|
||||
|
||||
|
||||
# Doas or sudo
|
||||
SETUID='doas'
|
||||
179
pywallter.py
179
pywallter.py
@@ -1,11 +1,12 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
from flask import Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file, escape, send_from_directory
|
||||
from flask import Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file, send_from_directory
|
||||
from werkzeug.utils import secure_filename
|
||||
from markupsafe import escape
|
||||
from wtforms import BooleanField, StringField, IntegerField, PasswordField, validators
|
||||
import sqlite3
|
||||
from flask_bcrypt import Bcrypt
|
||||
|
||||
from os import system
|
||||
|
||||
|
||||
from views.blog import blog
|
||||
@@ -14,36 +15,48 @@ from views.inscription import inscription
|
||||
from views.profil import profil
|
||||
from views.logs import logs
|
||||
from views.loginlogout import loginlogout
|
||||
from views.gallery import mygallery
|
||||
|
||||
from tools.databaseinit import init_db, init_dir
|
||||
from tools.databaseinit import init_db, init_dir, db_migrate
|
||||
|
||||
import glob, os, sys, time
|
||||
|
||||
app = Flask( 'pywallter' )
|
||||
app.config.from_pyfile('config.py')
|
||||
bcrypt = Bcrypt(app)
|
||||
|
||||
if init_db():
|
||||
print ("La base de données a été créer")
|
||||
exit()
|
||||
|
||||
init_db()
|
||||
db_migrate()
|
||||
if init_dir():
|
||||
print ("Le repertoire des utilisateurs a été créer")
|
||||
exit()
|
||||
|
||||
|
||||
|
||||
# Set the secret key. Keep this really secret
|
||||
app.secret_key = 'klfkdlfkdslfkln234325;cx!' # Chiffre les cookies si j'ai bien capté.
|
||||
# À générer aléatoirement impérativement avant de mettre en ligne.
|
||||
|
||||
#### Variables ####################################################################################
|
||||
#### Variables Globales #########################################################################
|
||||
|
||||
|
||||
DOSSIER_PERSO='users/'
|
||||
DOSSIER_PERSO= app.config['DOSSIER_APP']
|
||||
|
||||
extensionimg = {'.jpg', '.JPG', '.png', '.PNG', '.gif', '.GIF', '.bmp', '.BMP', '.jpeg', '.JPEG' }
|
||||
extensionimg = app.config['EXT_IMG']
|
||||
MAIL_SERVER = app.config['MAIL_SERVER']
|
||||
XMPP_SERVER = app.config['XMPP_SERVER']
|
||||
#################################################################################################
|
||||
|
||||
xmpp_server_not_installed = system('whereis prosodyctl')
|
||||
mail_server_not_installed = system('whereis set_mail_alias') + system('whereis set_mail_passwd') + \
|
||||
system('whereis dovecot') + system('whereis smtpd')
|
||||
|
||||
if XMPP_SERVER and xmpp_server_not_installed :
|
||||
print ("Vous avez activé la prise en charge du protocole XMPP mais prosody n'est pas installé")
|
||||
print ("Prosody doit être installé pour que pywaller puisse gérer les comptes XMPP")
|
||||
print ("pywallter ne peut démarrer en l'état, installez prosody ou désactiver la fonction XMPP")
|
||||
exit(1)
|
||||
|
||||
|
||||
if MAIL_SERVER and mail_server_not_installed :
|
||||
print("Vous avez activé la prise en charge des compte mail mais il manque des applications sur votre serveur pour que cela fonctionne")
|
||||
print(" Pywallter ne peut démarrer en l'état, désactivez la fonction Mail ou/et installé et confiurer les programme Dovecot et opensmtpd ainsi que les scripts pour gérer les comptes mails")
|
||||
exit(1)
|
||||
|
||||
##################################################################################################
|
||||
|
||||
app.register_blueprint(inscription)
|
||||
app.register_blueprint(blog)
|
||||
@@ -51,95 +64,53 @@ app.register_blueprint(filesupload)
|
||||
app.register_blueprint(profil)
|
||||
app.register_blueprint(logs)
|
||||
app.register_blueprint(loginlogout)
|
||||
|
||||
@app.route( '/gallery/')
|
||||
def gallery():
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
THUMBNAILS=DOSSIER_PERSO + UTILISATEUR + '/images/thumbnails/'
|
||||
fichiers = [fich for fich in os.listdir(THUMBNAILS)]
|
||||
return render_template('gallery.html', THUMBNAILS=THUMBNAILS, fichiers=fichiers)
|
||||
else :
|
||||
return redirect(url_for('loginlogout.login'))
|
||||
|
||||
@app.route( '/parametres/', methods=['GET','POST'] )
|
||||
def parametres() :
|
||||
if 'username' in session :
|
||||
return render_template('parametres.html')
|
||||
else:
|
||||
return redirect(url_for('loginlogout.login'))
|
||||
|
||||
@app.route('/up/view/<nom>')
|
||||
def download(nom):
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
nom = secure_filename(nom)
|
||||
if os.path.isfile(DOSSIER_PERSO + UTILISATEUR + '/files/' + nom): # si le fichier existe
|
||||
return send_file(DOSSIER_PERSO + UTILISATEUR + '/files/' + nom, as_attachment=True) # on l'envoie
|
||||
else:
|
||||
flash(u'Fichier {nom} inexistant.'.format(nom=nom), 'error')
|
||||
return redirect(url_for('list')) # sinon on redirige vers la liste, avec un message d'erreur
|
||||
else :
|
||||
return redirect(url_for('loginlogout.login'))
|
||||
|
||||
@app.route('/remove/<nom>')
|
||||
def remove(nom):
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
nom = secure_filename(nom)
|
||||
if os.path.isfile(DOSSIER_PERSO + UTILISATEUR + '/files/' + nom): # si le fichier existe
|
||||
os.remove(DOSSIER_PERSO + UTILISATEUR + '/files/' + nom) # on le supprime
|
||||
return redirect(url_for('filesupload.list', _external=True))
|
||||
else:
|
||||
if os.path.isfile(DOSSIER_PERSO + UTILISATEUR + '/images/thumbnails/' + nom): # si le fichier existe
|
||||
os.remove(DOSSIER_PERSO + UTILISATEUR + '/images/thumbnails/' + nom) # on le supprime
|
||||
os.remove(DOSSIER_PERSO + UTILISATEUR + '/images/' + nom) # on le supprime
|
||||
return redirect(url_for('gallery'))
|
||||
else:
|
||||
flash(u'Fichier {nom} inexistant.'.format(nom=nom), 'error')
|
||||
return redirect(url_for('filesupload.list', _external=True)) # sinon on redirige vers la liste, avec un message d'erreur
|
||||
|
||||
else :
|
||||
return redirect(url_for('loginlogout.login'))
|
||||
|
||||
|
||||
@app.route('/myfiles/<filename>')
|
||||
def myfiles(filename):
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
return send_from_directory(
|
||||
os.path.join(DOSSIER_PERSO, UTILISATEUR, 'files'), filename )
|
||||
else :
|
||||
return redirect(url_for('loginlogout.login'))
|
||||
|
||||
|
||||
@app.route('/myfiles/images/<filename>')
|
||||
def myimg(filename):
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
return send_from_directory(
|
||||
os.path.join(DOSSIER_PERSO, UTILISATEUR, 'images'), filename )
|
||||
else :
|
||||
return redirect(url_for('loginlogout.login'))
|
||||
|
||||
@app.route('/myfiles/images/thumbnails/<filename>')
|
||||
def mythumbnails(filename):
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
return send_from_directory(
|
||||
os.path.join(DOSSIER_PERSO, UTILISATEUR, 'images/thumbnails'), filename )
|
||||
else :
|
||||
return redirect(url_for('loginlogout.login'))
|
||||
|
||||
@app.route( '/' )
|
||||
def index():
|
||||
if 'username' in session :
|
||||
return redirect(url_for('filesupload.uploadfiles'))
|
||||
else :
|
||||
return redirect(url_for('loginlogout.login', _external=True))
|
||||
app.register_blueprint(mygallery)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def create_app():
|
||||
|
||||
app = Flask( 'pywallter' )
|
||||
app.config.from_pyfile('config.py')
|
||||
bcrypt = Bcrypt(app)
|
||||
xmpp_server_not_installed = system('whereis prosodyctl')
|
||||
mail_server_not_installed = system('whereis set_mail_alias') + system('whereis set_mail_passwd') + system('whereis smtpctl')
|
||||
|
||||
if XMPP_SERVER and xmpp_server_not_installed :
|
||||
print ("Vous avez activé la prise en charge du protocole XMPP mais prosody n'est pas installé")
|
||||
print ("Prosody doit être installé pour que pywaller puisse gérer les comptes XMPP")
|
||||
print ("pywallter ne peut démarrer en l'état installé prosody ou désactiver la fonction XMPP")
|
||||
exit(1)
|
||||
|
||||
|
||||
if MAIL_SERVER and mail_server_not_installed :
|
||||
print("Vous avez activé la prise en charge des comptes mail mais il manque des applications sur votre serveur pour que cela fonctionne")
|
||||
print(" Pywallter ne peut démarrer en l'état désactivé la fonction Mail ou/et installé et confiurer les programme Dovecot et opensmtpd ainsi que les scripts pour gérer les comptes mails")
|
||||
exit(1)
|
||||
|
||||
init_db()
|
||||
db_migrate()
|
||||
if init_dir():
|
||||
print ("Le repertoire des utilisateurs a été créer")
|
||||
|
||||
|
||||
|
||||
DOSSIER_PERSO= app.config['DOSSIER_APP']
|
||||
|
||||
extensionimg = app.config['EXT_IMG']
|
||||
|
||||
|
||||
app.register_blueprint(inscription)
|
||||
app.register_blueprint(postit)
|
||||
app.register_blueprint(filesupload)
|
||||
app.register_blueprint(profil)
|
||||
app.register_blueprint(logs)
|
||||
app.register_blueprint(loginlogout)
|
||||
app.register_blueprint(mygallery)
|
||||
|
||||
return app
|
||||
|
||||
if __name__ == '__main__' :
|
||||
app.run(host='127.0.0.1', port=8080, debug=True)
|
||||
app.run(host='127.0.0.1', port=8000, debug=True)
|
||||
|
||||
9
scripts/etc/mailconfig
Normal file
9
scripts/etc/mailconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
# Password file
|
||||
PASSWD_FILE="/etc/mail/passwd"
|
||||
|
||||
# Alias File
|
||||
ALIAS_FILE="/etc/mail/virtuals"
|
||||
|
||||
# APPLICATIONS MAIL ADDRESS
|
||||
APP_MAIL="/etc/mail/reserved"
|
||||
115
scripts/set_mail_alias
Executable file
115
scripts/set_mail_alias
Executable file
@@ -0,0 +1,115 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /etc/mailconfig
|
||||
|
||||
exit_failure(){
|
||||
mess=$1
|
||||
code_exit=$2
|
||||
echo "$mess";
|
||||
exit "$code_exit";
|
||||
}
|
||||
|
||||
check_domain()
|
||||
{
|
||||
mail=$1
|
||||
alias=$2
|
||||
|
||||
domain_mail=`echo $mail | awk -F '@' '{ print $2 }'`
|
||||
domain_alias=`echo $alias | awk -F '@' '{ print $2 }'`
|
||||
|
||||
[[ "$domain_mail" = `hostname` && "$domain_alias" = `hostname` ]] || exit_failure "Bad domain" 1;
|
||||
|
||||
grep -q "$mail" "$PASSWD_FILE" && true || exit_failure "Mail doesn't exist" 1;
|
||||
|
||||
}
|
||||
|
||||
check_mail_exist()
|
||||
{
|
||||
mail=$1
|
||||
grep -q "$mail" "$PASSWD_FILE" && exit_failure " This e-mail address already exist" 2 || true
|
||||
}
|
||||
|
||||
check_alias()
|
||||
{
|
||||
alias=$1
|
||||
grep -q "$alias" "$ALIAS_FILE" && exit_failure "This e- mail address already exist in alias" 2 || true
|
||||
}
|
||||
|
||||
check_app_mail()
|
||||
{
|
||||
alias=$1
|
||||
grep -q "$alias" "$APP_MAIL" && exit_failure "Address already exist in app mail" 2 || true
|
||||
}
|
||||
|
||||
add_alias()
|
||||
{
|
||||
print "$2":" $1" >> "$ALIAS_FILE"
|
||||
}
|
||||
|
||||
check_alias_exist(){
|
||||
alias_c="$1: $2"
|
||||
grep -q "$alias_c" "$ALIAS_FILE" && true || exit_failure "This alias doesn't exist" 3
|
||||
}
|
||||
|
||||
del_alias()
|
||||
{
|
||||
alias_line="$1: $2"
|
||||
egrep -v "$alias_line" "$ALIAS_FILE" > /tmp/alias.tmp
|
||||
mv /tmp/alias.tmp "$ALIAS_FILE"
|
||||
}
|
||||
|
||||
|
||||
usage(){
|
||||
print "This program ask 3 arguments : \n"
|
||||
print "First is email with domain name of this host second is add or del for \n"
|
||||
print "add or delete an alias "
|
||||
print "\t$0 email-adresse del alias@`hostname`\n"
|
||||
print "Other example:\n\t $0 test@`hostname` add myalias@`hostname` "
|
||||
print "This script require root privilèges"
|
||||
}
|
||||
|
||||
if [ `id -u` -ne 0 ]; then
|
||||
usage
|
||||
exit 4;
|
||||
fi
|
||||
|
||||
if [ -z $1 ];
|
||||
then
|
||||
usage
|
||||
exit 3;
|
||||
fi
|
||||
|
||||
if [ -z $2 ];
|
||||
then
|
||||
usage
|
||||
exit 3;
|
||||
fi
|
||||
|
||||
if [ -z $3 ];
|
||||
then
|
||||
usage
|
||||
exit 3;
|
||||
fi
|
||||
|
||||
|
||||
check_domain $1 $3
|
||||
|
||||
|
||||
case $2 in
|
||||
"add")
|
||||
check_mail_exist $3
|
||||
check_alias $3
|
||||
check_app_mail $3
|
||||
add_alias $1 $3
|
||||
smtpctl update table virtuals
|
||||
;;
|
||||
"del")
|
||||
check_alias_exist $3 $1
|
||||
del_alias $3 $1
|
||||
smtpctl update table virtuals
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 4;
|
||||
;;
|
||||
esac
|
||||
108
scripts/set_mail_passwd
Executable file
108
scripts/set_mail_passwd
Executable file
@@ -0,0 +1,108 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /etc/mailconfig
|
||||
|
||||
exit_failure(){
|
||||
mess=$1
|
||||
code_exit=$2
|
||||
echo "$mess";
|
||||
exit "$code_exit";
|
||||
}
|
||||
|
||||
check_domain()
|
||||
{
|
||||
mail=$1
|
||||
domain=`echo $mail | awk -F '@' '{ print $2 }'`
|
||||
[[ "$domain" = `hostname` ]] || exit_failure "Bad domain " 1
|
||||
|
||||
}
|
||||
|
||||
|
||||
check_alias()
|
||||
{
|
||||
mail=$1
|
||||
aliases=$(grep -v "$mail" $ALIAS_FILE)
|
||||
echo "$aliases" | grep -q "$mail" && exit_failure "Address already exist in alias" 2 || true
|
||||
}
|
||||
|
||||
check_app_mail()
|
||||
{
|
||||
alias=$1
|
||||
grep -q "$alias" "$APP_MAIL" && exit_failure "This e-mail address already exist in app mail" 2 || true
|
||||
}
|
||||
|
||||
|
||||
set_password()
|
||||
{
|
||||
mail=$1
|
||||
password=$2
|
||||
cat $PASSWD_FILE | grep -w -v -e "$mail" > /tmp/passwd.tmp
|
||||
print "$mail":`encrypt "$password"` >> /tmp/passwd.tmp
|
||||
mv /tmp/passwd.tmp $PASSWD_FILE
|
||||
}
|
||||
|
||||
add_mailbox()
|
||||
{
|
||||
mail=$1
|
||||
cat $ALIAS_FILE | grep -w -v -e "$mail: vmail" > /tmp/virtuals.tmp
|
||||
print "$1: vmail" >> /tmp/virtuals.tmp
|
||||
mv /tmp/virtuals.tmp $ALIAS_FILE
|
||||
}
|
||||
|
||||
delete_mail_account()
|
||||
{
|
||||
mail=$1
|
||||
cat $PASSWD_FILE | grep -w -v -e "$mail" > /tmp/passwd.tmp
|
||||
mv /tmp/passwd.tmp $PASSWD_FILE
|
||||
cat $ALIAS_FILE | grep -v "$mail" >> /tmp/virtuals.tmp
|
||||
mv /tmp/virtuals.tmp $ALIAS_FILE
|
||||
# rm -fr repertoir mail.
|
||||
}
|
||||
|
||||
usage(){
|
||||
print "This program ask 2 arguments : \n"
|
||||
print "For add or change password of mail account :\: "
|
||||
print "First is email with domain name of this host second is password \n:"
|
||||
print "\t$0 email-adresse 'password'\n"
|
||||
print "Example:\n\t $0 add example@`hostname` 'yourverysecurepassword' "
|
||||
|
||||
print "For delete a mail account:\n"
|
||||
print "$0 del test@`hostname`"
|
||||
|
||||
print "This script require root privilèges"
|
||||
}
|
||||
|
||||
if [ `id -u` -ne 0 ]; then
|
||||
usage
|
||||
exit 4;
|
||||
fi
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
usage
|
||||
exit 3;
|
||||
fi
|
||||
|
||||
if [ -z "$2" ]; then
|
||||
usage
|
||||
exit 3;
|
||||
fi
|
||||
|
||||
|
||||
|
||||
case $1 in
|
||||
"del")
|
||||
check_domain "$2"
|
||||
delete_mail_account "$2"
|
||||
smtpctl update table passwd
|
||||
smtpctl update table virtuals
|
||||
;;
|
||||
*)
|
||||
check_domain "$1"
|
||||
check_alias "$1"
|
||||
check_app_mail "$1"
|
||||
set_password "$1" "$2"
|
||||
add_mailbox "$1"
|
||||
smtpctl update table passwd
|
||||
smtpctl update table virtuals
|
||||
;;
|
||||
esac
|
||||
206
static/blog.css
Normal file
206
static/blog.css
Normal file
@@ -0,0 +1,206 @@
|
||||
/* kitoy <kitoy__at__kitoy.me> */
|
||||
|
||||
:root
|
||||
{
|
||||
--color-text: #fdfdfddd;
|
||||
--color-background: #202020;
|
||||
}
|
||||
|
||||
html{
|
||||
height: 100%;
|
||||
width: 80%;
|
||||
margin-left: 10%;
|
||||
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
|
||||
|
||||
hr {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
* {-moz-box-sizing: border-box; box-sizing: border-box;}
|
||||
|
||||
|
||||
a {
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.date {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.slug {
|
||||
//margin-left: 1rem;
|
||||
text-align: left;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.readmore {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.readmore a {
|
||||
color: var(--color-text);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
.copyleft {
|
||||
display:inline-block;
|
||||
transform: rotate(180deg);
|
||||
padding-bottom: -15px;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
}
|
||||
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
.articles {
|
||||
max-width: 80%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 5rem;
|
||||
margin-bottom: 3rem;
|
||||
padding:0.5em;
|
||||
border: 7px double;
|
||||
border-color: var(--text-color);
|
||||
border-radius: 10px 10px 10px 10px;
|
||||
line-height: 1.5;
|
||||
letter-spacing: 0.1vw;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.articles ul {
|
||||
list-style-type: disc;
|
||||
margin: 5vw;
|
||||
padding-top: 1vw;
|
||||
padding-bottom: 1vw;
|
||||
padding-left: 1.5vw;
|
||||
}
|
||||
|
||||
|
||||
.titre {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
.index {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.articles img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 50%;
|
||||
margin-bottom: 2vw;
|
||||
|
||||
}
|
||||
|
||||
.articles .description {
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-size: 1.5vw;
|
||||
padding-bottom: 30px;
|
||||
color: ;
|
||||
}
|
||||
|
||||
|
||||
.pagination a {
|
||||
border: 1px solid;
|
||||
border-color: $color_title;
|
||||
padding: 3px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.center {
|
||||
margin: auto;
|
||||
width: 50%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.contact{
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
footer {
|
||||
position: relative;
|
||||
bottom:0px;
|
||||
width: 100%;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 980px)
|
||||
{
|
||||
|
||||
.articles .description {
|
||||
font-size: 4vw;
|
||||
}
|
||||
|
||||
.articles {
|
||||
margin-left: 0;
|
||||
position: relative;
|
||||
font-size: 3.5vw;
|
||||
|
||||
}
|
||||
|
||||
footer {
|
||||
font-size: 3vw;
|
||||
}
|
||||
|
||||
.articles img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media only screen and (max-width: 980px){
|
||||
|
||||
html{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px)
|
||||
{
|
||||
.h1 {
|
||||
font-size: 5vw;
|
||||
}
|
||||
|
||||
.icons img {
|
||||
width: 7vw;
|
||||
height: 7vw;
|
||||
margin: 20px;
|
||||
display:inline-block;
|
||||
align-items:center;
|
||||
}
|
||||
|
||||
}
|
||||
1243
static/bootstrap.css
vendored
1243
static/bootstrap.css
vendored
File diff suppressed because it is too large
Load Diff
7
static/bootstrap.min.css
vendored
7
static/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
111
static/cover.css
111
static/cover.css
@@ -9,11 +9,13 @@ a:hover {
|
||||
color: #fff;
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
/* Custom default button */
|
||||
.btn-default,
|
||||
.btn-default:hover,
|
||||
.btn-default:focus {
|
||||
color: #333;
|
||||
color: #fff;
|
||||
text-shadow: none; /* Prevent inheritence from `body` */
|
||||
/*background-color: #fff;*/
|
||||
border: 1px solid #fff;
|
||||
@@ -29,12 +31,36 @@ body {
|
||||
height: 100%;
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
|
||||
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 1px 3px rgba(0,0,0,.5);
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-bottom: 5vw;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #428bca;
|
||||
|
||||
}
|
||||
|
||||
a:focus, a:hover {
|
||||
|
||||
color: #6cbdbd;
|
||||
text-decoration: underline;
|
||||
|
||||
}
|
||||
|
||||
.content p {
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
/* Extra markup and styles for table-esque vertical and horizontal centering */
|
||||
.site-wrapper {
|
||||
display: table;
|
||||
@@ -58,6 +84,47 @@ body {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
.modal-header .close {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.modal-body{
|
||||
background-color: #444;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
|
||||
.row {
|
||||
margin-top: 5vw;
|
||||
}
|
||||
|
||||
.container a {
|
||||
color #00abff;
|
||||
}
|
||||
|
||||
.panel-body a {
|
||||
color: #00abff;
|
||||
}
|
||||
|
||||
.well {
|
||||
margin-top : 7em;
|
||||
}
|
||||
|
||||
.well a {
|
||||
color: #00abff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Header
|
||||
@@ -95,6 +162,17 @@ body {
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
|
||||
|
||||
/* Footer */
|
||||
|
||||
footer {
|
||||
position: bottom;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.masthead-brand {
|
||||
float: left;
|
||||
@@ -239,3 +317,34 @@ body {
|
||||
}
|
||||
|
||||
/* ######### Animations ######### */
|
||||
/* ###### Simplemde editor ###### */
|
||||
|
||||
.editor-toolbar {
|
||||
background-color: white;
|
||||
}
|
||||
.editor-preview-side {
|
||||
text-align: justify;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
/* ### Style for post-it ### */
|
||||
.post-it h1 {
|
||||
font-size: 1.5vw;
|
||||
}
|
||||
|
||||
.post-it h2 {
|
||||
font-size: 1.2vw;
|
||||
}
|
||||
|
||||
.post-it h3 {
|
||||
font-size: 1vw;
|
||||
}
|
||||
|
||||
.post-it h3 {
|
||||
font-size: 0.9vw;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
function divhider() {
|
||||
var x = document.getElementsByClassName("msginfo");
|
||||
var x = document.getElementsByClassName("flashed");
|
||||
x[0].style.visibility = "hidden";
|
||||
}
|
||||
|
||||
|
||||
function animation() {
|
||||
var x = document.getElementsByClassName("msginfo");
|
||||
var x = document.getElementsByClassName("flashed");
|
||||
x[0].style.animation = "disparition 0.2s 1";
|
||||
}
|
||||
|
||||
window.setTimeout(divhider, 2200);
|
||||
window.setTimeout(animation, 2000);
|
||||
window.setTimeout(divhider, 8800);
|
||||
window.setTimeout(animation, 8000);
|
||||
|
||||
let darkBoxVisible = false;
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
BIN
static/fonts/glyphicons-halflings-regular.woff
Normal file
BIN
static/fonts/glyphicons-halflings-regular.woff
Normal file
Binary file not shown.
Binary file not shown.
BIN
static/glyphicons-halflings-regular.woff2
Normal file
BIN
static/glyphicons-halflings-regular.woff2
Normal file
Binary file not shown.
7
static/simplemde.min.css
vendored
Normal file
7
static/simplemde.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
15
static/simplemde.min.js
vendored
Normal file
15
static/simplemde.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -16,3 +16,18 @@ body {
|
||||
.theme-showcase .navbar .container {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #3cbdbd;
|
||||
}
|
||||
|
||||
a:focus, a:hover {
|
||||
|
||||
color: #6cbdbd;
|
||||
text-decoration: underline;
|
||||
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: 3em;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
margin: auto;
|
||||
margin-top: 5%;
|
||||
width: 50%;
|
||||
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.flashed p {
|
||||
@@ -48,13 +48,13 @@
|
||||
}
|
||||
|
||||
.succes p {
|
||||
background-color: #CDCBD0;
|
||||
color: #00A310;
|
||||
background-color: #444;
|
||||
color: #00C613;
|
||||
}
|
||||
|
||||
.error p {
|
||||
background-color: #CDCBD0;
|
||||
color: #B80000;
|
||||
background-color: #444;
|
||||
color: #FF4A4A;
|
||||
}
|
||||
|
||||
#majuscule {
|
||||
@@ -182,6 +182,7 @@
|
||||
|
||||
#gallery img:hover {
|
||||
filter:none;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
|
||||
5
templates/#_footer.html#
Normal file
5
templates/#_footer.html#
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
<footer>
|
||||
<
|
||||
<p> Réalisé avec Flask et un thème bootstrap @mdo </p>
|
||||
</footer>
|
||||
39
templates/#new_article_blog.html#
Normal file
39
templates/#new_article_blog.html#
Normal file
@@ -0,0 +1,39 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="col-sm-1"></div>
|
||||
<div class="col-sm-10">
|
||||
<br />
|
||||
<div class="well"> Hello <span id="majuscule">{{ session['username'] }} ! </span>
|
||||
Bienvenue sur la création d'un nouvel article de blog. Vous pouvez créer ou importer un article de blog ici,
|
||||
vous avez le choix de le rendre publique dès sa création en cochant publique ou le laisser en privé
|
||||
si vous souhaitez le modifier plus-tard avant sa publication.
|
||||
Par défaut il est laissé en privé pour éviter les publications
|
||||
accidentelles.
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<form method="POST" action="{{ url_for('blog.new_article') }}" id="postform">
|
||||
<!--<input type="text" name="category" id="category" placeholder="Catégorie" class="form-control"><br />-->
|
||||
<input type="text" name="title" id="title" placeholder="Titre" class="form-control"><br />
|
||||
<input type="text" name="subtitle" id="subtitle" placeholder="Sous-titre" class="form-control"><br />
|
||||
<hr>
|
||||
<textarea id="editeurMarkdown" class="form-control" form="postform" name="content" id="content" placeholder="Contenu" style="height:10vw;"></textarea><br />
|
||||
<div class="row">
|
||||
<div class="col-sm-4"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="privé" checked> Privé </div>
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="publique">Public<br></div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
<br />
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit"> Créer l'article </button>
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
15
templates/_flash_msgs.html
Normal file
15
templates/_flash_msgs.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<div class="msginfo">
|
||||
{# on affiche les messages d'erreur puis les messages de succes #}
|
||||
{% for categorie in ['error', 'succes'] %}
|
||||
{% with msgs = get_flashed_messages(category_filter=[categorie]) %}
|
||||
{% if msgs %}
|
||||
<div class="flashed {{ categorie }}">
|
||||
{% for m in msgs %}
|
||||
<p>{{ m|safe }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
7
templates/_footer.html
Normal file
7
templates/_footer.html
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
|
||||
<footer>
|
||||
|
||||
<p> Réalisé avec Flask et un thème bootstrap @mdo </p>
|
||||
|
||||
</footer>
|
||||
19
templates/_head.html
Normal file
19
templates/_head.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<link rel="icon" href="../../favicon.ico">
|
||||
|
||||
<title>Un serveur et des ...</title>
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="{{ url_for('static', filename='bootstrap.min.css') }}" rel="stylesheet">
|
||||
<!-- Bootstrap theme -->
|
||||
<link href="{{ url_for('static', filename='bootstrap-theme.min.css') }}" rel="stylesheet">
|
||||
<!-- Custom styles for this template -->
|
||||
<link href="{{ url_for('static', filename='up.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='cover.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='simplemde.min.css') }}" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
5
templates/_js-core.html
Normal file
5
templates/_js-core.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<!-- Bootstrap core JavaScript -->
|
||||
<!--================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="{{ url_for('static', filename='jquery.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='bootstrap.min.js') }}"></script>
|
||||
1
templates/_js-gallery.html
Normal file
1
templates/_js-gallery.html
Normal file
@@ -0,0 +1 @@
|
||||
<script src="{{ url_for('static', filename='docs.min.js') }}"></script>
|
||||
16
templates/_js.html
Normal file
16
templates/_js.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!-- Bootstrap core JavaScript -->
|
||||
<!--================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="{{ url_for('static', filename='jquery.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='bootstrap.min.js') }}"></script>
|
||||
|
||||
<script src="{{ url_for('static', filename='docs.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='simplemde.min.js') }}"></script>
|
||||
|
||||
<script>
|
||||
new SimpleMDE({
|
||||
element: document.getElementById("editeurMarkdown"),
|
||||
spellChecker: true,
|
||||
});
|
||||
|
||||
</script>
|
||||
10
templates/_js_editor.html
Normal file
10
templates/_js_editor.html
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
<script src="{{ url_for('static', filename='simplemde.min.js') }}"></script>
|
||||
|
||||
<script>
|
||||
new SimpleMDE({
|
||||
element: document.getElementById("editeurMarkdown"),
|
||||
spellChecker: true,
|
||||
});
|
||||
|
||||
</script>
|
||||
98
templates/_nav_userlogin.html
Normal file
98
templates/_nav_userlogin.html
Normal file
@@ -0,0 +1,98 @@
|
||||
<!-- Fixed navbar -->
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li{% if section == "Mon Blog" %} class="active" {% endif %}>
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="glyphicon glyphicon-globe" aria-hidden="true"></span>
|
||||
Mon blog
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li>
|
||||
<a href="/myblog/new-article/"> <span class="glyphicon" aria-hidden="true"></span>
|
||||
Ecrire un billet </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/myblog/list-articles/"><span class="glyphicon" aria-hidden="true">
|
||||
</span>
|
||||
Gérer mes billets
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/myblog/personalize/"><span class="glyphicon glyphicon-cog" aria-hidden="true"></span>
|
||||
Personnaliser mon blog
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/myblog/view/"><span class="glyphicon" aria-hidden="true"></span>
|
||||
Voir mon blog
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li{% if section == "Files" %} class="active" {% endif %} >
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="glyphicon glyphicon-folder-open" aria-hidden="true"></span> Mes Fichiers</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="/view/"> <span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span>
|
||||
Fichiers envoyés </a></li>
|
||||
<li><a href="/filesupload/"><span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span>
|
||||
Envoyer des fichiers</a></li>
|
||||
<li><a href="/gallery/"><span class="glyphicon glyphicon-cog" aria-hidden="true"></span>
|
||||
Gallerie d'images
|
||||
</a></li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
<li{% if section == "mailbox" %} class="active" {% endif %} >
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="glyphicon glyphicon-comment" aria-hidden="true"></span> Ma Messagerie </a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="/mymailbox/alias"><span class="glyphicon glyphicon-sunglasses" aria-hidden="true"></span>
|
||||
Gerer mes alias</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
<li{% if section == "Logs" %} class="active" {% endif %}>
|
||||
<a href="/logs/"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>
|
||||
Logs
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li {% if section == "Profil" %} class="dropdown active" {% else %} class="dropdown" {% endif %}>
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="glyphicon glyphicon-home" aria-hidden="true"></span>
|
||||
<span id="majuscule">{{ session['username'] }} </span>
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="/profil/"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Profil</a></li>
|
||||
<li><a href="/profil/change-password/"> <span class="glyphicon glyphicon-lock" aria-hidden="true"></span>
|
||||
Changer mon mot de passe </a></li>
|
||||
<li><a href="/invitation/"><span class="glyphicon glyphicon-cog" aria-hidden="true"></span> Inviter une personne</a></li>
|
||||
<li><a href="/delete_me/"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span> Supprimer mon compte </a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li>
|
||||
<a href="/logout/">
|
||||
<span class="glyphicon glyphicon-off" aria-hidden="true"></span>
|
||||
Se déconnecter
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
@@ -1,26 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="no-js" lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<link rel="icon" href="../../favicon.ico">
|
||||
|
||||
<title>MaPagePerso</title>
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="{{ url_for('static', filename='bootstrap.min.css') }}" rel="stylesheet">
|
||||
<!-- Bootstrap theme -->
|
||||
<link href="{{ url_for('static', filename='bootstrap-theme.min.css') }}" rel="stylesheet">
|
||||
<!-- Custom styles for this template -->
|
||||
<link href="{{ url_for('static', filename='up.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='cover.css') }}" rel="stylesheet">
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='divhider.js') }}"></script>
|
||||
|
||||
</head>
|
||||
<html lang="fr">
|
||||
|
||||
{% include '_head.html' %}
|
||||
<body>
|
||||
|
||||
{% block main %}
|
||||
@@ -34,41 +15,44 @@
|
||||
<div class="masthead clearfix">
|
||||
<div class="inner">
|
||||
<h3 class="masthead-brand">Pywallter</h3>
|
||||
<ul class="nav masthead-nav">
|
||||
<li class="active"><a href="/filesupload/"></a></li>
|
||||
<li><a href="#">Inscription</a></li>
|
||||
<li><a href="#">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner cover">
|
||||
<h1 class="cover-heading">Restez libres</h1>
|
||||
<p class="lead">Bienvenue sur Olala, hébergeur de fichier libre basé sur Flask et hébergé sur une simple petit ordinateur.
|
||||
Bientôt disponible, gallerie d'images, blog et d'autres. Site en construction permanente.</p>
|
||||
<p class="lead">Bienvenue sur Olala, un portail utilisateur libre basé sur Flask à héberger sur un petit ordinateur.
|
||||
Tu peux importer des fichiers et dans l'avenir les rendres disponibles pour ton site
|
||||
Tu peux consulter ou participer au tableau des post-its pour communiquer avec les autres membres ou
|
||||
simplement savoir ce qu'il se passe sur le serveur.<br/>
|
||||
Tu peux gérer ton compte MAIL et XMPP si les serveurs Mail(SMTP, IMAP) et XMPP sont actifs.
|
||||
<br/>
|
||||
<strong> Site en construction permanente. </strong></p>
|
||||
<br>
|
||||
<p class="lead">
|
||||
|
||||
{% include '_flash_msgs.html' %}
|
||||
<p class="lead">
|
||||
<form method="POST" action="{{ url_for('loginlogout.login') }}">
|
||||
<input type="text" name="user" id="user" placeholder="Utilisateur" class="form-control" width="200px"><br />
|
||||
<input type="password" name="passwd" id="passwd" placeholder="Mot de passe" class="form-control"><br />
|
||||
<br>
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit">Login</button>
|
||||
<p class="lead"><a href="{{ url_for('loginlogout.lost_password') }}"> Mouarf j'ai perdu mon mot de passe </a> </p>
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit"> Login </button>
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
<!-- Bootstrap core JavaScript -->
|
||||
<!--================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="{{ url_for('static', filename='jquery.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='bootstrap.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='docs.min.js') }}"></script>
|
||||
{% include '_footer.html' %}
|
||||
|
||||
{% include '_js.html' %}
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
@@ -1,114 +1,24 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title> Blog de {{ user }} </title>
|
||||
<link rel="stylesheet" href="/static/blog.css" type="text/css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="articles">
|
||||
|
||||
<h2 class="titre"> {{ post_info.title }} </h2>
|
||||
|
||||
<h5 class="titre">Publié le {{ post_info.time }} </h5>
|
||||
|
||||
<h2 class="description titre"> {{ post_info.subtitle }} </h2>
|
||||
<hr/>
|
||||
{{ content|safe }}
|
||||
|
||||
|
||||
{% block navbar %}
|
||||
<!-- Fixed navbar -->
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<!--<li class="active"><a href="/blog/">Blog</a></li>-->
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="active"><a href="/blog/"><span class="glyphicon glyphicon-globe" aria-hidden="true"></span> Blog</a></li>
|
||||
<li><a href="/filesupload/"><span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span> Upload</a></li>
|
||||
<li><a href="/view/"><span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span> Fichiers</a></li>
|
||||
<li><a href="/gallery/"><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> Gallerie</a></li>
|
||||
<li><a href="/logs/"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span> Logs</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-home" aria-hidden="true"></span> <span id="majuscule">{{ session['username'] }} </span><span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="/profil/{{ session['username'] }}"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Profil</a></li>
|
||||
<li><a href="/parametres/"><span class="glyphicon glyphicon-cog" aria-hidden="true"></span> Paramètres</a></li>
|
||||
<li class="divider"></li>
|
||||
<!--<li class="dropdown-header">Nav header</li>-->
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Déconnexion</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Exit</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<!-- Main jumbotron for a primary marketing message or call to action
|
||||
<div class="jumbotron">
|
||||
<h1>Blog</h1>
|
||||
<p><span id="majuscule">Hello {{ session['username'] }} ! </span>Bienvenue sur ce blog communautaire. Les articles de tous les auteurs du site sont actuellement disponibles sur cette page. Une page personnelle vous est fournie à l'adresse : <a href="/blog/{{ session['username'] }}">Page perso</a></p>
|
||||
<p><a href="http://flask.pocoo.org/" class="btn btn-primary btn-lg" role="button">En savoir plus »</a></p>
|
||||
</div>-->
|
||||
<div class="row">
|
||||
<div class="col-sm-1"></div>
|
||||
<div class="col-sm-10">
|
||||
<br />
|
||||
<div class="well"> Hello <span id="majuscule">{{ session['username'] }} ! </span>Bienvenue sur ce blog communautaire. Il vous est possible de poster des articles en tout genre sur cette page. Vous disposez pour cela d'un éditeur de type Markdown. Une page <a href="/blog/{{ session['username'] }}"><span class="glyphicon glyphicon-star" aria-hidden="true"></span> Page publique</a> et une <a href="/privateblog/"><span class="glyphicon glyphicon-star" aria-hidden="true"></span> Page privée</a> vous sont attribuées.<br>Ayez bien conscience que ce site est une expérience est qu'il est indispensable d'avoir une sauvegarde de tous vos articles. Nous ne pourrons, en aucun cas, être tenu responsable de la perte de vos données. Merci de votre compréhension.</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
|
||||
<form method="POST" action="{{ url_for('blog.racine_blog') }}" id="postform">
|
||||
<!--<input type="text" name="category" id="category" placeholder="Catégorie" class="form-control"><br />-->
|
||||
<input type="text" name="title" id="title" placeholder="Titre" class="form-control"><br />
|
||||
<textarea class="form-control" form="postform" name="content" id="content" placeholder="Contenu" style="height:30vw;"></textarea><br />
|
||||
<div class="row">
|
||||
<div class="col-sm-4"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="prive" checked>Privé</div>
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="public">Public<br></div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
<br />
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit">Publier</button>
|
||||
</form>
|
||||
|
||||
<br>
|
||||
{% for post in posts %}
|
||||
<div class="well">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-2">
|
||||
<img src="/static/usersprofil/{{ post.avatar }}" class="img-rounded" alt=""/><br><br>
|
||||
<p>{{ post.nom }}<br>{{ post.prenom }}<br>{{ post.age }} ans<br>{{ post.profession }}<br></p>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-9">
|
||||
<div class="well">
|
||||
<h6>{{ post.time }}</h6>
|
||||
<h2>{{ post.title }}</h2>
|
||||
|
||||
{{ post.content|safe }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-1">
|
||||
{% if post.author == session['username'] %}
|
||||
{% if post.status == 'prive' %}
|
||||
<h4><span class="label label-danger">Privé</span></h4>
|
||||
{% else %}
|
||||
<h4><span class="label label-success">Public</span></h4>
|
||||
{% endif %}
|
||||
<br /><br>
|
||||
<a href="{{ url_for('blog.edit', post=post.title) }}"><button type="button" class="btn btn-sm btn-primary"><span class="glyphicon glyphicon-edit" aria-hidden="true"></span></button></a><br /><br>
|
||||
<a href="{{ url_for('blog.delete', post=post.title) }}"><button type="button" class="btn btn-sm btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button></a><br /><br>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
71
templates/board.html
Normal file
71
templates/board.html
Normal file
@@ -0,0 +1,71 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
|
||||
{% block main %}
|
||||
|
||||
|
||||
|
||||
<div class="row">
|
||||
{% for post in posts %}
|
||||
|
||||
|
||||
<div class="well col-sm-5 post-it" style="margin: 30px;">
|
||||
|
||||
<div class="col-sm-1">
|
||||
{% if post.avatar != None %}
|
||||
<img src="/profil/{{ post.author }}/{{ post.avatar }}" class="img-rounded" alt="" width="50" height="50"/>
|
||||
{% endif %}
|
||||
|
||||
<br><br>
|
||||
<p> {{ post.author }} </p>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-8 content" style="margin: 10px;">
|
||||
<h6>{{ post.time }}</h6>
|
||||
<h1>{{ post.title }}</h1>
|
||||
{{ post.content[0:100]|safe }} ...
|
||||
<br/>
|
||||
<br/>
|
||||
<button type="button" class="btn btn-default btn-primary" data-toggle="modal" data-target="#{{ post.id_postit }}"> Déplier </button>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-1">
|
||||
{% if post.author == session['username'] %}
|
||||
{% if post.status == 'prive' %}
|
||||
<h4><span class="label label-danger">Privé</span></h4>
|
||||
{% else %}
|
||||
<h4><span class="label label-success">Public</span></h4>
|
||||
{% endif %}
|
||||
<br /><br>
|
||||
<a href="{{ url_for('post-it.edit', title=post.title, time=post.time) }}"><button type="button" class="btn btn-sm btn-primary"><span class="glyphicon glyphicon-edit" aria-hidden="true"></span></button></a><br /><br>
|
||||
<a href="{{ url_for('post-it.delete', title=post.title, time=post.time ) }}"><button type="button" class="btn btn-sm btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button></a><br /><br>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="{{ post.id_postit }}" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
|
||||
<!-- Modal content-->
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">{{ post.title }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{ post.content|safe }}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
34
templates/delete_account.html
Normal file
34
templates/delete_account.html
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="page-header">
|
||||
<h1> Supprimer mon compte </h1>
|
||||
<p class="text-center"> Vous voulez supprimer votre compte pas de problèmes toutes vos données seront effacées du serveur et après un periodes de {{ time_backup }} vos données seront complètements supprimées des sauvegardes, il n'y aura aucun retour en arrière possible.
|
||||
</p>
|
||||
<h3> Entrez votre mot de passe pour confirmer la suppression de votre compte </h3>
|
||||
</div>
|
||||
<form method="POST" action="{{ url_for('loginlogout.delete_account') }}">
|
||||
<input type="password" name="passwd" id="passwd" placeholder="Mot de passe" class="form-control"><br />
|
||||
<br>
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit"> Je supprime mon compte </button>
|
||||
</form>
|
||||
<div>
|
||||
</div>
|
||||
|
||||
{# on affiche les messages d'erreur puis les messages de succes #}
|
||||
{% for categorie in ['error', 'succes'] %}
|
||||
{% with msgs = get_flashed_messages(category_filter=[categorie]) %}
|
||||
{% if msgs %}
|
||||
|
||||
<div class="flashed {{ categorie }}">
|
||||
{% for m in msgs %}
|
||||
<p>{{ m|safe }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% endblock %}
|
||||
40
templates/edit_article.html
Normal file
40
templates/edit_article.html
Normal file
@@ -0,0 +1,40 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-1"></div>
|
||||
<div class="col-sm-10">
|
||||
<div class="well">Vous pouvez modifier votre article. Actuellement seule la date de première édition sera publiée. Prochainement : intégration de la date de mise à jour dans la base de donnée.</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2> {{ oldpost[0] }}</h2><br />
|
||||
<form action="" method="POST" id="postform" style="height: 15vw;">
|
||||
|
||||
<input type="text" name="subtitle" id="subtitle" placeholder="Titre" class="form-control" value="{{ oldpost[1] }}"><br />
|
||||
<textarea id="editeurMarkdown" class="form-control" form="postform" name="content" id="content" placeholder="Contenu" >{{ content }}</textarea><br />
|
||||
<h3> Visibilité </h3>
|
||||
<div class="row">
|
||||
{% if oldpost[2] == 'public' %}
|
||||
<div class="col-sm-4"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="prive"> <br/>Privé </div>
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="public" checked> <br/> Publique </div>
|
||||
<div class="col-sm-4"></div>
|
||||
{% else %}
|
||||
<div class="col-sm-4"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="Privé" checked> <br/> Privé </div>
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="public"> <br/> Publique </div>
|
||||
<div class="col-sm-4"></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<br />
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit"> Mettre à jour </button>
|
||||
</form>
|
||||
<br />
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
</div>
|
||||
@@ -1,52 +1,10 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
{% block navbar %}
|
||||
<!-- Fixed navbar -->
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<!--<a class="navbar-brand" href="/blog/">Blog</a>-->
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="/blog"><span class="glyphicon glyphicon-globe" aria-hidden="true"></span> Blog</a></li>
|
||||
<li><a href="/filesupload/"><span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span> Upload</a></li>
|
||||
<li><a href="/view/"><span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span> Fichiers</a></li>
|
||||
<li class="active"><a href="/gallery/"><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> Gallerie</a></li>
|
||||
<li><a href="/logs/"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span> Logs</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-home" aria-hidden="true"></span> <span id="majuscule">{{ session['username'] }} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="/profil/{{ session['username'] }}"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Profil</a></li>
|
||||
<li><a href="/parametres/"><span class="glyphicon glyphicon-cog" aria-hidden="true"></span> Paramètres</a></li>
|
||||
<li class="divider"></li>
|
||||
<!--<li class="dropdown-header">Nav header</li>-->
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Déconnexion</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Exit</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="container theme-showcase" role="main">
|
||||
|
||||
<!--<div class="page-header">
|
||||
<h1>Images uploadées :</h1>
|
||||
</div>-->
|
||||
|
||||
<br />
|
||||
|
||||
{% if fichiers %}
|
||||
|
||||
27
templates/index_blog.html
Normal file
27
templates/index_blog.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title> Blog de {{ user }} </title>
|
||||
<link rel="stylesheet" href="/static/blog.css" type="text/css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="articles">
|
||||
{% for post in posts %}
|
||||
|
||||
<h2 class="index"><a href="/blog/{{user}}/{{post.title}}"> {{ post.title }}</a></h2>
|
||||
<small>
|
||||
<time datetime="{{ post.time }}">
|
||||
Publié le {{ post.time }}
|
||||
</time>
|
||||
</small>
|
||||
<div class="slug">
|
||||
<p> {{ post.subtitle }} </p>
|
||||
<p class="readmore"> <a style="margin-right:2rem;" href="/blog/{{user}}/{{post.title}}"> Lire la suite... </a></p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -10,11 +10,14 @@
|
||||
|
||||
<div class="masthead clearfix">
|
||||
<div class="inner">
|
||||
<h3 class="masthead-brand">OpenBlogStock</h3>
|
||||
<h3 class="masthead-brand">Pywallter</h3>
|
||||
<ul class="nav masthead-nav">
|
||||
<li><a href="/filesupload/">Login</a></li>
|
||||
<li class="active"><a href="/inscription/">Inscription</a></li>
|
||||
<li><a href="#">Contact</a></li>
|
||||
<li><a href="/login/">Login</a></li>
|
||||
|
||||
{% if signin_enable %}
|
||||
<li class="active"><a href="/inscription/">Inscription</a></li>
|
||||
{% endif %}
|
||||
<li><a href="#">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -22,35 +25,35 @@
|
||||
<div class="inner cover">
|
||||
<h1 class="cover-heading">Inscription</h1>
|
||||
<br>
|
||||
<p class="lead">
|
||||
<form method="POST" action="{{ url_for('inscription.signin') }}">
|
||||
<input type="text" name="user" id="user" placeholder="Pseudo" class="form-control"><br />
|
||||
<input type="mail" name="mail" id="mail" placeholder="Adresse mail" class="form-control"><br />
|
||||
<input type="password" name="passwd" id="passwd" placeholder="Mot de passe" class="form-control"><br />
|
||||
<input type="password" name="passwdconfirm" id="passwdconfirm" placeholder="Confirmation du mot de passe" class="form-control"><br />
|
||||
<br>
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit">Envoyer</button>
|
||||
</form>
|
||||
</p>
|
||||
{% for i in users %}
|
||||
{% include '_flash_msgs.html' %}
|
||||
|
||||
{% if signin_enable %}
|
||||
<form method="POST" class="form-horizontal" action="{{ url_inscription }}">
|
||||
<h4> Choisissez votre nom d'utilisateur pour vous connecter sur le portail pywallter </h4>
|
||||
<input type="text" name="user" id="user" placeholder="Pseudo" class="form-control"><br />
|
||||
{% if MAIL_SERVER or XMPP_SERVER %}
|
||||
|
||||
<p>
|
||||
Votre nom d'utilisateur vous servira à vous connecter à votre compte Mail et de messagerie instantanné (XMPP)
|
||||
Par exemple vous souhaitez l'adresse toto@{{hostname}}; vous entrez le nom d'utilisateur toto :)
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<input type="password" name="passwd" id="passwd" placeholder="Mot de passe" class="form-control"><br />
|
||||
<input type="password" name="passwdconfirm" id="passwdconfirm" placeholder="Confirmation du mot de passe" class="form-control"><br />
|
||||
<br>
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit">Créer mon compte</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<p class="lead">
|
||||
Désolé les inscriptions ne sont pas activés sur le serveur
|
||||
</p>
|
||||
{%endif%}
|
||||
{% for i in users %}
|
||||
<p>{{i}}</p>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="msginfo">
|
||||
{# On affiche les messages d'erreur puis les messages de succés #}
|
||||
{% for categorie in ['error', 'succes'] %}
|
||||
{% with msgs = get_flashed_messages(category_filter=[categorie]) %}
|
||||
{% if msgs %}
|
||||
<div class="flashed {{ categorie }}">
|
||||
{% for m in msgs %}
|
||||
<p>{{ m|safe }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="mastfoot">
|
||||
<div class="inner">
|
||||
|
||||
53
templates/invitation.html
Normal file
53
templates/invitation.html
Normal file
@@ -0,0 +1,53 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="well">
|
||||
Si vous voulez vous pouvez inviter une personne à se crée un compte sur ce serveur
|
||||
pour cela vous devez crée un lien d'inscription. Ce lien restera valable tant
|
||||
que la personne ne s'est pas inscrite ou tant que vous ne créez pas un autre lien.
|
||||
Les invitations se font une par une et sont limité à 20 personnes pour ne pas surcharger notre petit serveur :).
|
||||
Une fois que la personne s'est incrite votre nombre d'invitations sera mis à jour
|
||||
</div>
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Création du lien d'inscription</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if token %}
|
||||
<h3> Votre lien d'inscription en cours: </h3>
|
||||
|
||||
<a href="{{ url_invitation }}">
|
||||
{{ url_invitation }}
|
||||
</a>
|
||||
{% else %}
|
||||
<h3> Pas d'invitation en attente </h3>
|
||||
{% endif %}
|
||||
<p> Il vous reste : {{ nb_invitation }} invitations à envoyer </p>
|
||||
<a href="/gen_token/">
|
||||
<button type="submit" id="tada" class="btn btn btn-success"> Créer un nouveau lien </button></a>
|
||||
|
||||
|
||||
<div class="msginfo">
|
||||
{# on affiche les messages d'erreur puis les messages de succes #}
|
||||
{% for categorie in ['error', 'succes'] %}
|
||||
{% with msgs = get_flashed_messages(category_filter=[categorie]) %}
|
||||
{% if msgs %}
|
||||
<div class="flashed {{ categorie }}">
|
||||
{% for m in msgs %}
|
||||
<p>{{ m|safe }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
44
templates/list_articles.html
Normal file
44
templates/list_articles.html
Normal file
@@ -0,0 +1,44 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
|
||||
{% block main %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2> Vos articles de blog </h2>
|
||||
<table class="table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Titre <span class="badge">{{ nb_articles }}</span></th>
|
||||
<th> Créé le : </th>
|
||||
<th> Dernière modification </th>
|
||||
<th> status </th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody style="text-align: left;">
|
||||
|
||||
{% for article in list_posts %}
|
||||
<tr>
|
||||
<td>{{ article.title }}</td>
|
||||
<td>{{ article.time }}</td>
|
||||
<td>{{ article.last_updated }} </td>
|
||||
<td>{{ article.status }}</td>
|
||||
<td><a href="{{ url_for('blog.edit', title=article.title) }}"><button type="button" class="btn btn-sm btn-info"> Editer </button></a></td>
|
||||
<td><a href="{{ url_for('blog.delete', title=article.title) }}"><button type="button" class="btn btn-sm btn-danger">Supprimer</button></a></td>
|
||||
<td><a href="{{ url_for('blog.edit', title=article.title) }}"><button type="button" class="btn btn-sm btn-success"> Publier </button></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,63 +0,0 @@
|
||||
{% extends 'accueil.html' %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="site-wrapper">
|
||||
|
||||
<div class="site-wrapper-inner">
|
||||
|
||||
<div class="cover-container">
|
||||
|
||||
<div class="masthead clearfix">
|
||||
<div class="inner">
|
||||
<h3 class="masthead-brand">OpenBlogSotck</h3>
|
||||
<ul class="nav masthead-nav">
|
||||
<li class="active"><a href="/uploadfiles/">Login</a></li>
|
||||
<li><a href="/inscription/">Inscription</a></li>
|
||||
<li><a href="#">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner cover">
|
||||
<h1 class="cover-heading">Restez libres</h1>
|
||||
<p class="lead">Bienvenue sur Olala, hébergeur de fichier libre basé sur Flask et hébergé sur une simple Orange Pi. Bientôt disponible, gallerie d'images, blog et d'autres. Site en construction.</p>
|
||||
<br>
|
||||
<p class="lead">
|
||||
<form method="POST" action="{{ url_for('loginlogout.login') }}">
|
||||
<input type="text" name="user" id="user" placeholder="Utilisateur" class="form-control"><br />
|
||||
<input type="password" name="passwd" id="passwd" placeholder="Mot de passe" class="form-control"><br />
|
||||
<br>
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit">Login</button>
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="msginfo">
|
||||
{# On affiche les messages d'erreur puis les messages de succés #}
|
||||
{% for categorie in ['error', 'succes'] %}
|
||||
{% with msgs = get_flashed_messages(category_filter=[categorie]) %}
|
||||
{% if msgs %}
|
||||
<div class="flashed {{ categorie }}">
|
||||
{% for m in msgs %}
|
||||
<p>{{ m|safe }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="mastfoot">
|
||||
<div class="inner">
|
||||
<p>Cover template for <a href="http://getbootstrap.com">Bootstrap</a>, by <a href="https://twitter.com/mdo">@mdo</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,49 +1,11 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
{% block navbar %}
|
||||
<!-- Fixed navbar -->
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<!--<a class="navbar-brand" href="/blog/">Blog</a>-->
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="/blog"><span class="glyphicon glyphicon-globe" aria-hidden="true"></span> Blog</a></li>
|
||||
<li><a href="/filesupload/"><span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span> Upload</a></li>
|
||||
<li><a href="/view/"><span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span> Fichiers</a></li>
|
||||
<li><a href="/gallery/"><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> Gallerie</a></li>
|
||||
<li class="active"><a href="/logs/"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span> Logs</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-home" aria-hidden="true"></span> <span id="majuscule">{{ session['username'] }} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="/profil/{{ session['username'] }}"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Profil</a></li>
|
||||
<li><a href="/parametres/"><span class="glyphicon glyphicon-cog" aria-hidden="true"></span> Paramètres</a></li>
|
||||
<li class="divider"></li>
|
||||
<!--<li class="dropdown-header">Nav header</li>-->
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Déconnexion</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Exit</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<!--<div class="page-header">
|
||||
<div class="page-header">
|
||||
<p class="text-center"><h1>Logs</h1></p>
|
||||
</div>-->
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
|
||||
53
templates/lost_password.html
Normal file
53
templates/lost_password.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
{% include '_head.html' %}
|
||||
<body>
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="site-wrapper">
|
||||
|
||||
<div class="site-wrapper-inner">
|
||||
|
||||
<div class="cover-container">
|
||||
|
||||
<div class="masthead clearfix">
|
||||
<div class="inner">
|
||||
<h3 class="masthead-brand">Pywallter</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner cover">
|
||||
<h1 class="cover-heading"> J'ai perdu mon mot de passe </h1>
|
||||
<p class="lead">
|
||||
Hé oui ca arrive à tout le monde... Il existe des gestionnaire des mots de passe pour éviter que t'arrives trop souvent. <a href="https://keepassxc.org/">Tiens en voilà un par exemple</a> et ca existe <a href="https://apps.apple.com/fr/app/keepass-password-manager/id6461546929?platform=iphone"> pour iphone </a> et <a href="https://www.keepassdx.com/"> pour android </a>
|
||||
<br/>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
{% include '_flash_msgs.html' %}
|
||||
<p class="lead">
|
||||
<form method="POST" action="{{ url_for('loginlogout.lost_password') }}">
|
||||
<input type="text" name="user" id="user" placeholder="Utilisateur" class="form-control" width="200px"><br />
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit"> Nom d'utilisateur </button>
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% include '_footer.html' %}
|
||||
|
||||
{% include '_js.html' %}
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
49
templates/mailbox.html
Normal file
49
templates/mailbox.html
Normal file
@@ -0,0 +1,49 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<!--<div class="page-header">
|
||||
<h1>Profil</h1>
|
||||
</div>-->
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-3"></div>
|
||||
<div class="col-sm-6">
|
||||
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"> Changer mon mot de passe </h3>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<form method="POST" action="" enctype="multipart/form-data">
|
||||
|
||||
<p> Votre Adresse e-mail sur ce serveur : {{ username }} </p>
|
||||
|
||||
<label> Mot de passe </label>
|
||||
<input type="password" name="password" id="password" placeholder="Votre mot de passe" class="form-control"><br />
|
||||
<input type="password" name="passwd_confirm" id="passwd_confirm" placeholder="Confirmation du mot de passe" class="form-control"><br />
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit">Envoyer</button>
|
||||
</form>
|
||||
|
||||
{# on affiche les messages d'erreur puis les messages de succes #}
|
||||
{% for categorie in ['error', 'succes'] %}
|
||||
{% with msgs = get_flashed_messages(category_filter=[categorie]) %}
|
||||
{% if msgs %}
|
||||
<div class="flashed {{ categorie }}">
|
||||
{% for m in msgs %}
|
||||
<p>{{ m|safe }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
89
templates/myalias.html
Normal file
89
templates/myalias.html
Normal file
@@ -0,0 +1,89 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
|
||||
|
||||
{% block main %}
|
||||
|
||||
|
||||
<div class="row">
|
||||
{% if MAIL_SERVER %}
|
||||
<div class="col-md-12">
|
||||
|
||||
<h3> A quoi ca sert les alias ? </h3>
|
||||
<p> Les alias c'est utile quand vous ne voulez pas donner votre vrai adresse e-mail.
|
||||
Vous pouvez creer une adresse que vous pouvez supprimer rapidemment, cela permet personnaliser une adresse pour un destinataire
|
||||
si vous n'avez pas confiance en lui ou de trier plus facilement les e-mails venant de ce destinataire.
|
||||
</p>
|
||||
<p> Vous n'avez pas besoin de configurer un autre compte mail sur vos applications, tous les e-mails
|
||||
arriveront sur votre adresse e-mail principale déjà configuré
|
||||
</p>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Mes Alias <span class="badge">{{ i }}</span></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if aliases %}
|
||||
{% for alias in aliases %}
|
||||
<tr>
|
||||
<td>{{ alias }}</td>
|
||||
<td><a href="{{ url_for('profil.remove_alias', aliasrm=alias) }}"><button type="button" class="btn btn-sm btn-danger">Supprimer</button></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"> Mes identités </h3>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="panel-body">
|
||||
<form method="POST" action="" enctype="multipart/form-data">
|
||||
|
||||
<p> Votre Adresse e-mail sur ce serveur : {{ email }} </p>
|
||||
|
||||
<label> Nouvelle identité </label>
|
||||
<br/>
|
||||
<div class="col-sm-7">
|
||||
<input type="text" name="alias" id="alias" placeholder="Nouvel_identité" class="form-control"><br />
|
||||
</div>
|
||||
<h4>@{{ hostname }}</h4>
|
||||
<br/>
|
||||
<br/>
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit">Ajouter</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"> Mes identitées </h3>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="panel-body">
|
||||
<h2> Le serveur de mail n'est pas activé cette fonctionnalité est désactivé <h2>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{# on affiche les messages d'erreur puis les messages de succes #}
|
||||
{% for categorie in ['error', 'succes'] %}
|
||||
{% with msgs = get_flashed_messages(category_filter=[categorie]) %}
|
||||
{% if msgs %}
|
||||
|
||||
{% for m in msgs %}
|
||||
<p>{{ m|safe }}</p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
40
templates/new_article_blog.html
Normal file
40
templates/new_article_blog.html
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="col-sm-1"></div>
|
||||
<div class="col-sm-10">
|
||||
<br />
|
||||
<div class="well"> Hello <span id="majuscule">{{ session['username'] }} ! </span>
|
||||
Bienvenue sur la création d'un nouvel article de blog. Vous pouvez créer ou importer un article de blog ici,
|
||||
vous avez le choix de le rendre publique dès sa création en cochant publique ou le laisser en privé
|
||||
si vous souhaitez le modifier plus-tard avant sa publication.
|
||||
Par défaut il est laissé en privé pour éviter les publications
|
||||
accidentelles.
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<form method="POST" action="{{ url_for('blog.new_article') }}" id="postform">
|
||||
<!--<input type="text" name="category" id="category" placeholder="Catégorie" class="form-control"><br />-->
|
||||
<input type="text" name="title" id="title" placeholder="Titre" class="form-control"><br />
|
||||
<input type="text" name="subtitle" id="subtitle" placeholder="Sous-titre" class="form-control"><br />
|
||||
<hr>
|
||||
<textarea id="editeurMarkdown" class="form-control" form="postform" name="content" id="content" placeholder="Contenu" style="height:10vw;"></textarea><br />
|
||||
<div class="row">
|
||||
<div class="col-sm-4"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="private" checked>Privé</div>
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="public">Public<br></div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
<br />
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit"> Créer l'article </button>
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,44 +1,5 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
{% block navbar %}
|
||||
<!-- Fixed navbar -->
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<!--<li class="active"><a href="/blog/">Blog</a></li>-->
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="/blog"><span class="glyphicon glyphicon-globe" aria-hidden="true"></span> Blog</a></li>
|
||||
<li><a href="/upload/"><span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span> Upload</a></li>
|
||||
<li><a href="/view/"><span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span> Fichiers</a></li>
|
||||
<li><a href="/gallery/"><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> Gallerie</a></li>
|
||||
<li><a href="/logs/"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span> Logs</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-home" aria-hidden="true"></span> {{ session['username'] }} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="/profil/{{ session['username'] }}"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Profil</a></li>
|
||||
<li><a href="/parametres/"><span class="glyphicon glyphicon-cog" aria-hidden="true"></span> Paramètres</a></li>
|
||||
<li class="divider"></li>
|
||||
<!--<li class="dropdown-header">Nav header</li>-->
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Déconnexion</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Exit</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="page-header">
|
||||
|
||||
@@ -1,77 +1,37 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
{% block navbar %}
|
||||
<!-- Fixed navbar -->
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<!--<li class="active"><a href="/blog/">Blog</a></li>-->
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="active"><a href="/blog"><span class="glyphicon glyphicon-globe" aria-hidden="true"></span> Blog</a></li>
|
||||
<li><a href="/upload/"><span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span> Upload</a></li>
|
||||
<li><a href="/view/"><span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span> Fichiers</a></li>
|
||||
<li><a href="/gallery/"><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> Gallerie</a></li>
|
||||
<li><a href="/logs/"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span> Logs</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-home" aria-hidden="true"></span> <span id="majuscule">{{ session['username'] }} </span><span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="/profil/{{ session['username'] }}"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Profil</a></li>
|
||||
<li><a href="/parametres/"><span class="glyphicon glyphicon-cog" aria-hidden="true"></span> Paramètres</a></li>
|
||||
<li class="divider"></li>
|
||||
<!--<li class="dropdown-header">Nav header</li>-->
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Déconnexion</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Exit</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<!-- Main jumbotron for a primary marketing message or call to action
|
||||
<div class="jumbotron">
|
||||
<h1>Blog</h1>
|
||||
<p><span id="majuscule">Hello {{ session['username'] }} ! </span>Bienvenue sur ce blog communautaire. Les articles de tous les auteurs du site sont actuellement disponibles sur cette page. Une page personnelle vous est fournie à l'adresse : <a href="/blog/{{ session['username'] }}">Page perso</a></p>
|
||||
<p><a href="http://flask.pocoo.org/" class="btn btn-primary btn-lg" role="button">En savoir plus »</a></p>
|
||||
</div>-->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-1"></div>
|
||||
<div class="col-sm-10">
|
||||
<br />
|
||||
<div class="well">Vous pouvez modifier votre article. Actuellement seule la date de première édition sera publiée. Prochainement : intégration des edit'time dans la base de donnée.</div>
|
||||
<div class="well">Vous pouvez modifier votre article. Actuellement seule la date de première édition sera publiée. Prochainement : intégration de la date de mise à jour dans la base de donnée.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="lead">
|
||||
<form action="" method="POST" id="postform">
|
||||
<form action="" method="POST" id="postform" style="height: 15vw;">
|
||||
<input type="text" name="title" id="title" placeholder="Titre" class="form-control" value="{{ oldpost[0] }}"><br />
|
||||
<textarea class="form-control" form="postform" name="content" id="content" placeholder="Contenu" style="height: 50%;">{{ oldpost[1] }}</textarea><br />
|
||||
<div class="row">
|
||||
<div class="col-sm-4"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="prive" checked>Privé</div>
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="public">Public<br></div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
<textarea id="editeurMarkdown" class="form-control" form="postform" name="content" id="content" placeholder="Contenu" >{{ oldpost[1] }}</textarea><br />
|
||||
<h3> Visibilité </h3>
|
||||
<div class="row">
|
||||
{% if oldpost[2] == 'public' %}
|
||||
<div class="col-sm-4"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="prive"> <br/>Privé </div>
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="public" checked> <br/> Publique </div>
|
||||
<div class="col-sm-4"></div>
|
||||
{% else %}
|
||||
<div class="col-sm-4"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="prive" checked> <br/> Privé </div>
|
||||
<div class="col-sm-2"></div>
|
||||
<div class="col-sm-1"><input type="radio" name="status" value="public"> <br/> Public </div>
|
||||
<div class="col-sm-4"></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<br />
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit">Publier</button>
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit"> Mettre à jour </button>
|
||||
</form>
|
||||
</p>
|
||||
<br>
|
||||
<br />
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="jumbotron">
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<p id="majuscule" class="text-center"><h3>Articles privés de <span id="majuscule">{{ UTILISATEUR }}</span></h3>
|
||||
<br />
|
||||
<h5>Articles visibles par vous seul ...</h5></p>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<img src="/static/usersprofil/{{ usersinfos[0] }}" class="img-rounded" alt=""/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
{% for post in posts %}
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<div class="well">
|
||||
<div class="row">
|
||||
<div class="col-sm-10">
|
||||
<div class="well">
|
||||
<h6>{{ post.time }}</h6>
|
||||
<h2>{{ post.title }}</h2>
|
||||
{{ post.content|safe }}
|
||||
|
||||
<h6>Auteur : {{ post.author }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
{% if post.author == session['username'] %}
|
||||
{% if post.status == 'prive' %}
|
||||
<h4><span class="label label-danger">Privé</span></h4>
|
||||
{% else %}
|
||||
<h4><span class="label label-success">Public</span></h4>
|
||||
{% endif %}
|
||||
<br /><br>
|
||||
<a href="{{ url_for('blog.edit', post=post.title) }}"><button type="button" class="btn btn-sm btn-primary"><span class="glyphicon glyphicon-edit" aria-hidden="true"></span></button></a><br /><br>
|
||||
<a href="{{ url_for('blog.delete', post=post.title) }}"><button type="button" class="btn btn-sm btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
</div>
|
||||
@@ -1,43 +1,5 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
{% block navbar %}
|
||||
<!-- Fixed navbar -->
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<!--<li class="active"><a href="/blog/">Blog</a></li>-->
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="/blog"><span class="glyphicon glyphicon-globe" aria-hidden="true"></span> Blog</a></li>
|
||||
<li><a href="/filesupload/"><span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span> Upload</a></li>
|
||||
<li><a href="/view/"><span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span> Fichiers</a></li>
|
||||
<li><a href="/gallery/"><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> Gallerie</a></li>
|
||||
<li><a href="/logs/"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span> Logs</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-home" aria-hidden="true"></span> <span id="majuscule">{{ session['username'] }} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="/profil/{{ session['username'] }}"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Profil</a></li>
|
||||
<li><a href="/parametres/"><span class="glyphicon glyphicon-cog" aria-hidden="true"></span> Paramètres</a></li>
|
||||
<li class="divider"></li>
|
||||
<!--<li class="dropdown-header">Nav header</li>-->
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Déconnexion</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Exit</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
@@ -46,57 +8,48 @@
|
||||
</div>-->
|
||||
|
||||
<div class="row">
|
||||
<!-- <div class="col-sm-6">
|
||||
<h3> Bienvenue </h3>
|
||||
<p> Si vous êtes sur cette page, c'est que vous diposez d'un compte sur ce serveur.
|
||||
Du coup, vous avez une adresse e-mail et une adresse XMPP que vous pouvez utiliser
|
||||
avec un client mail et avec un client XMPP (Bien évidemment)
|
||||
</p>
|
||||
|
||||
<p> Voici un exemple de <a href="https://www.thunderbird.net/fr/"> client mail </a>
|
||||
et <a href="https://gajim.org/">client XMPP </a> pour un ordinateur </p>
|
||||
|
||||
<p> un exemple de <a href="https://k9mail.app/"> client mail </a> et <a href="https://play.google.com/store/apps/details?id=org.snikket.android&hl=ln&gl=US">client XMPP</a>
|
||||
pour un téléphone sous Android </p>
|
||||
|
||||
<p> et un un exemple de<a href="https://support.apple.com/fr-fr/mail"> client mail</a> et <a href="https://itunes.apple.com/us/app/tigase-messenger/id1153516838"> client XMPP </a>sous iOS pour un iphone ou un Ipad </p>
|
||||
|
||||
<p> Ton profil sert aux autres membres à te reconnaitre si tu met un post-it sur le <a href="/post-it/"> tableau des post-its </a> aucun champs n'est obligatoire,
|
||||
tu mets simplement les informations dont tu as envie </p>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="col-sm-3"></div>
|
||||
<div class="col-sm-6">
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Image de profil</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<form method="post" action="" enctype="multipart/form-data">
|
||||
<label for="fic">Choisissez une image de profil :</label><input type="file" name="fic" id="fic"/>
|
||||
<br>
|
||||
<button type="submit" id="tada" class="btn btn btn-success">Envoyer</button>
|
||||
</form>
|
||||
|
||||
<div>
|
||||
<img src="/static/usersprofil/{{ imageprofil[0] }}" class="img-rounded" alt=""/>
|
||||
</div>
|
||||
|
||||
<div class="msginfo">
|
||||
{# on affiche les messages d'erreur puis les messages de succes #}
|
||||
{% for categorie in ['error', 'succes'] %}
|
||||
{% with msgs = get_flashed_messages(category_filter=[categorie]) %}
|
||||
{% if msgs %}
|
||||
<div class="flashed {{ categorie }}">
|
||||
{% for m in msgs %}
|
||||
<p>{{ m|safe }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
<div class="col-sm-3"></div>
|
||||
<div class="col-sm-6">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Informations personnelles</h3>
|
||||
<h3 class="panel-title">Mon profil</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form method="POST" action="" enctype="multipart/form-data">
|
||||
<div id="fic"><input type="file" name="fic" id="fic"/><br>
|
||||
<img id="fic" src="/static/usersprofil/{{ imageprofil[0] }}" class="img-rounded" alt=""/>
|
||||
</div>
|
||||
<br>
|
||||
<input type="text" name="nom" id="nom" placeholder="Nom" class="form-control"><br />
|
||||
<input type="text" name="prenom" id="prenom" placeholder="Prénom" class="form-control"><br />
|
||||
<input type="text" name="age" id="age" placeholder="Âge" class="form-control"><br />
|
||||
<input type="text" name="profession" id="profession" placeholder="Profession" class="form-control"><br />
|
||||
<div id="fic">
|
||||
<label> Photo de profil </label>
|
||||
<input type="file" name="fic" id="fic"/><br>
|
||||
<img id="fic" src="/profil/{{ username }}/{{ profil['avatar'] }}" class="img-rounded" alt=""/>
|
||||
</div>
|
||||
<br>
|
||||
<label>Nom </label>
|
||||
<input type="text" name="nom" id="nom" value="{% if profil['nom'] != None %}{{ profil['nom'] }}{%endif%}" class="form-control"><br />
|
||||
<label>Prenom </label>
|
||||
<input type="text" name="prenom" id="prenom" value="{% if profil['nom'] != None %}{{ profil['prenom'] }}{%endif%}" class="form-control"><br />
|
||||
<label> Age </label>
|
||||
<input type="text" name="age" value="{% if profil['age'] != None %}{{ profil['age'] }}{%endif%}" class="form-control"><br />
|
||||
<label> Mail de secours </label>
|
||||
<input type="text" name="mail_rescue" id="mail_rescue" value="{% if profil['mail_rescue'] != None %}{{ profil['mail_rescue'] }}{%endif%}" class="form-control"><br />
|
||||
<button id="tada" class="btn btn-default btn-primary" type="submit">Envoyer</button>
|
||||
</form>
|
||||
{# on affiche les messages d'erreur puis les messages de succes #}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="jumbotron">
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<p id="majuscule" class="text-center"><h3>Blog de <span id="majuscule">{{ username }}</span></h3></p>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<img src="/static/usersprofil/{{ usersinfos[0] }}" class="img-rounded" alt=""/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
{% for post in posts %}
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<div class="well">
|
||||
<div class="row">
|
||||
<div class="col-sm-10">
|
||||
<h6>{{ post.time }}</h6>
|
||||
<h2>{{ post.title }}</h2>
|
||||
{{ post.content|safe }}
|
||||
|
||||
<br><h6>Auteur : {{ post.author }}</h6>
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
{% if post.author == session['username'] %}
|
||||
{% if post.status == 'prive' %}
|
||||
<h4><span class="label label-danger">Privé</span></h4>
|
||||
{% else %}
|
||||
<h4><span class="label label-success">Public</span></h4>
|
||||
{% endif %}
|
||||
<br /><br>
|
||||
<a href="{{ url_for('blog.edit', post=post.title) }}"><button type="button" class="btn btn-sm btn-primary"><span class="glyphicon glyphicon-edit" aria-hidden="true"></span></button></a><br /><br>
|
||||
<a href="{{ url_for('blog.delete', post=post.title) }}"><button type="button" class="btn btn-sm btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button></a><br /><br>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
</div>
|
||||
30
templates/rmalias.html
Normal file
30
templates/rmalias.html
Normal file
@@ -0,0 +1,30 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
az
|
||||
|
||||
{% block main %}
|
||||
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Alias <span class="badge">{{ i }}</span></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if aliases %}
|
||||
{% for alias in aliases %}
|
||||
<tr>
|
||||
<td>{{ alias }}</td>
|
||||
<td><a href="{{ url_for('rmalias', alias=alias) }}"><button type="button" class="btn btn-sm btn-danger">Supprimer</button></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,74 +1,69 @@
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
{% block navbar %}
|
||||
<!-- Fixed navbar -->
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<!--<a class="navbar-brand" href="/blog/">Blog</a>-->
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="/blog"><span class="glyphicon glyphicon-globe" aria-hidden="true"></span> Blog</a></li>
|
||||
<li><a href="/filesupload/"><span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span> Upload</a></li>
|
||||
<li class="active"><a href="/view/"><span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span> Fichiers</a></li>
|
||||
<li><a href="/gallery/"><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> Gallerie</a></li>
|
||||
<li><a href="/logs/"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span> Logs</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-home" aria-hidden="true"></span> <span id="majuscule">{{ session['username'] }} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="/profil/{{ session['username'] }}"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Profil</a></li>
|
||||
<li><a href="/parametres/"><span class="glyphicon glyphicon-cog" aria-hidden="true"></span> Paramètres</a></li>
|
||||
<li class="divider"></li>
|
||||
<!--<li class="dropdown-header">Nav header</li>-->
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Déconnexion</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Exit</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<!--<div class="page-header">
|
||||
<h1>Liste des fichiers uploadés</h1>
|
||||
</div>-->
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2> Fichiers privés (Seul les personnes connectées et l'administrateur de l'ordinateur peuvent les voirs) </h2>
|
||||
{% if listFilesPrivate %}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Fichier(s) <span class="badge">{{ i }}</span></th>
|
||||
<th>Taille (en octets)</th>
|
||||
<th>Fichier(s) <span class="badge">{{ nb_pv }}</span></th>
|
||||
<th>Taille (en Megaoctect)</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if listeFichiers %}
|
||||
{% for fichier in listeFichiers %}
|
||||
|
||||
{% for file in listFilesPrivate %}
|
||||
<tr>
|
||||
<td>{{ fichier[0] }}</td>
|
||||
<td><a href="/myfiles/{{ fichier[1] }}">{{ fichier[1] }}</a></td>
|
||||
<td>{{ fichier[2] }}</td>
|
||||
<td><a href="{{ url_for('remove', nom=fichier[1]) }}"><button type="button" class="btn btn-sm btn-danger">Supprimer</button></a></td>
|
||||
</tr>
|
||||
<td>{{ file[0] }}</td>
|
||||
<td><a href="/myfiles/{{ username }}/{{ file[1] }}">{{ file[1] }}</a></td>
|
||||
<td>{{ file[2] }}</td>
|
||||
<td><a href="{{ url_for('filesupload.remove_privateFile', filename=file[1]) }}"><button type="button" class="btn btn-sm btn-danger">Supprimer</button></a></td>
|
||||
<td><a href="{{ url_for('filesupload.move_public', filename=file[1]) }}"><button type="button" class="btn btn-sm btn-success"> Rendre Publique </button></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p> Vous n'avez aucun fichiers privés </p>
|
||||
{% endif %}
|
||||
<br />
|
||||
<hr />
|
||||
<br />
|
||||
<h2> Fichiers publics (Tout le monde peut les voirs) </h2>
|
||||
{% if listFilesPublic %}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Fichier(s) <span class="badge">{{ nb_pu }}</span></th>
|
||||
<th>Taille (en Megaoctets)</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
{% for file in listFilesPublic %}
|
||||
<tr>
|
||||
<td>{{ file[0] }}</td>
|
||||
<td><a href="/public/{{ username }}/{{ file[1] }}">{{ file[1] }}</a></td>
|
||||
<td>{{ file[2] }}</td>
|
||||
<td><a href="{{ url_for('filesupload.remove_publicFile', filename=file[1]) }}"><button type="button" class="btn btn-sm btn-danger">Supprimer</button></a></td>
|
||||
<td><a href="{{ url_for('filesupload.move_private', filename=file[1]) }}"><button type="button" class="btn btn-sm btn-success"> Rendre Privée </button></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p> Vous n'avez aucun fichiers publics </p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,70 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="no-js" lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<html lang="fr">
|
||||
|
||||
<title>OpenBlogStock</title>
|
||||
{% include '_head.html' %}
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="{{ url_for('static', filename='bootstrap.min.css') }}" rel="stylesheet">
|
||||
<!-- Bootstrap theme -->
|
||||
<link href="{{ url_for('static', filename='bootstrap-theme.min.css') }}" rel="stylesheet">
|
||||
|
||||
<!-- Custom styles for this template -->
|
||||
<link href="{{ url_for('static', filename='theme.css') }}" rel="stylesheet">
|
||||
<!-- Mon CSS avec animations -->
|
||||
<link href="{{ url_for('static', filename='up.css') }}" rel="stylesheet">
|
||||
|
||||
<script src="{{ url_for('static', filename='bootstrap.js') }}"></script>
|
||||
|
||||
<!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
|
||||
<!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
|
||||
<!--<script src="../../assets/js/ie-emulation-modes-warning.js"></script>-->
|
||||
|
||||
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
|
||||
<!--<script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>-->
|
||||
|
||||
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='divhider.js') }}"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body role="document">
|
||||
{% block navbar %}{% endblock %}
|
||||
|
||||
<!--<div class="msginfo">
|
||||
{# on affiche les messages d'erreur puis les messages de succes #}
|
||||
{% for categorie in ['error', 'succes'] %}
|
||||
{% with msgs = get_flashed_messages(category_filter=[categorie]) %}
|
||||
{% if msgs %}
|
||||
<div class="flashed {{ categorie }}">
|
||||
{% for m in msgs %}
|
||||
<p>{{ m|safe }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>-->
|
||||
|
||||
{% include '_nav_userlogin.html'%}
|
||||
|
||||
|
||||
|
||||
<div class="container theme-showcase" role="main">
|
||||
{% block main %}{% endblock %}
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap core JavaScript -->
|
||||
<!--================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="{{ url_for('static', filename='jquery.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='bootstrap.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='docs.min.js') }}"></script>
|
||||
{% include '_flash_msgs.html' %}
|
||||
{% include '_footer.html' %}
|
||||
{% include '_js.html' %}
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
@@ -1,68 +1,19 @@
|
||||
|
||||
|
||||
{% include '_nav_userlogin.html' %}
|
||||
{% extends 'up_squelette.html' %}
|
||||
|
||||
{% block navbar %}
|
||||
<!-- Fixed navbar -->
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<!--<a class="navbar-brand" href="/blog/">Blog</a>-->
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="/blog/"><span class="glyphicon glyphicon-globe" aria-hidden="true"></span> Blog</a></li>
|
||||
<li class="active"><a href="/uploadfiles/"><span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span> Upload</a></li>
|
||||
<li><a href="/view/"><span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span> Fichiers</a></li>
|
||||
<li><a href="/gallery/"><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> Gallerie</a></li>
|
||||
<li><a href="/logs/"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span> Logs</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-home" aria-hidden="true"></span> <span id="majuscule">{{ session['username'] }} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="/profil/{{ session['username'] }}"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Profil</a></li>
|
||||
<li><a href="/parametres/"><span class="glyphicon glyphicon-cog" aria-hidden="true"></span> Paramètres</a></li>
|
||||
<li class="divider"></li>
|
||||
<!--<li class="dropdown-header">Nav header</li>-->
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Déconnexion</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/logout/"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Exit</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<div class="container theme-showcase" role="main">
|
||||
|
||||
<!-- Main jumbotron for a primary marketing message or call to action -->
|
||||
<!--<div class="jumbotron">
|
||||
<h1>Hello, {{ session['username'] }} !</h1>
|
||||
<p>Hébergeur de fichiers basé sur Flask + Bootstrap 3 et hébergé sur une Orange Pi, vise à promouvoir l'informatique libre. Site en construction.</p>
|
||||
<p><a href="http://flask.pocoo.org/" class="btn btn-primary btn-lg" role="button">En savoir plus »</a></p>
|
||||
</div>-->
|
||||
|
||||
|
||||
|
||||
<!--<div class="page-header">
|
||||
<h1>Upload</h1>
|
||||
</div>-->
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-3"></div>
|
||||
<div class="col-sm-6">
|
||||
<br />
|
||||
<div class="well">Ici, vous pouvez envoyer des fichiers afin de les sauvegarder ou de les rendre accessibles à quelqu'un d'autre. Ils seront par la suite disponibles en téléchargement dans notre rubrique <a href="/view/"><span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span> Fichiers</a>. Les images envoyées, quand à elles se retrouveront directement dans la <a href="/gallery/"><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> Gallerie</a>.<br>Ayez bien conscience que ce site est une expérience est qu'il est indispensable d'avoir une sauvegarde de tous vos fichiers. Nous ne pourrons, en aucun cas, être tenu responsable de la perte de vos données. Merci de votre compréhension.</div>
|
||||
<br />
|
||||
<div class="panel panel-primary">
|
||||
<div class="well">Ici, vous pouvez envoyer des fichiers afin de les sauvegarder ou de les rendre accessibles à quelqu'un d'autre. Ils seront par la suite disponibles en téléchargement dans notre rubrique <a href="/view/"><span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span> Fichiers</a>. Les images envoyées, quand à elles se retrouveront directement dans la <a href="/gallery/"><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> Gallerie</a>.<br>Ayez bien conscience que ce site est une expérience est qu'il est indispensable d'avoir une sauvegarde de tous vos fichiers. Nous ne pourrons, en aucun cas, être tenu responsable de la perte de vos données. Merci de votre compréhension.
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Choisissez un ou plusieurs fichiers à uploader</h3>
|
||||
</div>
|
||||
@@ -90,16 +41,13 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--<script src="https://en.lichess.org/training/embed?theme=blue3&bg=auto"></script>
|
||||
<script src="https://en.lichess.org/tv/embed?theme=blue2&bg=dark"></script>-->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div> <!-- /container -->
|
||||
|
||||
{% endblock %}
|
||||
|
||||
168
tools/databaseinit.py
Normal file → Executable file
168
tools/databaseinit.py
Normal file → Executable file
@@ -1,49 +1,141 @@
|
||||
#!venv/bin/python
|
||||
from flask import Flask
|
||||
import sqlite3
|
||||
import os
|
||||
from tools.utils import gen_token
|
||||
from flask_bcrypt import Bcrypt
|
||||
|
||||
app = Flask( 'pywallter' )
|
||||
app.config.from_pyfile('config.py')
|
||||
bcrypt = Bcrypt(app)
|
||||
|
||||
DATABASE = app.config['DATABASE']
|
||||
DOSSIER_PERSO = app.config['DOSSIER_APP']
|
||||
DATABASE = app.config['DATABASE']
|
||||
|
||||
|
||||
import sqlite3
|
||||
import os.path
|
||||
|
||||
def init_db():
|
||||
if os.path.isfile('base.db'):
|
||||
return False
|
||||
else:
|
||||
conn = sqlite3.connect('base.db')
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS users(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
name TEXT,
|
||||
mail TEXT,
|
||||
passwd TEXT,
|
||||
avatar TEXT,
|
||||
nom, TEXT,
|
||||
prenom TEXT,
|
||||
age TEXT,
|
||||
profession TEXT
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
print ('table users OK')
|
||||
conn = sqlite3.connect(DATABASE)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS users(
|
||||
Mail TEXT UNIQUE,
|
||||
name TEXT primary KEY UNIQUE NOT NULL,
|
||||
alias TEXT,
|
||||
xmpp TEXT,
|
||||
passwd TEXT,
|
||||
avatar TEXT,
|
||||
nom TEXT,
|
||||
prenom TEXT,
|
||||
age TEXT,
|
||||
website TEXT,
|
||||
blog_theme TEXT,
|
||||
Token CHAR(64),
|
||||
Lost_password_token CHAR(128),
|
||||
invitations INTEGER DEFAULT (20),
|
||||
Mail_rescue TEXT )
|
||||
""")
|
||||
conn.commit()
|
||||
print ('table users Ok')
|
||||
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS posts(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
title TEXT,
|
||||
content TEXT,
|
||||
time TEXT,
|
||||
category TEXT,
|
||||
author TEXT,
|
||||
status TEXT
|
||||
)
|
||||
""")
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS posts(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
title TEXT,
|
||||
content TEXT,
|
||||
time TEXT,
|
||||
category TEXT,
|
||||
author TEXT,
|
||||
status TEXT
|
||||
)
|
||||
""")
|
||||
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS Blog_posts(
|
||||
title TEXT NOT NULL,
|
||||
subtitle TEXT,
|
||||
comments TEXT,
|
||||
filename TEXT,
|
||||
time TEXT,
|
||||
last_updated TEXT,
|
||||
category TEXT,
|
||||
author TEXT,
|
||||
status TEXT,
|
||||
PRIMARY KEY(title, author)
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
|
||||
|
||||
cursor.execute("""select * from users""")
|
||||
accounts = cursor.fetchall()
|
||||
# Si aucun compte utilisateur existe on créé l'utilisateur
|
||||
# pywallter qui permet la première inscription
|
||||
if not(accounts) :
|
||||
user = "pywallter"
|
||||
token = gen_token()
|
||||
passwd_bcrypt = bcrypt.generate_password_hash(token)
|
||||
cursor.execute("""INSERT INTO users(name, passwd, token) VALUES(?, ?, ?)""", (user, passwd_bcrypt, token))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print ('table posts OK')
|
||||
return True
|
||||
|
||||
conn.close()
|
||||
print ('table posts OK')
|
||||
|
||||
def init_dir():
|
||||
if os.path.isdir('users'):
|
||||
return False
|
||||
else:
|
||||
os.makedirs('./users/')
|
||||
|
||||
def db_migrate():
|
||||
conn = sqlite3.connect(DATABASE)
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""SELECT name FROM PRAGMA_TABLE_INFO('users');""")
|
||||
db_columns = cursor.fetchall()
|
||||
invitations_col = False
|
||||
blog_theme_col = False
|
||||
updated_col = False
|
||||
lost_password_token_col = False
|
||||
|
||||
for col in db_columns:
|
||||
if "invitations" == col[0]:
|
||||
invitations_col = True
|
||||
if "Lost_password_token" == col[0]:
|
||||
lost_password_token_col = True
|
||||
|
||||
|
||||
cursor.execute("""SELECT name FROM PRAGMA_TABLE_INFO('Blog_posts');""")
|
||||
db_columns = cursor.fetchall()
|
||||
for col in db_columns:
|
||||
if "blog_theme" == col[0]:
|
||||
blog_theme_col = True
|
||||
if "last_updated" == col[0]:
|
||||
updated_col = True
|
||||
|
||||
|
||||
|
||||
if not(invitations_col):
|
||||
cursor.execute("""ALTER TABLE users ADD COLUMN invitations INTEGER DEFAULT (20);""")
|
||||
conn.commit()
|
||||
print ("Ajout du champ invitations dans la table users")
|
||||
|
||||
|
||||
if not(lost_password_token_col):
|
||||
cursor.execute("""ALTER TABLE Users ADD COLUMN Lost_password_token CHAR(64);""")
|
||||
conn.commit()
|
||||
print ("Ajout du champ Lost_password_token dans la table Users")
|
||||
|
||||
|
||||
if not(blog_theme_col):
|
||||
cursor.execute("""ALTER TABLE Blog_posts ADD COLUMN blog_theme TEXT;""")
|
||||
conn.commit()
|
||||
print ("Ajout du champ blog_theme dans la table Blog")
|
||||
|
||||
if not(updated_col):
|
||||
cursor.execute("""ALTER TABLE Blog_posts ADD COLUMN last_updated TEXT;""")
|
||||
conn.commit()
|
||||
print ("Ajout du champ updated dans la table BLog")
|
||||
|
||||
|
||||
|
||||
conn.close()
|
||||
|
||||
12
tools/filesutils.py
Normal file
12
tools/filesutils.py
Normal file
@@ -0,0 +1,12 @@
|
||||
import os
|
||||
from math import floor
|
||||
|
||||
def getFileSizeMo(filename): # Prend un nom de fichier en arguments renvoie la taille en Mo
|
||||
tmp = os.path.getsize(filename)
|
||||
size = floor (tmp / 1024) / 1000
|
||||
return size
|
||||
|
||||
def getFileSizeKo(filename): # Prend un nom de fichier en arguments renvoie la taille en Mo
|
||||
tmp = os.path.getsize(filename)
|
||||
size = floor(tmp / 1024)
|
||||
return size
|
||||
65
tools/mailer.py
Normal file
65
tools/mailer.py
Normal file
@@ -0,0 +1,65 @@
|
||||
from flask import Flask
|
||||
import os, smtplib, ssl
|
||||
from email.message import EmailMessage
|
||||
|
||||
|
||||
app = Flask( 'pywallter' )
|
||||
app.config.from_pyfile('config.py')
|
||||
|
||||
|
||||
|
||||
class Mailer:
|
||||
|
||||
def __init__(self):
|
||||
self._smtp_server = app.config['SMTP_SERVER']
|
||||
self._smtp_port = app.config['SMTP_PORT']
|
||||
self._smtp_user = app.config['SMTP_USER']
|
||||
self._smtp_passwd = app.config['SMTP_PASSWD']
|
||||
self._sender_address = app.config['SENDER_ADDRESS']
|
||||
|
||||
|
||||
def get_smtp_conf(self):
|
||||
print ("Serveur SMTP: _smtp_server")
|
||||
|
||||
return self._smtp_server
|
||||
|
||||
def send_email(self, receiver_email, subject, message):
|
||||
|
||||
mail = EmailMessage()
|
||||
mail['Subject'] = subject
|
||||
mail['From'] = self._sender_address
|
||||
mail['To'] = receiver_email
|
||||
mail.set_content(message)
|
||||
|
||||
match self._smtp_port:
|
||||
case "465":
|
||||
self._send_ssl_mail(receiver_email, mail)
|
||||
case "587":
|
||||
self._send_starttls_mail(receiver_email, mail)
|
||||
case "25":
|
||||
with smtplib.SMTP(self._smtp_server, self._smtp_port) as server:
|
||||
server.login(self._smtp_user, self._smtp_password)
|
||||
server.sendmail(self._sender_address, receiver_email, mail.as_string())
|
||||
case _:
|
||||
print ("There are problem with mail port configuration ")
|
||||
|
||||
|
||||
def _send_starttls_mail(self, receiver_email, mail):
|
||||
|
||||
context = ssl.create_default_context()
|
||||
with smtplib.SMTP(self._smtp_server, self._smtp_port) as server:
|
||||
server.ehlo() # Can be omitted
|
||||
server.starttls(context=context)
|
||||
server.ehlo() # Can be omitted
|
||||
server.login(self._smtp_user, self._smtp_passwd)
|
||||
server.sendmail(self._sender_address, receiver_email, mail.as_string())
|
||||
|
||||
|
||||
|
||||
def _send_ssl_mail(receiver_email, mail):
|
||||
|
||||
context = ssl.create_default_context()
|
||||
with smtplib.SMTP(self._smtp_server, self._smtp_port) as server:
|
||||
|
||||
server.login(sender_email, password)
|
||||
server.sendmail(self._sender_address, receiver_email, mail.as_string())
|
||||
131
tools/utils.py
Normal file
131
tools/utils.py
Normal file
@@ -0,0 +1,131 @@
|
||||
from flask import Flask
|
||||
import sqlite3
|
||||
import os
|
||||
import string
|
||||
import random
|
||||
|
||||
app = Flask( 'pywallter' )
|
||||
app.config.from_pyfile('config.py')
|
||||
|
||||
|
||||
DATABASE = app.config['DATABASE']
|
||||
DOSSIER_PERSO = app.config['DOSSIER_APP']
|
||||
DATABASE = app.config['DATABASE']
|
||||
|
||||
def append_to_log(log_line, user):
|
||||
log_file=os.path.join(DOSSIER_PERSO, user, "log.txt")
|
||||
logs=open(log_file, "r")
|
||||
tmp=logs.read()
|
||||
logs.close()
|
||||
log=open(log_file, "w")
|
||||
log.write(log_line)
|
||||
log.write(tmp)
|
||||
log.close()
|
||||
|
||||
|
||||
def valid_username(username):
|
||||
valid=True
|
||||
# Caractères non autorisés dans la RFC #822
|
||||
invalid_char = { '(', ')', '<', '>', ',', ';', ':', '"', '[', ']', '|', 'ç', '%', '&', ' ' }
|
||||
|
||||
for character in invalid_char:
|
||||
if character in username:
|
||||
valid=False
|
||||
|
||||
return valid
|
||||
|
||||
|
||||
def email_disp(email):
|
||||
disp = True
|
||||
unique_at = len(email.split('@'))
|
||||
if len(email) < 80 and unique_at == 2:
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
|
||||
cursor.execute("""SELECT mail FROM users WHERE mail=?""", (email,))
|
||||
testmail = cursor.fetchall()
|
||||
if testmail and disp:
|
||||
disp = False
|
||||
|
||||
if disp:
|
||||
cursor.execute("""SELECT alias FROM users""")
|
||||
aliases = cursor.fetchall()
|
||||
for alist in aliases:
|
||||
for alias in alist:
|
||||
if alias:
|
||||
if email in alias:
|
||||
disp=False
|
||||
else:
|
||||
disp = False
|
||||
|
||||
return disp
|
||||
|
||||
|
||||
def valid_passwd(password):
|
||||
if '"' in password or "&" in password:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def valid_token_register(token, token_type):
|
||||
valid = True
|
||||
print(token)
|
||||
if len(token) != 30 and len(token) != 64 :
|
||||
valid = False
|
||||
|
||||
if valid:
|
||||
conn = sqlite3.connect(DATABASE)
|
||||
cursor = conn.cursor()
|
||||
match token_type:
|
||||
case "Lost password":
|
||||
cursor.execute("""SELECT name FROM users where Lost_password_token=?""", (token,))
|
||||
case "Invitation":
|
||||
cursor.execute("""SELECT name FROM users where token=?""", (token,))
|
||||
tmp = cursor.fetchone()
|
||||
conn.close()
|
||||
print (tmp)
|
||||
if tmp:
|
||||
valid = True
|
||||
else:
|
||||
valid = False
|
||||
|
||||
return valid
|
||||
|
||||
|
||||
|
||||
def get_user_by_token(token, token_type):
|
||||
|
||||
|
||||
if len(token) != 30 and len(token) != 64:
|
||||
user = "Invalid Token"
|
||||
|
||||
|
||||
conn = sqlite3.connect(DATABASE)
|
||||
cursor = conn.cursor()
|
||||
match token_type:
|
||||
case "Lost password":
|
||||
cursor.execute("""SELECT name FROM users where Lost_password_token=?""", (token,))
|
||||
case "Invitation":
|
||||
cursor.execute("""SELECT name FROM users where token=?""", (token,))
|
||||
user = cursor.fetchone()[0]
|
||||
conn.close()
|
||||
print ("User: " + user)
|
||||
|
||||
if not(user):
|
||||
user = "Invalid Token"
|
||||
return user
|
||||
|
||||
|
||||
|
||||
#Génère un token de 30 ou 64 caratères aléatoires
|
||||
def gen_token(token_type):
|
||||
letters = random.choices(string.ascii_letters, k=128)
|
||||
digits = random.choices(string.digits, k=30)
|
||||
match token_type:
|
||||
case "Invitation":
|
||||
sample = ''.join(random.sample(digits + letters, 30))
|
||||
case "Lost password":
|
||||
sample = ''.join(random.sample(digits + letters, 64))
|
||||
return sample
|
||||
211
views/blog.py
211
views/blog.py
@@ -1,104 +1,177 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
from flask import Blueprint, escape, render_template, session, redirect, url_for, request, flash, abort
|
||||
from flask import Blueprint, render_template, session, redirect, url_for, request, flash, abort, Flask
|
||||
import time
|
||||
from markupsafe import escape
|
||||
import sqlite3
|
||||
from markdown import markdown
|
||||
from tools.filesutils import getFileSizeKo
|
||||
import string
|
||||
|
||||
blog = Blueprint('blog', __name__, template_folder='templates')
|
||||
|
||||
# Un bon gros bug de flask il ne faut pas mettre le meme nom d'une parti ici
|
||||
# a une fonction sinon ca fait une erreur
|
||||
# k/app.py", line 958, in register_blueprint
|
||||
# if blueprint.name in self.blueprints:
|
||||
#https://github.com/pallets/flask/issues/1327
|
||||
app = Flask( 'pywallter' )
|
||||
app.config.from_pyfile('config.py')
|
||||
|
||||
@blog.route('/blog/', methods=['GET', 'POST'])
|
||||
def racine_blog():
|
||||
|
||||
########################### Variables Globales #################################
|
||||
extensionimg = app.config['EXT_IMG']
|
||||
DATABASE = app.config['DATABASE']
|
||||
BASE_URL = app.config['BASE_URL']
|
||||
DOSSIER_PERSO= app.config['DOSSIER_APP']+'/'
|
||||
DOSSIER_PUBLIC= app.config['DOSSIER_PUBLIC']+'/'
|
||||
|
||||
################################################################################
|
||||
|
||||
@blog.route('/myblog/new-article/', methods=['GET', 'POST'])
|
||||
def new_article():
|
||||
if 'username' in session:
|
||||
UTILISATEUR='%s'% escape(session['username'])
|
||||
user = '%s'% escape(session['username'])
|
||||
folder_blog = DOSSIER_PERSO + user + "/blog/articles/"
|
||||
if request.method == 'POST':
|
||||
title= request.form['title']
|
||||
content = markdown(request.form['content'])
|
||||
#category = request.form['category']
|
||||
title = request.form['title']
|
||||
subtitle = request.form['subtitle']
|
||||
content = request.form['content']
|
||||
status = request.form['status']
|
||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
||||
conn = sqlite3.connect('base.db') # Connexion la base de donne
|
||||
post_date = time.strftime("%d/%m/%Y %H:%M:%S")
|
||||
filename = title.replace(" ", "_") + ".md"
|
||||
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""INSERT INTO posts(title, content, time, author, status) VALUES(?, ?, ?, ?, ?)""", (title, content, TIME, UTILISATEUR, status)) # Insérer des valeurs
|
||||
cursor.execute("""INSERT INTO Blog_posts(title, subtitle, filename, time, author, status) VALUES(?, ?, ?, ?, ?, ?)""", (title, subtitle, filename, post_date, user, status)) # Insérer des valeurs
|
||||
conn.commit()
|
||||
cursor.execute("""SELECT title, content, time, author, status, avatar, nom, prenom, age, profession FROM posts INNER JOIN users ON author = name AND status='public'""")
|
||||
posts = [dict(title=row[0], content=row[1], time=row[2], author=row[3], status=row[4], avatar=row[5], nom=row[6], prenom=row[7], age=row[8], profession=row[9]) for row in reversed(cursor.fetchall())]
|
||||
conn.close()
|
||||
return render_template('blog.html', posts=posts)
|
||||
## On génère le fichiers markdown
|
||||
with open(folder_blog + filename, 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
return redirect(url_for('blog.list_articles_blog'))
|
||||
else:
|
||||
conn = sqlite3.connect('base.db') # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT title, content, time, author, status, avatar, nom, prenom, age, profession FROM posts INNER JOIN users ON author = name AND status='public'""")
|
||||
posts = [dict(title=row[0], content=row[1], time=row[2], author=row[3], status=row[4], avatar=row[5], nom=row[6], prenom=row[7], age=row[8], profession=row[9]) for row in reversed(cursor.fetchall())]
|
||||
conn.close()
|
||||
return render_template('blog.html', posts=posts)
|
||||
return render_template('new_article_blog.html')
|
||||
else:
|
||||
return redirect(url_for('loginlogout.login', _external=True))
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
@blog.route('/blog/<username>')
|
||||
def members(username):
|
||||
conn = sqlite3.connect('base.db') # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT title, content, time, author, status FROM posts WHERE author=? AND status='public'""", (username,))
|
||||
posts = [dict(title=row[0], content=row[1], time=row[2], author=row[3], status=row[4]) for row in reversed(cursor.fetchall())]
|
||||
cursor.execute("""SELECT avatar, nom, prenom, age, profession FROM users WHERE name=?""", (username,))
|
||||
usersinfos = (cursor.fetchone())
|
||||
conn.close()
|
||||
return render_template('publicblog.html', username=username, posts=posts, usersinfos=usersinfos)
|
||||
|
||||
@blog.route('/privateblog/')
|
||||
def privateblog():
|
||||
UTILISATEUR='%s'% escape(session['username'])
|
||||
if 'username' in session :
|
||||
conn = sqlite3.connect('base.db') # Connexion à la base de donnée
|
||||
@blog.route('/myblog/list-articles/', methods=['GET'])
|
||||
def list_articles_blog():
|
||||
if 'username' in session:
|
||||
user = '%s'% escape(session['username'])
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT title, content, time, author, status FROM posts WHERE author=? AND status='prive'""", (UTILISATEUR,))
|
||||
posts = [dict(title=row[0], content=row[1], time=row[2], author=row[3], status=row[4]) for row in reversed(cursor.fetchall())]
|
||||
cursor.execute("""SELECT avatar, nom, prenom, age, profession FROM users WHERE name=?""", (UTILISATEUR,))
|
||||
usersinfos = (cursor.fetchone())
|
||||
conn.close()
|
||||
return render_template('privateblog.html', UTILISATEUR=UTILISATEUR, posts=posts, usersinfos=usersinfos)
|
||||
cursor.execute("""SELECT title, subtitle, time, last_updated, status FROM Blog_posts WHERE author=? """, (user,) )
|
||||
list_posts=cursor.fetchall()
|
||||
posts=list()
|
||||
nb_articles=0
|
||||
for post in list_posts:
|
||||
posts.append(dict(title=post[0],
|
||||
subtitle=post[1],
|
||||
time=post[2],
|
||||
last_updated=post[3],
|
||||
status=post[4]))
|
||||
nb_articles =+ 1
|
||||
|
||||
return render_template('list_articles.html',
|
||||
section="Articles",
|
||||
list_posts=posts,
|
||||
nb_articles=nb_articles
|
||||
)
|
||||
else:
|
||||
return redirect(url_for('loginlogout.login', _external=True)) # sinon on redirige vers login
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
@blog.route('/delete/<post>')
|
||||
def delete(post):
|
||||
|
||||
@blog.route('/myblog/delete/<title>')
|
||||
def delete(title):
|
||||
if 'username' in session :
|
||||
conn = sqlite3.connect('base.db') # Connexion à la base de donnée
|
||||
user='%s'% escape(session['username'])
|
||||
folder_blog = DOSSIER_PERSO + user + "/blog/articles/"
|
||||
folder_blog_public = DOSSIER_PUBLIC + user + "/blog/articles/"
|
||||
filename = title.replace(" ", "_")
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""DELETE FROM posts WHERE title=?""", (post,))
|
||||
cursor.execute("""DELETE FROM Blog_posts WHERE title=? AND author=?""", (title, user))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return redirect(url_for('blog.racine_blog'))
|
||||
os.remove(folder_blog+filename+".md")
|
||||
os.remove(folder_blog_public+filename+".html")
|
||||
return redirect(url_for('blog.list_articles_blog'))
|
||||
else:
|
||||
return redirect(url_for('loginlogout.login', _external=True)) # sinon on redirige vers login
|
||||
return redirect(BASE_URL, code=401) # sinon on redirige vers login
|
||||
|
||||
@blog.route('/edit/<post>', methods=['GET', 'POST'])
|
||||
def edit(post):
|
||||
@blog.route('/myblog/edit/<title>', methods=['GET', 'POST'])
|
||||
def edit(title):
|
||||
if 'username' in session :
|
||||
user='%s'% escape(session['username'])
|
||||
filename = title.replace(" ", "_") + ".md"
|
||||
folder_blog = DOSSIER_PERSO + user + "/blog/articles/"
|
||||
|
||||
if request.method == 'POST' :
|
||||
newtitle = request.form['title']
|
||||
newcontent = markdown(request.form['content'])
|
||||
subtitle = request.form['subtitle']
|
||||
newcontent = request.form['content']
|
||||
newstatus = request.form['status']
|
||||
conn = sqlite3.connect('base.db')
|
||||
updated = time.strftime("%d/%m/%Y %H:%M:%S")
|
||||
conn = sqlite3.connect(DATABASE)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""UPDATE posts SET title=?, content=?, status=? WHERE title=?""",
|
||||
(newtitle, newcontent, newstatus, post,))
|
||||
cursor.execute("""UPDATE Blog_posts SET subtitle=?, last_updated=?, status=? WHERE title=? AND author=?""", (subtitle, updated, newstatus, title, user))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return redirect(url_for('blog.racine_blog'))
|
||||
|
||||
with open(folder_blog + filename, 'w') as f:
|
||||
f.write(newcontent)
|
||||
|
||||
|
||||
return redirect(url_for('blog.list_articles_blog'))
|
||||
else:
|
||||
conn = sqlite3.connect('base.db') # Connexion à la base de donnée
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT title, content FROM posts WHERE title=?""", (post,))
|
||||
oldpost = (cursor.fetchone())
|
||||
cursor.execute("""SELECT title, subtitle, status FROM Blog_posts WHERE title=? AND author=?""", (title, user))
|
||||
oldpost = cursor.fetchone()
|
||||
conn.close()
|
||||
return render_template('postedit.html', oldpost=oldpost)
|
||||
|
||||
with open(folder_blog + filename, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
return render_template('edit_article.html',
|
||||
section='Post-it',
|
||||
oldpost=oldpost,
|
||||
content=content)
|
||||
else:
|
||||
return redirect(url_for('loginlogout.login', _external=True)) # sinon on redirige vers login)
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
@blog.route('/blog/<username>/', methods=['GET'])
|
||||
def view(username):
|
||||
user = username
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT title, subtitle, time, author FROM Blog_posts WHERE status='public' AND author=? """, (user,) )
|
||||
list_posts=cursor.fetchall()
|
||||
posts=list()
|
||||
id=0
|
||||
|
||||
conn.close()
|
||||
print (list_posts)
|
||||
if list_posts != None:
|
||||
for post in list_posts:
|
||||
posts.append(dict(title=post[0], subtitle=post[1], time=post[2], author=post[3]))
|
||||
else:
|
||||
return redirect(BASE_URL, code=404)
|
||||
|
||||
|
||||
return render_template('index_blog.html', section='Blog', posts=posts, user=user)
|
||||
|
||||
@blog.route('/blog/<username>/<title>', methods=['GET'])
|
||||
def viewArticle(username, title):
|
||||
folder_blog = DOSSIER_PERSO + username + "/blog/articles/"
|
||||
filename = title.replace(" ", "_") + ".md"
|
||||
user = username
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT title, subtitle, time, author FROM Blog_posts WHERE author=? AND title=? """, (user, title) )
|
||||
post = cursor.fetchone()
|
||||
conn.close()
|
||||
if post != None:
|
||||
post_info = (dict(title=post[0], subtitle=post[1], time=post[2], author=post[3]))
|
||||
with open(folder_blog + filename, 'r') as f:
|
||||
content_md = f.read()
|
||||
content = markdown(content_md)
|
||||
return render_template('blog.html', post_info=post_info, content=content)
|
||||
else:
|
||||
flash(u"Cet article n'existe pas", 'error');
|
||||
|
||||
|
||||
@@ -1,95 +1,197 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file, escape, flash, abort
|
||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, flash, abort, send_file, send_from_directory
|
||||
from werkzeug.utils import secure_filename
|
||||
from markupsafe import escape
|
||||
from PIL import Image
|
||||
import time
|
||||
import sqlite3
|
||||
import os
|
||||
|
||||
|
||||
|
||||
from shutil import move
|
||||
from tools.filesutils import getFileSizeMo
|
||||
|
||||
filesupload = Blueprint('filesupload', __name__, template_folder='templates')
|
||||
|
||||
DOSSIER_PERSO='users/'
|
||||
extensionimg = {'.jpg', '.JPG', '.png', '.PNG', '.gif', '.GIF', '.bmp', '.BMP', '.jpeg', '.JPEG' }
|
||||
app = Flask( 'pywallter' )
|
||||
app.config.from_pyfile('config.py')
|
||||
|
||||
|
||||
#### Variables ####################################################################################
|
||||
|
||||
DOSSIER_PERSO= app.config['DOSSIER_APP']+'/'
|
||||
DOSSIER_PUBLIC= app.config['DOSSIER_PUBLIC']+'/'
|
||||
|
||||
extensionimg = app.config['EXT_IMG']
|
||||
DATABASE = app.config['DATABASE']
|
||||
BASE_URL= app.config['BASE_URL']
|
||||
##################################################################################################
|
||||
|
||||
|
||||
@filesupload.route( '/filesupload/', methods=['GET', 'POST'])
|
||||
def uploadfiles():
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s'% escape(session['username'])
|
||||
user = '%s'% escape(session['username'])
|
||||
if request.method == 'POST' :
|
||||
files = request.files.getlist('fic')
|
||||
for f in files :
|
||||
if f: # On vérifie qu'un fichier a bien été envoyé
|
||||
nom = secure_filename(f.filename)
|
||||
if os.path.isfile(DOSSIER_PERSO + UTILISATEUR + '/files/' + nom):
|
||||
flash(u'Fichier déjà existant, merci de spécifier un autre nom de fichier', 'error')
|
||||
else:
|
||||
if os.path.isfile(DOSSIER_PERSO + UTILISATEUR + '/images/' + nom):
|
||||
flash(u'Image déjà existante, merci de spécifier un autre nom de fichier', 'error')
|
||||
else:
|
||||
file, ext = os.path.splitext(nom)
|
||||
if ext in extensionimg :
|
||||
f.save(DOSSIER_PERSO + UTILISATEUR + '/images/' + nom)
|
||||
image=DOSSIER_PERSO + UTILISATEUR + '/images/' + nom
|
||||
with Image.open(image) as img :
|
||||
img.thumbnail((300,300))
|
||||
img.save( DOSSIER_PERSO + UTILISATEUR + '/images/thumbnails/' + nom )
|
||||
if os.path.isfile(DOSSIER_PERSO + UTILISATEUR + '/images/' + nom) :
|
||||
if os.path.isfile(DOSSIER_PERSO + UTILISATEUR + '/images/thumbnails/' + nom):
|
||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
||||
IP=request.environ['REMOTE_ADDR']
|
||||
CLIENT_PLATFORM=request.headers.get('User-Agent')
|
||||
LOG=open("log.txt", "a")
|
||||
LOG.write (TIME + ' - ' + IP + ' - ' + UTILISATEUR + ' - ' + CLIENT_PLATFORM + '\n' + '---> ' + nom + '\n')
|
||||
LOG.close()
|
||||
flash(u'Image envoyée et traitée avec succés', 'succes')
|
||||
else:
|
||||
flash(u'Échec lors du traitement de l\'image', 'error')
|
||||
return redirect(url_for('filesupload.uploadfiles'))
|
||||
else:
|
||||
flash(u'Éches lors de l\'envoi de l\'image', 'error')
|
||||
return redirect(url_for('filesupload.uploadfiles'))
|
||||
else:
|
||||
f.save(DOSSIER_PERSO + UTILISATEUR + '/files/' + nom)
|
||||
if os.path.isfile(DOSSIER_PERSO + UTILISATEUR + '/files/' + nom) :
|
||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
||||
IP=request.environ['REMOTE_ADDR']
|
||||
CLIENT_PLATFORM=request.headers.get('User-Agent')
|
||||
LOG=open("log.txt", "a") # Ouvre fichier log.txt
|
||||
LOG.write (TIME + ' - ' + IP + ' - ' + UTILISATEUR + ' - ' + CLIENT_PLATFORM + '\n' + '---> ' + nom + '\n') # Écrit dans log
|
||||
LOG.close() # Ferme log.txt
|
||||
flash(u'Fichier envoyé avec succés', 'succes')
|
||||
#return redirect(url_for('filesupload.upload'))
|
||||
else:
|
||||
return redirect(url_for('filesupload.uploadfiles'))
|
||||
else:
|
||||
flash(u'Error : Vous avez oublié le fichier !', 'error')
|
||||
return redirect(url_for('filesupload.uploadfiles'))
|
||||
resp = make_response(render_template('up_up.html'))
|
||||
nom = secure_filename(f.filename)
|
||||
if os.path.isfile(DOSSIER_PERSO + user + '/files/' + nom) or os.path.isfile(DOSSIER_PERSO + user + '/images/' + nom):
|
||||
flash(u'Un fichier avec le même nom existe déjà, merci de spécifier un autre nom de fichier', 'error')
|
||||
else:
|
||||
file, ext = os.path.splitext(nom)
|
||||
if ext in extensionimg :
|
||||
f.save(DOSSIER_PERSO + user + '/images/' + nom)
|
||||
image = DOSSIER_PERSO + user + '/images/' + nom
|
||||
with Image.open(image) as img :
|
||||
img.thumbnail((300,300))
|
||||
img.save( DOSSIER_PERSO + user + '/images/thumbnails/' + nom )
|
||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
||||
IP=request.environ['REMOTE_ADDR']
|
||||
CLIENT_PLATFORM=request.headers.get('User-Agent')
|
||||
log_file=os.path.join(DOSSIER_PERSO, user, "log.txt")
|
||||
LOG=open(log_file, "a")
|
||||
LOG.write (TIME + ' - ' + IP + ' - ' + user + ' - ' + CLIENT_PLATFORM + '\n' + '---> ' + nom + '\n')
|
||||
LOG.close()
|
||||
flash(u'Image envoyée et traitée avec succés', 'succes')
|
||||
else:
|
||||
f.save(DOSSIER_PERSO + user + '/files/' + nom)
|
||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
||||
IP=request.environ['REMOTE_ADDR']
|
||||
CLIENT_PLATFORM=request.headers.get('User-Agent')
|
||||
LOG=open("log.txt", "a") # Ouvre fichier log.txt
|
||||
LOG.write (TIME + ' - ' + IP + ' - ' + user + ' - ' + CLIENT_PLATFORM + '\n' + '---> ' + nom + '\n') # Écrit dans log
|
||||
LOG.close() # Ferme log.txt
|
||||
flash(u'Fichier envoyé avec succés', 'succes')
|
||||
|
||||
else:
|
||||
flash(u'Error : Vous avez oublié le fichier !', 'error')
|
||||
return redirect(url_for('filesupload.uploadfiles'))
|
||||
resp = make_response(render_template('up_up.html', section="Upload"))
|
||||
resp.set_cookie('username', session['username'])
|
||||
return resp
|
||||
else :
|
||||
return redirect(url_for('loginlogout.login', _external=True))
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
|
||||
@filesupload.route('/view/')
|
||||
def list():
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s'% escape(session['username'])
|
||||
i = 0
|
||||
fichiers = os.listdir(DOSSIER_PERSO + UTILISATEUR + '/files/')
|
||||
listeFichiers = []
|
||||
if fichiers:
|
||||
for fich in fichiers:
|
||||
i += 1
|
||||
size = os.path.getsize(DOSSIER_PERSO + UTILISATEUR + '/files/' + fich) # size = taille des fichiers
|
||||
listeFichiers.append([i, fich, size]) # On implémente la listeFichiers avec le num le ficier et sa taille
|
||||
return render_template('up_list.html',size=size, i=i, listeFichiers=listeFichiers)
|
||||
else :
|
||||
flash(u'Aucun fichier uploadé ! Redirection vers Upload', 'error')
|
||||
return redirect(url_for('filesupload.uploadfiles', external=True))
|
||||
user = '%s'% escape(session['username'])
|
||||
files_public = os.listdir(DOSSIER_PUBLIC + user + '/files')
|
||||
files_private = os.listdir(DOSSIER_PERSO + user + '/files/')
|
||||
listFilesPublic = []
|
||||
listFilesPrivate = []
|
||||
nb_pv = 0
|
||||
if files_private:
|
||||
for fich in files_private:
|
||||
nb_pv += 1
|
||||
size = getFileSizeMo(DOSSIER_PERSO + user + '/files/' + fich) # size = taille des fichiers
|
||||
listFilesPrivate.append([nb_pv, fich, size]) # On implémente la listeFichiers avec le num le ficier et sa taille
|
||||
|
||||
nb_pu = 0
|
||||
if files_public:
|
||||
for fich in files_public:
|
||||
nb_pu += 1
|
||||
size = getFileSizeMo(DOSSIER_PUBLIC + user + '/files/' + fich) # size = taille des fichiers
|
||||
listFilesPublic.append([nb_pu, fich, size])
|
||||
|
||||
return render_template('up_list.html',
|
||||
section="Files",
|
||||
size=size,
|
||||
username=user,
|
||||
nb_pv=nb_pv,
|
||||
nb_pu=nb_pu,
|
||||
listFilesPrivate=listFilesPrivate,
|
||||
listFilesPublic=listFilesPublic)
|
||||
|
||||
else :
|
||||
return redirect(url_for('loginlogout.login', _external=True))
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
@filesupload.route('/myfiles/<username>/<filename>')
|
||||
def myfiles(username, filename):
|
||||
if 'username' in session :
|
||||
user = '%s' % escape(session['username'])
|
||||
return send_from_directory(
|
||||
os.path.join(DOSSIER_PERSO, username, 'files'), filename )
|
||||
else :
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
@filesupload.route('/make_public/<filename>')
|
||||
def move_public(filename):
|
||||
if 'username' in session:
|
||||
user = '%s' % escape(session['username'])
|
||||
src = os.path.join(DOSSIER_PERSO, user, 'files', filename)
|
||||
dst = os.path.join(DOSSIER_PUBLIC, user, 'files/')
|
||||
move (src, dst)
|
||||
return redirect(url_for('filesupload.list', _external=True))
|
||||
else:
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
@filesupload.route('/make_private/<filename>')
|
||||
def move_private(filename):
|
||||
if 'username' in session:
|
||||
user = '%s' % escape(session['username'])
|
||||
src = os.path.join(DOSSIER_PUBLIC, user, 'files', filename)
|
||||
dst = os.path.join(DOSSIER_PERSO, user, 'files/')
|
||||
move (src, dst)
|
||||
return redirect(url_for('filesupload.list', _external=True))
|
||||
else:
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
|
||||
@filesupload.route('/public/<username>/<filename>')
|
||||
def publicfiles(username, filename):
|
||||
return send_from_directory(
|
||||
os.path.join(DOSSIER_PUBLIC, username, 'files'), filename )
|
||||
|
||||
|
||||
@filesupload.route('/remove_privateFile/<filename>')
|
||||
def remove_privateFile(filename):
|
||||
if 'username' in session :
|
||||
user = '%s' % escape(session['username'])
|
||||
filename = secure_filename(filename)
|
||||
try:
|
||||
os.remove(DOSSIER_PERSO + user + '/files/' + filename) # on le supprime
|
||||
except FileNotFoundError:
|
||||
flash(u'Fichier {filename} inexistant.'.format(filename=filename), 'error')
|
||||
return redirect(url_for('filesupload.list', _external=True))
|
||||
else :
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
@filesupload.route('/remove_privateImage/<filename>')
|
||||
def remove_privateImage(filename):
|
||||
if 'username' in session :
|
||||
user = '%s' % escape(session['username'])
|
||||
filename = secure_filename(filename)
|
||||
try:
|
||||
os.remove(DOSSIER_PERSO + user + '/images/thumbnails/' + filename) # on le supprime
|
||||
os.remove(DOSSIER_PERSO + user + '/images/' + filename) # on le supprime
|
||||
except FileNotFoundError:
|
||||
flash(u'Image {filename} inexistante.'.format(filename=filename), 'error')
|
||||
return redirect(url_for('gallery'))
|
||||
|
||||
|
||||
@filesupload.route('/remove_publicFile/<filename>')
|
||||
def remove_publicFile(filename):
|
||||
if 'username' in session :
|
||||
user = '%s' % escape(session['username'])
|
||||
filename = secure_filename(filename)
|
||||
try:
|
||||
os.remove(DOSSIER_PUBLIC + user + '/files/' + filename) # on le supprime
|
||||
except FileNotFoundError:
|
||||
flash(u'Fichier {filename} inexistant.'.format(filename=filename), 'error')
|
||||
return redirect(url_for('filesupload.list', _external=True))
|
||||
else :
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
@filesupload.route('/remove_publicImage/<filename>')
|
||||
def remove_publicImage(filename):
|
||||
if 'username' in session :
|
||||
user = '%s' % escape(session['username'])
|
||||
filename = secure_filename(filename)
|
||||
try:
|
||||
os.remove(DOSSIER_PUBLIC + user + '/images/thumbnails/' + filename) # on le supprime
|
||||
os.remove(DOSSIER_PUBLIC + user + '/images/' + filename) # on le supprime
|
||||
except FileNotFoundError:
|
||||
flash(u'Image {filename} inexistante.'.format(filename=filename), 'error')
|
||||
return redirect(url_for('gallery'))
|
||||
|
||||
56
views/gallery.py
Normal file
56
views/gallery.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file, flash, abort, send_file, send_from_directory
|
||||
from werkzeug.utils import secure_filename
|
||||
from markupsafe import escape
|
||||
from PIL import Image
|
||||
import time
|
||||
import sqlite3
|
||||
import os
|
||||
|
||||
|
||||
mygallery = Blueprint('mygallery', __name__, template_folder='templates')
|
||||
|
||||
app = Flask( 'pywallter' )
|
||||
app.config.from_pyfile('config.py')
|
||||
|
||||
|
||||
#### Variables ####################################################################################
|
||||
|
||||
DOSSIER_PERSO= app.config['DOSSIER_APP']
|
||||
|
||||
extensionimg = app.config['EXT_IMG']
|
||||
|
||||
DATABASE = app.config['DATABASE']
|
||||
##################################################################################################
|
||||
|
||||
@mygallery.route( '/gallery/')
|
||||
def gallery():
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
THUMBNAILS=DOSSIER_PERSO + UTILISATEUR + '/images/thumbnails/'
|
||||
fichiers = [fich for fich in os.listdir(THUMBNAILS)]
|
||||
return render_template('gallery.html',
|
||||
section='Gallery',
|
||||
THUMBNAILS=THUMBNAILS,
|
||||
fichiers=fichiers)
|
||||
else :
|
||||
return redirect(url_for('loginlogout.login'), code=401)
|
||||
|
||||
@mygallery.route('/myfiles/images/<filename>')
|
||||
def myimg(filename):
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
return send_from_directory(
|
||||
os.path.join(DOSSIER_PERSO, UTILISATEUR, 'images'), filename )
|
||||
else :
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
@mygallery.route('/myfiles/images/thumbnails/<filename>')
|
||||
def mythumbnails(filename):
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
return send_from_directory(
|
||||
os.path.join(DOSSIER_PERSO, UTILISATEUR, 'images/thumbnails'), filename )
|
||||
else :
|
||||
return redirect(BASE_URL, code=401)
|
||||
@@ -1,63 +1,153 @@
|
||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file, escape
|
||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file
|
||||
from flask_bcrypt import Bcrypt
|
||||
|
||||
import sqlite3
|
||||
import glob, os, sys, time
|
||||
|
||||
from tools.utils import email_disp, valid_token_register, valid_passwd, valid_username
|
||||
from socket import gethostname
|
||||
|
||||
app = Flask( 'pywallter' )
|
||||
app.config.from_pyfile('config.py')
|
||||
bcrypt = Bcrypt(app)
|
||||
|
||||
DOSSIER_PERSO='users/'
|
||||
#### Variables ##################################################################################
|
||||
|
||||
|
||||
DATAS_USER = app.config['DOSSIER_APP']
|
||||
extensionimg = app.config['EXT_IMG']
|
||||
DATABASE = app.config['DATABASE']
|
||||
MAIL_SERVER = app.config['MAIL_SERVER']
|
||||
XMPP_SERVER = app.config['XMPP_SERVER']
|
||||
SETUID = app.config['SETUID']
|
||||
BASE_URL = app.config['BASE_URL']
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
||||
|
||||
inscription = Blueprint('inscription', __name__, template_folder='templates')
|
||||
|
||||
@inscription.route( '/inscription/', methods=['GET','POST'] )
|
||||
def signin() :
|
||||
if 'username' in session :
|
||||
return redirect(url_for('filesupload'))
|
||||
else :
|
||||
if request.method == 'POST' :
|
||||
conn = sqlite3.connect('base.db') # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
user = request.form['user']
|
||||
mail = request.form['mail']
|
||||
passwd = bcrypt.generate_password_hash(request.form['passwd'])
|
||||
passwdconfirm = request.form['passwdconfirm']
|
||||
cursor.execute("""SELECT name FROM users WHERE name=?""", (user,))
|
||||
testuser=cursor.fetchone()
|
||||
cursor.execute("""SELECT mail FROM users WHERE mail=?""", (mail,))
|
||||
testmail=cursor.fetchone()
|
||||
conn.close()
|
||||
if testuser or testmail:
|
||||
flash(u'Non d\'utilisateur ou email déjà utilisé, merci d\'en choisir un autre', 'error')
|
||||
return render_template('inscription.html')
|
||||
else:
|
||||
confirmation = bcrypt.check_password_hash(passwd, passwdconfirm)
|
||||
if confirmation is True:
|
||||
conn = sqlite3.connect('base.db') # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""INSERT INTO users(name, mail, passwd) VALUES(?, ?, ?)""", (user, mail, passwd)) # Insérer des valeurs
|
||||
conn.commit() # Sauvegarder valeurs dans la bdd
|
||||
cursor.execute("""SELECT name, mail, passwd FROM users""")
|
||||
users = cursor.fetchall()
|
||||
for i in users:
|
||||
i = print('{0} - {1} - {2}'.format(i[0], i[1], i[2]))
|
||||
conn.close()
|
||||
userracine = DOSSIER_PERSO + user
|
||||
userfiles = userracine + '/files'
|
||||
userimages = userracine + '/images'
|
||||
userthumbnails = userracine + '/images/thumbnails'
|
||||
userprofile = userracine + '/profile'
|
||||
if not os.path.exists(userracine):
|
||||
os.makedirs(userracine)
|
||||
os.makedirs(userfiles)
|
||||
os.makedirs(userimages)
|
||||
os.makedirs(userthumbnails)
|
||||
os.makedirs(userprofile)
|
||||
flash(u'Inscription réalisée avec succés !', 'succes')
|
||||
return render_template('login.html')
|
||||
else:
|
||||
flash(u'Les mots de passe ne sont pas identiques !', 'error')
|
||||
return render_template('inscription.html')
|
||||
@inscription.route( '/inscription/<token>', methods=['GET','POST'] )
|
||||
def signin(token) :
|
||||
hostname = gethostname()
|
||||
url_inscription = url_for('loginlogout.index', _external=True)+'inscription/'+token
|
||||
resp = None
|
||||
if valid_token_register(token):
|
||||
if 'username' in session :
|
||||
resp = redirect(url_for('profil.profile', _external=True))
|
||||
else :
|
||||
return render_template('inscription.html')
|
||||
|
||||
# Réponse si la requete est de type GET ou si la requete POST echoue
|
||||
resp = render_template('inscription.html',
|
||||
signin_enable=app.config['SIGNIN_ENABLE'],
|
||||
token=token, hostname=hostname,
|
||||
url_inscription=url_inscription,
|
||||
MAIL_SERVER=MAIL_SERVER, XMPP_SERVER=XMPP_SERVER)
|
||||
|
||||
|
||||
if request.method == 'POST':
|
||||
|
||||
#On test si aucun champs du formulaire n'est vide.
|
||||
if len(request.form['user']) == 0 or \
|
||||
len(request.form['passwd']) == 0 or \
|
||||
len(request.form['passwdconfirm']) == 0:
|
||||
|
||||
flash(u'Il faut remplir le formulaire en entier, les champs ne peuvent pas etre vide ', 'error')
|
||||
return render_template('inscription.html',
|
||||
signin_enable=app.config['SIGNIN_ENABLE'],
|
||||
token=token, hostname=hostname,
|
||||
url_inscription=url_inscription,
|
||||
MAIL_SERVER=MAIL_SERVER, XMPP_SERVER=XMPP_SERVER)
|
||||
|
||||
|
||||
user = request.form['user']
|
||||
passwd = request.form['passwd']
|
||||
passwdconfirm = request.form['passwdconfirm']
|
||||
bcrypt_passwd = bcrypt.generate_password_hash(request.form['passwd'])
|
||||
mail_passwd_change = 0
|
||||
|
||||
password_valid = valid_passwd(passwd)
|
||||
not_error = True
|
||||
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
|
||||
cursor.execute("""SELECT name FROM users WHERE name=?""", (user,))
|
||||
testuser = cursor.fetchone()
|
||||
conn.close()
|
||||
|
||||
if testuser and valid_username(user):
|
||||
flash(u'Non d\'utilisateur déjà utilisé ou contient des caractères invalides, merci d\'en choisir un autre', 'error')
|
||||
flash(u'Les caractères espaces et \' ( ) < > , ; : " [ ] | ç % & ne sont pas autorisés', 'error')
|
||||
not_error = False
|
||||
|
||||
if not(password_valid):
|
||||
flash (u'Les caractère & et " ne sont pas autorisé dans les mots de passe', 'error')
|
||||
not_error = False
|
||||
|
||||
if MAIL_SERVER:
|
||||
mail = user.lower()+'@'+hostname
|
||||
if not(email_disp(mail)) :
|
||||
flash(u'Cette Adresse email est déjà utilisée , merci d\'en choisir une autre', 'error')
|
||||
not_error = False
|
||||
|
||||
if not_error:
|
||||
confirmation = bcrypt.check_password_hash(bcrypt_passwd, passwdconfirm)
|
||||
if confirmation is False:
|
||||
flash(u'Les mots de passe ne sont pas identiques !', 'error')
|
||||
else:
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""INSERT INTO users(name, mail, passwd) VALUES(?, ?, ?)""", (user, mail, bcrypt_passwd)) # Insérer des valeurs
|
||||
conn.commit() # Sauvegarder valeurs dans la bdd
|
||||
|
||||
# On change le mot de passe du compte mail
|
||||
if MAIL_SERVER:
|
||||
cmd = SETUID + ' set_mail_passwd ' + '"'+mail+'" ' + '"'+passwd+'"'
|
||||
mail_passwd_change = os.system(cmd)
|
||||
if mail_passwd_change != 0:
|
||||
flash(u'Il y a eu une problème lors du changement de mot passe pour le compte Mail', 'error')
|
||||
|
||||
# On change le mot de passe du compte XMPP
|
||||
if XMPP_SERVER:
|
||||
tmp = mail.split('@')
|
||||
cmd = SETUID+ ' prosodyctl register ' "'"+tmp[0]+"' " + "'"+tmp[1]+"' " + "'"+passwd+"'"
|
||||
res = os.system(cmd)
|
||||
if res != 0:
|
||||
flash(u'Il y a eu un problème pour la création du compte XMPP !', 'error')
|
||||
|
||||
# on créé les dossier de l'utilisateur
|
||||
userracine = DATAS_USER + user
|
||||
userfiles = userracine + '/files'
|
||||
userimages = userracine + '/images'
|
||||
userthumbnails = userracine + '/images/thumbnails'
|
||||
userprofile = userracine + '/profile'
|
||||
userlog = userracine + '/log.txt'
|
||||
if not os.path.exists(userracine):
|
||||
os.makedirs(userracine)
|
||||
os.makedirs(userfiles)
|
||||
os.makedirs(userimages)
|
||||
os.makedirs(userthumbnails)
|
||||
os.makedirs(userprofile)
|
||||
fp = open(userlog, 'x')
|
||||
fp.close()
|
||||
|
||||
|
||||
# Une fois que tout c'est bien passé pour l'inscription on détruit le jeton.
|
||||
cursor.execute("""SELECT name, invitations FROM users where Token=?""", (token,))
|
||||
tmp = cursor.fetchone()
|
||||
username = tmp[0]
|
||||
invitations_count=tmp[1] - 1
|
||||
if username == "pywallter":
|
||||
cursor.execute("""DELETE from users where name = ?""", (username,))
|
||||
else:
|
||||
cursor.execute("""UPDATE users set invitations=?, Token='' where name=?""", (invitations_count, username,))
|
||||
conn.commit()
|
||||
|
||||
flash(u'Inscription réalisée avec succés !', 'succes')
|
||||
resp = redirect(url_for('loginlogout.login'))
|
||||
|
||||
else:
|
||||
resp = redirect(BASE_URL, code=401)
|
||||
|
||||
return resp
|
||||
|
||||
@@ -1,33 +1,185 @@
|
||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file, escape
|
||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file
|
||||
import sqlite3
|
||||
from markupsafe import escape
|
||||
from flask_bcrypt import Bcrypt
|
||||
from socket import gethostname
|
||||
from os import remove, system
|
||||
from tools.utils import email_disp, valid_token_register, valid_passwd, valid_username, gen_token
|
||||
from tools.mailer import Mailer
|
||||
|
||||
app = Flask( 'pywallter' )
|
||||
app.config.from_pyfile('config.py')
|
||||
bcrypt = Bcrypt(app)
|
||||
|
||||
#### Variables ####################################################################################
|
||||
|
||||
bcrypt = Bcrypt(app)
|
||||
DATAS_USER = app.config['DOSSIER_APP']
|
||||
|
||||
extensionimg = app.config['EXT_IMG']
|
||||
|
||||
DATABASE = app.config['DATABASE']
|
||||
|
||||
BASE_URL = app.config['BASE_URL']
|
||||
SETUID = app.config['SETUID']
|
||||
MAIL_SERVER = app.config['MAIL_SERVER']
|
||||
XMPP_SERVER = app.config['XMPP_SERVER']
|
||||
BACKUP_TIME = app.config['BACKUP_TIME']
|
||||
##################################################################################################
|
||||
|
||||
|
||||
loginlogout = Blueprint('loginlogout', __name__, template_folder='templates')
|
||||
|
||||
@loginlogout.route( '/login/', methods=['GET','POST'] )
|
||||
def login() :
|
||||
if 'username' in session :
|
||||
return redirect(url_for('filesupload.uploadfiles', _external=True))
|
||||
resp = redirect(url_for('profil.profile', _external=True))
|
||||
else :
|
||||
resp = redirect(url_for('loginlogout.login', _external=True))
|
||||
if request.method == 'POST' :
|
||||
conn = sqlite3.connect('base.db') # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT name, passwd FROM users""")
|
||||
users = cursor.fetchall()
|
||||
conn.close()
|
||||
user = request.form['user']
|
||||
password = request.form['passwd']
|
||||
for i in users:
|
||||
if i[0] == request.form['user'] and bcrypt.check_password_hash(i[1], password) is True:
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT name, passwd FROM users WHERE name=?""", (user,))
|
||||
user_exist = cursor.fetchone()
|
||||
conn.close()
|
||||
|
||||
if user_exist:
|
||||
user = user_exist[0]
|
||||
passwd_bcrypt = user_exist[1].decode()
|
||||
|
||||
if user == request.form['user'] and bcrypt.check_password_hash(passwd_bcrypt, password) is True:
|
||||
session['username'] = request.form['user']
|
||||
return redirect(url_for('filesupload.uploadfiles', _external=True))
|
||||
return redirect(url_for('loginlogout.login', _external=True))
|
||||
resp = redirect(url_for('profil.profile', _external=True))
|
||||
else:
|
||||
flash(u'Mauvais mot de passe', 'error')
|
||||
else:
|
||||
flash(u"L'utilisateur n'existe pas", 'error')
|
||||
else:
|
||||
return render_template('login.html')
|
||||
resp = render_template('accueil.html', signin_enable=app.config['SIGNIN_ENABLE'])
|
||||
return resp
|
||||
|
||||
|
||||
@loginlogout.route( '/logout/' )
|
||||
def logout():
|
||||
session.pop('username', None) # Supprimer username de la session s'il s'y trouve
|
||||
return redirect(url_for('index'))
|
||||
return redirect(url_for('loginlogout.index'))
|
||||
|
||||
|
||||
@loginlogout.route( '/delete_me/', methods=['GET','POST'])
|
||||
def delete_account():
|
||||
if 'username' in session :
|
||||
user='%s'% escape(session['username'])
|
||||
resp = render_template('delete_account.html', time_backup=BACKUP_TIME)
|
||||
if request.method == 'POST' :
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT passwd FROM users WHERE name=?""", (user,))
|
||||
passwd = cursor.fetchone()[0].decode()
|
||||
conn.close()
|
||||
password = request.form['passwd']
|
||||
if bcrypt.check_password_hash(passwd, password) is True:
|
||||
not_error = True
|
||||
try:
|
||||
cmd = 'rm -r ' + DATAS_USER + '/' + user
|
||||
if system(cmd) != 0:
|
||||
raise TypeError("Remove directory error")
|
||||
except:
|
||||
not_error = False
|
||||
flash(u'Erreur lors de la suppression de votre dossier utilisateur.', 'error')
|
||||
|
||||
if MAIL_SERVER:
|
||||
try:
|
||||
cmd = SETUID + ' set_mail_passwd del' + '"'+mail+'"'
|
||||
system(cmd)
|
||||
except:
|
||||
not_error = False
|
||||
flash(u'Erreur lors de la suppression de votre compte Mail.', 'error')
|
||||
|
||||
if XMPP_SERVER:
|
||||
try:
|
||||
tmp = mail.split('@')
|
||||
cmd = SETUID+ ' prosodyctl deluser ' "'"+tmp[0]+"' " + "'"+tmp[1]+"'"
|
||||
system(cmd)
|
||||
except:
|
||||
not_error = False
|
||||
flash(u'Erreur lors de la suppression de votre compte XMPP.', 'error')
|
||||
|
||||
if not_error:
|
||||
try:
|
||||
conn = sqlite3.connect(DATABASE)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""DELETE FROM users WHERE name=?""", (user,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
except:
|
||||
flash(u'Erreur lors de la suppression de votre compte.', 'error')
|
||||
else:
|
||||
flash(u'Désinscription réalisé avec succés, y\'a plus rien !', 'succes')
|
||||
resp = redirect(url_for('loginlogout.logout'))
|
||||
else:
|
||||
flash(u'Mauvais mot de passe', 'error')
|
||||
return resp
|
||||
|
||||
|
||||
@loginlogout.route( '/lost_password/', methods=['GET', 'POST'])
|
||||
def lost_password():
|
||||
if request.method == 'POST' :
|
||||
user = request.form['user']
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT name, Mail_rescue FROM users WHERE name=?""", (user,))
|
||||
find_user = cursor.fetchone()
|
||||
|
||||
if find_user:
|
||||
token = gen_token("Lost password")
|
||||
cursor.execute("UPDATE users SET Lost_password_token=? WHERE name=?",
|
||||
(token, user))
|
||||
conn.commit()
|
||||
mail_lost_password=Mailer()
|
||||
message = """
|
||||
"Vous avez fait une demande pour changer votre mot de passe, cliquez sur le liens en
|
||||
dessous pour changer votre mot de passe :
|
||||
"""+ BASE_URL + url_for('profil.change_passwd_lost', token=token) + """
|
||||
|
||||
Si ce n'est pas vous qui avez fait cette demande vous pouvez détruire le lien de changement
|
||||
de mot de passe en cliquant sur le lien en dessous \n
|
||||
"""+ BASE_URL + url_for('profil.deltoken_passwd_lost', token=token) + """
|
||||
|
||||
|
||||
Au plaisir de vous revoir sur pywallter """
|
||||
|
||||
if find_user[1]:
|
||||
flash(u"Un lien pour changer votre mot de passe a été envoyer à votre adresse email de secour ", 'succes')
|
||||
mail_lost_password.send_email(find_user[1], "Récupération de votre mot de passe", message )
|
||||
else:
|
||||
flash(u"L'utilisateur "+ user + " n'existe pas.", 'error')
|
||||
|
||||
|
||||
return render_template('lost_password.html')
|
||||
|
||||
@loginlogout.route( '/' )
|
||||
def index():
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT token passwd FROM users where name=? """, ("pywallter", ))
|
||||
tmp = cursor.fetchone()
|
||||
conn.close
|
||||
if tmp:
|
||||
token = tmp[0]
|
||||
else:
|
||||
token = None
|
||||
|
||||
if 'username' in session :
|
||||
return redirect(url_for('profil.profile'))
|
||||
else :
|
||||
if token:
|
||||
hostname = gethostname()
|
||||
url_inscription = BASE_URL+'inscription/'+token
|
||||
return render_template('inscription.html', signin_enable=app.config['SIGNIN_ENABLE'],
|
||||
token=token, hostname=hostname,
|
||||
url_inscription=url_inscription,
|
||||
MAIL_SERVER=MAIL_SERVER)
|
||||
else:
|
||||
return redirect(url_for('loginlogout.login', _external=True))
|
||||
|
||||
@@ -1,16 +1,32 @@
|
||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file, escape
|
||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file
|
||||
import glob, os, sys
|
||||
from markupsafe import escape
|
||||
|
||||
logs = Blueprint('logs', __name__, template_folder='templates')
|
||||
|
||||
app = Flask( 'pywallter' )
|
||||
app.config.from_pyfile('config.py')
|
||||
|
||||
|
||||
#### Variables ####################################################################################
|
||||
|
||||
DOSSIER_PERSO= app.config['DOSSIER_APP']
|
||||
|
||||
extensionimg = app.config['EXT_IMG']
|
||||
|
||||
DATABASE = app.config['DATABASE']
|
||||
##################################################################################################
|
||||
|
||||
|
||||
@logs.route('/logs/')
|
||||
def logfile():
|
||||
if 'username' in session :
|
||||
with open('log.txt', 'r') as log:
|
||||
if 'username' in session:
|
||||
UTILISATEUR='%s'% escape(session['username'])
|
||||
log_file=os.path.join(DOSSIER_PERSO, UTILISATEUR, "log.txt")
|
||||
with open(log_file, 'r') as log:
|
||||
print("on passe ici")
|
||||
logs=log.readlines()
|
||||
log.close()
|
||||
for line in logs:
|
||||
return render_template('logs.html', logs=logs, line=line)
|
||||
return render_template('logs.html', section="Logs", logs=logs)
|
||||
else :
|
||||
return redirect(url_for('loginlogout.login', _external=True))
|
||||
|
||||
return redirect(url_for('loginlogout.login', _external=True), code=401)
|
||||
|
||||
531
views/profil.py
531
views/profil.py
@@ -1,80 +1,475 @@
|
||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file, escape, flash, abort
|
||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file, flash, abort, send_from_directory
|
||||
from werkzeug.utils import secure_filename
|
||||
from PIL import Image
|
||||
from markupsafe import escape
|
||||
import time
|
||||
import sqlite3
|
||||
import os
|
||||
from socket import gethostname
|
||||
from flask_bcrypt import Bcrypt
|
||||
from tools.utils import email_disp, append_to_log, gen_token, valid_passwd, valid_token_register, get_user_by_token
|
||||
|
||||
profil = Blueprint('profil', __name__, template_folder='templates')
|
||||
|
||||
DOSSIER_PERSO='users/'
|
||||
extensionimg = {'.jpg', '.JPG', '.png', '.PNG', '.gif', '.GIF', '.bmp', '.BMP', '.jpeg', '.JPEG' }
|
||||
app = Flask( 'pywallter' )
|
||||
app.config.from_pyfile('config.py')
|
||||
|
||||
@profil.route('/profil/<username>/', methods=['GET','POST'] )
|
||||
def profile(username=None) :
|
||||
|
||||
#### Variables ####################################################################################
|
||||
|
||||
bcrypt = Bcrypt(app)
|
||||
DOSSIER_PERSO = app.config['DOSSIER_APP']
|
||||
|
||||
extensionimg = app.config['EXT_IMG']
|
||||
|
||||
DATABASE = app.config['DATABASE']
|
||||
DATAS_USER = app.config['DOSSIER_APP']
|
||||
MAIL_SERVER = app.config['MAIL_SERVER']
|
||||
XMPP_SERVER = app.config['XMPP_SERVER']
|
||||
SETUID = app.config['SETUID']
|
||||
BASE_URL = app.config['BASE_URL']
|
||||
BACKUP_TIME = app.config['BACKUP_TIME']
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
||||
@profil.route( '/profil/<user>/<img>', methods=['GET'] )
|
||||
def profil_img(user, img) :
|
||||
if 'username' in session :
|
||||
|
||||
return send_from_directory( os.path.join(DOSSIER_PERSO, user, 'profile'), img )
|
||||
else:
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
|
||||
|
||||
@profil.route('/profil/', methods=['GET','POST'] )
|
||||
def profile() :
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
conn = sqlite3.connect('base.db') # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT avatar FROM users WHERE name=?""", (username,))
|
||||
imageprofil = cursor.fetchone()
|
||||
conn.close()
|
||||
if request.method == 'POST' :
|
||||
f = request.files['fic']
|
||||
nom = request.form['nom']
|
||||
prenom = request.form['prenom']
|
||||
age = request.form['age']
|
||||
profession = request.form['profession']
|
||||
if f: # On vérifie qu'un fichier a bien été envoyé
|
||||
nom = secure_filename(f.filename)
|
||||
f.save(DOSSIER_PERSO + UTILISATEUR + '/profile/' + nom)
|
||||
image = DOSSIER_PERSO + UTILISATEUR + '/profile/' + nom
|
||||
with Image.open(image) as img:
|
||||
img.tumbnails(resize='80x80')
|
||||
img.save(filename = DOSSIER_PERSO + UTILISATEUR + '/profile/' + nom)
|
||||
imagelocation = DOSSIER_PERSO + UTILISATEUR + '/profile/' + nom
|
||||
conn = sqlite3.connect('base.db') # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("UPDATE users SET avatar=? WHERE name=?", (imagelocation, username))
|
||||
conn.commit()
|
||||
cursor.execute("""SELECT avatar FROM users WHERE name=?""", (username,))
|
||||
imageprofil = cursor.fetchone()
|
||||
conn.close()
|
||||
flash(u'Image de profil mise à jour', 'succes')
|
||||
return render_template('profil.html', imageprofil=imageprofil, username=username)
|
||||
else:
|
||||
# return render_template('profil.html', imageprofil=imageprofil, username=username)
|
||||
####### Informations personnelles #######
|
||||
if nom:
|
||||
if prenom:
|
||||
if age:
|
||||
if profession:
|
||||
conn = sqlite3.connect('base.db') # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("UPDATE users SET nom=?, prenom=?, age=?, profession=? WHERE name=?""", (nom, prenom, age, profession, username,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
flash(u'Informations transmisent à la base', 'succes')
|
||||
return render_template('profil.html', imageprofil=imageprofil, username=username)
|
||||
else:
|
||||
flash(u'Veuillez renseigner une profession', 'error')
|
||||
return render_template('profil.html', imageprofil=imageprofil, username=username)
|
||||
else:
|
||||
flash(u'Veuillez renseigner votre âge', 'error')
|
||||
return render_template('profil.html', imageprofil=imageprofil, username=username)
|
||||
else:
|
||||
flash(u'Veuillez renseigner votre prénom', 'error')
|
||||
return render_template('profil.html', imageprofil=imageprofil, username=username)
|
||||
else:
|
||||
flash(u'Veuillez renseigner votre nom', 'error')
|
||||
return render_template('profil.html', imageprofil=imageprofil, username=username)
|
||||
else:
|
||||
conn = sqlite3.connect('base.db') # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT avatar FROM users WHERE name=?""", (username,))
|
||||
imageprofil = cursor.fetchone()
|
||||
conn.close()
|
||||
return render_template('profil.html', imageprofil=imageprofil, username=username)
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT avatar, nom, prenom, age, Mail_rescue FROM users WHERE name=?""", (UTILISATEUR,))
|
||||
tmp = (cursor.fetchone())
|
||||
profil_user = dict()
|
||||
profil_user['avatar'] = tmp[0]
|
||||
profil_user['nom'] = tmp[1]
|
||||
profil_user['prenom'] = tmp[2]
|
||||
profil_user['age'] = tmp[3]
|
||||
profil_user['mail_rescue'] = tmp[4]
|
||||
conn.close()
|
||||
|
||||
if request.method == 'POST' :
|
||||
|
||||
f = request.files['fic']
|
||||
if request.form['nom']:
|
||||
profil_user['nom'] = request.form['nom']
|
||||
if request.form['prenom']:
|
||||
profil_user['prenom'] = request.form['prenom']
|
||||
if request.form['age']:
|
||||
profil_user['age'] = request.form['age']
|
||||
if '@' in request.form['mail_rescue']:
|
||||
if len(request.form['mail_rescue']) > 4:
|
||||
profil_user['mail_rescue'] = request.form['mail_rescue']
|
||||
else:
|
||||
flash(u'Adresse de courriel invalide', 'error')
|
||||
else:
|
||||
flash(u'Adresse de courriel invalide', 'error')
|
||||
if f: # On vérifie qu'un fichier a bien été envoyé
|
||||
nom = secure_filename(f.filename)
|
||||
f.save(DOSSIER_PERSO + UTILISATEUR + '/profile/' + nom)
|
||||
image = DOSSIER_PERSO + UTILISATEUR + '/profile/' + nom
|
||||
with Image.open(image) as img:
|
||||
img.thumbnail((300,200))
|
||||
img.save( DOSSIER_PERSO + UTILISATEUR + '/profile/' + nom)
|
||||
filename = nom
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("UPDATE users SET avatar=? WHERE name=?",
|
||||
(filename, UTILISATEUR))
|
||||
conn.commit()
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
conn.close()
|
||||
flash(u'Image de profil mise à jour', 'succes')
|
||||
|
||||
else:
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l\'objet "curseur"
|
||||
cursor.execute("UPDATE users SET nom=?, prenom=?, age=?, mail_rescue=? WHERE name=?",
|
||||
(profil_user['nom'], profil_user['prenom'], profil_user['age'], profil_user['mail_rescue'],
|
||||
UTILISATEUR))
|
||||
conn.commit()
|
||||
flash(u'Le profil a été mis à jour', 'succes')
|
||||
|
||||
|
||||
|
||||
|
||||
return render_template('profil.html',
|
||||
section="Profil",
|
||||
profil=profil_user,
|
||||
username=UTILISATEUR)
|
||||
|
||||
else :
|
||||
return redirect(url_for('loginlogout.login', _external=True))
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
@profil.route('/profil/change-password/', methods=['GET','POST'] )
|
||||
def change_passwd() :
|
||||
if 'username' in session:
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT Mail, alias, xmpp FROM users WHERE name=?""", (UTILISATEUR,))
|
||||
tmp = cursor.fetchone()
|
||||
mailbox = dict()
|
||||
mailbox['Mail'] = tmp[0]
|
||||
mailbox['alias'] = tmp[1]
|
||||
mailbox['xmpp'] = tmp[2]
|
||||
|
||||
|
||||
if request.method == 'POST' :
|
||||
|
||||
password = request.form['password']
|
||||
password_confirm = request.form['passwd_confirm']
|
||||
|
||||
if password == password_confirm and valid_passwd(password):
|
||||
mail_passwd_change = 0
|
||||
xmpp_passwd_change = 0
|
||||
passwd = request.form['password']
|
||||
|
||||
if MAIL_SERVER:
|
||||
cmd = SETUID+ ' set_mail_passwd ' + '"'+mailbox['Mail']+'" '+ '"'+passwd+'"'
|
||||
mail_passwd_change = os.system(cmd)
|
||||
|
||||
|
||||
if XMPP_SERVER:
|
||||
tmp = mailbox['Mail'].split('@')
|
||||
cmd = SETUID+ " prosodyctl register '"+tmp[0]+"' " + "'"+tmp[1]+"' " + "'"+passwd+"'"
|
||||
xmpp_passwd_change = os.system(cmd)
|
||||
if xmpp_passwd_change != 0:
|
||||
flash(u'Il y a eu un problème pour le changement du mot de passe du compte XMPP !', 'error')
|
||||
|
||||
|
||||
if mail_passwd_change == 0:
|
||||
passwd_bcrypt = bcrypt.generate_password_hash(passwd)
|
||||
cursor.execute("UPDATE users SET passwd=? WHERE name=?",
|
||||
(passwd_bcrypt, UTILISATEUR))
|
||||
conn.commit()
|
||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
||||
IP=request.environ['REMOTE_ADDR']
|
||||
CLIENT_PLATFORM=request.headers.get('User-Agent')
|
||||
log=TIME + ' - ' + IP + ' - ' + UTILISATEUR + ' - ' + CLIENT_PLATFORM + '\n' + '---> ' + "Changement du mot de passe" + '\n'
|
||||
append_to_log(log, UTILISATEUR)
|
||||
flash(u'Votre mot de passe a été changé', 'succes')
|
||||
else:
|
||||
if not( valid_passwd(password) ):
|
||||
flash(u'Le mot de passe ne peut pas contenir les caractères " et &', 'error')
|
||||
else:
|
||||
flash(u'Les mot de passes ne sont pas identique :/ ', 'error')
|
||||
|
||||
conn.close()
|
||||
return render_template('mailbox.html',
|
||||
section="Profil",
|
||||
address=mailbox['Mail'],
|
||||
alias=mailbox['alias'],
|
||||
username=UTILISATEUR)
|
||||
|
||||
else :
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
|
||||
@profil.route('/change-password-lost/<token>', methods=['GET','POST'] )
|
||||
def change_passwd_lost(token) :
|
||||
|
||||
if valid_token_register(token, "Lost password"):
|
||||
|
||||
user = get_user_by_token(token, "Lost password")
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT Mail, alias, xmpp FROM users WHERE name=?""", (user,))
|
||||
tmp = cursor.fetchone()
|
||||
mailbox = dict()
|
||||
mailbox['Mail'] = tmp[0]
|
||||
mailbox['alias'] = tmp[1]
|
||||
mailbox['xmpp'] = tmp[2]
|
||||
|
||||
|
||||
if request.method == 'GET' :
|
||||
return render_template('mailbox.html',
|
||||
section="Profil",
|
||||
address=mailbox['Mail'],
|
||||
username=user)
|
||||
else:
|
||||
|
||||
password = request.form['password']
|
||||
password_confirm = request.form['passwd_confirm']
|
||||
|
||||
if password == password_confirm and valid_passwd(password):
|
||||
mail_passwd_change = 0
|
||||
xmpp_passwd_change = 0
|
||||
|
||||
|
||||
if MAIL_SERVER:
|
||||
cmd = SETUID+ ' set_mail_passwd ' + '"'+mailbox['Mail']+'" '+ '"'+password+'"'
|
||||
mail_passwd_change = os.system(cmd)
|
||||
|
||||
if XMPP_SERVER:
|
||||
tmp = mailbox['Mail'].split('@')
|
||||
cmd = SETUID+ " prosodyctl register '"+tmp[0]+"' " + "'"+tmp[1]+"' " + "'"+password+"'"
|
||||
xmpp_change_passwd = os.system(cmd)
|
||||
if xmpp_passwd_change != 0:
|
||||
flash(u'Il y a eu un problème pour le changement du mot de passe du compte XMPP !', 'error')
|
||||
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
|
||||
if mail_passwd_change == 0:
|
||||
passwd_bcrypt = bcrypt.generate_password_hash(password)
|
||||
cursor.execute("UPDATE users SET passwd=? WHERE name=?",
|
||||
(passwd_bcrypt, user))
|
||||
conn.commit()
|
||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
||||
IP=request.environ['REMOTE_ADDR']
|
||||
CLIENT_PLATFORM=request.headers.get('User-Agent')
|
||||
log=TIME + ' - ' + IP + ' - ' + user + ' - ' + CLIENT_PLATFORM + '\n' + '---> ' + "Changement du mot de passe" + '\n'
|
||||
append_to_log(log, user)
|
||||
flash(u'Votre mot de passe a été changé', 'succes')
|
||||
cursor.execute("""UPDATE users set Lost_password_token='' where name=?""", (user,))
|
||||
conn.close()
|
||||
resp = redirect(url_for('loginlogout.login'))
|
||||
|
||||
else:
|
||||
if not( valid_passwd(password) ):
|
||||
flash(u'Le mot de passe ne peut pas contenir les caractères " et &', 'error')
|
||||
else:
|
||||
flash(u'Les mot de passes ne sont pas identique :/ ', 'error')
|
||||
|
||||
resp = render_template('mailbox.html',
|
||||
section="Profil",
|
||||
address=mailbox['Mail'],
|
||||
username=user)
|
||||
|
||||
return resp
|
||||
else:
|
||||
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
|
||||
@profil.route('/deltoken-password-lost/<token>', methods=['GET','POST'] )
|
||||
def deltoken_passwd_lost(token) :
|
||||
|
||||
if valid_token_register(token, "Lost password"):
|
||||
user = get_user_by_token(token, "Lost password")
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
|
||||
cursor.execute("""UPDATE users set Lost_password_token='' where name=?""", (user,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
flash(u'Votre jeton pour changer votre mot de passe a été supprimé', 'succes')
|
||||
else:
|
||||
flash(u'Votre jeton est invalide', 'succes')
|
||||
return redirect(url_for('loginlogout.login', _external=True))
|
||||
|
||||
|
||||
@profil.route('/mymailbox/alias', methods=['GET', 'POST'] )
|
||||
def myalias():
|
||||
hostname=gethostname()
|
||||
if 'username' in session:
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
if request.method == 'POST' and MAIL_SERVER:
|
||||
if request.form['alias']:
|
||||
alias = request.form['alias'].lower()+'@'+hostname
|
||||
else:
|
||||
flash(u'Addresse invalide')
|
||||
|
||||
if email_disp(alias):
|
||||
cursor.execute("""SELECT Mail, alias FROM users where name=?""", (UTILISATEUR,))
|
||||
tmp = cursor.fetchone()
|
||||
mail = tmp[0]
|
||||
if tmp[1]:
|
||||
alias_list = tmp[1]
|
||||
aliases = alias_list + "," +alias
|
||||
else:
|
||||
aliases = alias
|
||||
cmd = SETUID+ " set_mail_alias " + "'"+mail+"'"+" add "+"'"+alias+"'"
|
||||
res = os.system(cmd)
|
||||
if res == 0:
|
||||
cursor.execute("UPDATE users SET alias=? WHERE name=?",
|
||||
(aliases, UTILISATEUR))
|
||||
conn.commit()
|
||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
||||
IP=request.environ['REMOTE_ADDR']
|
||||
CLIENT_PLATFORM=request.headers.get('User-Agent')
|
||||
|
||||
log=TIME + ' - ' + IP + ' - ' + UTILISATEUR + ' - ' + CLIENT_PLATFORM + '\n' + '---> ' + "Ajout de l'alias "+ alias + '\n'
|
||||
append_to_log(log, UTILISATEUR)
|
||||
flash(u'Votre alias a été ajouté', 'succes')
|
||||
else:
|
||||
flash(u'Adresse indisponible', 'error')
|
||||
else:
|
||||
flash(u'Adresse indisponible', 'error')
|
||||
|
||||
cursor.execute("""SELECT Mail, alias FROM users WHERE name=?""",
|
||||
(UTILISATEUR,))
|
||||
tmp = cursor.fetchone()
|
||||
mailbox = dict()
|
||||
mailbox['Mail'] = tmp[0]
|
||||
if tmp[1]:
|
||||
mailbox['alias'] = tmp[1].split(',')
|
||||
else:
|
||||
mailbox['alias'] = list()
|
||||
conn.close()
|
||||
return render_template('myalias.html',
|
||||
section="mailbox",
|
||||
email=mailbox['Mail'],
|
||||
aliases=mailbox['alias'],
|
||||
hostname=hostname,
|
||||
MAIL_SERVER=MAIL_SERVER,
|
||||
username=UTILISATEUR )
|
||||
|
||||
else:
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
@profil.route('/mymailbox/rmalias/<aliasrm>')
|
||||
def remove_alias(aliasrm):
|
||||
if 'username' in session:
|
||||
if MAIL_SERVER:
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT Mail, alias FROM users WHERE name=?""", (UTILISATEUR,))
|
||||
tmp = cursor.fetchone()
|
||||
mail = tmp[0]
|
||||
alias_list = tmp[1].split(',')
|
||||
aliases = ""
|
||||
for alias in alias_list:
|
||||
if alias != aliasrm:
|
||||
if aliases:
|
||||
aliases = aliases + "," + alias
|
||||
else:
|
||||
aliases = alias
|
||||
cmd = SETUID + " set_mail_alias " + "'"+mail+"'"+" del "+"'"+alias+"'"
|
||||
res = os.system(cmd)
|
||||
if res == 0:
|
||||
cursor.execute("UPDATE users SET alias=? WHERE name=?",
|
||||
(aliases, UTILISATEUR))
|
||||
conn.commit()
|
||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
||||
IP=request.environ['REMOTE_ADDR']
|
||||
CLIENT_PLATFORM=request.headers.get('User-Agent')
|
||||
log = TIME + ' - ' + IP + ' - ' + UTILISATEUR + ' - ' + CLIENT_PLATFORM + '\n' + '---> ' + "Suppression de l'alias "+ alias + '\n'
|
||||
append_to_log(log, UTILISATEUR)
|
||||
flash(u'Votre alias a été supprimé', 'succes')
|
||||
else:
|
||||
flash(u'Il y a eu une erreur', 'error')
|
||||
|
||||
return redirect(url_for('profil.myalias', _external=True))
|
||||
else:
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
|
||||
|
||||
@profil.route('/invitation/', methods=['GET'])
|
||||
def invitation():
|
||||
if 'username' in session:
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT Token, invitations FROM users WHERE name=?""", (UTILISATEUR,))
|
||||
tmp = cursor.fetchone()
|
||||
token = tmp[0]
|
||||
if token:
|
||||
url_invitation = BASE_URL + 'inscription/' + token
|
||||
else:
|
||||
url_invitation = ""
|
||||
invitations_count = tmp[1]
|
||||
conn.close()
|
||||
|
||||
return render_template('invitation.html',
|
||||
section='Profil',
|
||||
nb_invitation=invitations_count,
|
||||
token=token,
|
||||
url_invitation=url_invitation)
|
||||
else:
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
@profil.route('/gen_token/', methods=['GET'])
|
||||
def generate_token():
|
||||
if 'username' in session:
|
||||
UTILISATEUR='%s' % escape(session['username'])
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
token = gen_token("Invitation")
|
||||
cursor.execute("UPDATE users SET Token=? WHERE name=?",
|
||||
(token, UTILISATEUR))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return redirect(BASE_URL+'invitation/')
|
||||
else:
|
||||
return redirect(BASE_URL, code=401)
|
||||
|
||||
|
||||
@profil.route( '/delete_me/', methods=['GET','POST'])
|
||||
def delete_account():
|
||||
if 'username' in session :
|
||||
UTILISATEUR='%s'% escape(session['username'])
|
||||
resp = render_template('delete_account.html', time_backup=BACKUP_TIME)
|
||||
if request.method == 'POST' :
|
||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||
cursor.execute("""SELECT passwd FROM users WHERE name=?""", (UTILISATEUR,))
|
||||
passwd = cursor.fetchone()[0]
|
||||
cursor.execute("""SELECT mail FROM users WHERE name=?""", (UTILISATEUR,))
|
||||
mail = cursor.fetchone()[0]
|
||||
conn.close()
|
||||
password = request.form['passwd']
|
||||
if bcrypt.check_password_hash(passwd, password) is True:
|
||||
not_error = True
|
||||
|
||||
if MAIL_SERVER:
|
||||
try:
|
||||
cmd = SETUID + ' set_mail_passwd del ' + '"'+mail+'"'
|
||||
print(cmd)
|
||||
os.system(cmd)
|
||||
except:
|
||||
not_error = False
|
||||
flash(u'Erreur lors de la suppression de votre compte Mail.', 'error')
|
||||
|
||||
|
||||
|
||||
if XMPP_SERVER:
|
||||
try:
|
||||
tmp = mail.split('@')
|
||||
cmd = SETUID+ ' prosodyctl deluser ' "'"+tmp[0]+"' " + "'"+tmp[1]+"'"
|
||||
os.system(cmd)
|
||||
except:
|
||||
not_error = False
|
||||
flash(u'Erreur lors de la suppression de votre compte XMPP.', 'error')
|
||||
|
||||
if not_error:
|
||||
try:
|
||||
cmd = 'rm -r ' + DATAS_USER + '/' + UTILISATEUR
|
||||
if os.system(cmd) != 0:
|
||||
raise TypeError("Remove directory error")
|
||||
except:
|
||||
flash(u'Erreur lors de la suppression de votre dossier utilisateur.', 'error')
|
||||
|
||||
|
||||
try:
|
||||
conn = sqlite3.connect(DATABASE)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""DELETE FROM users WHERE name=?""", (UTILISATEUR,))
|
||||
cursor.execute("""DELETE FROM posts WHERE author=?""", (UTILISATEUR,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
except:
|
||||
flash(u'Erreur lors de la suppression de votre compte.', 'error')
|
||||
else:
|
||||
flash(u'Désinscription réalisé avec succés, y\'a plus rien !', 'succes')
|
||||
resp = redirect(url_for('loginlogout.logout'))
|
||||
else:
|
||||
flash(u'Mauvais mot de passe', 'error')
|
||||
return resp
|
||||
|
||||
|
||||
Reference in New Issue
Block a user