Compare commits

...

56 Commits

Author SHA1 Message Date
8ca5e4a457 Add lost password recovery 2025-05-12 16:37:59 +02:00
15c0f4fd79 Add lost password recovery 2025-05-12 16:37:30 +02:00
c91fdad70b Correct 2024-03-31 01:41:03 +01:00
5ccf91701f Correction on signup 2024-03-31 01:37:25 +01:00
722fc7062e Actualiser templates/profil.html
Correction links
2024-03-11 05:34:09 +01:00
beccb99088 Finalize delete account 2023-12-14 20:15:28 +01:00
f5901a2ed4 update code for flask 3.0 2023-11-02 08:03:21 +01:00
abaa9c66ce Correction Formulaire inscription 2023-07-19 01:38:55 +02:00
450fe88faa Corrections éditions des posts 2023-07-06 05:52:10 +02:00
54be4c878f Corrections du CSS 2023-07-06 05:33:21 +02:00
1ce6020bff Amélioration des post-it Ajout supp son compte 2023-07-06 05:07:34 +02:00
2eb2d7fe98 update scripts 2023-03-18 23:10:07 +01:00
5cdd623e6a update scripts 2023-03-18 23:08:43 +01:00
740c744fc1 Supprimer 'scripts/mailconfig' 2022-12-23 13:23:49 +01:00
5fdee1d5ae correction config.py 2022-12-23 09:00:30 +01:00
37600d8bf2 Fautes d'orthographes ... :/ 2022-09-16 04:00:16 +02:00
cb49a4417d Travaux sur les messages aux utilisateurs 2022-09-16 03:56:11 +02:00
35c20b20e0 Corrections des fautes orthographes et déplacement de certaines messages 2022-09-16 03:18:58 +02:00
4e525f5d79 Correction d'un bug 2022-09-01 10:32:31 +02:00
1ac275c415 Travaux sur la validité des mails et des mots de passes 2022-09-01 07:29:49 +02:00
b8f03b77da Ajout de la licence du programme 2022-08-26 04:10:47 +02:00
f10523e706 Ajouter 'LICENSE' 2022-08-26 04:06:04 +02:00
c03142fe71 Suppression fichiers et variables inutiles 2022-08-22 05:43:55 +02:00
4bb19ff8a9 Correction de bugs 2022-08-22 05:34:56 +02:00
f5cd7021c5 Merge branch 'master' of https://kitoy.me/git/kitoy/pywallter
Simple oubli
2022-08-13 04:40:02 +02:00
bfb4cca7d3 modifié : README.md 2022-08-13 04:39:18 +02:00
kitoy
2fee7bef88 modified: config.py.example 2022-08-13 04:32:09 +02:00
5c1cc0a650 renommé : config.py -> config.py.example 2022-08-13 04:21:32 +02:00
6ee1b4decb modifié : .gitignore 2022-08-13 04:19:48 +02:00
3c149711f5 modifié : config.py 2022-08-13 04:18:11 +02:00
8cb8806673 Mise à jour de 'scripts/set_mail_passwd' 2022-08-13 01:42:12 +02:00
7c56207b4e Mise à jour de 'scripts/set_mail_passwd' 2022-08-13 01:41:38 +02:00
0d36ba7dcb Mise à jour de 'scripts/set_mail_passwd'
Oublie d'update une table
2022-08-13 01:41:01 +02:00
ecb3d4ac50 Mise à jour de 'Todo' 2022-08-12 16:35:41 +02:00
101f363293 Mise à jour de 'scripts/mailconfig' 2022-08-12 16:34:04 +02:00
kitoy
4f7afa21e8 modified: templates/accueil.html 2022-08-12 16:31:41 +02:00
kitoy
9d71b83218 modified: .gitignore 2022-08-12 16:25:34 +02:00
kitoy
a5b4ee42ed modified: config.py 2022-08-12 16:24:48 +02:00
kitoy
dfebabe92d modified: scripts/set_mail_alias
modified:   templates/myalias.html
	modified:   views/inscription.py
	modified:   views/profil.py
2022-08-12 16:18:46 +02:00
265e6d5f65 supprimé : sqlite
modifié :         views/loginlogout.py
2022-08-07 18:32:07 +02:00
f33e9f611a modifié : views/inscription.py 2022-08-07 18:25:37 +02:00
78227870bc Ajout fonction première connexion et correction base de donnée 2022-08-07 17:36:20 +02:00
kitoy
3451259a57 modified: templates/blog.html
modified:   templates/board.html
	modified:   templates/profil.html
	modified:   templates/up_up.html
	modified:   views/blog.py
	modified:   views/profil.py
2022-08-07 08:32:21 +02:00
kitoy
aef308e3fd modified: templates/profil.html
modified:   views/profil.py
2022-08-07 07:32:42 +02:00
kitoy
87a088f54d Correction de bugs inscription et changements de MDP 2022-08-07 06:10:36 +02:00
kitoy
4a278699d9 modified: scripts/set_mail_alias 2022-08-07 04:06:29 +02:00
kitoy
73002b5fb3 Correction des scripts d'exemple 2022-08-07 04:03:55 +02:00
kitoy
9094654956 supprimé : #README.md#
supprimé :        #wsgi.py#
2022-08-06 23:50:28 +02:00
kitoy
b34695a41b Work to flask derrière Nginx 2022-08-06 23:49:16 +02:00
083a7147ff Correction profil.py 2022-08-06 20:12:50 +02:00
d7a44c04a3 modifié : README.md 2022-08-06 19:25:27 +02:00
e42fdfd83e modifié : README.md
supprimé :        base.db.bkp
2022-08-06 19:04:38 +02:00
d923a5eb97 Ajout support serveur MAIL et XMPP 2022-08-06 18:22:24 +02:00
beb1e65ca7 Ajout d'un fichiers de configuration 2022-07-11 00:38:03 +02:00
66375d272f remplacement des menu et ajout d'un fichiers de configuration 2022-07-11 00:36:31 +02:00
6b264cd46b Suppression du blog par les post-it 2022-07-10 15:09:03 +02:00
72 changed files with 4137 additions and 1624 deletions

4
.gitignore vendored
View File

@@ -1,4 +1,8 @@
__pycache__/
base.db
log.txt
config.py
users/
sys
*~
#*

27
LICENSE Normal file
View 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.

View File

@@ -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
View File

@@ -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
View 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'

View File

@@ -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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -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;
}

View File

@@ -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;

View File

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Binary file not shown.

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

File diff suppressed because one or more lines are too long

View File

@@ -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;
}

View File

@@ -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
View File

@@ -0,0 +1,5 @@
<footer>
<
<p> Réalisé avec Flask et un thème bootstrap @mdo </p>
</footer>

View 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 %}

View 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
View 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
View 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
View 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>

View File

@@ -0,0 +1 @@
<script src="{{ url_for('static', filename='docs.min.js') }}"></script>

16
templates/_js.html Normal file
View 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
View 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>

View 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/>

View File

@@ -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>

View File

@@ -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 &raquo;</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
View 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">&times;</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 %}

View 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 %}

View 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>

View File

@@ -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
View 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>

View File

@@ -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
View 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 %}

View 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 %}

View File

@@ -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 %}

View File

@@ -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 />

View 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
View 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
View 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 %}

View 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 %}

View File

@@ -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">

View File

@@ -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 &raquo;</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 %}

View File

@@ -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>

View File

@@ -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 #}

View File

@@ -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
View 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 %}

View File

@@ -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 %}

View File

@@ -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>

View File

@@ -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 &raquo;</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 %}

View File

168
tools/databaseinit.py Normal file → Executable file
View 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
View 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
View 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
View 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

View File

@@ -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');

View File

@@ -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
View 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)

View File

@@ -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

View File

@@ -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))

View File

@@ -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)

View File

@@ -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

6
wsgi.py Normal file
View File

@@ -0,0 +1,6 @@
from gevent.pywsgi import WSGIServer
from pywallter import create_app
app = create_app()
http_server = WSGIServer(("127.0.0.1", 8000), app)
http_server.serve_forever()