Compare commits
72 Commits
4288eca551
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ff1f6a2aa | |||
| 4fa225900f | |||
| a4fe70de60 | |||
| 5abbf367ab | |||
| 0e79fdcb36 | |||
| ff5870a33c | |||
| a6ce2c5647 | |||
| 3da7b70cd1 | |||
| 2b04397f7d | |||
| c669987ae7 | |||
| 1f92257ca8 | |||
| 3aa76bb320 | |||
| b1a1a521c2 | |||
| 81aabb21ab | |||
| 7befe1a430 | |||
| f2fea7a61f | |||
| 50db0fcce2 | |||
| d6b4d64390 | |||
| 9baeb3736b | |||
| 51b016aa69 | |||
| 5e54c1d383 | |||
| 7d4a374d3e | |||
| 9c36563ffd | |||
| 7bd8614359 | |||
| 6984d7b04f | |||
| c8633335f3 | |||
| eafb8cac70 | |||
| 496d0bd059 | |||
| 385fe8110e | |||
| af5c93a1df | |||
| 193fc29c82 | |||
| e3100e77b2 | |||
| 481e179833 | |||
| 3266b02be7 | |||
| 89400555ed | |||
| b47999b1b6 | |||
| 8b918dd2a7 | |||
| b4a49b406c | |||
| 4f89b16a1c | |||
| 0803124c14 | |||
|
|
685502aec7 | ||
|
|
6a4089243a | ||
|
|
9a7f22f9eb | ||
|
|
3e1c9439ec | ||
|
|
5c1dfb1fee | ||
|
|
c4b9eaf60a | ||
|
|
f9e873f1e7 | ||
|
|
0ef6950a69 | ||
|
|
c2068c1d45 | ||
|
|
6201e71d2c | ||
|
|
66eff29692 | ||
|
|
76e3cfb870 | ||
| 3bcfc43ed5 | |||
|
|
c3da453425 | ||
|
|
c4e1318722 | ||
|
|
899759a2fb | ||
|
|
e90834725c | ||
|
|
89bfce21b6 | ||
| f67ccfdd19 | |||
| 1e4d097425 | |||
| 417bbe021f | |||
| a985840bc8 | |||
| 2f61155040 | |||
| a5ba0b90bb | |||
| 68d798845d | |||
| 304a2f1a45 | |||
| ed7fd0d0f5 | |||
| d887acd164 | |||
| 603c19de26 | |||
| 57241b843b | |||
| 0e282894a6 | |||
| e14677e701 |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,8 +1,11 @@
|
|||||||
__pycache__/
|
*__pycache__/
|
||||||
base.db
|
*.db
|
||||||
log.txt
|
log.txt
|
||||||
config.py
|
config.py
|
||||||
users/
|
users/
|
||||||
sys
|
sys
|
||||||
*~
|
*~
|
||||||
#*
|
*#*
|
||||||
|
.*
|
||||||
|
base.db.new
|
||||||
|
public/*
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ on pourrait ajoute de la double authentification mais bon ...
|
|||||||
### Sur OpenBSD (7.1)
|
### Sur OpenBSD (7.1)
|
||||||
Il faut installer FLask et quelques dépendances
|
Il faut installer FLask et quelques dépendances
|
||||||
pkg_add py3-werkzeug py3-jinja2 py3-Pillow py3-wtforms py3-flask-wtf py3-flask \
|
pkg_add py3-werkzeug py3-jinja2 py3-Pillow py3-wtforms py3-flask-wtf py3-flask \
|
||||||
py3-bcrypt py3-markdown py3-gevent py3-zopeinterface py3-qrcode
|
py3-bcrypt py3-markdown py3-gevent py3-zopeinterface py3-qrcode py3-pyotp
|
||||||
|
|
||||||
Il reste malheuresment une dépendances sur flask-bcrypt a installé avec pip:
|
Il reste malheuresment une dépendances sur flask-bcrypt a installé avec pip:
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ Il reste malheuresment une dépendances sur flask-bcrypt a installé avec pip:
|
|||||||
|
|
||||||
### Sur Debian
|
### Sur Debian
|
||||||
apt install python3-flask python3-flask-bcrypt python3-wtforms python3-pil python3-markdown \
|
apt install python3-flask python3-flask-bcrypt python3-wtforms python3-pil python3-markdown \
|
||||||
python3-gevent python3-zope.interface python3-qrcode
|
python3-gevent python3-zope.interface python3-qrcode python3-pyotp
|
||||||
|
|
||||||
## Démarrer le programme :
|
## Démarrer le programme :
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,22 @@
|
|||||||
# L'adresse de base de votre site.
|
# L'Adresse de base de votre site.
|
||||||
# example BASE_URL="https://example.com"
|
# example BASE_URL="https://example.com"
|
||||||
# BASE_URL="http://localhost:8000/" # si vous lancez pywallter avec flask run"
|
# BASE_URL="http://localhost:8000/" # si vous lancez pywallter avec flask run"
|
||||||
|
# Addresse et port sur lequel doit ecouté le service pywallter
|
||||||
|
HOST="127.0.0.1" #ADDRESS IP DOMAIN
|
||||||
|
PORT="5001" # A Free port who
|
||||||
|
|
||||||
|
BASE_URL="https://your-domain.com/"
|
||||||
BASE_URL="https://example.com/"
|
# Essentiels pour authentifier les cookies changer cette valeur par une phrase de passe ou une longue suite de caractères
|
||||||
# Essentiels pour les cookies
|
|
||||||
SECRET_KEY="CHANGE-ME"
|
SECRET_KEY="CHANGE-ME"
|
||||||
|
|
||||||
# Dossier où seront stocker les fichiers
|
TITLE_SERVER="Un titre pour votre serveur "
|
||||||
|
DESC_SERVER="Une description"
|
||||||
|
|
||||||
|
BACKUP_TIME="15 jours"
|
||||||
|
|
||||||
|
# Dossier ou seront stocker les fichiers
|
||||||
DOSSIER_APP = "./users/"
|
DOSSIER_APP = "./users/"
|
||||||
|
DOSSIER_PUBLIC = "./public/"
|
||||||
|
|
||||||
# Fichiers sqlite
|
# Fichiers sqlite
|
||||||
DATABASE = "./base.db"
|
DATABASE = "./base.db"
|
||||||
@@ -20,12 +28,31 @@ EXT_IMG= {'.jpg', '.JPG', '.png', '.PNG', '.gif', '.GIF', '.bmp', '.BMP', '.jpeg
|
|||||||
# XMPP = True => Le service est installé et lancer
|
# XMPP = True => Le service est installé et lancer
|
||||||
# XMMP = False => Le service est désactivé
|
# XMMP = False => Le service est désactivé
|
||||||
XMPP_SERVER = False
|
XMPP_SERVER = False
|
||||||
|
# URL for XMPP Web client
|
||||||
|
XMPP_WEBSERVICE = None # Si vous vous voulez proposer une interface web client pour votre service XMPP
|
||||||
|
|
||||||
# Service Mail
|
# Service Mail
|
||||||
# MAIL_SERVER = True => Le service est installé et lancer
|
# MAIL_SERVER = True => Le service est installé et lancer
|
||||||
# MAIL_SERVER = False => Le service est désactivé
|
# MAIL_SERVER = False => Le service est désactivé
|
||||||
MAIL_SERVER = False
|
MAIL_SERVER = True
|
||||||
|
MAIL_DOMAIN="" # Votre domain mail . Si vous voulez fournir des adresse @votredomaine.net
|
||||||
|
IMAP_ADDRESS = "example.net" # Adresse du serveur IMAP
|
||||||
|
SMTP_ADDRESS = "example.net" # Adresse du serveur SMTP
|
||||||
|
|
||||||
|
# URL for email Web client
|
||||||
|
MAIL_WEBSERVICE = None # Si vous voulez proposer une interface web pour consulter les mails sur votre serveur
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Doas or sudo
|
# Doas or sudo
|
||||||
SETUID='doas'
|
SETUID='doas'
|
||||||
|
|
||||||
|
# Sending email for account recovery
|
||||||
|
SMTP_SERVER="mx.example.net"
|
||||||
|
SMTP_PORT="25"
|
||||||
|
SMTP_USER="smtp_user"
|
||||||
|
SMTP_PASSWD="your password"
|
||||||
|
SENDER_ADDRESS="" # l'adresse mail qui sera afficher lors d'un envoi de mail de votre application
|
||||||
|
#Activer les inscriptions
|
||||||
|
# cette option va disparaitre car elle n'a pas vraiment de sens ... si ce n'est de pouvoir fermer les inscriptions
|
||||||
|
SIGNIN_ENABLE=True
|
||||||
|
|||||||
31
pywallter.py
31
pywallter.py
@@ -18,7 +18,8 @@ from views.logs import logs
|
|||||||
from views.loginlogout import loginlogout
|
from views.loginlogout import loginlogout
|
||||||
from views.gallery import mygallery
|
from views.gallery import mygallery
|
||||||
|
|
||||||
from tools.databaseinit import init_db, init_dir, db_migrate
|
from tools.databaseinit import init_db, check_directories, db_migrate, check_directories
|
||||||
|
|
||||||
|
|
||||||
import glob, os, sys, time
|
import glob, os, sys, time
|
||||||
|
|
||||||
@@ -26,22 +27,25 @@ app = Flask( 'pywallter' )
|
|||||||
app.config.from_pyfile('config.py')
|
app.config.from_pyfile('config.py')
|
||||||
bcrypt = Bcrypt(app)
|
bcrypt = Bcrypt(app)
|
||||||
|
|
||||||
init_db()
|
|
||||||
db_migrate()
|
|
||||||
if init_dir():
|
|
||||||
print ("Le repertoire des utilisateurs a été créer")
|
|
||||||
|
|
||||||
|
|
||||||
#### Variables Globales #########################################################################
|
#### Variables Globales #########################################################################
|
||||||
|
|
||||||
|
|
||||||
DOSSIER_PERSO= app.config['DOSSIER_APP']
|
DOSSIER_PERSO= app.config['DOSSIER_APP']
|
||||||
|
DATABASE= app.config['DATABASE']
|
||||||
extensionimg = app.config['EXT_IMG']
|
extensionimg = app.config['EXT_IMG']
|
||||||
MAIL_SERVER = app.config['MAIL_SERVER']
|
MAIL_SERVER = app.config['MAIL_SERVER']
|
||||||
XMPP_SERVER = app.config['XMPP_SERVER']
|
XMPP_SERVER = app.config['XMPP_SERVER']
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
|
|
||||||
|
init_db(DATABASE)
|
||||||
|
check_directories(DOSSIER_PERSO)
|
||||||
|
db_migrate(DATABASE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
xmpp_server_not_installed = system('whereis prosodyctl')
|
xmpp_server_not_installed = system('whereis prosodyctl')
|
||||||
mail_server_not_installed = system('whereis set_mail_alias') + system('whereis set_mail_passwd') + \
|
mail_server_not_installed = system('whereis set_mail_alias') + system('whereis set_mail_passwd') + \
|
||||||
system('whereis dovecot') + system('whereis smtpd')
|
system('whereis dovecot') + system('whereis smtpd')
|
||||||
@@ -77,8 +81,11 @@ def create_app():
|
|||||||
app = Flask( 'pywallter' )
|
app = Flask( 'pywallter' )
|
||||||
app.config.from_pyfile('config.py')
|
app.config.from_pyfile('config.py')
|
||||||
bcrypt = Bcrypt(app)
|
bcrypt = Bcrypt(app)
|
||||||
|
database= app.config['DATABASE']
|
||||||
xmpp_server_not_installed = system('whereis prosodyctl')
|
xmpp_server_not_installed = system('whereis prosodyctl')
|
||||||
mail_server_not_installed = system('whereis set_mail_alias') + system('whereis set_mail_passwd') + system('whereis smtpctl')
|
mail_server_not_installed = system('whereis set_mail_alias') + system('whereis set_mail_passwd') + system('whereis smtpctl')
|
||||||
|
folder_users= app.config['DOSSIER_APP']
|
||||||
|
extensionimg = app.config['EXT_IMG']
|
||||||
|
|
||||||
if XMPP_SERVER and xmpp_server_not_installed :
|
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 ("Vous avez activé la prise en charge du protocole XMPP mais prosody n'est pas installé")
|
||||||
@@ -92,21 +99,19 @@ def create_app():
|
|||||||
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")
|
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)
|
exit(1)
|
||||||
|
|
||||||
init_db()
|
init_db(database)
|
||||||
db_migrate()
|
db_migrate(database)
|
||||||
if init_dir():
|
if check_directories(folder_users):
|
||||||
print ("Le repertoire des utilisateurs a été créer")
|
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(inscription)
|
||||||
app.register_blueprint(blog)
|
app.register_blueprint(blog)
|
||||||
app.register_blueprint(filesupload)
|
app.register_blueprint(filesupload)
|
||||||
|
app.register_blueprint(mymailbox)
|
||||||
app.register_blueprint(profil)
|
app.register_blueprint(profil)
|
||||||
app.register_blueprint(logs)
|
app.register_blueprint(logs)
|
||||||
app.register_blueprint(loginlogout)
|
app.register_blueprint(loginlogout)
|
||||||
|
|||||||
237
static/blog-blanc&noir.css
Normal file
237
static/blog-blanc&noir.css
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
/* kitoy <kitoy__at__kitoy.me> */
|
||||||
|
|
||||||
|
:root
|
||||||
|
{
|
||||||
|
--color-background: #fefefe;
|
||||||
|
--color-title: #010101;
|
||||||
|
--color-text: #0f0f0f;
|
||||||
|
--color-link: #010101;
|
||||||
|
--font-emoji : "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
|
||||||
|
--font-basic : system-ui,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,Helvetica,Arial,"Helvetica Neue",sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
html{
|
||||||
|
height: 100%;
|
||||||
|
width: 80%;
|
||||||
|
margin-left: 10%;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: var(--color-text);
|
||||||
|
background-color: var(--color-background);
|
||||||
|
font-family: var(--font-basic);
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5{
|
||||||
|
color: var(--color-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
* {-moz-box-sizing: border-box; box-sizing: border-box;}
|
||||||
|
|
||||||
|
a {
|
||||||
|
box-shadow: inset 0 0 0 0 var(--color-text);
|
||||||
|
color: --color-link;
|
||||||
|
padding: 0 .25rem;
|
||||||
|
margin: 0 -.25rem;
|
||||||
|
transition: color .3s ease-in-out, box-shadow .3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: var(--color-background);
|
||||||
|
box-shadow: inset 300px 0 0 0 var(--color-text);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-link);
|
||||||
|
text-decoration: underline 2px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.date {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slug {
|
||||||
|
//margin-left: 1rem;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readmore {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.head-article {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.text-article p {
|
||||||
|
padding-left: 2vw;
|
||||||
|
padding-right:2vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-article h2, h3, h4, h5 {
|
||||||
|
padding-left: 1vw;
|
||||||
|
padding-right:1vw;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.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;
|
||||||
|
padding-bottom:1vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media only screen and (max-width: 980px)
|
||||||
|
{
|
||||||
|
|
||||||
|
.articles .description {
|
||||||
|
font-size: 4vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.articles {
|
||||||
|
max-width: 100%;
|
||||||
|
margin-left: auto;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
237
static/blog-noir&blanc.css
Normal file
237
static/blog-noir&blanc.css
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
/* kitoy <kitoy__at__kitoy.me> */
|
||||||
|
|
||||||
|
:root
|
||||||
|
{
|
||||||
|
--color-background: #010101;
|
||||||
|
--color-title: #fefefe;
|
||||||
|
--color-text: #fdfdfd;
|
||||||
|
--color-link: #fefefe;
|
||||||
|
--font-emoji : "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
|
||||||
|
--font-basic : system-ui,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,Helvetica,Arial,"Helvetica Neue",sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
html{
|
||||||
|
height: 100%;
|
||||||
|
width: 80%;
|
||||||
|
margin-left: 10%;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: var(--color-text);
|
||||||
|
background-color: var(--color-background);
|
||||||
|
font-family: var(--font-basic);
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5{
|
||||||
|
color: var(--color-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
* {-moz-box-sizing: border-box; box-sizing: border-box;}
|
||||||
|
|
||||||
|
a {
|
||||||
|
box-shadow: inset 0 0 0 0 var(--color-text);
|
||||||
|
color: --color-link;
|
||||||
|
padding: 0 .25rem;
|
||||||
|
margin: 0 -.25rem;
|
||||||
|
transition: color .3s ease-in-out, box-shadow .3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: var(--color-background);
|
||||||
|
box-shadow: inset 300px 0 0 0 var(--color-text);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-link);
|
||||||
|
text-decoration: underline 2px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.date {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slug {
|
||||||
|
//margin-left: 1rem;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readmore {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.head-article {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.text-article p {
|
||||||
|
padding-left: 2vw;
|
||||||
|
padding-right:2vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-article h2, h3, h4, h5 {
|
||||||
|
padding-left: 1vw;
|
||||||
|
padding-right:1vw;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.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;
|
||||||
|
padding-bottom:1vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media only screen and (max-width: 980px)
|
||||||
|
{
|
||||||
|
|
||||||
|
.articles .description {
|
||||||
|
font-size: 4vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.articles {
|
||||||
|
max-width: 100%;
|
||||||
|
margin-left: auto;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
238
static/blog-orange&noir.css
Normal file
238
static/blog-orange&noir.css
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
/* kitoy <kitoy__at__kitoy.me> */
|
||||||
|
|
||||||
|
:root
|
||||||
|
{
|
||||||
|
--color-background: #010101;
|
||||||
|
--color-title: #ee794c;
|
||||||
|
--color-text: #fdfdfd;
|
||||||
|
--color-link: #ee794c;
|
||||||
|
--font-emoji : "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
|
||||||
|
--font-basic : system-ui,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,Helvetica,Arial,"Helvetica Neue",sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
html{
|
||||||
|
height: 100%;
|
||||||
|
width: 80%;
|
||||||
|
margin-left: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: var(--color-text);
|
||||||
|
background-color: var(--color-background);
|
||||||
|
font-family: var(--font-basic);
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5{
|
||||||
|
color: var(--color-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
-moz-box-sizing: border-box; box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
box-shadow: inset 0 0 0 0 var(--color-text);
|
||||||
|
color: --color-link;
|
||||||
|
padding: 0 .25rem;
|
||||||
|
margin: 0 -.25rem;
|
||||||
|
transition: color .3s ease-in-out, box-shadow .3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: var(--color-background);
|
||||||
|
box-shadow: inset 300px 0 0 0 var(--color-text);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-link);
|
||||||
|
text-decoration: underline 2px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.date {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slug {
|
||||||
|
//margin-left: 1rem;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readmore {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.head-article {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.text-article p {
|
||||||
|
padding-left: 2vw;
|
||||||
|
padding-right:2vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-article h2, h3, h4, h5 {
|
||||||
|
padding-left: 1vw;
|
||||||
|
padding-right:1vw;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.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;
|
||||||
|
padding-bottom:1vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media only screen and (max-width: 980px)
|
||||||
|
{
|
||||||
|
|
||||||
|
.articles .description {
|
||||||
|
font-size: 4vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.articles {
|
||||||
|
max-width: 100%;
|
||||||
|
margin-left: auto;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
237
static/blog-orangina.css
Normal file
237
static/blog-orangina.css
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
/* kitoy <kitoy__at__kitoy.me> */
|
||||||
|
|
||||||
|
:root
|
||||||
|
{
|
||||||
|
--color-background: #1e227b;
|
||||||
|
--color-title: #e9d43a;
|
||||||
|
--color-text: #fdfdfd;
|
||||||
|
--color-link: #e9d43a;
|
||||||
|
--font-emoji : "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
|
||||||
|
--font-basic : system-ui,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,Helvetica,Arial,"Helvetica Neue",sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
html{
|
||||||
|
height: 100%;
|
||||||
|
width: 80%;
|
||||||
|
margin-left: 10%;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: var(--color-text);
|
||||||
|
background-color: var(--color-background);
|
||||||
|
font-family: var(--font-basic);
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5{
|
||||||
|
color: var(--color-title);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
* {-moz-box-sizing: border-box; box-sizing: border-box;}
|
||||||
|
|
||||||
|
a {
|
||||||
|
box-shadow: inset 0 0 0 0 var(--color-text);
|
||||||
|
color: --color-link;
|
||||||
|
padding: 0 .25rem;
|
||||||
|
margin: 0 -.25rem;
|
||||||
|
transition: color .3s ease-in-out, box-shadow .3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: var(--color-background);
|
||||||
|
box-shadow: inset 300px 0 0 0 var(--color-text);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-link);
|
||||||
|
text-decoration: underline 2px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.date {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slug {
|
||||||
|
//margin-left: 1rem;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readmore {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.head-article {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.text-article p {
|
||||||
|
padding-left: 2vw;
|
||||||
|
padding-right:2vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-article h2, h3, h4, h5 {
|
||||||
|
padding-left: 1vw;
|
||||||
|
padding-right:1vw;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.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;
|
||||||
|
padding-bottom:1vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media only screen and (max-width: 980px)
|
||||||
|
{
|
||||||
|
|
||||||
|
.articles .description {
|
||||||
|
font-size: 4vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.articles {
|
||||||
|
max-width: 100%;
|
||||||
|
margin-left: auto;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,8 +2,13 @@
|
|||||||
|
|
||||||
:root
|
:root
|
||||||
{
|
{
|
||||||
--color-text: #fdfdfddd;
|
|
||||||
--color-background: #202020;
|
--color-background: #202020;
|
||||||
|
--color-title: #fdfdfd;
|
||||||
|
--color-text: #dddddd;
|
||||||
|
--color-link: #fdfdfd;
|
||||||
|
--font-emoji : "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
|
||||||
|
--font-basic : system-ui,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,Helvetica,Arial,"Helvetica Neue",sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
html{
|
html{
|
||||||
@@ -17,21 +22,43 @@
|
|||||||
body {
|
body {
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
|
font-family: var(--font-basic);
|
||||||
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5{
|
||||||
|
color: var(--color-title);
|
||||||
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
* {-moz-box-sizing: border-box; box-sizing: border-box;}
|
* {-moz-box-sizing: border-box; box-sizing: border-box;}
|
||||||
|
|
||||||
|
a {
|
||||||
|
box-shadow: inset 0 0 0 0 var(--color-text);
|
||||||
|
color: --color-link;
|
||||||
|
padding: 0 .25rem;
|
||||||
|
margin: 0 -.25rem;
|
||||||
|
transition: color .3s ease-in-out, box-shadow .3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--color-text);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: var(--color-background);
|
||||||
|
box-shadow: inset 300px 0 0 0 var(--color-text);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-link);
|
||||||
|
text-decoration: underline 2px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.date {
|
.date {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
@@ -46,17 +73,6 @@
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.readmore a {
|
|
||||||
color: var(--color-text);
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.copyleft {
|
|
||||||
display:inline-block;
|
|
||||||
transform: rotate(180deg);
|
|
||||||
padding-bottom: -15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
white-space: pre-wrap; /* css-3 */
|
white-space: pre-wrap; /* css-3 */
|
||||||
@@ -97,17 +113,29 @@
|
|||||||
padding-left: 1.5vw;
|
padding-left: 1.5vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.titre {
|
.head-article {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.text-article p {
|
||||||
|
padding-left: 2vw;
|
||||||
|
padding-right:2vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-article h2, h3, h4, h5 {
|
||||||
|
padding-left: 1vw;
|
||||||
|
padding-right:1vw;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.index {
|
.index {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.articles img {
|
.articles img {
|
||||||
display: block;
|
display: block;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
@@ -125,6 +153,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.pagination a {
|
.pagination a {
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
border-color: $color_title;
|
border-color: $color_title;
|
||||||
@@ -147,8 +176,10 @@
|
|||||||
bottom:0px;
|
bottom:0px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align:center;
|
text-align:center;
|
||||||
|
padding-bottom:1vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@media only screen and (max-width: 980px)
|
@media only screen and (max-width: 980px)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -157,7 +188,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.articles {
|
.articles {
|
||||||
margin-left: 0;
|
margin-left: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 3.5vw;
|
font-size: 3.5vw;
|
||||||
|
|
||||||
|
|||||||
@@ -330,3 +330,78 @@
|
|||||||
margin:5px;
|
margin:5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Share */
|
||||||
|
.social-share
|
||||||
|
{
|
||||||
|
display: inline-block;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Ccircle cx='18' cy='5' r='3'/%3E%3Ccircle cx='6' cy='12' r='3'/%3E%3Ccircle cx='18' cy='19' r='3'/%3E%3Cpath d='m8.59 13.51l6.83 3.98m-.01-10.98l-6.82 3.98'/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
background-color: currentColor;
|
||||||
|
-webkit-mask-image: var(--svg);
|
||||||
|
mask-image: var(--svg);
|
||||||
|
-webkit-mask-repeat: no-repeat;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
-webkit-mask-size: 100% 100%;
|
||||||
|
mask-size: 100% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.share {
|
||||||
|
display: inline-block;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M18.8 8.2H16V7h3.001c.55 0 .999.446.999.996v13.008a1 1 0 0 1-.996.996H4.996A1 1 0 0 1 4 21.004V7.996A1 1 0 0 1 4.999 7H8v1.2H5.2v12.6h13.6zm-6.2-3.938V13.5h-1.2V4.262L9.313 6.349L8.464 5.5l2.829-2.828a1 1 0 0 1 1.414 0L15.536 5.5l-.849.849z'/%3E%3C/svg%3E");
|
||||||
|
background-color: currentColor;
|
||||||
|
-webkit-mask-image: var(--svg);
|
||||||
|
mask-image: var(--svg);
|
||||||
|
-webkit-mask-repeat: no-repeat;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
-webkit-mask-size: 100% 100%;
|
||||||
|
mask-size: 100% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unshare
|
||||||
|
{
|
||||||
|
display: inline-block;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Ccircle cx='18' cy='5' r='3'/%3E%3Ccircle cx='6' cy='12' r='3'/%3E%3Ccircle cx='18' cy='19' r='3'/%3E%3Cpath d='m8.59 13.51l6.83 3.98m-.01-10.98l-6.82 3.98'/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
background-color: currentColor;
|
||||||
|
-webkit-mask-image: var(--svg);
|
||||||
|
mask-image: var(--svg);
|
||||||
|
-webkit-mask-repeat: no-repeat;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
-webkit-mask-size: 100% 100%;
|
||||||
|
mask-size: 100% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete
|
||||||
|
{
|
||||||
|
display: inline-block;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='m6.774 6.4l.812 13.648a.8.8 0 0 0 .798.752h7.232a.8.8 0 0 0 .798-.752L17.226 6.4zm11.655 0l-.817 13.719A2 2 0 0 1 15.616 22H8.384a2 2 0 0 1-1.996-1.881L5.571 6.4H3.5v-.7a.5.5 0 0 1 .5-.5h16a.5.5 0 0 1 .5.5v.7zM14 3a.5.5 0 0 1 .5.5v.7h-5v-.7A.5.5 0 0 1 10 3zM9.5 9h1.2l.5 9H10zm3.8 0h1.2l-.5 9h-1.2z'/%3E%3C/svg%3E");
|
||||||
|
background-color: currentColor;
|
||||||
|
-webkit-mask-image: var(--svg);
|
||||||
|
mask-image: var(--svg);
|
||||||
|
-webkit-mask-repeat: no-repeat;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
-webkit-mask-size: 100% 100%;
|
||||||
|
mask-size: 100% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-link{
|
||||||
|
display: inline-block;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M8 4H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2M16 4h2a2 2 0 0 1 2 2v4m1 4H11'/%3E%3Cpath d='m15 10l-4 4l4 4'/%3E%3C/g%3E%3C/svg%3E");
|
||||||
|
background-color: currentColor;
|
||||||
|
-webkit-mask-image: var(--svg);
|
||||||
|
mask-image: var(--svg);
|
||||||
|
-webkit-mask-repeat: no-repeat;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
-webkit-mask-size: 100% 100%;
|
||||||
|
mask-size: 100% 100%;
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,17 +16,19 @@ body
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden{
|
.hidden {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
grid-area: header;
|
grid-area: header;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
main
|
body > main
|
||||||
{
|
{
|
||||||
grid-area: main;
|
grid-area: main;
|
||||||
|
width: 80%;
|
||||||
text-align: justify;
|
text-align: justify;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
@@ -52,6 +54,36 @@ main > nav
|
|||||||
color: var(--pico-color-green-500);
|
color: var(--pico-color-green-500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1200px)
|
||||||
|
{
|
||||||
|
.list-articles{
|
||||||
|
padding-top: 2vw;
|
||||||
|
display: inline-flex;
|
||||||
|
gap:30px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
article {
|
||||||
|
text-align: center;
|
||||||
|
width: 30vw;
|
||||||
|
height: 35vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
article > header {
|
||||||
|
height: 15vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
article > .subtitle {
|
||||||
|
height: 10vw;
|
||||||
|
}
|
||||||
|
article footer{
|
||||||
|
display: block;
|
||||||
|
height: 5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 600px)
|
@media only screen and (max-width: 600px)
|
||||||
{
|
{
|
||||||
body {
|
body {
|
||||||
|
|||||||
97
static/simplemde-custom.css
Normal file
97
static/simplemde-custom.css
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
.editor-toolbar a {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none !important;
|
||||||
|
color: var(--pico-primary) !important;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
margin: 0;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.editor-toolbar.fullscreen {
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: var(--pico-background-color);
|
||||||
|
border: 0;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
opacity: 1;
|
||||||
|
z-index: 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror {
|
||||||
|
background-color: var(--pico-background-color);
|
||||||
|
color: var(--pico-color) !important;
|
||||||
|
border-color: var(--pico-primary-hover) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-preview-active{
|
||||||
|
background: var(--pico-background-color);
|
||||||
|
color: var(--pico-color) !important;
|
||||||
|
padding-right : 4vw;
|
||||||
|
padding-left: 4vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-preview-active-side {
|
||||||
|
background: var(--pico-background-color);
|
||||||
|
color: var(--pico-color) !important;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
width: 50%;
|
||||||
|
top: 50px;
|
||||||
|
right: 0;
|
||||||
|
z-index: 9;
|
||||||
|
border: 2px solid;
|
||||||
|
border-color: var(--pico-primary-hover) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.CodeMirror .CodeMirror-code .cm-tag {
|
||||||
|
color: #63a35c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror .CodeMirror-code .cm-attribute {
|
||||||
|
color: #795da3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror .CodeMirror-code .cm-string {
|
||||||
|
color: #183691;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror .CodeMirror-selected {
|
||||||
|
background: var(--pico-text-selection-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.CodeMirror .CodeMirror-code .cm-link {
|
||||||
|
color: #7f8c8d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror .CodeMirror-code .cm-url {
|
||||||
|
color: #aab2b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-cursor {
|
||||||
|
border-left-color: var(--pico-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-statusbar .lines:before {
|
||||||
|
color: var(--pico-primary) !important;
|
||||||
|
content: 'lignes: '
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-statusbar .words:before {
|
||||||
|
color: var(--pico-primary) !important;
|
||||||
|
content: 'Mots: '
|
||||||
|
}
|
||||||
2
static/vendors/dropzone/dropzone-min.js
vendored
Normal file
2
static/vendors/dropzone/dropzone-min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/vendors/dropzone/dropzone-min.js.map
vendored
Normal file
1
static/vendors/dropzone/dropzone-min.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/vendors/dropzone/dropzone.css
vendored
Normal file
1
static/vendors/dropzone/dropzone.css
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@keyframes passing-through{0%{opacity:0;transform:translateY(40px)}30%,70%{opacity:1;transform:translateY(0px)}100%{opacity:0;transform:translateY(-40px)}}@keyframes slide-in{0%{opacity:0;transform:translateY(40px)}30%{opacity:1;transform:translateY(0px)}}@keyframes pulse{0%{transform:scale(1)}10%{transform:scale(1.1)}20%{transform:scale(1)}}.dropzone,.dropzone *{box-sizing:border-box}.dropzone{min-height:150px;border:1px solid rgba(0,0,0,.8);border-radius:5px;padding:20px 20px}.dropzone.dz-clickable{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{cursor:pointer}.dropzone.dz-started .dz-message{display:none}.dropzone.dz-drag-hover{border-style:solid}.dropzone.dz-drag-hover .dz-message{opacity:.5}.dropzone .dz-message{text-align:center;margin:3em 0}.dropzone .dz-message .dz-button{background:none;color:inherit;border:none;padding:0;font:inherit;cursor:pointer;outline:inherit}.dropzone .dz-preview{position:relative;display:inline-block;vertical-align:top;margin:16px;min-height:100px}.dropzone .dz-preview:hover{z-index:1000}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview.dz-file-preview .dz-image{border-radius:20px;background:#999;background:linear-gradient(to bottom, #eee, #ddd)}.dropzone .dz-preview.dz-file-preview .dz-details{opacity:1}.dropzone .dz-preview.dz-image-preview{background:#fff}.dropzone .dz-preview.dz-image-preview .dz-details{transition:opacity .2s linear}.dropzone .dz-preview .dz-remove{font-size:14px;text-align:center;display:block;cursor:pointer;border:none}.dropzone .dz-preview .dz-remove:hover{text-decoration:underline}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview .dz-details{z-index:20;position:absolute;top:0;left:0;opacity:0;font-size:13px;min-width:100%;max-width:100%;padding:2em 1em;text-align:center;color:rgba(0,0,0,.9);line-height:150%}.dropzone .dz-preview .dz-details .dz-size{margin-bottom:1em;font-size:16px}.dropzone .dz-preview .dz-details .dz-filename{white-space:nowrap}.dropzone .dz-preview .dz-details .dz-filename:hover span{border:1px solid rgba(200,200,200,.8);background-color:hsla(0,0%,100%,.8)}.dropzone .dz-preview .dz-details .dz-filename:not(:hover){overflow:hidden;text-overflow:ellipsis}.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span{border:1px solid rgba(0,0,0,0)}.dropzone .dz-preview .dz-details .dz-filename span,.dropzone .dz-preview .dz-details .dz-size span{background-color:hsla(0,0%,100%,.4);padding:0 .4em;border-radius:3px}.dropzone .dz-preview:hover .dz-image img{transform:scale(1.05, 1.05);filter:blur(8px)}.dropzone .dz-preview .dz-image{border-radius:20px;overflow:hidden;width:120px;height:120px;position:relative;display:block;z-index:10}.dropzone .dz-preview .dz-image img{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview.dz-error .dz-error-mark{opacity:1;animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview .dz-success-mark,.dropzone .dz-preview .dz-error-mark{pointer-events:none;opacity:0;z-index:500;position:absolute;display:block;top:50%;left:50%;margin-left:-27px;margin-top:-27px;background:rgba(0,0,0,.8);border-radius:50%}.dropzone .dz-preview .dz-success-mark svg,.dropzone .dz-preview .dz-error-mark svg{display:block;width:54px;height:54px;fill:#fff}.dropzone .dz-preview.dz-processing .dz-progress{opacity:1;transition:all .2s linear}.dropzone .dz-preview.dz-complete .dz-progress{opacity:0;transition:opacity .4s ease-in}.dropzone .dz-preview:not(.dz-processing) .dz-progress{animation:pulse 6s ease infinite}.dropzone .dz-preview .dz-progress{opacity:1;z-index:1000;pointer-events:none;position:absolute;height:20px;top:50%;margin-top:-10px;left:15%;right:15%;border:3px solid rgba(0,0,0,.8);background:rgba(0,0,0,.8);border-radius:10px;overflow:hidden}.dropzone .dz-preview .dz-progress .dz-upload{background:#fff;display:block;position:relative;height:100%;width:0;transition:width 300ms ease-in-out;border-radius:17px}.dropzone .dz-preview.dz-error .dz-error-message{display:block}.dropzone .dz-preview.dz-error:hover .dz-error-message{opacity:1;pointer-events:auto}.dropzone .dz-preview .dz-error-message{pointer-events:none;z-index:1000;position:absolute;display:block;display:none;opacity:0;transition:opacity .3s ease;border-radius:8px;font-size:13px;top:130px;left:-10px;width:140px;background:#b10606;padding:.5em 1em;color:#fff}.dropzone .dz-preview .dz-error-message:after{content:"";position:absolute;top:-6px;left:64px;width:0;height:0;border-left:6px solid rgba(0,0,0,0);border-right:6px solid rgba(0,0,0,0);border-bottom:6px solid #b10606}/*# sourceMappingURL=dropzone.css.map */
|
||||||
1
static/vendors/htmx/htmx.min.js
vendored
Normal file
1
static/vendors/htmx/htmx.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
85
static/vendors/picocss/theme-switcher.js
vendored
85
static/vendors/picocss/theme-switcher.js
vendored
@@ -2,34 +2,83 @@
|
|||||||
* Minimal theme switcher
|
* Minimal theme switcher
|
||||||
*
|
*
|
||||||
* Pico.css - https://picocss.com
|
* Pico.css - https://picocss.com
|
||||||
* Copyright 2020 - Licensed under MIT
|
* Copyright 2019-2023 - Licensed under MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const themeSwitcher = {
|
const themeSwitcher = {
|
||||||
// Config
|
// Config
|
||||||
|
_scheme: "auto",
|
||||||
|
menuTarget: "details[role='list']",
|
||||||
buttonsTarget: "a[data-theme-switcher]",
|
buttonsTarget: "a[data-theme-switcher]",
|
||||||
buttonAttribute: "data-theme-switcher",
|
buttonAttribute: "data-theme-switcher",
|
||||||
rootAttribute: "data-theme",
|
rootAttribute: "data-theme",
|
||||||
|
localStorageKey: "picoPreferredColorScheme",
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
init() {
|
init() {
|
||||||
document.querySelectorAll(this.buttonsTarget).forEach(
|
this.scheme = this.schemeFromLocalStorage;
|
||||||
function (button) {
|
this.initSwitchers();
|
||||||
button.addEventListener(
|
},
|
||||||
"click",
|
|
||||||
function (event) {
|
// Get color scheme from local storage
|
||||||
event.preventDefault();
|
get schemeFromLocalStorage() {
|
||||||
document
|
if (typeof window.localStorage !== "undefined") {
|
||||||
.querySelector("html")
|
if (window.localStorage.getItem(this.localStorageKey) !== null) {
|
||||||
.setAttribute(
|
return window.localStorage.getItem(this.localStorageKey);
|
||||||
this.rootAttribute,
|
}
|
||||||
event.target.getAttribute(this.buttonAttribute)
|
}
|
||||||
);
|
return this._scheme;
|
||||||
}.bind(this),
|
},
|
||||||
false
|
|
||||||
);
|
// Preferred color scheme
|
||||||
}.bind(this)
|
get preferredColorScheme() {
|
||||||
);
|
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
||||||
|
},
|
||||||
|
|
||||||
|
// Init switchers
|
||||||
|
initSwitchers() {
|
||||||
|
const buttons = document.querySelectorAll(this.buttonsTarget);
|
||||||
|
buttons.forEach((button) => {
|
||||||
|
button.addEventListener(
|
||||||
|
"click",
|
||||||
|
(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
// Set scheme
|
||||||
|
this.scheme = button.getAttribute(this.buttonAttribute);
|
||||||
|
// Close dropdown
|
||||||
|
document.querySelector(this.menuTarget).removeAttribute("open");
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Set scheme
|
||||||
|
set scheme(scheme) {
|
||||||
|
if (scheme == "auto") {
|
||||||
|
this.preferredColorScheme == "dark" ? (this._scheme = "dark") : (this._scheme = "light");
|
||||||
|
} else if (scheme == "dark" || scheme == "light") {
|
||||||
|
this._scheme = scheme;
|
||||||
|
}
|
||||||
|
this.applyScheme();
|
||||||
|
this.schemeToLocalStorage();
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get scheme
|
||||||
|
get scheme() {
|
||||||
|
return this._scheme;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Apply scheme
|
||||||
|
applyScheme() {
|
||||||
|
document.querySelector("html").setAttribute(this.rootAttribute, this.scheme);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Store scheme to local storage
|
||||||
|
schemeToLocalStorage() {
|
||||||
|
if (typeof window.localStorage !== "undefined") {
|
||||||
|
window.localStorage.setItem(this.localStorageKey, this.scheme);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
@@ -11,7 +11,5 @@
|
|||||||
<link href="{{ url_for('static', filename='vendors/picocss/pico.colors.min.css') }}" rel="stylesheet">
|
<link href="{{ url_for('static', filename='vendors/picocss/pico.colors.min.css') }}" rel="stylesheet">
|
||||||
<link href="{{ url_for('static', filename='pywallter.css') }}" rel="stylesheet">
|
<link href="{{ url_for('static', filename='pywallter.css') }}" rel="stylesheet">
|
||||||
<link href="{{ url_for('static', filename='icons.css') }}" rel="stylesheet">
|
<link href="{{ url_for('static', filename='icons.css') }}" rel="stylesheet">
|
||||||
<link href="{{ url_for('static', filename='vendors/simplemde/simplemde.min.css') }}" rel="stylesheet">
|
|
||||||
<link href="{{ url_for('static', filename='vendors/glightbox/glightbox.min.css') }}" rel="stylesheet">
|
<link href="{{ url_for('static', filename='vendors/glightbox/glightbox.min.css') }}" rel="stylesheet">
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|||||||
@@ -5,6 +5,15 @@
|
|||||||
<span class="menu-icon"></span>
|
<span class="menu-icon"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
||||||
|
<details class="dropdown">
|
||||||
|
<summary role="button" class="secondary menu-header">Theme</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#" data-theme-switcher="auto">Auto</a></li>
|
||||||
|
<li><a href="#" data-theme-switcher="light">Clair</a></li>
|
||||||
|
<li><a href="#" data-theme-switcher="dark">Sombre</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
<a href="/logs/">
|
<a href="/logs/">
|
||||||
<button class="menu-header">
|
<button class="menu-header">
|
||||||
Mes logs <br/>
|
Mes logs <br/>
|
||||||
@@ -19,14 +28,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<details class="dropdown">
|
|
||||||
<summary role="button" class="secondary menu-header">Theme</summary>
|
|
||||||
<ul>
|
|
||||||
<li><a href="#" data-theme-switcher="auto">Auto</a></li>
|
|
||||||
<li><a href="#" data-theme-switcher="light">Clair</a></li>
|
|
||||||
<li><a href="#" data-theme-switcher="dark">Sombre</a></li>
|
|
||||||
</ul>
|
|
||||||
</details>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
26
templates/_js_dropzone.html
Normal file
26
templates/_js_dropzone.html
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
<script>
|
||||||
|
window.onload = function () {
|
||||||
|
|
||||||
|
var dropzoneOptions = {
|
||||||
|
dictDefaultMessage: 'Déposez vos fichiers ici!',
|
||||||
|
paramName: "file",
|
||||||
|
maxFilesize: 1024, // MB
|
||||||
|
url: "/upload-dropzone",
|
||||||
|
chunking: true,
|
||||||
|
forceChunking: true,
|
||||||
|
chunkSize: 1000000,
|
||||||
|
autoProcessQueue: true,
|
||||||
|
init: function () {
|
||||||
|
this.on("success", function (file) {
|
||||||
|
console.log("success > " + file.name);
|
||||||
|
setTimeout(() => { this.removeFile(file); }, 2000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var uploader = document.querySelector('#uploader');
|
||||||
|
var myDropzone = new Dropzone(uploader, dropzoneOptions);
|
||||||
|
console.log("Loaded");
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
4
templates/_js_htmx.html
Normal file
4
templates/_js_htmx.html
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
|
||||||
|
<script src="{{ url_for('static', filename='vendors/htmx/htmx.min.js') }}"> </script>
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
<li>
|
<li>
|
||||||
|
|
||||||
<a href="/myblog/new-article/" {% if request.path == "/myblog/new-article/" %} class="invert" {% endif %} > <span class="icons new-article-blog"></span>
|
<a href="/myblog/new-article/" {% if request.path == "/myblog/new-article/" %} class="invert" {% endif %} > <span class="icons new-article-blog"></span>
|
||||||
Ecrire un billet </a>
|
Écrire un billet </a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/myblog/list-articles/" {% if request.path == "/myblog/list-articles/" %} class="invert" {% endif %} ><span class="icons list-articles-blog"></span>
|
<a href="/myblog/list-articles/" {% if request.path == "/myblog/list-articles/" %} class="invert" {% endif %} ><span class="icons list-articles-blog"></span>
|
||||||
@@ -21,14 +21,21 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/myblog/personalize/" {% if request.path == "/myblog/personalize/" %} class="invert" {% endif %} ><span class="icons custom-blog"></span>
|
<a href="/myblog/personnalize/" {% if request.path == "/myblog/personnalize/" %} class="invert" {% endif %} ><span class="icons custom-blog"></span>
|
||||||
Configurer mon site web
|
Personnaliser mon blog
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/myblog/view/" {% if request.path == "/myblog/view/" %} class="invert" {% endif %} ><span class="icons view-blog" aria-hidden="true"></span>
|
<a href="/myblog/" {% if request.path == "/myblog/" %} class="invert" {% endif %} ><span class="icons view-blog" aria-hidden="true"></span>
|
||||||
Voir mon blog
|
Voir mon blog
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/private-blog/" {% if request.path == "/private-blog/" %} class="invert" {% endif %} ><span class="icons view-blog" aria-hidden="true"></span>
|
||||||
|
Blog du serveur
|
||||||
|
</a>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -38,14 +45,13 @@
|
|||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a href="/view/" {% if request.path == "/view/" %} class="invert" {% endif %}> <span class="icons myfiles"></span> Mes dossiers personels </a>
|
<a href="/view/" {% if request.path == "/view/" %} class="invert" {% endif %}> <span class="icons myfiles"></span> Mon dossier personnel </a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/gallery/" {% if request.path == "/gallery/" %} class="invert" {% endif %} > <span class="icons mygallery"></span> Ma gallerie d'images </a>
|
<a href="/gallery/" {% if request.path == "/gallery/" %} class="invert" {% endif %} > <span class="icons mygallery"></span> Ma galerie d'images </a>
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/filesupload/" {% if request.path == "/filesupload/" %} class="invert" {% endif %}> <span class="icons send-files"></span> Envoyer des fichiers </a>
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
@@ -57,16 +63,15 @@
|
|||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a href="/mymailbox/alias" {% if request.path == "/mymailbox/messagerie" %} class="invert" {% endif %}><span class="icons infos-messaging"></span>
|
<a href="/mymailbox/" {% if request.path == "/mymailbox/" %} class="invert" {% endif %}><span class="icons infos-messaging"></span>
|
||||||
Ma messagerie
|
Ma messagerie
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/mymailbox/alias" {% if request.path == "/mymailbox/alias" %} class="invert" {% endif %} ><span class="icons myalias"></span>
|
<a href="/mymailbox/alias" {% if request.path == "/mymailbox/alias" %} class="invert" {% endif %} ><span class="icons myalias"></span>
|
||||||
Gerer mes alias
|
Gérer mes alias
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,17 +9,20 @@
|
|||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
|
|
||||||
<h1> Bienvenue sur</h1>
|
<h1> Bienvenue sur : "{{ server_title }}" </h1>
|
||||||
|
<h3> {{ server_desc }} </h3>
|
||||||
|
|
||||||
<p>Bienvenue sur Olala, un portail utilisateur libre basé sur Flask à héberger sur un petit ordinateur.
|
<p>Bienvenue sur Pywallter, un application web basé sur Flask qui se veut être la plus légère possible.
|
||||||
Tu peux importer des fichiers et dans l'avenir les rendres disponibles pour ton site.
|
Tu peux importer des fichiers et dans l'avenir les rendres disponibles pour ton site ou ton blog.
|
||||||
Tu peux consulter ou participer au tableau des post-its pour communiquer avec les autres membres ou
|
Tu peux participer ou consulter le blog général du serveur pour te faire connaître par les autres membres ou
|
||||||
simplement savoir ce qu'il se passe sur le serveur.
|
simplement savoir ce qu'il se passe sur le serveur. Tu peux poster sur ton blog public et te faire connaître par les internets :p
|
||||||
</p>
|
</p>
|
||||||
|
{% if mail_server %}
|
||||||
<p>
|
<p>
|
||||||
Tu peux gérer ton compte MAIL et XMPP si les serveurs Mail(SMTP, IMAP) et XMPP sont actifs.
|
Si tu as la chance d'avoir un compte ici tu as accès à une messagerie e-mail et une messagerie instantanné avec ce même compte.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
{% include '_flash_msgs.html' %}
|
{% include '_flash_msgs.html' %}
|
||||||
|
|
||||||
|
|
||||||
@@ -38,10 +41,31 @@
|
|||||||
<p class="center"><a href="{{ url_for('loginlogout.lost_password') }}"> Mouarf j'ai perdu mon mot de passe </a> </p>
|
<p class="center"><a href="{{ url_for('loginlogout.lost_password') }}"> Mouarf j'ai perdu mon mot de passe </a> </p>
|
||||||
<button class="btn btn-default btn-primary" type="submit"> Login </button>
|
<button class="btn btn-default btn-primary" type="submit"> Login </button>
|
||||||
</form>
|
</form>
|
||||||
|
{% if list_posts %}
|
||||||
|
<h2> Les derniers articles de blog sur le serveur </h2>
|
||||||
|
<div class="list-articles" >
|
||||||
|
|
||||||
|
{% for article in list_posts %}
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h3> {{ article.title }} </h3>
|
||||||
|
<h5> par <a href="/blog/{{ article.author }}/">{{ article.author }}</a> </h5>
|
||||||
|
<br/>
|
||||||
|
<small> Créé le : {{ article.creation_date }} </small> <br/>
|
||||||
|
{% if article.last_updated %}
|
||||||
|
<small> Modifié le : {{ article.last_updated }}</small><br/>
|
||||||
|
{% endif %}
|
||||||
|
</header>
|
||||||
|
<div class="subtitle">
|
||||||
|
<p> {{ article.subtitle }} </p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
<footer><a href="/blog//public_unified/{{ article.author }}/{{ article.title }}"> <button> Lire la suite </button> </a></footer>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,33 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title> Blog de {{ user }} </title>
|
<title> Article de {{ post_info.author }} </title>
|
||||||
<link rel="stylesheet" href="/static/blog.css" type="text/css">
|
|
||||||
|
<link rel="stylesheet" href="/{{ post_info.author }}/blog.css" type="text/css">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="articles">
|
<div class="articles">
|
||||||
|
<div class="head-article">
|
||||||
<h2 class="titre"> {{ post_info.title }} </h2>
|
<h2> {{ post_info.title }} </h2>
|
||||||
|
|
||||||
<h5 class="titre">Publié le {{ post_info.time }} </h5>
|
<h5>Publié le : {{ post_info.creation_date }} par <a href="{{ url_for('blog.view') }}/{{ post_info.author }}"> {{ post_info.author }} </h5></a>
|
||||||
|
{% if post_info.last_updated %}
|
||||||
<h2 class="description titre"> {{ post_info.subtitle }} </h2>
|
<h5>Mis à jour le : {{ post_info.last_updated }} </h5>
|
||||||
<hr/>
|
{% endif %}
|
||||||
|
<h3 class="description"> {{ post_info.subtitle }} </h3>
|
||||||
|
</div>
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<div class="text-article">
|
||||||
{{ content|safe }}
|
{{ content|safe }}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<footer> <p> pywallter </p> </footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
26
templates/blog_author.html
Normal file
26
templates/blog_author.html
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title> Article de {{ post_info.author }} </title>
|
||||||
|
<link rel="stylesheet" href="/{{ post_info.author}}/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.creation_date }} </h5>
|
||||||
|
{% if post_info.last_updated %}
|
||||||
|
<h5 class="titre">Mis à jour le : {{ post_info.last_updated }} </h5>
|
||||||
|
{% endif %}
|
||||||
|
<h3 class="description titre"> {{ post_info.subtitle }} </h3>
|
||||||
|
<hr/>
|
||||||
|
{{ content|safe }}
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
35
templates/blog_rss.xml
Normal file
35
templates/blog_rss.xml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<rss version="2.0"
|
||||||
|
xmlns:content="http://purl.org/rss/1.0/modules/content/"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:atom="http://www.w3.org/2005/Atom"
|
||||||
|
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
|
||||||
|
xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
|
||||||
|
<channel>
|
||||||
|
<title> Le blog de {{ blog_name }} </title>
|
||||||
|
<link> {{ base_url }}/blog/ </link>
|
||||||
|
{% if blog_description %}
|
||||||
|
<description> {{ blog_description }} </description>
|
||||||
|
{% endif %}
|
||||||
|
<language>fr</language>
|
||||||
|
<lastBuildDate> {{ last_build_date }} </lastBuildDate>
|
||||||
|
|
||||||
|
{% for post in posts %}
|
||||||
|
<item>
|
||||||
|
<title> {{ post.title }} </title>
|
||||||
|
<pubdate> {% if post.last_updated %} {{ post.last_updated }} {% else %} {{ post.time }} {% endif %} </pubdate>
|
||||||
|
<link> {{base_url}}/blog/{{ post.status }}/{{post.author}}/{{post.title}}</link>
|
||||||
|
<guid> {{base_url}}/blog/{{ post.status }}/{{post.author}}/{{post.title}}</guid>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
{{ post.subtitle }}
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<content:encoded>
|
||||||
|
{{ post.content | safe }}
|
||||||
|
</content:encoded>
|
||||||
|
</item>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
3
templates/css/dropzone.html
Normal file
3
templates/css/dropzone.html
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<script src="{{ url_for('static', filename='vendors/dropzone/dropzone-min.js') }}"></script>
|
||||||
|
<link href="{{ url_for('static', filename='vendors/dropzone/dropzone.css') }}" rel="stylesheet">
|
||||||
|
|
||||||
3
templates/css/simple_editor.html
Normal file
3
templates/css/simple_editor.html
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
<link href="{{ url_for('static', filename='vendors/simplemde/simplemde.min.css') }}" rel="stylesheet">
|
||||||
|
<link href="{{ url_for('static', filename='simplemde-custom.css') }}" rel="stylesheet">
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<h1> Supprimer mon compte </h1>
|
<h1> Supprimer mon compte </h1>
|
||||||
<p class="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 class="center"> Vous voulez supprimer votre compte pas de problème, 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>
|
</p>
|
||||||
<h3> Entrez votre mot de passe pour confirmer la suppression de votre compte </h3>
|
<h3> Entrez votre mot de passe pour confirmer la suppression de votre compte </h3>
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,63 @@
|
|||||||
{% extends 'up_squelette.html' %}
|
{% extends 'up_squelette.html' %}
|
||||||
|
|
||||||
{% block main %}
|
{% block css %}
|
||||||
|
{% include 'css/simple_editor.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<p>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.</p>
|
{% block main %}
|
||||||
|
|
||||||
|
|
||||||
<h2> {{ oldpost[0] }}</h2><br />
|
<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['title'] }}"><br />
|
||||||
|
<input type="text" name="subtitle" id="subtitle" placeholder="sous-titre" class="form-control" value="{{ oldpost['subtitle'] }}"><br />
|
||||||
<input type="text" name="subtitle" id="subtitle" placeholder="Titre" class="form-control" value="{{ oldpost[1] }}"><br />
|
<input type="text" name="category" id="category" placeholder="Catégorie" class="form-control" value="{{ oldpost['category'] }}"><br />
|
||||||
<textarea id="editeurMarkdown" class="form-control" form="postform" name="content" id="content" placeholder="Contenu" style="height:20vw;">{{ content }}</textarea><br />
|
<textarea id="editeurMarkdown" class="form-control" form="postform" name="content" id="content" placeholder="Contenu" style="height:20vw;">{{ oldpost['content'] }}</textarea>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
<h3> Visibilité </h3>
|
<h3> Visibilité </h3>
|
||||||
|
|
||||||
<div class="center">
|
<div class="center">
|
||||||
{% if oldpost[2] == 'public' %}
|
<p> Les articles brouillons ne sont visibles que par vous même</p>
|
||||||
<input type="radio" name="status" value="prive"> Privé
|
<p> Les articles privés ne sont visibles que par les membres du serveur </p>
|
||||||
|
<p> Les articles public sont visibles par tout le monde </p>
|
||||||
|
|
||||||
|
|
||||||
|
{% if oldpost['status'] == 'public' or oldpost['status'] == "public_unified" %}
|
||||||
|
<input type="radio" name="status" value="draft"> Brouillon
|
||||||
|
<input type="radio" name="status" value="private"> Privé
|
||||||
<input type="radio" name="status" value="public" checked> Publique
|
<input type="radio" name="status" value="public" checked> Publique
|
||||||
|
|
||||||
{% else %}
|
{% elif oldpost['status'] == 'private' or oldpost['status'] == "private_unified" %}
|
||||||
<input type="radio" name="status" value="Privé" checked> Privé
|
<input type="radio" name="status" value="draft"> Brouillon
|
||||||
|
<input type="radio" name="status" value="private" checked> Privé
|
||||||
<input type="radio" name="status" value="public"> Publique
|
<input type="radio" name="status" value="public"> Publique
|
||||||
|
{% else %}
|
||||||
|
<input type="radio" name="status" value="draft" checked> Brouillon
|
||||||
|
<input type="radio" name="status" value="private"> Privé
|
||||||
|
<input type="radio" name="status" value="public"> Publique
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
|
||||||
|
<fieldset>
|
||||||
|
<label>
|
||||||
|
|
||||||
|
{% if oldpost['status'] == "private_unified" or oldpost['status'] == "public_unified" %}
|
||||||
|
<input id="blog-unified" name="blog-unified" type="checkbox" role="switch" checked />
|
||||||
|
{% else %}
|
||||||
|
<input id="blog-unified" name="blog-unified" type="checkbox" role="switch" />
|
||||||
|
{% endif %}
|
||||||
|
Publier cet article dans le blog général
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<button type="submit"> Mettre à jour </button>
|
<button type="submit"> Mettre à jour </button>
|
||||||
</form>
|
</form>
|
||||||
<br />
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{% include '_js_editor.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
50
templates/files.html
Normal file
50
templates/files.html
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{% extends 'up_squelette.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
{% include 'css/dropzone.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
|
||||||
|
|
||||||
|
<p>Quand vous envoyez des images, elles se retrouveront directement dans <a href="/gallery/"> votre Galerie</a>. </p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Ayez bien conscience que ce site est une expérience et qu'il est indispensable d'avoir
|
||||||
|
une sauvegarde de tous les fichiers qui vous mettrez ici. Nous ne pourrons, en aucun cas, être tenu responsable de la
|
||||||
|
perte de vos données. Merci de votre compréhension.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
|
||||||
|
<form id="uploader" methods="POST" class="dropzone dz-clickable"></form>
|
||||||
|
|
||||||
|
<h2> Fichiers privés </h2>
|
||||||
|
<h5>
|
||||||
|
Vous pouvez partager des liens de vos fichiers avec les autres membres de ce serveur uniquement. Si vous partagez un lien avec une personne non inscrite elle ne pourra pas y avoir accès
|
||||||
|
</h5>
|
||||||
|
<div hx-get="/files/private/" hx-trigger="load, every 10s">
|
||||||
|
Chargement ...
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<h2> Fichiers publics </h2>
|
||||||
|
<h5> Vous pouvez partager les liens de ces fichiers avec n'importe qui sur Internet ils y auront accès </h5>
|
||||||
|
|
||||||
|
<div hx-get="/files/public/" hx-trigger="load, every 10s">
|
||||||
|
Chargement ...
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{% include '_js_dropzone.html' %}
|
||||||
|
{% include '_js_htmx.html' %}
|
||||||
|
{% endblock %}
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
{% extends 'up_squelette.html' %}
|
{% extends 'up_squelette.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
<h3> Ma gallerie </h3>
|
<h3> Ma gallerie </h3>
|
||||||
|
|
||||||
|
|
||||||
{% if fichiers %}
|
{% if fichiers %}
|
||||||
|
|
||||||
|
|
||||||
@@ -24,7 +27,7 @@
|
|||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
<h2> Il n'y a aucunes images dans votre gallerie </h2>
|
<h2> Il n'y a aucune image dans votre galerie </h2>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|||||||
42
templates/index_author_blog.html
Normal file
42
templates/index_author_blog.html
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title> Le Blog du serveur </title>
|
||||||
|
<link rel="stylesheet" href="/{{ author }}/blog.css" type="text/css">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
{% if not(posts) %}
|
||||||
|
<h1 style="text-align: center;"> Désolé ce blog n'existe pas encore :/ </h1>
|
||||||
|
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<a href="/blog/{{ author }}/rss.xml"> S'abonner au flux RSS </a>
|
||||||
|
<div class="articles">
|
||||||
|
<a href="/blog/{{ author }}/rss.xml"> S'abonner au fl RSS </a>
|
||||||
|
{% for post in posts %}
|
||||||
|
|
||||||
|
<h2 class="index"> {{ post.title }} </h2>
|
||||||
|
<small>
|
||||||
|
<time datetime="{{ post.time }}">
|
||||||
|
Publié le {{ post.creation_date }}
|
||||||
|
</time>
|
||||||
|
<br/>
|
||||||
|
{% if post.last_updated %}
|
||||||
|
<time datetime="{{ post.last_updated }}">
|
||||||
|
Mis à jour le {{ post.last_updated }}
|
||||||
|
</time>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
</small>
|
||||||
|
<div class="slug">
|
||||||
|
<p> {{ post.subtitle }} </p>
|
||||||
|
<p class="readmore"> <a style="margin-right:2rem;" href="/blog/{{ post.status }}/{{post.author}}/{{post.title}}"> Lire la suite... </a></p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,27 +1,47 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title> Blog de {{ user }} </title>
|
<title> Le Blog du serveur </title>
|
||||||
|
{% if author %}
|
||||||
|
<link rel="stylesheet" href="/{{author}}/blog.css" type="text/css">
|
||||||
|
{% else %}
|
||||||
<link rel="stylesheet" href="/static/blog.css" type="text/css">
|
<link rel="stylesheet" href="/static/blog.css" type="text/css">
|
||||||
|
{% endif %}
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
{% if not(posts) %}
|
||||||
|
<h1 style="text-align: center;"> Désolé ce blog n'existe pas encore :/ </h1>
|
||||||
|
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
|
||||||
<div class="articles">
|
<div class="articles">
|
||||||
|
<a href="/blog/rss.xml"> Suivre ce blog par RSS </a>
|
||||||
{% for post in posts %}
|
{% for post in posts %}
|
||||||
|
|
||||||
<h2 class="index"><a href="/blog/{{user}}/{{post.title}}"> {{ post.title }}</a></h2>
|
<h2 class="index"> {{ post.title }}</h2>
|
||||||
<small>
|
<small>
|
||||||
<time datetime="{{ post.time }}">
|
<time datetime="{{ post.time }}">
|
||||||
Publié le {{ post.time }}
|
Publié le {{ post.creation_date }} par <a href="{{ url_for('blog.view') }}/{{ post.author }}"> {{ post.author }}</a>
|
||||||
</time>
|
</time>
|
||||||
</small>
|
<br/>
|
||||||
<div class="slug">
|
{% if post.last_updated %}
|
||||||
<p> {{ post.subtitle }} </p>
|
<time datetime="{{ post.last_updated }}">
|
||||||
<p class="readmore"> <a style="margin-right:2rem;" href="/blog/{{user}}/{{post.title}}"> Lire la suite... </a></p>
|
Mis à jour le {{ post.last_updated }}
|
||||||
</div>
|
</time>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
</small>
|
||||||
|
<div class="slug">
|
||||||
|
<p> {{ post.subtitle }} </p>
|
||||||
|
<p class="readmore"> <a style="margin-right:2rem;" href="/blog/{{ post.status }}/{{post.author}}/{{post.title}}"> Lire la suite... </a></p>
|
||||||
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -2,69 +2,46 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
<div class="site-wrapper">
|
|
||||||
|
|
||||||
<div class="site-wrapper-inner">
|
<h1>Inscription</h1>
|
||||||
|
<br>
|
||||||
|
{% include '_flash_msgs.html' %}
|
||||||
|
|
||||||
<div class="cover-container">
|
{% if signin_enable %}
|
||||||
|
<form method="POST" action="{{ url_inscription }}">
|
||||||
|
<h4> Choisissez votre nom d'utilisateur pour vous connecter sur le portail pywallter </h4>
|
||||||
|
|
||||||
<div class="masthead clearfix">
|
{% if MAIL_SERVER or XMPP_SERVER %}
|
||||||
<div class="inner">
|
<fieldset role="group">
|
||||||
<h3 class="masthead-brand">Pywallter</h3>
|
<input type="text" name="user" id="user" placeholder="Votre pseudo">
|
||||||
<ul class="nav masthead-nav">
|
<button class="outline">
|
||||||
<li><a href="/login/">Login</a></li>
|
@{{ hostname }}
|
||||||
|
</button>
|
||||||
{% if signin_enable %}
|
</fieldset>
|
||||||
<li class="active"><a href="/inscription/">Inscription</a></li>
|
|
||||||
{% endif %}
|
<p>
|
||||||
<li><a href="#">Contact</a></li>
|
Votre pseudo vous servira à vous connecter à votre compte Mail et de messagerie instantanné (XMPP)
|
||||||
</ul>
|
Par exemple vous souhaitez l'adresse toto@{{hostname}}; vous entrez le pseudo toto :)
|
||||||
</div>
|
</p>
|
||||||
</div>
|
|
||||||
|
{% else %}
|
||||||
<div class="inner cover">
|
<input type="text" name="user" id="user" placeholder="Votre Pseudo"><br />
|
||||||
<h1 class="cover-heading">Inscription</h1>
|
{% endif %}
|
||||||
<br>
|
|
||||||
{% include '_flash_msgs.html' %}
|
<input type="password" name="passwd" id="passwd" placeholder="Mot de passe"><br />
|
||||||
|
<input type="password" name="passwdconfirm" id="passwdconfirm" placeholder="Confirmation du mot de passe"><br />
|
||||||
{% if signin_enable %}
|
<br>
|
||||||
<form method="POST" class="form-horizontal" action="{{ url_inscription }}">
|
<button type="submit">Créer mon compte</button>
|
||||||
<h4> Choisissez votre nom d'utilisateur pour vous connecter sur le portail pywallter </h4>
|
</form>
|
||||||
<input type="text" name="user" id="user" placeholder="Pseudo" class="form-control"><br />
|
{% else %}
|
||||||
{% if MAIL_SERVER or XMPP_SERVER %}
|
<p class="lead">
|
||||||
|
Désolé les inscriptions ne sont pas activés sur le serveur
|
||||||
<p>
|
</p>
|
||||||
Votre nom d'utilisateur vous servira à vous connecter à votre compte Mail et de messagerie instantanné (XMPP)
|
{%endif%}
|
||||||
Par exemple vous souhaitez l'adresse toto@{{hostname}}; vous entrez le nom d'utilisateur toto :)
|
{% for i in users %}
|
||||||
</p>
|
<p>{{i}}</p>
|
||||||
{% endif %}
|
{% endfor %}
|
||||||
|
|
||||||
<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 %}
|
|
||||||
</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 %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -6,11 +6,10 @@
|
|||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Si vous voulez vous pouvez inviter une personne à se crée un compte sur ce serveur
|
Si vous voulez vous pouvez inviter une personne à se créer un compte sur ce serveur.
|
||||||
pour cela vous devez crée un lien d'inscription. Ce lien restera valable tant
|
Pour cela vous devez créer un lien d'inscription. Ce lien restera valable tant que vous ne créez pas un autre lien.
|
||||||
que la personne ne s'est pas inscrite ou tant que vous ne créez pas un autre lien.
|
Les invitations sont limité à 20 personnes pour ne pas surcharger notre petit serveur :).
|
||||||
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 inscrite votre nombre d'invitations sera mis à jour.
|
||||||
Une fois que la personne s'est incrite votre nombre d'invitations sera mis à jour
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
@@ -19,9 +18,16 @@
|
|||||||
{% if token %}
|
{% if token %}
|
||||||
<h3> Votre lien d'inscription en cours: </h3>
|
<h3> Votre lien d'inscription en cours: </h3>
|
||||||
|
|
||||||
<a href="{{ url_invitation }}">
|
<a href="{{ url_invitation }}" id="copy-link">
|
||||||
{{ url_invitation }}
|
{{ url_invitation }}
|
||||||
</a>
|
</a> <button class="ghost" onclick="copyLinkToClipboard()" > Copier le lien </button>
|
||||||
|
|
||||||
|
|
||||||
|
<p> ou faîtes scanner ce qrcode :)</p>
|
||||||
|
|
||||||
|
<img src="/invitation.png"/>
|
||||||
|
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<h3> Pas d'invitation en attente </h3>
|
<h3> Pas d'invitation en attente </h3>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -29,7 +35,22 @@
|
|||||||
<a href="/gen_token/">
|
<a href="/gen_token/">
|
||||||
<button type="submit" id="tada" class="btn btn btn-success"> Créer un nouveau lien </button></a>
|
<button type="submit" id="tada" class="btn btn btn-success"> Créer un nouveau lien </button></a>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function copyLinkToClipboard(){
|
||||||
|
|
||||||
|
elt = document.getElementById("copy-link");
|
||||||
|
try {
|
||||||
|
console.log(elt.outerText);
|
||||||
|
navigator.clipboard.writeText(elt.outerText);
|
||||||
|
} catch (error)
|
||||||
|
{
|
||||||
|
console.error (error.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
|
{% if nb_articles > 1 %}
|
||||||
<h2> Vos articles de blog </h2>
|
<h2> Vos {{ nb_articles }} articles de blog </h2>
|
||||||
|
{% endif %}
|
||||||
|
<br/>
|
||||||
|
|
||||||
{% for article in list_posts %}
|
{% for article in list_posts %}
|
||||||
<article>
|
<article>
|
||||||
@@ -14,13 +15,29 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<small> Créé le : {{ article.time }} </small> <br/>
|
<small> Créé le : {{ article.time }} </small> <br/>
|
||||||
<small> Modifié le : {{ article.last_updated }}</small>
|
|
||||||
<p> Status : {{ article.status }}</p>
|
{% if article.last_updated %}
|
||||||
<br/>
|
<small> Modifié le : {{ article.last_updated }}</small><br/>
|
||||||
|
{% endif %}
|
||||||
|
<br/>
|
||||||
|
{% if article.status == "private" %}
|
||||||
|
<small> Status : privé </small>
|
||||||
|
<small> (L'article n'est pas publié dans le blog général) </small>
|
||||||
|
{% elif article.status == "private_unified" %}
|
||||||
|
<small> Status : privé </small>
|
||||||
|
<small> (L'article est publié dans le blog général) </small>
|
||||||
|
{% elif article.status == "public" %}
|
||||||
|
<small> Status : public </small>
|
||||||
|
<small> (L'article n'est pas publié dans le blog général) </small>
|
||||||
|
{% elif article.status == "public_unified" %}
|
||||||
|
<small> Status : public </small>
|
||||||
|
<small> (L'article est publié dans le blog général) </small>
|
||||||
|
{% endif %}
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
<a href="{{ url_for('blog.edit', title=article.title) }}"><button type="button"> Editer </button></a>
|
<a href="{{ url_for('blog.edit', title=article.title) }}"><button type="button"> Editer </button></a>
|
||||||
<a href="{{ url_for('blog.delete', title=article.title) }}"><button type="button">Supprimer</button></a>
|
<a href="{{ url_for('blog.delete', title=article.title) }}"><button type="button">Supprimer</button></a>
|
||||||
<a href="{{ url_for('blog.edit', title=article.title) }}"><button type="button"> Publier </button></a>
|
|
||||||
</article>
|
</article>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|||||||
54
templates/list_files.html
Normal file
54
templates/list_files.html
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
{% if listFiles %}
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>Fichier(s) <span class="badge">{{ nb_files }}</span></th>
|
||||||
|
<th>Taille (en Megaoctect)</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
{% for file in listFiles %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ file[0] }}</td>
|
||||||
|
<td><a href="/myfiles/{{ username }}/{{ file[1] }}">{{ file[1] }}</a></td>
|
||||||
|
<td>{{ file[2] }}</td>
|
||||||
|
<td>
|
||||||
|
{% if status == "public" %}
|
||||||
|
<td>
|
||||||
|
<a href="{{ url_for('filesupload.remove_publicFile', filename=file[1]) }}">
|
||||||
|
<button type="button" title="Supprimer"> <span class="icons delete"></span></button>
|
||||||
|
</a>
|
||||||
|
<a href="{{ url_for('filesupload.move_private', filename=file[1]) }}">
|
||||||
|
<button type="button" title="Passer ce fichier en status privé"><span class="icons share"></span></button>
|
||||||
|
</a>
|
||||||
|
<button type="button" onclick="navigator.clipboard.writeText('{{BASE_URL}}{{ url_for('filesupload.publicfiles', username=username, filename=file[1]) }}');" title="Copier le lien du fichier">
|
||||||
|
<span class="icons copy-link"> </span>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="{{ url_for('filesupload.remove_privateFile', filename=file[1]) }}">
|
||||||
|
<button type="button" title="Supprimer"> <span class="icons delete"></span></button>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ url_for('filesupload.move_public', filename=file[1]) }}">
|
||||||
|
<button type="button" title="Passer ce fichier en status public"><span class="icons share"></span></button>
|
||||||
|
</a>
|
||||||
|
<button type="button" onclick="navigator.clipboard.writeText('{{BASE_URL}}{{ url_for('filesupload.publicfiles', username=username, filename=file[1]) }}');" title="Copier le lien du fichier">
|
||||||
|
<span class="icons copy-link"> </span>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<h5> Aucun fichier ici </h5>
|
||||||
|
{% endif %}
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
{% include '_footer.html' %}
|
{% include '_footer.html' %}
|
||||||
|
|
||||||
{% include '_js.html' %}
|
{% include '_js-core.html' %}
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -5,85 +5,62 @@
|
|||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
{% if MAIL_SERVER %}
|
{% if MAIL_SERVER %}
|
||||||
<div class="col-md-12">
|
<h3> Mes identités : A quoi ça sert les alias ? </h3>
|
||||||
|
<p> Les alias d'e-mail, c'est utile quand vous ne voulez pas donner votre vrai adresse e-mail.
|
||||||
<h3> A quoi ca sert les alias ? </h3>
|
Vous pouvez creer une adresse que vous pouvez supprimer rapidemment, cela permet de creer une adresse pour un destinataire particulier
|
||||||
<p> Les alias c'est utile quand vous ne voulez pas donner votre vrai adresse e-mail.
|
si vous n'avez pas confiance en lui par exemple ou de trier plus facilement les e-mails venant de ce destinataire.
|
||||||
Vous pouvez creer une adresse que vous pouvez supprimer rapidemment, cela permet personnaliser une adresse pour un destinataire
|
</p>
|
||||||
si vous n'avez pas confiance en lui ou de trier plus facilement les e-mails venant de ce destinataire.
|
<p> Vous n'avez pas besoin de configurer un autre compte mail sur vos applications mail, tous les e-mails
|
||||||
</p>
|
arriveront sur votre adresse e-mail principale déjà configurée. Faîtes attention de bien répondre avec votre mail d'alias cependant !
|
||||||
<p> Vous n'avez pas besoin de configurer un autre compte mail sur vos applications, tous les e-mails
|
</p>
|
||||||
arriveront sur votre adresse e-mail principale déjà configuré
|
<table class="table">
|
||||||
</p>
|
<thead>
|
||||||
<table class="table">
|
<tr>
|
||||||
<thead>
|
<th>Mes identités <span class="badge">{{ i }}</span></th>
|
||||||
<tr>
|
<th></th>
|
||||||
<th>Mes Alias <span class="badge">{{ i }}</span></th>
|
</tr>
|
||||||
<th></th>
|
</thead>
|
||||||
</tr>
|
<tbody>
|
||||||
</thead>
|
{% if aliases %}
|
||||||
<tbody>
|
{% for alias in aliases %}
|
||||||
{% if aliases %}
|
<tr>
|
||||||
{% for alias in aliases %}
|
<td>{{ alias }}</td>
|
||||||
<tr>
|
<td><a href="{{ url_for('mymailbox.remove_alias', aliasrm=alias) }}"><button type="button" class="btn btn-sm btn-danger">Supprimer</button></a></td>
|
||||||
<td>{{ alias }}</td>
|
</tr>
|
||||||
<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 %}
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3 class="panel-title"> Mes identités </h3>
|
||||||
|
|
||||||
|
|
||||||
|
<form method="POST" action="" enctype="multipart/form-data">
|
||||||
|
|
||||||
|
<h4> Votre addresse e-mail sur ce serveur : {{ email }} </h4>
|
||||||
|
|
||||||
|
<label> Nouvelle identité </label>
|
||||||
|
<br/>
|
||||||
|
<fieldset role="group">
|
||||||
|
<input type="text" name="alias" id="alias" placeholder="Nouvel_identité">
|
||||||
|
<button class="outline">
|
||||||
|
@{{ hostname }}
|
||||||
|
</button>
|
||||||
|
</fieldset>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<button class="btn btn-default btn-primary" type="submit">Créer cette identité</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<h3 class="panel-title"> Mes identitées </h3>
|
||||||
|
|
||||||
|
<h2> Le serveur de mail n'est pas activé cette fonctionnalitée est désactivé <h2>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
89
templates/mymessaging.html
Normal file
89
templates/mymessaging.html
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
{% extends 'up_squelette.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
|
||||||
|
{% if not(mail_server) or not(xmpp_server) %}
|
||||||
|
|
||||||
|
<h3 class="panel-title"> Ma Messagerie </h3>
|
||||||
|
|
||||||
|
<h2> Le service de messagerie n'est pas activé sur ce serveur <h2>
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3> Bienvenue {{ username }} dans votre messagerie</h3>
|
||||||
|
|
||||||
|
<h4> Votre compte est : {{ myemail }} </h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Si vous êtes sur cette page, c'est que vous disposez d'un compte de messaegerie sur ce serveur.
|
||||||
|
Vous pouvez utiliser votre compte mail avec un client mail et votre compte XMPP avec un client XMPP.
|
||||||
|
</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>
|
||||||
|
|
||||||
|
{% if mail_webservice %}
|
||||||
|
<p>
|
||||||
|
Vous pouvez aussi accéder à vos mails avec votre navigateur web actuel en utilisant le webmail disponible à l'adresse <a href="{{ mail_webservice }}"> {{ mail_webservice }} </a>.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if xmpp_webservice %}
|
||||||
|
<p>
|
||||||
|
Vous pouvez aussi accéder à votre messagerie instantanné avec votre Navgateur web actuel en utilisant le tchat disponible à l'adresse <a href="{{ xmpp_webservice }}"> {{ xmpp_webservice }} </a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if xmpp_server %}
|
||||||
|
|
||||||
|
<h3> Vos informations pour configurer vos clients XMPP </h3>
|
||||||
|
<p> Si vous voulez configurer votre compte XMPP dans votre, voici les informations à rentrer dans votre client XMPP </p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li> identifiant : {{ myemail }} </li>
|
||||||
|
<li> mot de passse : <pre> Le même mot de passe que vous avez utilisé pour vous connecter ici </pre></li>
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<h4 class="alert" > La messagerie XMPP est désativé sur ce serveur </h4>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if mail_server %}
|
||||||
|
<h3> Vos informations pour configurer vos clients Mail </h3>
|
||||||
|
<p> Si vous voulez configurer votre adresse e-mail, voici les informations à rentrer dans votre client mail </p>
|
||||||
|
<h4>Courrier entrant : </h4>
|
||||||
|
<ul>
|
||||||
|
<li> Protocol : IMAP </li>
|
||||||
|
<li> Addresse du serveur : {{ imap_address }} </li>
|
||||||
|
<li> Port : 993 SSL </li>
|
||||||
|
<li> identifiant : {{ myemail }} </li>
|
||||||
|
<li> mot de passse : <pre> Le même mot de passe que vous avez utilisé pour vous connecter ici </pre> </li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>Courrier sortant : </h4>
|
||||||
|
<ul>
|
||||||
|
<li> Protocol : SMTP </li>
|
||||||
|
<li> Addresse du serveur : {{ smtp_address }} </li>
|
||||||
|
<li> Port : 587 STARTTLS </li>
|
||||||
|
<li> identifiant : {{ myemail }} </li>
|
||||||
|
<li> mot de passse : <pre> Le même mot de passe que vous avez utilisé pour vous connecter ici </pre> </li>
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<h4 class="alert" > La messagerie e-mail est désativé sur ce serveur </h4>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
<p> Voici quelques exemple de générateur de mot de passe à usage unique (OTP en anglais) pour <a href="https://getaegis.app/">Android</a>, <a href="https://apps.apple.com/us/app/totp-authenticator-fast-2fa/id1404230533">iOS</a> et <a href="https://keepassxc.org/">Linux/BSD et windows</a>
|
<p> Voici quelques exemple de générateur de mot de passe à usage unique (OTP en anglais) pour <a href="https://getaegis.app/">Android</a>, <a href="https://apps.apple.com/us/app/totp-authenticator-fast-2fa/id1404230533">iOS</a> et <a href="https://keepassxc.org/">Linux/BSD et windows</a>
|
||||||
|
|
||||||
<p> Afin que le serveur et votre application génère le même code en même temps; il vous faut valider la clef sécrete partager par votre application et le serveur. Pour cela, si ce n'est pas déjà fait, scannez ou entrez la clef secrète dans votre application. Pour finir, cliquez sur valider la clef en entrant le code générer par votre application. Si le test réussi parfait c'est configuré ! </p>
|
<p> Afin que le serveur et votre application génèrent le même code en même temps; il vous faut valider la clef sécrete partager par votre application et le serveur. Pour cela, si ce n'est pas déjà fait, scannez ou entrez la clef secrète dans votre application. Pour finir, cliquez sur valider la clef en entrant le code généré par votre application. Si le test réussi parfait c'est configuré ! </p>
|
||||||
|
|
||||||
<p> Pour changer votre clef secrète vous devez d'abord supprimer votre clef actuelle pour en regénérer une nouvelle. </p>
|
<p> Pour changer votre clef secrète vous devez d'abord supprimer votre clef actuelle pour en regénérer une nouvelle. </p>
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
<p class="success"> Votre clef secrète est valide et activé </p>
|
<p class="success"> Votre clef secrète est valide et activé </p>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
<p class="alert"> Votre clef secrète n'est pas validé et donc non active </p>
|
<p class="alert"> Votre clef secrète n'est pas validée et donc non active </p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form method="POST" action="{{ url_for('profil.set_totp') }}" >
|
<form method="POST" action="{{ url_for('profil.set_totp') }}" >
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<p> Hello <span id="majuscule">{{ session['username'] }} ! </span>
|
<p> 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,
|
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é
|
vous avez le choix de le rendre public dès sa création en cochant public ou le laisser en privé
|
||||||
si vous souhaitez le modifier plus-tard avant sa publication.
|
si vous souhaitez le modifier plus-tard avant sa publication.
|
||||||
Par défaut il est laissé en privé pour éviter les publications
|
Par défaut il est laissé en privé pour éviter les publications
|
||||||
accidentelles.
|
accidentelles.
|
||||||
@@ -15,20 +15,40 @@
|
|||||||
<br />
|
<br />
|
||||||
|
|
||||||
<form method="POST" action="{{ url_for('blog.new_article') }}" id="postform">
|
<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="title" id="title" placeholder="Titre" class="form-control"><br />
|
||||||
<input type="text" name="subtitle" id="subtitle" placeholder="Sous-titre" class="form-control"><br />
|
<input type="text" name="subtitle" id="subtitle" placeholder="Sous-titre" class="form-control"><br />
|
||||||
|
<input type="text" name="category" id="category" placeholder="Catégories #hashtag" class="form-control"><br />
|
||||||
<hr>
|
<hr>
|
||||||
<textarea id="editeurMarkdown" class="form-control" form="postform" name="content" id="content" placeholder="Contenu" style="height:20vw;"></textarea><br />
|
<textarea id="editeurMarkdown" class="form-control" form="postform" name="content" id="content" placeholder="Contenu" style="height:20vw; margin-right:2vw;"></textarea><br />
|
||||||
|
|
||||||
|
<h3> Visibilité </h3>
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<input type="radio" name="status" value="private" checked> Privé
|
<p> Les articles brouillons ne sont visibles que par vous même</p>
|
||||||
|
<p> Les articles privés ne sont visibles que par les membres du serveur </p>
|
||||||
|
<p> Les articles public sont visibles par tout le monde </p>
|
||||||
|
<input type="radio" name="status" value="draft"> Brouillon
|
||||||
|
<input type="radio" name="status" value="private" checked> Privé
|
||||||
<input type="radio" name="status" value="public">Public<br>
|
<input type="radio" name="status" value="public">Public<br>
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<button id="tada" type="submit"> Créer l'article </button>
|
|
||||||
|
<fieldset>
|
||||||
|
<label>
|
||||||
|
|
||||||
|
<input id="blog-unified" name="blog-unified" type="checkbox" role="switch" />
|
||||||
|
Publier cet article dans le blog général
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<button type="submit"> Créer l'article </button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{% include '_js_editor.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
34
templates/personnalize_blog.html
Normal file
34
templates/personnalize_blog.html
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{% extends 'up_squelette.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
|
||||||
|
<h2> Personnalisation du blog </h2>
|
||||||
|
|
||||||
|
<form method="POST" action="" enctype="multipart/form-data">
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<label for="blog-theme">Theme</label>
|
||||||
|
<select id="blog-theme" name="blog-theme">
|
||||||
|
<option selected> Default </option>
|
||||||
|
<option>orangina</option>
|
||||||
|
<option>blanc&noir</option>
|
||||||
|
<option>noir&blanc</option>
|
||||||
|
<option>orange&noir</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="personnal-blog-theme" class="center">
|
||||||
|
<p> Vous pouvez faire le choix d'envoyer un fichier css pour personnaliser votre blog directement.
|
||||||
|
<label> Envoyer mon thème </label>
|
||||||
|
<input type="file" class="center" name="personnal-blog-theme" id="personnal-blog-theme"/>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-default btn-primary" type="submit"> Enregistrer mes modifications </button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -4,9 +4,7 @@
|
|||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3> Mon profil </h3>
|
<h3> Mon profil </h3>
|
||||||
<p>
|
<p>
|
||||||
@@ -15,8 +13,10 @@
|
|||||||
cela vous convient.
|
cela vous convient.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p> Pour votre mail de secours il sert à vous envoyer un mail pour changer de mot de passe en cas de perte de ce dernier. Il n'y a
|
<p>
|
||||||
pas encore de validation de l'e-mail donc vérifiez bien ce que vous tapez. </p>
|
Pour votre mail de secours il sert à vous envoyer un mail pour changer de mot de passe en cas de perte de ce dernier. Il n'y a
|
||||||
|
pas encore de validation de l'e-mail donc vérifiez bien ce que vous tapez.
|
||||||
|
</p>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
@@ -30,40 +30,40 @@
|
|||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<label for="theme">Theme</label>
|
<label for="theme">Thème</label>
|
||||||
<select id="theme" name="theme" required>
|
<select id="theme" name="theme">
|
||||||
<option value="" selected>Default</option>
|
<option value="" selected>Choisissez votre couleur</option>
|
||||||
<option>amber</option>
|
<option>amber</option>
|
||||||
<option>blue</option>
|
<option>blue</option>
|
||||||
<option>cyan</option>
|
<option>cyan</option>
|
||||||
<option>fuchsia</option>
|
<option>fuchsia</option>
|
||||||
<option>green</option>
|
<option>green</option>
|
||||||
<option>grey</option>
|
<option>grey</option>
|
||||||
<option>indigo</option>
|
<option>indigo</option>
|
||||||
<option>jade</option>
|
<option>jade</option>
|
||||||
<option>orange</option>
|
<option>orange</option>
|
||||||
<option>rose</option>
|
<option>rose</option>
|
||||||
<option>pumpkin</option>
|
<option>pumpkin</option>
|
||||||
<option>purple</option>
|
<option>purple</option>
|
||||||
<option>red</option>
|
<option>red</option>
|
||||||
<option>sand</option>
|
<option>sand</option>
|
||||||
<option>slate</option>
|
<option>slate</option>
|
||||||
<option>violet</option>
|
<option>violet</option>
|
||||||
<option>yellow</option>
|
<option>yellow</option>
|
||||||
<option>zinc</option>
|
<option>zinc</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<label>Nom </label>
|
<label>Nom </label>
|
||||||
<input type="text" name="nom" id="nom" value="{% if profil['nom'] != None %}{{ profil['nom'] }}{%endif%}"><br />
|
<input type="text" name="nom" id="nom" value="{% if profil['nom'] != None %}{{ profil['nom'] }}{%endif%}"><br />
|
||||||
<label>Prenom </label>
|
<label>Prenom </label>
|
||||||
<input type="text" name="prenom" id="prenom" value="{% if profil['nom'] != None %}{{ profil['prenom'] }}{%endif%}"><br />
|
<input type="text" name="prenom" id="prenom" value="{% if profil['nom'] != None %}{{ profil['prenom'] }}{%endif%}"><br />
|
||||||
<label> Age </label>
|
<label> Age </label>
|
||||||
<input type="text" name="age" value="{% if profil['age'] != None %}{{ profil['age'] }}{%endif%}"><br />
|
<input type="text" name="age" value="{% if profil['age'] != None %}{{ profil['age'] }}{%endif%}"><br />
|
||||||
<label> Mail de secours </label>
|
<label> Mail de secours </label>
|
||||||
<input type="text" name="mail_rescue" id="mail_rescue" value="{% if profil['mail_rescue'] != None %}{{ profil['mail_rescue'] }}{%endif%}"><br />
|
<input type="text" name="mail_rescue" id="mail_rescue" value="{% if profil['mail_rescue'] != None %}{{ profil['mail_rescue'] }}{%endif%}"><br />
|
||||||
<button id="tada" class="btn btn-default btn-primary" type="submit">Envoyer</button>
|
<button id="tada" class="btn btn-default btn-primary" type="submit">Envoyer</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
{% extends 'up_squelette.html' %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
|
|
||||||
<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">{{ nb_pv }}</span></th>
|
|
||||||
<th>Taille (en Megaoctect)</th>
|
|
||||||
<th></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
|
|
||||||
{% for file in listFilesPrivate %}
|
|
||||||
<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 %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
<p> Vous n'avez aucun fichiers privés </p>
|
|
||||||
{% endif %}
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<h2> Fichiers publics (Tout le monde peut les voirs) </h2>
|
|
||||||
{% if listFilesPublic %}
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th></th>
|
|
||||||
<th>Fichier(s) <span class="badge">{{ nb_pu }}</span></th>
|
|
||||||
<th>Taille (en Megaoctets)</th>
|
|
||||||
<th></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
|
|
||||||
{% for file in listFilesPublic %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ file[0] }}</td>
|
|
||||||
<td><a href="/public/{{ username }}/{{ file[1] }}">{{ file[1] }}</a></td>
|
|
||||||
<td>{{ file[2] }}</td>
|
|
||||||
<td><a href="{{ url_for('filesupload.remove_publicFile', filename=file[1]) }}"><button type="button" class="btn btn-sm btn-danger">Supprimer</button></a></td>
|
|
||||||
<td><a href="{{ url_for('filesupload.move_private', filename=file[1]) }}"><button type="button" class="btn btn-sm btn-success"> Rendre Privée </button></a></td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
<p> Vous n'avez aucun fichiers publics </p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
{% include '_head.html' %}
|
{% include '_head.html' %}
|
||||||
|
{% block css %} {% endblock %}
|
||||||
|
{% include 'css/simple_editor.html' %}
|
||||||
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
@@ -20,9 +22,13 @@
|
|||||||
|
|
||||||
|
|
||||||
{% include '_footer.html' %}
|
{% include '_footer.html' %}
|
||||||
{% include '_js-core.html' %}
|
|
||||||
{% include '_js-gallery.html' %}
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
{% include '_js-core.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block js %} {% endblock %}
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
{% include '_nav_userlogin.html' %}
|
|
||||||
{% extends 'up_squelette.html' %}
|
|
||||||
{% block main %}
|
|
||||||
|
|
||||||
|
|
||||||
<br />
|
|
||||||
<p>Ici, vous pouvez envoyer des fichiers afin de les sauvegarder ou de les rendre accessibles à quelqu'un d'autre. Tu pourras ensuite
|
|
||||||
les consulter dans notre rubrique <a href="/view/"> Mes fichiers </a>. Les images envoyées, quand à elles se retrouveront directement
|
|
||||||
dans la <a href="/gallery/"> 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 qui vous mettrez ici. Nous ne pourrons, en aucun cas, être tenu responsable de la perte de vos
|
|
||||||
données. Merci de votre compréhension.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br />
|
|
||||||
<h3>Choisissez un ou plusieurs fichiers à téléverser </h3>
|
|
||||||
|
|
||||||
|
|
||||||
<form action="" method="post" enctype="multipart/form-data">
|
|
||||||
<input type="file" class="center" name="fic"id="fic" multiple>
|
|
||||||
<br>
|
|
||||||
<button type="submit" id="tada" class="btn btn btn-success"> Téléverser !</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
@@ -5,17 +5,12 @@ from tools.utils import gen_token
|
|||||||
from flask_bcrypt import Bcrypt
|
from flask_bcrypt import Bcrypt
|
||||||
|
|
||||||
app = Flask( 'pywallter' )
|
app = Flask( 'pywallter' )
|
||||||
app.config.from_pyfile('config.py')
|
|
||||||
bcrypt = Bcrypt(app)
|
bcrypt = Bcrypt(app)
|
||||||
|
|
||||||
DATABASE = app.config['DATABASE']
|
|
||||||
DOSSIER_PERSO = app.config['DOSSIER_APP']
|
|
||||||
DATABASE = app.config['DATABASE']
|
|
||||||
|
|
||||||
|
|
||||||
|
def init_db(database):
|
||||||
def init_db():
|
conn = sqlite3.connect(database)
|
||||||
conn = sqlite3.connect(DATABASE)
|
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
CREATE TABLE IF NOT EXISTS users(
|
CREATE TABLE IF NOT EXISTS users(
|
||||||
@@ -37,27 +32,15 @@ def init_db():
|
|||||||
Mail_rescue TEXT )
|
Mail_rescue TEXT )
|
||||||
""")
|
""")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
print ('table users Ok')
|
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("""
|
cursor.execute("""
|
||||||
CREATE TABLE IF NOT EXISTS Blog_posts(
|
CREATE TABLE IF NOT EXISTS Blog_posts(
|
||||||
title TEXT NOT NULL,
|
title TEXT NOT NULL,
|
||||||
subtitle TEXT,
|
subtitle TEXT,
|
||||||
comments TEXT,
|
comments TEXT,
|
||||||
filename TEXT,
|
content TEXT,
|
||||||
time TEXT,
|
creation_date TEXT,
|
||||||
last_updated TEXT,
|
last_updated TEXT,
|
||||||
category TEXT,
|
category TEXT,
|
||||||
author TEXT,
|
author TEXT,
|
||||||
@@ -66,7 +49,7 @@ def init_db():
|
|||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
print ("Table Blog_posts Ok !")
|
||||||
|
|
||||||
cursor.execute("""select * from users""")
|
cursor.execute("""select * from users""")
|
||||||
accounts = cursor.fetchall()
|
accounts = cursor.fetchall()
|
||||||
@@ -74,31 +57,38 @@ def init_db():
|
|||||||
# pywallter qui permet la première inscription
|
# pywallter qui permet la première inscription
|
||||||
if not(accounts) :
|
if not(accounts) :
|
||||||
user = "pywallter"
|
user = "pywallter"
|
||||||
token = gen_token()
|
token = gen_token("Invitation")
|
||||||
passwd_bcrypt = bcrypt.generate_password_hash(token)
|
passwd_bcrypt = bcrypt.generate_password_hash(token)
|
||||||
cursor.execute("""INSERT INTO users(name, passwd, token) VALUES(?, ?, ?)""", (user, passwd_bcrypt, token))
|
cursor.execute("""INSERT INTO users(name, passwd, token) VALUES(?, ?, ?)""", (user, passwd_bcrypt, token))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
print ('table posts OK')
|
print ('table posts OK')
|
||||||
|
|
||||||
def init_dir():
|
def check_directories(users_folder):
|
||||||
if os.path.isdir('users'):
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
os.makedirs('./users/')
|
|
||||||
|
|
||||||
def db_migrate():
|
if os.path.isdir(users_folder):
|
||||||
conn = sqlite3.connect(DATABASE)
|
print("Le dossier {} existe".format(users_folder))
|
||||||
|
else:
|
||||||
|
os.makedirs(users_folder)
|
||||||
|
print("Le dossier {} a été créé".format(users_folder))
|
||||||
|
|
||||||
|
def db_migrate(database):
|
||||||
|
|
||||||
|
|
||||||
|
invitations_col = False
|
||||||
|
lost_password_token_col = False
|
||||||
|
totp_col = False
|
||||||
|
blog_unified_col = False
|
||||||
|
blog_theme_col = False
|
||||||
|
updated_col = False
|
||||||
|
creation_date_col = False
|
||||||
|
content_col = False
|
||||||
|
|
||||||
|
conn = sqlite3.connect(database)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cursor.execute("""SELECT name FROM PRAGMA_TABLE_INFO('users');""")
|
cursor.execute("""SELECT name FROM PRAGMA_TABLE_INFO('users');""")
|
||||||
db_columns = cursor.fetchall()
|
db_columns = cursor.fetchall()
|
||||||
invitations_col = False
|
|
||||||
blog_theme_col = False
|
|
||||||
updated_col = False
|
|
||||||
lost_password_token_col = False
|
|
||||||
totp_col = False
|
|
||||||
|
|
||||||
for col in db_columns:
|
for col in db_columns:
|
||||||
if "invitations" == col[0]:
|
if "invitations" == col[0]:
|
||||||
invitations_col = True
|
invitations_col = True
|
||||||
@@ -106,15 +96,21 @@ def db_migrate():
|
|||||||
lost_password_token_col = True
|
lost_password_token_col = True
|
||||||
if "totp" == col[0]:
|
if "totp" == col[0]:
|
||||||
totp_col = True
|
totp_col = True
|
||||||
|
if "blog_theme" == col[0]:
|
||||||
|
blog_theme_col = True
|
||||||
|
|
||||||
|
|
||||||
cursor.execute("""SELECT name FROM PRAGMA_TABLE_INFO('Blog_posts');""")
|
cursor.execute("""SELECT name FROM PRAGMA_TABLE_INFO('Blog_posts');""")
|
||||||
db_columns = cursor.fetchall()
|
db_columns = cursor.fetchall()
|
||||||
for col in db_columns:
|
for col in db_columns:
|
||||||
if "blog_theme" == col[0]:
|
|
||||||
blog_theme_col = True
|
|
||||||
if "last_updated" == col[0]:
|
if "last_updated" == col[0]:
|
||||||
updated_col = True
|
updated_col = True
|
||||||
|
if "content" == col[0]:
|
||||||
|
content_col = True
|
||||||
|
if "creation_date" == col[0]:
|
||||||
|
creation_date_col= True
|
||||||
|
if "category" == col[0]:
|
||||||
|
category_col= True
|
||||||
|
|
||||||
|
|
||||||
if not(invitations_col):
|
if not(invitations_col):
|
||||||
@@ -124,19 +120,18 @@ def db_migrate():
|
|||||||
|
|
||||||
|
|
||||||
if not(lost_password_token_col):
|
if not(lost_password_token_col):
|
||||||
cursor.execute("""ALTER TABLE Users ADD COLUMN Lost_password_token CHAR(64);""")
|
cursor.execute("""ALTER TABLE users ADD COLUMN Lost_password_token CHAR(64);""")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
print ("Ajout du champ Lost_password_token dans la table Users")
|
print ("Ajout du champ Lost_password_token dans la table Users")
|
||||||
|
|
||||||
if not(totp_col):
|
if not(totp_col):
|
||||||
cursor.execute("""ALTER TABLE Users ADD COLUMN totp CHAR(40);""")
|
cursor.execute("""ALTER TABLE users ADD COLUMN totp CHAR(40);""")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
print ("Ajout du champ totp dans la table Users")
|
print ("Ajout du champ totp dans la table Users")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if not(blog_theme_col):
|
if not(blog_theme_col):
|
||||||
cursor.execute("""ALTER TABLE Blog_posts ADD COLUMN blog_theme TEXT;""")
|
cursor.execute("""ALTER TABLE users ADD COLUMN blog_theme TEXT;""")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
print ("Ajout du champ blog_theme dans la table Blog")
|
print ("Ajout du champ blog_theme dans la table Blog")
|
||||||
|
|
||||||
@@ -146,5 +141,20 @@ def db_migrate():
|
|||||||
print ("Ajout du champ updated dans la table BLog")
|
print ("Ajout du champ updated dans la table BLog")
|
||||||
|
|
||||||
|
|
||||||
|
if not(content_col):
|
||||||
|
cursor.execute("""ALTER TABLE Blog_posts RENAME COLUMN filename TO content;""")
|
||||||
|
conn.commit()
|
||||||
|
print ("Filename renomé en content")
|
||||||
|
|
||||||
|
|
||||||
|
if not(creation_date_col):
|
||||||
|
cursor.execute("""ALTER TABLE Blog_posts RENAME COLUMN time TO creation_date;""")
|
||||||
|
conn.commit()
|
||||||
|
print ("Time renomé en creation_date")
|
||||||
|
|
||||||
|
if not(category_col):
|
||||||
|
cursor.execute("""ALTER TABLE Blog_posts ADD COLUMN category TEXT;""")
|
||||||
|
conn.commit()
|
||||||
|
print ("Ajout de la colono category")
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|||||||
@@ -27,27 +27,72 @@ def login_required(f):
|
|||||||
|
|
||||||
|
|
||||||
def append_to_log(log_line, user):
|
def append_to_log(log_line, user):
|
||||||
|
tmp=""
|
||||||
log_file=os.path.join(DOSSIER_PERSO, user, "log.txt")
|
log_file=os.path.join(DOSSIER_PERSO, user, "log.txt")
|
||||||
logs=open(log_file, "r")
|
if os.path.exists(log_file):
|
||||||
tmp=logs.read()
|
logs=open(log_file, "r")
|
||||||
logs.close()
|
tmp=logs.read()
|
||||||
|
logs.close()
|
||||||
log=open(log_file, "w")
|
log=open(log_file, "w")
|
||||||
log.write(log_line)
|
log.write(log_line)
|
||||||
log.write(tmp)
|
log.write(tmp)
|
||||||
log.close()
|
log.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def valid_email(mail):
|
||||||
|
valid=True
|
||||||
|
# Caractères non autorisés dans la RFC #822
|
||||||
|
invalid_char = { '(', ')', '<', '>', ',', ';', ':', '"', '[', ']', '|', 'ç', '%', '&', ' ' }
|
||||||
|
mail_cut = mail.split('@')
|
||||||
|
tld = mail_cut[-1].split('.')
|
||||||
|
|
||||||
|
for character in invalid_char:
|
||||||
|
if character in mail:
|
||||||
|
valid=False
|
||||||
|
|
||||||
|
print(tld)
|
||||||
|
if len(mail_cut) > 1 and len(tld) > 1 and valid:
|
||||||
|
if len(tld[0]) < 1 or len(tld[-1]) < 2 :
|
||||||
|
valid=False
|
||||||
|
else:
|
||||||
|
valid=False
|
||||||
|
|
||||||
|
return valid
|
||||||
|
|
||||||
|
|
||||||
def valid_username(username):
|
def valid_username(username):
|
||||||
valid=True
|
valid=True
|
||||||
# Caractères non autorisés dans la RFC #822
|
# Caractères non autorisés dans la RFC #822
|
||||||
invalid_char = { '(', ')', '<', '>', ',', ';', ':', '"', '[', ']', '|', 'ç', '%', '&', ' ' }
|
invalid_char = { '(', ')', '<', '>', ',', ';', ':', '"', '[', ']', '|', 'ç', '%', '&', ' ' }
|
||||||
|
|
||||||
for character in invalid_char:
|
for character in invalid_char:
|
||||||
if character in username:
|
if character in username:
|
||||||
valid=False
|
valid=False
|
||||||
|
|
||||||
|
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=?""", (username,))
|
||||||
|
tmp = cursor.fetchone()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
if tmp:
|
||||||
|
valid = True
|
||||||
|
else:
|
||||||
|
valid = False
|
||||||
|
|
||||||
|
|
||||||
return valid
|
return valid
|
||||||
|
|
||||||
|
def set_mail_domain():
|
||||||
|
mail_domain = ""
|
||||||
|
if app.config['MAIL_SERVER']:
|
||||||
|
mail_domain = app.config['MAIL_DOMAIN']
|
||||||
|
else:
|
||||||
|
mail_domain = None
|
||||||
|
return mail_domain
|
||||||
|
|
||||||
|
|
||||||
def email_disp(email):
|
def email_disp(email):
|
||||||
disp = True
|
disp = True
|
||||||
@@ -99,7 +144,7 @@ def valid_token_register(token, token_type):
|
|||||||
cursor.execute("""SELECT name FROM users where token=?""", (token,))
|
cursor.execute("""SELECT name FROM users where token=?""", (token,))
|
||||||
tmp = cursor.fetchone()
|
tmp = cursor.fetchone()
|
||||||
conn.close()
|
conn.close()
|
||||||
print (tmp)
|
|
||||||
if tmp:
|
if tmp:
|
||||||
valid = True
|
valid = True
|
||||||
else:
|
else:
|
||||||
@@ -111,7 +156,6 @@ def valid_token_register(token, token_type):
|
|||||||
|
|
||||||
def get_user_by_token(token, token_type):
|
def get_user_by_token(token, token_type):
|
||||||
|
|
||||||
|
|
||||||
if len(token) != 30 and len(token) != 64:
|
if len(token) != 30 and len(token) != 64:
|
||||||
user = "Invalid Token"
|
user = "Invalid Token"
|
||||||
|
|
||||||
|
|||||||
321
views/blog.py
321
views/blog.py
@@ -7,6 +7,7 @@ import sqlite3
|
|||||||
from markdown import markdown
|
from markdown import markdown
|
||||||
from tools.filesutils import getFileSizeKo
|
from tools.filesutils import getFileSizeKo
|
||||||
import string
|
import string
|
||||||
|
from shutil import copy
|
||||||
from tools.utils import login_required
|
from tools.utils import login_required
|
||||||
|
|
||||||
blog = Blueprint('blog', __name__, template_folder='templates')
|
blog = Blueprint('blog', __name__, template_folder='templates')
|
||||||
@@ -16,154 +17,294 @@ app.config.from_pyfile('config.py')
|
|||||||
|
|
||||||
|
|
||||||
########################### Variables Globales #################################
|
########################### Variables Globales #################################
|
||||||
extensionimg = app.config['EXT_IMG']
|
extensionimg = app.config.get('EXT_IMG')
|
||||||
DATABASE = app.config['DATABASE']
|
DATABASE = app.config.get('DATABASE')
|
||||||
BASE_URL= app.config['BASE_URL']
|
BASE_URL = app.config.get('BASE_URL')
|
||||||
DOSSIER_PERSO= app.config['DOSSIER_APP']+'/'
|
DOSSIER_PERSO = app.config.get('DOSSIER_APP')+'/'
|
||||||
DOSSIER_PUBLIC= app.config['DOSSIER_PUBLIC']+'/'
|
DOSSIER_PUBLIC = app.config.get('DOSSIER_PUBLIC')+'/'
|
||||||
|
TITLE_SERVER = app.config.get('TITLE_SERVER')
|
||||||
|
DESC_SERVER = app.config.get('DESC_SERVER')
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
@blog.route('/myblog/new-article/', methods=['GET', 'POST'])
|
@blog.route('/myblog/new-article/', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def new_article():
|
def new_article():
|
||||||
user = '%s'% escape(session['username'])
|
user = '%s'% escape(session['username'])
|
||||||
folder_blog = DOSSIER_PERSO + user + "/blog/articles/"
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
title = request.form['title']
|
title = str(request.form['title'])
|
||||||
subtitle = request.form['subtitle']
|
subtitle = str(request.form['subtitle'])
|
||||||
content = request.form['content']
|
category = str(request.form['category'])
|
||||||
status = request.form['status']
|
content = str(request.form['content'])
|
||||||
|
status = str(request.form['status'])
|
||||||
post_date = time.strftime("%d/%m/%Y %H:%M:%S")
|
post_date = time.strftime("%d/%m/%Y %H:%M:%S")
|
||||||
filename = title.replace(" ", "_") + ".md"
|
if 'blog-unified' in request.form.keys():
|
||||||
|
status = status+'_unified'
|
||||||
|
|
||||||
conn = sqlite3.connect(DATABASE) # 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 = conn.cursor() # Création de l'objet "curseur"
|
||||||
cursor.execute("""INSERT INTO Blog_posts(title, subtitle, filename, time, author, status) VALUES(?, ?, ?, ?, ?, ?)""", (title, subtitle, filename, post_date, user, status)) # Insérer des valeurs
|
cursor.execute("""INSERT INTO Blog_posts(title, subtitle, category, content, creation_date, author, status) VALUES(?, ?, ?, ?, ?, ?, ?)""", (title, subtitle, category, content, post_date, user, status)) # Insérer des valeurs
|
||||||
conn.commit()
|
conn.commit()
|
||||||
## 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'))
|
return redirect(url_for('blog.list_articles_blog'))
|
||||||
else:
|
else:
|
||||||
return render_template('new_article_blog.html')
|
return render_template('new_article_blog.html')
|
||||||
|
|
||||||
|
@blog.route('/myblog/edit/<title>', methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
def edit(title):
|
||||||
|
user='%s'% escape(session['username'])
|
||||||
|
folder_blog = DOSSIER_PERSO + user + "/blog/articles/"
|
||||||
|
if request.method == 'POST' :
|
||||||
|
newtitle = str(request.form['title'])
|
||||||
|
subtitle = str(request.form['subtitle'])
|
||||||
|
category = str(request.form['category'])
|
||||||
|
newcontent = str(request.form['content'])
|
||||||
|
newstatus = str(request.form['status'])
|
||||||
|
updated = time.strftime("%d/%m/%Y %H:%M:%S")
|
||||||
|
conn = sqlite3.connect(DATABASE)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
if 'blog-unified' in request.form.keys():
|
||||||
|
newstatus = newstatus+'_unified'
|
||||||
|
|
||||||
|
cursor.execute("""UPDATE Blog_posts SET title=?, subtitle=?, category=?, last_updated=?, status=?, content=? WHERE title=? AND author=?""", (newtitle, subtitle, category, updated, newstatus, newcontent, title, user))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
return redirect(url_for('blog.list_articles_blog'))
|
||||||
|
else:
|
||||||
|
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||||
|
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||||
|
cursor.execute("""SELECT title, subtitle, category, content, status FROM Blog_posts WHERE title=? AND author=?""", (title, user))
|
||||||
|
oldpost = cursor.fetchone()
|
||||||
|
conn.close()
|
||||||
|
post = dict(title=oldpost[0], subtitle=oldpost[1], category=oldpost[2], content=oldpost[3], status=oldpost[4])
|
||||||
|
return render_template('edit_article.html',
|
||||||
|
section='Post-it',
|
||||||
|
oldpost=post)
|
||||||
|
|
||||||
|
|
||||||
@blog.route('/myblog/list-articles/', methods=['GET'])
|
@blog.route('/myblog/list-articles/', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def list_articles_blog():
|
def list_articles_blog():
|
||||||
user = '%s'% escape(session['username'])
|
user = '%s'% escape(session['username'])
|
||||||
conn = sqlite3.connect(DATABASE) # 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 = conn.cursor() # Création de l'objet "curseur"
|
||||||
cursor.execute("""SELECT title, subtitle, time, last_updated, status FROM Blog_posts WHERE author=? """, (user,) )
|
cursor.execute("""SELECT title, subtitle, creation_date, last_updated, status FROM Blog_posts WHERE author=? """, (user,) )
|
||||||
list_posts=cursor.fetchall()
|
list_posts=cursor.fetchall()
|
||||||
posts=list()
|
posts=list()
|
||||||
nb_articles=0
|
nb_articles=0
|
||||||
for post in list_posts:
|
for post in list_posts:
|
||||||
posts.append(dict(title=post[0],
|
posts = [dict(title=post[0],
|
||||||
subtitle=post[1],
|
subtitle=post[1],
|
||||||
time=post[2],
|
time=post[2],
|
||||||
last_updated=post[3],
|
last_updated=post[3],
|
||||||
status=post[4]))
|
status=post[4])] + posts
|
||||||
nb_articles =+ 1
|
nb_articles = nb_articles + 1
|
||||||
|
|
||||||
return render_template('list_articles.html',
|
return render_template('list_articles.html',
|
||||||
section="Articles",
|
section="Articles",
|
||||||
list_posts=posts,
|
list_posts=posts,
|
||||||
nb_articles=nb_articles
|
nb_articles=nb_articles )
|
||||||
)
|
|
||||||
|
|
||||||
@blog.route('/myblog/delete/<title>')
|
@blog.route('/myblog/delete/<title>')
|
||||||
@login_required
|
@login_required
|
||||||
def delete(title):
|
def delete(title):
|
||||||
|
title = escape(title)
|
||||||
user='%s'% escape(session['username'])
|
user='%s'% escape(session['username'])
|
||||||
folder_blog = DOSSIER_PERSO + user + "/blog/articles/"
|
folder_blog = DOSSIER_PERSO + user + "/blog/articles/"
|
||||||
folder_blog_public = DOSSIER_PUBLIC + user + "/blog/articles/"
|
folder_blog_public = DOSSIER_PUBLIC + user + "/blog/articles/"
|
||||||
filename = title.replace(" ", "_")
|
|
||||||
conn = sqlite3.connect(DATABASE) # 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 = conn.cursor() # Création de l'objet "curseur"
|
||||||
cursor.execute("""DELETE FROM Blog_posts WHERE title=? AND author=?""", (title, user))
|
cursor.execute("""DELETE FROM Blog_posts WHERE title=? AND author=?""", (title, user))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
os.remove(folder_blog+filename+".md")
|
|
||||||
os.remove(folder_blog_public+filename+".html")
|
|
||||||
return redirect(url_for('blog.list_articles_blog'))
|
return redirect(url_for('blog.list_articles_blog'))
|
||||||
|
|
||||||
@blog.route('/myblog/edit/<title>', methods=['GET', 'POST'])
|
|
||||||
|
@blog.route('/myblog/personnalize/', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def edit(title):
|
def personnalize_blog():
|
||||||
user='%s'% escape(session['username'])
|
user='%s' % escape(session['username'])
|
||||||
filename = title.replace(" ", "_") + ".md"
|
|
||||||
folder_blog = DOSSIER_PERSO + user + "/blog/articles/"
|
|
||||||
|
|
||||||
if request.method == 'POST' :
|
|
||||||
subtitle = request.form['subtitle']
|
|
||||||
newcontent = request.form['content']
|
|
||||||
newstatus = request.form['status']
|
|
||||||
updated = time.strftime("%d/%m/%Y %H:%M:%S")
|
|
||||||
conn = sqlite3.connect(DATABASE)
|
|
||||||
cursor = conn.cursor()
|
|
||||||
cursor.execute("""UPDATE Blog_posts SET subtitle=?, last_updated=?, status=? WHERE title=? AND author=?""", (subtitle, updated, newstatus, title, user))
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
with open(folder_blog + filename, 'w') as f:
|
|
||||||
f.write(newcontent)
|
|
||||||
|
|
||||||
|
|
||||||
return redirect(url_for('blog.list_articles_blog'))
|
|
||||||
else:
|
|
||||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
|
||||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
|
||||||
cursor.execute("""SELECT title, subtitle, status FROM Blog_posts WHERE title=? AND author=?""", (title, user))
|
|
||||||
oldpost = cursor.fetchone()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
with open(folder_blog + filename, 'r') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
return render_template('edit_article.html',
|
|
||||||
section='Post-it',
|
|
||||||
oldpost=oldpost,
|
|
||||||
content=content)
|
|
||||||
|
|
||||||
@blog.route('/blog/<username>/', methods=['GET'])
|
|
||||||
def view(username):
|
|
||||||
user = username
|
|
||||||
conn = sqlite3.connect(DATABASE) # 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 = conn.cursor() # Création de l'objet "curseur"
|
||||||
cursor.execute("""SELECT title, subtitle, time, author FROM Blog_posts WHERE status='public' AND author=? """, (user,) )
|
cursor.execute("""SELECT blog_theme FROM users WHERE name=?""", (user,))
|
||||||
|
blog_info = cursor.fetchone()
|
||||||
|
conn.close()
|
||||||
|
blog_unified = blog_info[0]
|
||||||
|
if request.method == 'POST' :
|
||||||
|
|
||||||
|
f = request.files['personnal-blog-theme']
|
||||||
|
|
||||||
|
blog_theme = str(request.form['blog-theme'])
|
||||||
|
print(blog_theme)
|
||||||
|
|
||||||
|
if blog_theme != "Default":
|
||||||
|
copy( "static/blog-"+blog_theme+".css",
|
||||||
|
DOSSIER_PERSO+ user +'/blog.css' )
|
||||||
|
|
||||||
|
if f: # On vérifie qu'un fichier a bien été envoyé
|
||||||
|
nom = secure_filename(f.filename)
|
||||||
|
f.save(DOSSIER_PERSO + user + nom)
|
||||||
|
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 blog_theme=? WHERE name=?", (blog_theme, user))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
return render_template('personnalize_blog.html', section='personnalize_blog', blog_theme=blog_info[0])
|
||||||
|
|
||||||
|
@blog.route('/myblog/', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def viewmyblog():
|
||||||
|
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, subtitle, creation_date, author, status FROM Blog_posts WHERE author=? AND status!='draft'""", (user,))
|
||||||
list_posts=cursor.fetchall()
|
list_posts=cursor.fetchall()
|
||||||
posts=list()
|
posts=list()
|
||||||
id=0
|
id=0
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
print (list_posts)
|
if list_posts != None:
|
||||||
|
for post in list_posts:
|
||||||
|
posts=[dict(title=post[0], subtitle=post[1], creation_date=post[2], author=post[3], status=post[4])] + posts
|
||||||
|
|
||||||
|
return render_template('index_blog.html', section='Blog', posts=posts, author=user)
|
||||||
|
|
||||||
|
|
||||||
|
@blog.route('/private-blog/', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def view_internal():
|
||||||
|
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||||
|
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||||
|
cursor.execute("""SELECT title, subtitle, content, creation_date, last_updated, author, status FROM Blog_posts WHERE status='private_unified' OR status='public_unified' """ )
|
||||||
|
list_posts=cursor.fetchall()
|
||||||
|
conn.close()
|
||||||
|
posts=list()
|
||||||
|
id=0
|
||||||
if list_posts != None:
|
if list_posts != None:
|
||||||
for post in list_posts:
|
for post in list_posts:
|
||||||
posts.append(dict(title=post[0], subtitle=post[1], time=post[2], author=post[3]))
|
posts = [dict(title=post[0], subtitle=post[1], content=post[2], creation_date=post[3], last_updated=post[4], author=post[5], status=post[6] )] + posts
|
||||||
else:
|
else:
|
||||||
return redirect(BASE_URL, code=404)
|
return redirect(BASE_URL, code=404)
|
||||||
|
|
||||||
|
return render_template('index_blog.html', section='Blog', posts=posts)
|
||||||
return render_template('index_blog.html', section='Blog', posts=posts, user=user)
|
|
||||||
|
@blog.route('/blog/', methods=['GET'])
|
||||||
@blog.route('/blog/<username>/<title>', methods=['GET'])
|
def view():
|
||||||
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
|
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
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) )
|
cursor.execute("""SELECT title, subtitle, creation_date, author, status FROM Blog_posts WHERE status='public_unified'""" )
|
||||||
|
list_posts=cursor.fetchall()
|
||||||
|
posts=list()
|
||||||
|
id=0
|
||||||
|
conn.close()
|
||||||
|
if list_posts != None:
|
||||||
|
for post in list_posts:
|
||||||
|
posts=[dict(title=post[0], subtitle=post[1], creation_date=post[2], author=post[3], status=post[4])] + posts
|
||||||
|
|
||||||
|
return render_template('index_blog.html', section='Blog', posts=posts)
|
||||||
|
|
||||||
|
|
||||||
|
@blog.route('/blog/<author>/', methods=['GET'])
|
||||||
|
def viewuser(author):
|
||||||
|
author = escape(author)
|
||||||
|
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||||
|
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||||
|
if 'username' in session :
|
||||||
|
cursor.execute("""SELECT title, subtitle, creation_date, last_updated, author, status FROM Blog_posts WHERE author=? AND status != 'draft' """, (author,))
|
||||||
|
else:
|
||||||
|
cursor.execute("""SELECT title, subtitle, creation_date, last_updated, author, status FROM Blog_posts WHERE author=? AND status='public' OR status='public_unified' """, (author,))
|
||||||
|
list_posts=cursor.fetchall()
|
||||||
|
posts=None
|
||||||
|
id=0
|
||||||
|
conn.close()
|
||||||
|
if list_posts != None:
|
||||||
|
posts=list()
|
||||||
|
for post in list_posts:
|
||||||
|
posts=[dict(title=post[0], subtitle=post[1], creation_date=post[2], last_updated=post[3], author=post[4], status=post[5])] + posts
|
||||||
|
|
||||||
|
|
||||||
|
return render_template('index_blog.html', section='Blog', posts=posts, author=author)
|
||||||
|
|
||||||
|
@blog.route('/blog/<author>/rss.xml', methods=['GET'])
|
||||||
|
def viewauthorrss(author):
|
||||||
|
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||||
|
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||||
|
cursor.execute("""SELECT MAX (creation_date) FROM Blog_posts WHERE author=? AND status='public_unified' OR status='public'""", (author, ) )
|
||||||
|
last_article_date = cursor.fetchone()
|
||||||
|
cursor.execute("""SELECT title, subtitle, content, creation_date, author, status FROM Blog_posts WHERE author=? AND status='public_unified' OR status='public'""", (author, ) )
|
||||||
|
list_posts=cursor.fetchall()
|
||||||
|
posts=list()
|
||||||
|
id=0
|
||||||
|
conn.close()
|
||||||
|
if list_posts != None:
|
||||||
|
last_build=last_article_date[0]
|
||||||
|
for post in list_posts:
|
||||||
|
posts=[dict(title=post[0], subtitle=post[1], content=markdown(post[2]), creation_date=post[3], author=post[4], status=post[5])] + posts
|
||||||
|
|
||||||
|
return render_template('blog_rss.xml',
|
||||||
|
base_url=BASE_URL,
|
||||||
|
blog_name=author,
|
||||||
|
last_build_date=last_build,
|
||||||
|
posts=posts)
|
||||||
|
|
||||||
|
|
||||||
|
@blog.route('/blog/private_unified/<username>/<title>', methods=['GET'])
|
||||||
|
@blog.route('/blog/private/<username>/<title>', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def viewPrivateArticle(username, title):
|
||||||
|
user = escape(username)
|
||||||
|
title = escape(title)
|
||||||
|
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||||
|
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||||
|
cursor.execute("""SELECT title, subtitle, content, creation_date, last_updated, author, status FROM Blog_posts WHERE author=? AND title=? AND status!='draft' """, (user, title))
|
||||||
post = cursor.fetchone()
|
post = cursor.fetchone()
|
||||||
conn.close()
|
conn.close()
|
||||||
if post != None:
|
if post != None:
|
||||||
post_info = (dict(title=post[0], subtitle=post[1], time=post[2], author=post[3]))
|
post_info = (dict(title=post[0], subtitle=post[1], creation_date=post[3], last_updated=post[4],author=post[5]))
|
||||||
with open(folder_blog + filename, 'r') as f:
|
content = markdown(post[2])
|
||||||
content_md = f.read()
|
|
||||||
content = markdown(content_md)
|
|
||||||
return render_template('blog.html', post_info=post_info, content=content)
|
return render_template('blog.html', post_info=post_info, content=content)
|
||||||
else:
|
else:
|
||||||
flash(u"Cet article n'existe pas", 'error');
|
return redirect(url_for('blog'), code=404)
|
||||||
|
|
||||||
|
|
||||||
|
@blog.route('/blog/public_unified/<username>/<title>', methods=['GET'])
|
||||||
|
@blog.route('/blog/public/<username>/<title>', methods=['GET'])
|
||||||
|
def viewArticle(username, title):
|
||||||
|
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, content, creation_date, last_updated, author FROM Blog_posts WHERE author=? AND title=? AND status='public_unified' """, (user, title) )
|
||||||
|
post = cursor.fetchone()
|
||||||
|
conn.close()
|
||||||
|
if post != None:
|
||||||
|
post_info = (dict(title=post[0], subtitle=post[1], creation_date=post[3], last_updated=post[4],author=post[5]))
|
||||||
|
content= markdown(post[2])
|
||||||
|
|
||||||
|
return render_template('blog.html', post_info=post_info, content=content)
|
||||||
|
else:
|
||||||
|
return redirect(url_for('blog.view'), code=404)
|
||||||
|
|
||||||
|
@blog.route('/blog/rss.xml', methods=['GET'])
|
||||||
|
def viewrss():
|
||||||
|
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||||
|
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||||
|
cursor.execute("""SELECT MAX(creation_date) FROM Blog_posts WHERE status='public_unified'""")
|
||||||
|
last_article_date = cursor.fetchone()
|
||||||
|
print (last_article_date[0])
|
||||||
|
cursor.execute("""SELECT title, subtitle, content, creation_date, author, status FROM Blog_posts WHERE status='public_unified'""" )
|
||||||
|
list_posts=cursor.fetchall()
|
||||||
|
posts=list()
|
||||||
|
id=0
|
||||||
|
conn.close()
|
||||||
|
if list_posts != None:
|
||||||
|
last_build=last_article_date[0]
|
||||||
|
for post in list_posts:
|
||||||
|
posts=[dict(title=post[0], subtitle=post[1], content=markdown(post[2]), creation_date=post[3], author=post[4], status=post[5])] + posts
|
||||||
|
|
||||||
|
return render_template('blog_rss.xml',
|
||||||
|
base_url=BASE_URL,
|
||||||
|
blog_name= TITLE_SERVER,
|
||||||
|
last_build_date=last_build,
|
||||||
|
blog_description=DESC_SERVER,
|
||||||
|
posts=posts)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, flash, abort, send_file, send_from_directory
|
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 werkzeug.utils import secure_filename
|
||||||
from markupsafe import escape
|
from markupsafe import escape
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
@@ -16,109 +17,165 @@ filesupload = Blueprint('filesupload', __name__, template_folder='templates')
|
|||||||
app = Flask( 'pywallter' )
|
app = Flask( 'pywallter' )
|
||||||
app.config.from_pyfile('config.py')
|
app.config.from_pyfile('config.py')
|
||||||
|
|
||||||
|
#### Variables ##################################################################################
|
||||||
|
|
||||||
#### Variables ####################################################################################
|
DOSSIER_PERSO= app.config.get('DOSSIER_APP')
|
||||||
|
DOSSIER_PUBLIC= app.config.get('DOSSIER_PUBLIC')
|
||||||
|
|
||||||
DOSSIER_PERSO= app.config['DOSSIER_APP']+'/'
|
extensionimg = app.config.get('EXT_IMG')
|
||||||
DOSSIER_PUBLIC= app.config['DOSSIER_PUBLIC']+'/'
|
DATABASE = app.config.get('DATABASE')
|
||||||
|
BASE_URL= app.config.get('BASE_URL')
|
||||||
extensionimg = app.config['EXT_IMG']
|
|
||||||
DATABASE = app.config['DATABASE']
|
|
||||||
BASE_URL= app.config['BASE_URL']
|
|
||||||
##################################################################################################
|
##################################################################################################
|
||||||
|
|
||||||
|
|
||||||
@filesupload.route( '/filesupload/', methods=['GET', 'POST'])
|
@filesupload.route( '/filesupload/', methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def uploadfiles():
|
def upload():
|
||||||
user = '%s'% escape(session['username'])
|
user = '%s'% escape(session['username'])
|
||||||
if request.method == 'POST' :
|
if 'fic' not in request.files:
|
||||||
|
flash(u'Mauvais format de ficher', 'error')
|
||||||
if 'fic' not in request.files:
|
return redirect(request.url)
|
||||||
flash(u'Mauvais format de ficher', 'error')
|
file = request.files['fic']
|
||||||
return redirect(request.url)
|
|
||||||
file = request.files['fic']
|
|
||||||
|
|
||||||
# If the user does not select a file, the browser submits an
|
# If the user does not select a file, the browser submits an
|
||||||
# empty file without a filename.
|
# empty file without a filename.
|
||||||
if file.filename == '':
|
if file.filename == '':
|
||||||
flash(u'Vous avez oubliez de selectionner un fichier', 'error' )
|
flash(u'Vous avez oubliez de selectionner un fichier', 'error' )
|
||||||
return redirect(request.url)
|
else:
|
||||||
|
|
||||||
files = request.files.getlist('fic')
|
files = request.files.getlist('fic')
|
||||||
for f in files :
|
for f in files :
|
||||||
nom = secure_filename(f.filename)
|
nom = secure_filename(f.filename)
|
||||||
check_and_create(DOSSIER_PERSO+ user + 'files')
|
check_and_create(os.path.join(DOSSIER_PERSO, user, 'files'))
|
||||||
check_and_create(DOSSIER_PERSO+ user + 'images')
|
check_and_create(os.path.join(DOSSIER_PERSO, user, 'images'))
|
||||||
if os.path.isfile(DOSSIER_PERSO + user + '/files/' + nom) or os.path.isfile(DOSSIER_PERSO + user + '/images/' + nom):
|
if os.path.isfile(os.path.join(DOSSIER_PERSO,user, 'files', nom) or
|
||||||
flash(u'Un fichier avec le même nom existe déjà, merci de spécifier un autre nom de fichier', 'error')
|
os.path.isfile(DOSSIER_PERSO, user, 'images', nom)):
|
||||||
|
alert = "Le fichier "+str(f.filename)+" avec le même nom existe déjà, merci de spécifier un autre nom de fichier \n"
|
||||||
|
flash(alert, 'error')
|
||||||
else:
|
else:
|
||||||
file, ext = os.path.splitext(nom)
|
file, ext = os.path.splitext(nom)
|
||||||
if ext in extensionimg :
|
if ext in extensionimg :
|
||||||
f.save(DOSSIER_PERSO + user + '/images/' + nom)
|
f.save(os.path.join(DOSSIER_PERSO, user, 'images', nom))
|
||||||
image = DOSSIER_PERSO + user + '/images/' + nom
|
image = os.path.join(DOSSIER_PERSO, user, 'images', nom)
|
||||||
with Image.open(image) as img :
|
with Image.open(image) as img :
|
||||||
img.thumbnail((300,300))
|
img.thumbnail((300,300))
|
||||||
img.save( DOSSIER_PERSO + user + '/images/thumbnails/' + nom )
|
img.save(os.path.join(DOSSIER_PERSO, user, 'images','thumbnails', nom ))
|
||||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
time_img_create=time.strftime("%A %d %B %Y %H:%M:%S")
|
||||||
IP=request.environ['REMOTE_ADDR']
|
IP=request.environ['REMOTE_ADDR']
|
||||||
CLIENT_PLATFORM=request.headers.get('User-Agent')
|
client_platform=request.headers.get('User-Agent')
|
||||||
log_file=os.path.join(DOSSIER_PERSO, user, "log.txt")
|
log_file=os.path.join(DOSSIER_PERSO, user, "log.txt")
|
||||||
LOG=open(log_file, "a")
|
log=open(log_file, "a")
|
||||||
LOG.write (TIME + ' - ' + IP + ' - ' + user + ' - ' + CLIENT_PLATFORM + '\n' + '---> ' + nom + '\n')
|
log.write (time_img_create + ' - ' + IP + ' - ' + user + ' - ' + client_platform + '\n' + '---> ' + nom + '\n')
|
||||||
LOG.close()
|
log.close()
|
||||||
flash(u'Image envoyée et traitée avec succés', 'succes')
|
|
||||||
else:
|
else:
|
||||||
f.save(DOSSIER_PERSO + user + '/files/' + nom)
|
f.save(os.path.join(DOSSIER_PERSO, user, 'files', nom))
|
||||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
time_file_upload=time.strftime("%A %d %B %Y %H:%M:%S")
|
||||||
IP=request.environ['REMOTE_ADDR']
|
IP=request.environ.get('REMOTE_ADDR')
|
||||||
CLIENT_PLATFORM=request.headers.get('User-Agent')
|
client_platform=request.headers.get('User-Agent')
|
||||||
LOG=open("log.txt", "a") # Ouvre fichier log.txt
|
log=open("log.txt", "a") # Ouvre fichier log.txt
|
||||||
LOG.write (TIME + ' - ' + IP + ' - ' + user + ' - ' + CLIENT_PLATFORM + '\n' + '---> ' + nom + '\n') # Écrit dans log
|
log.write (time_file_upload + ' - ' + IP + ' - ' + user + ' - ' + client_platform + '\n' + '---> ' + nom + '\n') # Écrit dans log
|
||||||
LOG.close() # Ferme log.txt
|
log.close() # Ferme log.txt
|
||||||
flash(u'Fichier envoyé avec succés', 'succes')
|
flash(u'Les fichiers envoyées ont été traitée avec succés', 'succes')
|
||||||
|
|
||||||
|
|
||||||
resp = make_response(render_template('up_up.html', section="Upload"))
|
|
||||||
resp.set_cookie('username', session['username'])
|
return redirect(url_for('filesupload.list'))
|
||||||
return resp
|
|
||||||
|
|
||||||
|
@filesupload.route( '/upload-dropzone', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def drop_upload():
|
||||||
|
user = '%s'% escape(session['username'])
|
||||||
|
file = request.files['file']
|
||||||
|
check_and_create(os.path.join(DOSSIER_PERSO, user, 'files'))
|
||||||
|
check_and_create(os.path.join(DOSSIER_PERSO, user, 'images' ))
|
||||||
|
filename = secure_filename(file.filename)
|
||||||
|
ext = os.path.splitext(filename)
|
||||||
|
is_image = False
|
||||||
|
print("nom du fichier :" +filename)
|
||||||
|
if ext in extensionimg :
|
||||||
|
save_path = os.path.join(DOSSIER_PERSO, user, 'images', filename )
|
||||||
|
is_image = True
|
||||||
|
else:
|
||||||
|
save_path = os.path.join(DOSSIER_PERSO, user, 'files', filename )
|
||||||
|
|
||||||
@filesupload.route('/view/')
|
current_chunk = int(request.form['dzchunkindex'])
|
||||||
|
print (current_chunk)
|
||||||
|
|
||||||
|
if (os.path.isfile(save_path) or os.path.isfile( os.path.join(DOSSIER_PERSO, user, 'images', filename ))) and current_chunk == 0:
|
||||||
|
return make_response(('Un fichier avec le même nom existe déjà', 400))
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(save_path, 'ab') as f:
|
||||||
|
f.seek(int(request.form['dzchunkbyteoffset']))
|
||||||
|
f.write(file.stream.read())
|
||||||
|
except OSError:
|
||||||
|
return make_response(("Une erreur est survenue,"
|
||||||
|
" Impossible d'écrire le fichier sur le disque", 500))
|
||||||
|
total_chunks = int(request.form['dztotalchunkcount'])
|
||||||
|
if current_chunk + 1 == total_chunks:
|
||||||
|
# This was the last chunk, the file should be complete and the size we expect
|
||||||
|
if os.path.getsize(save_path) != int(request.form['dztotalfilesize']):
|
||||||
|
return make_response(('La taille du fichier source est différentes', 500))
|
||||||
|
else:
|
||||||
|
time_file_upload=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_file_upload + ' - ' + IP + ' - ' + user + ' - ' + client_platform + '\n' + '---> ' + filename + '\n') # Écrit dans log
|
||||||
|
log.close() # Ferme log.txt
|
||||||
|
|
||||||
|
if is_image :
|
||||||
|
with Image.open(save_path) as img :
|
||||||
|
img.thumbnail((300,300))
|
||||||
|
img.save(os.path.join(DOSSIER_PERSO, user, 'images', 'thumbnails', filename ) )
|
||||||
|
|
||||||
|
return make_response(('Chunk upload succesfull', 200))
|
||||||
|
|
||||||
|
@filesupload.route('/view/', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def list():
|
def list():
|
||||||
|
|
||||||
user = '%s'% escape(session['username'])
|
user = '%s'% escape(session['username'])
|
||||||
|
|
||||||
check_and_create(DOSSIER_PUBLIC + user + '/files/')
|
check_and_create(os.path.join(DOSSIER_PUBLIC, user, 'files'))
|
||||||
check_and_create(DOSSIER_PERSO + user + '/files/')
|
check_and_create(os.path.join(DOSSIER_PERSO, user, 'files'))
|
||||||
files_public = os.listdir(DOSSIER_PUBLIC + user + '/files/')
|
|
||||||
files_private = os.listdir(DOSSIER_PERSO + user + '/files/')
|
return render_template('files.html',
|
||||||
listFilesPublic = []
|
|
||||||
listFilesPrivate = []
|
|
||||||
nb_pv = 0
|
|
||||||
size=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",
|
section="Files",
|
||||||
|
BASE_URL=BASE_URL,
|
||||||
|
username=user)
|
||||||
|
|
||||||
|
|
||||||
|
@filesupload.route('/files/<status>/', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def list_files(status: str ):
|
||||||
|
user = '%s' % escape(session['username'])
|
||||||
|
listFiles = []
|
||||||
|
nb_files = 0
|
||||||
|
size=0
|
||||||
|
folder=""
|
||||||
|
|
||||||
|
if status == "public":
|
||||||
|
folder=DOSSIER_PUBLIC
|
||||||
|
else:
|
||||||
|
folder=DOSSIER_PERSO
|
||||||
|
|
||||||
|
files = os.listdir(os.path.join(folder, user, 'files'))
|
||||||
|
|
||||||
|
if files:
|
||||||
|
for fich in files:
|
||||||
|
nb_files += 1
|
||||||
|
size = getFileSizeMo(os.path.join(folder, user, 'files', fich)) # size = taille des fichiers
|
||||||
|
listFiles.append([nb_files, fich, size]) # On implémente la listeFichiers avec le num le ficier et sa taille
|
||||||
|
resp = "<h2> Bonjour " + user +" ça va bien putain ca marche ? </h2>"
|
||||||
|
|
||||||
|
return render_template('list_files.html',
|
||||||
|
BASE_URL=BASE_URL,
|
||||||
|
status=status,
|
||||||
size=size,
|
size=size,
|
||||||
username=user,
|
username=user,
|
||||||
nb_pv=nb_pv,
|
nb_files=nb_files,
|
||||||
nb_pu=nb_pu,
|
listFiles=listFiles)
|
||||||
listFilesPrivate=listFilesPrivate,
|
|
||||||
listFilesPublic=listFilesPublic)
|
|
||||||
|
|
||||||
|
|
||||||
@filesupload.route('/myfiles/<username>/<filename>')
|
@filesupload.route('/myfiles/<username>/<filename>')
|
||||||
@@ -132,11 +189,9 @@ def myfiles(username, filename):
|
|||||||
@login_required
|
@login_required
|
||||||
def move_public(filename):
|
def move_public(filename):
|
||||||
user = '%s' % escape(session['username'])
|
user = '%s' % escape(session['username'])
|
||||||
check_and_create(DOSSIER_PUBLIC + user + '/files/')
|
|
||||||
check_and_create(DOSSIER_PERSO + user + '/files/')
|
|
||||||
|
|
||||||
src = os.path.join(DOSSIER_PERSO, user, 'files', filename)
|
src = os.path.join(DOSSIER_PERSO, user, 'files', filename)
|
||||||
dst = os.path.join(DOSSIER_PUBLIC, user, 'files/')
|
dst = os.path.join(DOSSIER_PUBLIC, user, 'files')
|
||||||
move (src, dst)
|
move (src, dst)
|
||||||
return redirect(url_for('filesupload.list', _external=True))
|
return redirect(url_for('filesupload.list', _external=True))
|
||||||
|
|
||||||
@@ -144,10 +199,8 @@ def move_public(filename):
|
|||||||
@login_required
|
@login_required
|
||||||
def move_private(filename):
|
def move_private(filename):
|
||||||
user = '%s' % escape(session['username'])
|
user = '%s' % escape(session['username'])
|
||||||
check_and_create(DOSSIER_PUBLIC + user + '/files/')
|
|
||||||
check_and_create(DOSSIER_PERSO + user + '/files/')
|
|
||||||
src = os.path.join(DOSSIER_PUBLIC, user, 'files', filename)
|
src = os.path.join(DOSSIER_PUBLIC, user, 'files', filename)
|
||||||
dst = os.path.join(DOSSIER_PERSO, user, 'files/')
|
dst = os.path.join(DOSSIER_PERSO, user, 'files')
|
||||||
move (src, dst)
|
move (src, dst)
|
||||||
return redirect(url_for('filesupload.list', _external=True))
|
return redirect(url_for('filesupload.list', _external=True))
|
||||||
|
|
||||||
@@ -160,7 +213,7 @@ def remove_privateFile(filename):
|
|||||||
user = '%s' % escape(session['username'])
|
user = '%s' % escape(session['username'])
|
||||||
filename = secure_filename(filename)
|
filename = secure_filename(filename)
|
||||||
try:
|
try:
|
||||||
os.remove(DOSSIER_PERSO + user + '/files/' + filename) # on le supprime
|
os.remove( os.path.join(DOSSIER_PERSO, user, 'files', filename)) # on le supprime
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
flash(u'Fichier {filename} inexistant.'.format(filename=filename), 'error')
|
flash(u'Fichier {filename} inexistant.'.format(filename=filename), 'error')
|
||||||
return redirect(url_for('filesupload.list', _external=True))
|
return redirect(url_for('filesupload.list', _external=True))
|
||||||
@@ -172,19 +225,28 @@ def remove_publicFile(filename):
|
|||||||
user = '%s' % escape(session['username'])
|
user = '%s' % escape(session['username'])
|
||||||
filename = secure_filename(filename)
|
filename = secure_filename(filename)
|
||||||
try:
|
try:
|
||||||
os.remove(DOSSIER_PUBLIC + user + '/files/' + filename) # on le supprime
|
os.remove( os.path.join(DOSSIER_PUBLIC, user, 'files', filename)) # on le supprime
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
flash(u'Fichier {filename} inexistant.'.format(filename=filename), 'error')
|
flash(u'Fichier {filename} inexistant.'.format(filename=filename), 'error')
|
||||||
return redirect(url_for('filesupload.list', _external=True))
|
return redirect(url_for('filesupload.list', _external=True))
|
||||||
|
|
||||||
|
|
||||||
|
@filesupload.route('/<author>/blog.css')
|
||||||
|
def blog_theme(author):
|
||||||
|
user = author
|
||||||
|
if os.path.isfile(os.path.join(DOSSIER_PERSO, user,'blog.css')):
|
||||||
|
return send_file(os.path.join(DOSSIER_PERSO, user, 'blog.css'), mimetype='text/css')
|
||||||
|
else:
|
||||||
|
return send_file("static/blog.css", mimetype='text/css')
|
||||||
|
|
||||||
@filesupload.route('/theme.min.css')
|
@filesupload.route('/theme.min.css')
|
||||||
def theme():
|
def theme():
|
||||||
if 'username' in session:
|
if 'username' in session:
|
||||||
user = '%s' % escape(session['username'])
|
user = '%s' % escape(session['username'])
|
||||||
if os.path.isfile(DOSSIER_PERSO+ user +'/theme.min.css'):
|
if os.path.isfile(os.path.join(DOSSIER_PERSO, user,'theme.min.css')):
|
||||||
return send_file(DOSSIER_PERSO+ user +'/theme.min.css', mimetype='text/css')
|
return send_file(os.path.join(DOSSIER_PERSO, user,'theme.min.css'), mimetype='text/css')
|
||||||
else:
|
|
||||||
return send_file("static/default.min.css", mimetype='text/css')
|
return send_file("static/default.min.css", mimetype='text/css')
|
||||||
|
|
||||||
@filesupload.route('/public/<username>/<filename>')
|
@filesupload.route('/public/<username>/<filename>')
|
||||||
def publicfiles(username, filename):
|
def publicfiles(username, filename):
|
||||||
|
|||||||
@@ -18,22 +18,24 @@ app.config.from_pyfile('config.py')
|
|||||||
|
|
||||||
#### Variables ##################################################################################
|
#### Variables ##################################################################################
|
||||||
|
|
||||||
DOSSIER_PERSO= app.config['DOSSIER_APP']
|
DOSSIER_PERSO = app.config.get("DOSSIER_APP")
|
||||||
DOSSIER_PUBLIC= app.config['DOSSIER_PUBLIC']+'/'
|
DOSSIER_PUBLIC = app.config.get("DOSSIER_PUBLIC")
|
||||||
extensionimg = app.config['EXT_IMG']
|
extensionimg = app.config.get("EXT_IMG")
|
||||||
|
|
||||||
DATABASE = app.config['DATABASE']
|
DATABASE = app.config.get("DATABASE")
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
|
|
||||||
@mygallery.route( '/gallery/')
|
@mygallery.route( '/gallery/')
|
||||||
@login_required
|
@login_required
|
||||||
def gallery():
|
def gallery():
|
||||||
user ='%s' % escape(session['username'])
|
user ='%s' % escape(session['username'])
|
||||||
check_and_create(DOSSIER_PUBLIC + user + '/images/')
|
print (DOSSIER_PUBLIC)
|
||||||
check_and_create(DOSSIER_PUBLIC + user + '/images/thumbnails/')
|
print (os.path.join(DOSSIER_PUBLIC, user , 'images'))
|
||||||
check_and_create(DOSSIER_PERSO + user + '/images/')
|
check_and_create(os.path.join(DOSSIER_PUBLIC, user , 'images'))
|
||||||
check_and_create(DOSSIER_PERSO + user + '/images/thumbnails/')
|
check_and_create(os.path.join(DOSSIER_PUBLIC, user , 'images', 'thumbnails'))
|
||||||
THUMBNAILS=DOSSIER_PERSO + user + '/images/thumbnails/'
|
check_and_create(os.path.join(DOSSIER_PERSO , user , 'images'))
|
||||||
|
check_and_create(os.path.join(DOSSIER_PERSO, user, 'images','thumbnails'))
|
||||||
|
THUMBNAILS=os.path.join(DOSSIER_PERSO, user, 'images','thumbnails')
|
||||||
fichiers = [fich for fich in os.listdir(THUMBNAILS)]
|
fichiers = [fich for fich in os.listdir(THUMBNAILS)]
|
||||||
return render_template('gallery.html',
|
return render_template('gallery.html',
|
||||||
section='Gallery',
|
section='Gallery',
|
||||||
@@ -44,16 +46,16 @@ def gallery():
|
|||||||
@mygallery.route('/myfiles/images/<filename>')
|
@mygallery.route('/myfiles/images/<filename>')
|
||||||
@login_required
|
@login_required
|
||||||
def myimg(filename):
|
def myimg(filename):
|
||||||
UTILISATEUR='%s' % escape(session['username'])
|
user = '%s' % escape(session['username'])
|
||||||
return send_from_directory(
|
return send_from_directory(
|
||||||
os.path.join(DOSSIER_PERSO, UTILISATEUR, 'images'), filename )
|
os.path.join(DOSSIER_PERSO, user, 'images'), filename )
|
||||||
|
|
||||||
@mygallery.route('/myfiles/images/thumbnails/<filename>')
|
@mygallery.route('/myfiles/images/thumbnails/<filename>')
|
||||||
@login_required
|
@login_required
|
||||||
def mythumbnails(filename):
|
def mythumbnails(filename):
|
||||||
UTILISATEUR='%s' % escape(session['username'])
|
user='%s' % escape(session['username'])
|
||||||
return send_from_directory(
|
return send_from_directory(
|
||||||
os.path.join(DOSSIER_PERSO, UTILISATEUR, 'images/thumbnails'), filename )
|
os.path.join(DOSSIER_PERSO, user, 'images','thumbnails'), filename )
|
||||||
|
|
||||||
@mygallery.route('/remove_privateImage/<filename>')
|
@mygallery.route('/remove_privateImage/<filename>')
|
||||||
@login_required
|
@login_required
|
||||||
@@ -61,8 +63,8 @@ def remove_privateImage(filename):
|
|||||||
user = '%s' % escape(session['username'])
|
user = '%s' % escape(session['username'])
|
||||||
filename = secure_filename(filename)
|
filename = secure_filename(filename)
|
||||||
try:
|
try:
|
||||||
os.remove(DOSSIER_PERSO + user + '/images/thumbnails/' + filename) # on le supprime
|
os.remove(os.path.join(DOSSIER_PERSO, user, 'images','thumbnails', filename)) # on le supprime
|
||||||
os.remove(DOSSIER_PERSO + user + '/images/' + filename) # on le supprime
|
os.remove(os.path.join(DOSSIER_PERSO, user, 'images', filename)) # on le supprime
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
flash(u'Image {filename} inexistante.'.format(filename=filename), 'error')
|
flash(u'Image {filename} inexistante.'.format(filename=filename), 'error')
|
||||||
return redirect(url_for('mygallery.gallery'))
|
return redirect(url_for('mygallery.gallery'))
|
||||||
@@ -74,8 +76,8 @@ def remove_publicImage(filename):
|
|||||||
user = '%s' % escape(session['username'])
|
user = '%s' % escape(session['username'])
|
||||||
filename = secure_filename(filename)
|
filename = secure_filename(filename)
|
||||||
try:
|
try:
|
||||||
os.remove(DOSSIER_PUBLIC + user + '/images/thumbnails/' + filename) # on le supprime
|
os.remove(os.path.join(DOSSIER_PUBLIC, user, 'images','thumbnails', filename)) # on le supprime
|
||||||
os.remove(DOSSIER_PUBLIC + user + '/images/' + filename) # on le supprime
|
os.remove(os.path.join(DOSSIER_PUBLIC, user, 'images', filename)) # on le supprime
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
flash(u'Image {filename} inexistante.'.format(filename=filename), 'error')
|
flash(u'Image {filename} inexistante.'.format(filename=filename), 'error')
|
||||||
return redirect(url_for('mygallery.gallery'))
|
return redirect(url_for('mygallery.gallery'))
|
||||||
|
|||||||
@@ -1,25 +1,29 @@
|
|||||||
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file
|
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, send_file
|
||||||
from flask_bcrypt import Bcrypt
|
from flask_bcrypt import Bcrypt
|
||||||
|
import time
|
||||||
|
from markupsafe import escape
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import glob, os, sys, time
|
import glob, os, sys, time
|
||||||
from tools.utils import email_disp, valid_token_register, valid_passwd, valid_username
|
from tools.utils import email_disp, valid_token_register, valid_passwd, valid_username
|
||||||
from socket import gethostname
|
from socket import gethostname
|
||||||
|
import subprocess
|
||||||
|
from tools.filesutils import check_and_create
|
||||||
|
from tools.utils import set_mail_domain
|
||||||
app = Flask( 'pywallter' )
|
app = Flask( 'pywallter' )
|
||||||
app.config.from_pyfile('config.py')
|
app.config.from_pyfile('config.py')
|
||||||
bcrypt = Bcrypt(app)
|
bcrypt = Bcrypt(app)
|
||||||
|
|
||||||
#### Variables ##################################################################################
|
#### Variables ##################################################################################
|
||||||
|
|
||||||
|
DATAS_USER = app.config.get('DOSSIER_APP')
|
||||||
|
DOSSIER_PERSO = app.config.get('DOSSIER_APP')
|
||||||
|
extensionimg = app.config.get('EXT_IMG')
|
||||||
|
DATABASE = app.config.get('DATABASE')
|
||||||
|
MAIL_SERVER = app.config.get('MAIL_SERVER')
|
||||||
|
XMPP_SERVER = app.config.get('XMPP_SERVER')
|
||||||
|
SETUID = app.config.get('SETUID')
|
||||||
|
BASE_URL = app.config.get('BASE_URL')
|
||||||
|
|
||||||
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']
|
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
|
|
||||||
|
|
||||||
@@ -28,24 +32,35 @@ inscription = Blueprint('inscription', __name__, template_folder='templates')
|
|||||||
|
|
||||||
@inscription.route( '/inscription/<token>', methods=['GET','POST'] )
|
@inscription.route( '/inscription/<token>', methods=['GET','POST'] )
|
||||||
def signin(token) :
|
def signin(token) :
|
||||||
hostname = gethostname()
|
|
||||||
url_inscription = url_for('loginlogout.index', _external=True)+'inscription/'+token
|
mail_domain = set_mail_domain()
|
||||||
|
|
||||||
|
url_inscription = BASE_URL +'/'+'inscription/'+token
|
||||||
resp = None
|
resp = None
|
||||||
if valid_token_register(token, "Invitation"):
|
if valid_token_register(token, "Invitation"):
|
||||||
if 'username' in session :
|
if 'username' in session :
|
||||||
resp = redirect(url_for('profil.profile', _external=True))
|
resp = redirect(url_for('profil.profile', _external=True))
|
||||||
else :
|
else :
|
||||||
|
|
||||||
# Réponse si la requete est de type GET ou si la requete POST echoue
|
# Réponse si la requete est de type GET ou si la requete POST echoue
|
||||||
resp = render_template('inscription.html',
|
resp = render_template('inscription.html',
|
||||||
signin_enable=app.config['SIGNIN_ENABLE'],
|
signin_enable=app.config['SIGNIN_ENABLE'],
|
||||||
token=token, hostname=hostname,
|
token=token, hostname=mail_domain,
|
||||||
url_inscription=url_inscription,
|
url_inscription=url_inscription,
|
||||||
MAIL_SERVER=MAIL_SERVER, XMPP_SERVER=XMPP_SERVER)
|
MAIL_SERVER=MAIL_SERVER, XMPP_SERVER=XMPP_SERVER)
|
||||||
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
|
||||||
|
# Une fois que tout c'est bien passé pour l'inscription on détruit le jeton.
|
||||||
|
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||||
|
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||||
|
|
||||||
|
cursor.execute("""SELECT name, invitations FROM users where Token=?""", (token,))
|
||||||
|
tmp = cursor.fetchone()
|
||||||
|
user_invite = tmp[0]
|
||||||
|
invitations_count=tmp[1]
|
||||||
|
conn.close()
|
||||||
|
|
||||||
#On test si aucun champs du formulaire n'est vide.
|
#On test si aucun champs du formulaire n'est vide.
|
||||||
if len(request.form['user']) == 0 or \
|
if len(request.form['user']) == 0 or \
|
||||||
len(request.form['passwd']) == 0 or \
|
len(request.form['passwd']) == 0 or \
|
||||||
@@ -54,38 +69,31 @@ def signin(token) :
|
|||||||
flash(u'Il faut remplir le formulaire en entier, les champs ne peuvent pas etre vide ', 'error')
|
flash(u'Il faut remplir le formulaire en entier, les champs ne peuvent pas etre vide ', 'error')
|
||||||
return render_template('inscription.html',
|
return render_template('inscription.html',
|
||||||
signin_enable=app.config['SIGNIN_ENABLE'],
|
signin_enable=app.config['SIGNIN_ENABLE'],
|
||||||
token=token, hostname=hostname,
|
token=token, hostname=mail_domain,
|
||||||
url_inscription=url_inscription,
|
url_inscription=url_inscription,
|
||||||
MAIL_SERVER=MAIL_SERVER, XMPP_SERVER=XMPP_SERVER)
|
MAIL_SERVER=MAIL_SERVER, XMPP_SERVER=XMPP_SERVER)
|
||||||
|
|
||||||
|
user = str(request.form['user'])
|
||||||
user = request.form['user']
|
passwd = str(request.form['passwd'])
|
||||||
passwd = request.form['passwd']
|
passwdconfirm = str(request.form['passwdconfirm'])
|
||||||
passwdconfirm = request.form['passwdconfirm']
|
|
||||||
bcrypt_passwd = bcrypt.generate_password_hash(request.form['passwd'])
|
bcrypt_passwd = bcrypt.generate_password_hash(passwd)
|
||||||
mail_passwd_change = 0
|
mail_passwd_change = 0
|
||||||
|
|
||||||
password_valid = valid_passwd(passwd)
|
|
||||||
not_error = True
|
not_error = True
|
||||||
|
|
||||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
if invitations_count < 1 :
|
||||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
flash(u'Votre lien d\'inscription est invalide', 'error')
|
||||||
|
not_error=False
|
||||||
cursor.execute("""SELECT name FROM users WHERE name=?""", (user,))
|
|
||||||
testuser = cursor.fetchone()
|
if not_error and valid_username(user):
|
||||||
conn.close()
|
flash(u'Le Nom d\'utilisateur déjà utilisé ou contient des caractères invalides, merci d\'en choisir un autre', 'error')
|
||||||
|
|
||||||
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')
|
flash(u'Les caractères espaces et \' ( ) < > , ; : " [ ] | ç % & ne sont pas autorisés', 'error')
|
||||||
not_error = False
|
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:
|
if MAIL_SERVER:
|
||||||
mail = user.lower()+'@'+hostname
|
mail = user.lower()+'@'+mail_domain
|
||||||
if not(email_disp(mail)) :
|
if not(email_disp(mail)) :
|
||||||
flash(u'Cette Adresse email est déjà utilisée , merci d\'en choisir une autre', 'error')
|
flash(u'Cette Adresse email est déjà utilisée , merci d\'en choisir une autre', 'error')
|
||||||
not_error = False
|
not_error = False
|
||||||
@@ -102,38 +110,53 @@ def signin(token) :
|
|||||||
|
|
||||||
# On change le mot de passe du compte mail
|
# On change le mot de passe du compte mail
|
||||||
if MAIL_SERVER:
|
if MAIL_SERVER:
|
||||||
cmd = SETUID + ' set_mail_passwd ' + '"'+mail+'" ' + '"'+passwd+'"'
|
cmd = subprocess.run([SETUID, 'set_mail_passwd', mail, passwd],stdout=subprocess.PIPE)
|
||||||
mail_passwd_change = os.system(cmd)
|
if cmd.returncode != 0:
|
||||||
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')
|
flash(u'Il y a eu une problème lors du changement de mot passe pour le compte Mail', 'error')
|
||||||
else:
|
else:
|
||||||
cursor.execute("UPDATE users SET mail=? WHERE name=?", mail, user)
|
cursor.execute("UPDATE users SET mail=? WHERE name=?", (mail, user))
|
||||||
|
|
||||||
# On change le mot de passe du compte XMPP
|
# On change le mot de passe du compte XMPP
|
||||||
if XMPP_SERVER:
|
if XMPP_SERVER:
|
||||||
tmp = mail.split('@')
|
jid = mail.split('@')
|
||||||
cmd = SETUID+ ' prosodyctl register ' "'"+tmp[0]+"' " + "'"+tmp[1]+"' " + "'"+passwd+"'"
|
cmd = subprocess.run([SETUID,'prosodyctl', 'register', jid[0],jid[1],passwd],stdout=subprocess.PIPE)
|
||||||
res = os.system(cmd)
|
|
||||||
if res != 0:
|
if cmd.returncode != 0:
|
||||||
flash(u'Il y a eu un problème pour la création du compte XMPP !', 'error')
|
flash(u'Il y a eu un problème pour la création du compte XMPP !', 'error')
|
||||||
|
|
||||||
|
check_and_create(DOSSIER_PERSO + user)
|
||||||
|
time_create_user = time.strftime("%A %d %B %Y %H:%M:%S")
|
||||||
|
ip_address=request.environ['REMOTE_ADDR']
|
||||||
|
client_plateform=request.headers.get('User-Agent')
|
||||||
|
|
||||||
|
log=time_create_user + ' - ' + ip_address + ' - ' + user + ' - ' + client_plateform + '\n' + '---> ' + 'Création du compte \n'
|
||||||
|
log_file=os.path.join(DOSSIER_PERSO,user,"log.txt")
|
||||||
|
try:
|
||||||
|
with open(log_file, 'x') as file:
|
||||||
|
file.write(log)
|
||||||
|
except FileExistsError:
|
||||||
|
print('The file '+log_file +' already exists')
|
||||||
|
|
||||||
|
|
||||||
# Une fois que tout c'est bien passé pour l'inscription on détruit le jeton.
|
if user_invite == "pywallter":
|
||||||
cursor.execute("""SELECT name, invitations FROM users where Token=?""", (token,))
|
cursor.execute("""DELETE from users where name = ?""", (user_invite,))
|
||||||
tmp = cursor.fetchone()
|
elif invitations_count > 0:
|
||||||
username = tmp[0]
|
invitations_count= invitations_count - 1
|
||||||
invitations_count=tmp[1] - 1
|
cursor.execute("""UPDATE users set invitations=? where name=?""", (invitations_count, user_invite,))
|
||||||
if username == "pywallter":
|
|
||||||
cursor.execute("""DELETE from users where name = ?""", (username,))
|
|
||||||
else:
|
else:
|
||||||
cursor.execute("""UPDATE users set invitations=?, Token='' where name=?""", (invitations_count, username,))
|
cursor.execute("""UPDATE users set invitations=?, Token='' where name=?""", (invitations_count, user_invite,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
flash(u'Inscription réalisée avec succés !', 'succes')
|
flash(u'Inscription réalisée avec succés !', 'success')
|
||||||
resp = redirect(url_for('loginlogout.login'))
|
resp = redirect(url_for('loginlogout.login'))
|
||||||
|
else:
|
||||||
|
return render_template('inscription.html',
|
||||||
|
signin_enable=app.config['SIGNIN_ENABLE'],
|
||||||
|
token=token, hostname=mail_domain,
|
||||||
|
url_inscription=url_inscription,
|
||||||
|
MAIL_SERVER=MAIL_SERVER, XMPP_SERVER=XMPP_SERVER)
|
||||||
else:
|
else:
|
||||||
resp = redirect(BASE_URL, code=401)
|
resp = redirect(BASE_URL, code=401)
|
||||||
|
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|||||||
@@ -15,16 +15,18 @@ bcrypt = Bcrypt(app)
|
|||||||
#### Variables ####################################################################################
|
#### Variables ####################################################################################
|
||||||
|
|
||||||
bcrypt = Bcrypt(app)
|
bcrypt = Bcrypt(app)
|
||||||
DATAS_USER = app.config['DOSSIER_APP']
|
DATAS_USER = app.config.get('DOSSIER_APP')
|
||||||
|
|
||||||
extensionimg = app.config['EXT_IMG']
|
extensionimg = app.config.get('EXT_IMG')
|
||||||
|
|
||||||
DATABASE = app.config['DATABASE']
|
DATABASE = app.config.get('DATABASE')
|
||||||
BASE_URL = app.config['BASE_URL']
|
BASE_URL = app.config.get('BASE_URL')
|
||||||
SETUID = app.config['SETUID']
|
SETUID = app.config.get('SETUID')
|
||||||
MAIL_SERVER = app.config['MAIL_SERVER']
|
MAIL_SERVER = app.config.get('MAIL_SERVER')
|
||||||
XMPP_SERVER = app.config['XMPP_SERVER']
|
XMPP_SERVER = app.config.get('XMPP_SERVER')
|
||||||
BACKUP_TIME = app.config['BACKUP_TIME']
|
BACKUP_TIME = app.config.get('BACKUP_TIME')
|
||||||
|
SERVER_TITLE = app.config.get('TITLE_SERVER')
|
||||||
|
SERVER_DESC = app.config.get('DESC_SERVER')
|
||||||
##################################################################################################
|
##################################################################################################
|
||||||
|
|
||||||
|
|
||||||
@@ -48,11 +50,12 @@ def index():
|
|||||||
else :
|
else :
|
||||||
if token:
|
if token:
|
||||||
hostname = gethostname()
|
hostname = gethostname()
|
||||||
url_inscription = BASE_URL+'inscription/'+token
|
url_inscription = BASE_URL+'/inscription/'+token
|
||||||
return render_template('inscription.html', signin_enable=app.config['SIGNIN_ENABLE'],
|
return render_template('inscription.html', signin_enable=app.config['SIGNIN_ENABLE'],
|
||||||
token=token, hostname=hostname,
|
token=token, hostname=hostname,
|
||||||
url_inscription=url_inscription,
|
url_inscription=url_inscription,
|
||||||
MAIL_SERVER=MAIL_SERVER)
|
server_title=SERVER_TITLE,
|
||||||
|
mail_server=MAIL_SERVER)
|
||||||
else:
|
else:
|
||||||
return redirect(url_for('loginlogout.login', _external=True))
|
return redirect(url_for('loginlogout.login', _external=True))
|
||||||
|
|
||||||
@@ -63,9 +66,9 @@ def login():
|
|||||||
else :
|
else :
|
||||||
resp = redirect(url_for('loginlogout.login', _external=True))
|
resp = redirect(url_for('loginlogout.login', _external=True))
|
||||||
if request.method == 'POST' :
|
if request.method == 'POST' :
|
||||||
user = request.form['user']
|
user = str(request.form['user'])
|
||||||
password = request.form['passwd']
|
password = str(request.form['passwd'])
|
||||||
totp = request.form['code_totp']
|
totp = str(request.form['code_totp'])
|
||||||
|
|
||||||
conn = sqlite3.connect(DATABASE) # 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 = conn.cursor() # Création de l'objet "curseur"
|
||||||
@@ -85,7 +88,23 @@ def login():
|
|||||||
else:
|
else:
|
||||||
flash(u"L'utilisateur n'existe pas", 'error')
|
flash(u"L'utilisateur n'existe pas", 'error')
|
||||||
else:
|
else:
|
||||||
resp = render_template('accueil.html', signin_enable=app.config['SIGNIN_ENABLE'])
|
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||||
|
cursor = conn.cursor() # Création de l'objet "curseur"
|
||||||
|
cursor.execute("""SELECT title, subtitle, creation_date, last_updated, author FROM Blog_posts WHERE status='public_unified'""" )
|
||||||
|
list_posts=cursor.fetchall()
|
||||||
|
posts=list()
|
||||||
|
id=0
|
||||||
|
conn.close()
|
||||||
|
if list_posts != None:
|
||||||
|
for post in list_posts:
|
||||||
|
posts=[dict(title=post[0], subtitle=post[1], creation_date=post[2], last_updated=post[3], author=post[4])] + posts
|
||||||
|
|
||||||
|
resp = render_template('accueil.html',
|
||||||
|
server_title=SERVER_TITLE,
|
||||||
|
server_desc=SERVER_DESC,
|
||||||
|
mail_server=MAIL_SERVER,
|
||||||
|
list_posts=posts,
|
||||||
|
signin_enable=app.config['SIGNIN_ENABLE'])
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,19 +11,19 @@ app.config.from_pyfile('config.py')
|
|||||||
|
|
||||||
#### Variables ####################################################################################
|
#### Variables ####################################################################################
|
||||||
|
|
||||||
DOSSIER_PERSO= app.config['DOSSIER_APP']
|
DOSSIER_PERSO= app.config.get('DOSSIER_APP')
|
||||||
|
|
||||||
extensionimg = app.config['EXT_IMG']
|
extensionimg = app.config.get('EXT_IMG')
|
||||||
|
|
||||||
DATABASE = app.config['DATABASE']
|
DATABASE = app.config.get('DATABASE')
|
||||||
##################################################################################################
|
##################################################################################################
|
||||||
|
|
||||||
|
|
||||||
@logs.route('/logs/')
|
@logs.route('/logs/')
|
||||||
@login_required
|
@login_required
|
||||||
def logfile():
|
def logfile():
|
||||||
UTILISATEUR='%s'% escape(session['username'])
|
user='%s'% escape(session['username'])
|
||||||
log_file=os.path.join(DOSSIER_PERSO, UTILISATEUR, "log.txt")
|
log_file=os.path.join(DOSSIER_PERSO, user, "log.txt")
|
||||||
with open(log_file, 'r') as log:
|
with open(log_file, 'r') as log:
|
||||||
logs=log.readlines()
|
logs=log.readlines()
|
||||||
log.close()
|
log.close()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import sqlite3
|
|||||||
import os
|
import os
|
||||||
from shutil import copy
|
from shutil import copy
|
||||||
from socket import gethostname
|
from socket import gethostname
|
||||||
from tools.utils import email_disp, append_to_log, gen_token, valid_passwd, login_required
|
from tools.utils import email_disp, append_to_log, gen_token, valid_passwd, login_required, set_mail_domain
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -17,38 +17,67 @@ app = Flask( 'pywallter' )
|
|||||||
app.config.from_pyfile('config.py')
|
app.config.from_pyfile('config.py')
|
||||||
|
|
||||||
|
|
||||||
#### Variables ####################################################################################
|
#### Variables ###################################################################################
|
||||||
DOSSIER_PERSO = app.config['DOSSIER_APP']
|
DOSSIER_PERSO = app.config.get('DOSSIER_APP')
|
||||||
|
|
||||||
extensionimg = app.config['EXT_IMG']
|
extensionimg = app.config.get('EXT_IMG')
|
||||||
|
|
||||||
DATABASE = app.config['DATABASE']
|
DATABASE = app.config.get('DATABASE')
|
||||||
DATAS_USER = app.config['DOSSIER_APP']
|
DATAS_USER = app.config.get('DOSSIER_APP')
|
||||||
MAIL_SERVER = app.config['MAIL_SERVER']
|
MAIL_SERVER = app.config.get('MAIL_SERVER')
|
||||||
XMPP_SERVER = app.config['XMPP_SERVER']
|
XMPP_SERVER = app.config.get('XMPP_SERVER')
|
||||||
SETUID = app.config['SETUID']
|
SETUID = app.config.get('SETUID')
|
||||||
BASE_URL = app.config['BASE_URL']
|
BASE_URL = app.config.get('BASE_URL')
|
||||||
BACKUP_TIME = app.config['BACKUP_TIME']
|
MAIL_WEBSERVICE = app.config.get('MAIL_WEBSERVICE')
|
||||||
|
XMPP_WEBSERVICE = app.config.get('XMPP_WEBSERVICE')
|
||||||
|
|
||||||
##################################################################################################
|
##################################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@mymailbox.route('/mymailbox/', methods=['GET'] )
|
||||||
|
@login_required
|
||||||
|
def mymessaging():
|
||||||
|
|
||||||
|
hostname=set_mail_domain()
|
||||||
|
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 Mail FROM users where name=?""", (user,))
|
||||||
|
tmp = cursor.fetchone()
|
||||||
|
myemail = tmp[0]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return render_template('mymessaging.html',
|
||||||
|
section="mymessaging",
|
||||||
|
hostname=hostname,
|
||||||
|
myemail=myemail,
|
||||||
|
imap_address=app.config.get('IMAP_ADDRESS'),
|
||||||
|
smtp_address=app.config.get('SMTP_ADDRESS'),
|
||||||
|
mail_server=MAIL_SERVER,
|
||||||
|
mail_webservice=MAIL_WEBSERVICE,
|
||||||
|
xmpp_server=XMPP_SERVER,
|
||||||
|
xmpp_webservice=XMPP_WEBSERVICE,
|
||||||
|
username=user )
|
||||||
|
|
||||||
|
|
||||||
@mymailbox.route('/mymailbox/alias', methods=['GET', 'POST'] )
|
@mymailbox.route('/mymailbox/alias', methods=['GET', 'POST'] )
|
||||||
@login_required
|
@login_required
|
||||||
def myalias():
|
def myalias():
|
||||||
hostname=gethostname()
|
hostname = set_mail_domain()
|
||||||
UTILISATEUR='%s' % escape(session['username'])
|
user='%s' % escape(session['username'])
|
||||||
conn = sqlite3.connect(DATABASE) # 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 = conn.cursor() # Création de l'objet "curseur"
|
||||||
if request.method == 'POST' and MAIL_SERVER:
|
if request.method == 'POST' and MAIL_SERVER:
|
||||||
if request.form['alias']:
|
if request.form['alias']:
|
||||||
alias = request.form['alias'].lower()+'@'+hostname
|
alias = request.form['alias'].lower()+'@'+hostname
|
||||||
else:
|
else:
|
||||||
flash(u'Addresse invalide')
|
flash(u'Addresse invalide', 'error')
|
||||||
|
|
||||||
if email_disp(alias):
|
if email_disp(alias):
|
||||||
cursor.execute("""SELECT Mail, alias FROM users where name=?""", (UTILISATEUR,))
|
cursor.execute("""SELECT Mail, alias FROM users where name=?""", (user,))
|
||||||
tmp = cursor.fetchone()
|
tmp = cursor.fetchone()
|
||||||
mail = tmp[0]
|
mail = tmp[0]
|
||||||
if tmp[1]:
|
if tmp[1]:
|
||||||
@@ -59,23 +88,23 @@ def myalias():
|
|||||||
cmd = SETUID+ " set_mail_alias " + "'"+mail+"'"+" add "+"'"+alias+"'"
|
cmd = SETUID+ " set_mail_alias " + "'"+mail+"'"+" add "+"'"+alias+"'"
|
||||||
res = os.system(cmd)
|
res = os.system(cmd)
|
||||||
if res == 0:
|
if res == 0:
|
||||||
cursor.execute("UPDATE users SET alias=? WHERE name=?",
|
cursor.execute("UPDATE users SET alias=? WHERE name=?",
|
||||||
(aliases, UTILISATEUR))
|
(aliases, user))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
time_create_alias = time.strftime("%A %d %B %Y %H:%M:%S")
|
||||||
IP=request.environ['REMOTE_ADDR']
|
ip_address=request.environ['REMOTE_ADDR']
|
||||||
CLIENT_PLATFORM=request.headers.get('User-Agent')
|
client_plateform=request.headers.get('User-Agent')
|
||||||
|
|
||||||
log=TIME + ' - ' + IP + ' - ' + UTILISATEUR + ' - ' + CLIENT_PLATFORM + '\n' + '---> ' + "Ajout de l'alias "+ alias + '\n'
|
log=time_create_alias + ' - ' + ip_address + ' - ' + user + ' - ' + client_plateform + '\n' + '---> ' + "Ajout de l'alias "+ alias + '\n'
|
||||||
append_to_log(log, UTILISATEUR)
|
append_to_log(log, user)
|
||||||
flash(u'Votre alias a été ajouté', 'succes')
|
flash(u'Votre alias a été ajouté', 'succes')
|
||||||
else:
|
else:
|
||||||
flash(u'Adresse indisponible', 'error')
|
flash(u'Adresse indisponible', 'error')
|
||||||
else:
|
else:
|
||||||
flash(u'Adresse indisponible', 'error')
|
flash(u'Adresse indisponible', 'error')
|
||||||
|
|
||||||
cursor.execute("""SELECT Mail, alias FROM users WHERE name=?""",
|
cursor.execute("""SELECT Mail, alias FROM users WHERE name=?""",
|
||||||
(UTILISATEUR,))
|
(user,))
|
||||||
tmp = cursor.fetchone()
|
tmp = cursor.fetchone()
|
||||||
mailbox = dict()
|
mailbox = dict()
|
||||||
mailbox['Mail'] = tmp[0]
|
mailbox['Mail'] = tmp[0]
|
||||||
@@ -91,17 +120,18 @@ def myalias():
|
|||||||
aliases=mailbox['alias'],
|
aliases=mailbox['alias'],
|
||||||
hostname=hostname,
|
hostname=hostname,
|
||||||
MAIL_SERVER=MAIL_SERVER,
|
MAIL_SERVER=MAIL_SERVER,
|
||||||
username=UTILISATEUR )
|
username=user )
|
||||||
|
|
||||||
|
|
||||||
@mymailbox.route('/mymailbox/rmalias/<aliasrm>')
|
@mymailbox.route('/mymailbox/rmalias/<aliasrm>')
|
||||||
@login_required
|
@login_required
|
||||||
def remove_alias(aliasrm):
|
def remove_alias(aliasrm):
|
||||||
|
aliasrm = escape(aliasrm)
|
||||||
if MAIL_SERVER:
|
if MAIL_SERVER:
|
||||||
UTILISATEUR='%s' % escape(session['username'])
|
user='%s' % escape(session['username'])
|
||||||
conn = sqlite3.connect(DATABASE) # 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 = conn.cursor() # Création de l'objet "curseur"
|
||||||
cursor.execute("""SELECT Mail, alias FROM users WHERE name=?""", (UTILISATEUR,))
|
cursor.execute("""SELECT Mail, alias FROM users WHERE name=?""", (user,))
|
||||||
tmp = cursor.fetchone()
|
tmp = cursor.fetchone()
|
||||||
mail = tmp[0]
|
mail = tmp[0]
|
||||||
alias_list = tmp[1].split(',')
|
alias_list = tmp[1].split(',')
|
||||||
@@ -116,16 +146,16 @@ def remove_alias(aliasrm):
|
|||||||
res = os.system(cmd)
|
res = os.system(cmd)
|
||||||
if res == 0:
|
if res == 0:
|
||||||
cursor.execute("UPDATE users SET alias=? WHERE name=?",
|
cursor.execute("UPDATE users SET alias=? WHERE name=?",
|
||||||
(aliases, UTILISATEUR))
|
(aliases, user))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
TIME=time.strftime("%A %d %B %Y %H:%M:%S")
|
time_del_alias=time.strftime("%A %d %B %Y %H:%M:%S")
|
||||||
IP=request.environ['REMOTE_ADDR']
|
ip_address=request.environ['REMOTE_ADDR']
|
||||||
CLIENT_PLATFORM=request.headers.get('User-Agent')
|
client_platform=request.headers.get('User-Agent')
|
||||||
log = TIME + ' - ' + IP + ' - ' + UTILISATEUR + ' - ' + CLIENT_PLATFORM + '\n' + '---> ' + "Suppression de l'alias "+ alias + '\n'
|
log = time_del_alias + ' - ' + ip_address + ' - ' + user + ' - ' + client_platform + '\n' + '---> ' + "Suppression de l'alias "+ alias + '\n'
|
||||||
append_to_log(log, UTILISATEUR)
|
append_to_log(log, user)
|
||||||
flash(u'Votre alias a été supprimé', 'succes')
|
flash(u'Votre alias a été supprimé', 'succes')
|
||||||
else:
|
else:
|
||||||
flash(u'Il y a eu une erreur', 'error')
|
flash(u'Il y a eu une erreur', 'error')
|
||||||
|
|
||||||
return redirect(url_for('mymailbox.myalias', _external=True))
|
return redirect(url_for('mymailbox.myalias'))
|
||||||
|
|
||||||
|
|||||||
153
views/profil.py
153
views/profil.py
@@ -5,11 +5,13 @@ from markupsafe import escape
|
|||||||
import time
|
import time
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
from shutil import copy
|
from shutil import copy
|
||||||
from socket import gethostname
|
from socket import gethostname
|
||||||
from flask_bcrypt import Bcrypt
|
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, totp_is_valid, login_required
|
from tools.utils import email_disp, append_to_log, gen_token, valid_passwd, valid_token_register, get_user_by_token, totp_is_valid, login_required, valid_email
|
||||||
from pyotp import random_base32
|
from pyotp import random_base32
|
||||||
|
from tools.filesutils import check_and_create
|
||||||
import qrcode
|
import qrcode
|
||||||
|
|
||||||
|
|
||||||
@@ -22,17 +24,17 @@ app.config.from_pyfile('config.py')
|
|||||||
#### Variables ####################################################################################
|
#### Variables ####################################################################################
|
||||||
|
|
||||||
bcrypt = Bcrypt(app)
|
bcrypt = Bcrypt(app)
|
||||||
DOSSIER_PERSO = app.config['DOSSIER_APP']
|
DOSSIER_PERSO = app.config.get('DOSSIER_APP')
|
||||||
|
|
||||||
extensionimg = app.config['EXT_IMG']
|
extensionimg = app.config.get('EXT_IMG')
|
||||||
|
|
||||||
DATABASE = app.config['DATABASE']
|
DATABASE = app.config.get('DATABASE')
|
||||||
DATAS_USER = app.config['DOSSIER_APP']
|
DATAS_USER = app.config.get('DOSSIER_APP')
|
||||||
MAIL_SERVER = app.config['MAIL_SERVER']
|
MAIL_SERVER = app.config.get('MAIL_SERVER')
|
||||||
XMPP_SERVER = app.config['XMPP_SERVER']
|
XMPP_SERVER = app.config.get('XMPP_SERVER')
|
||||||
SETUID = app.config['SETUID']
|
SETUID = app.config.get('SETUID')
|
||||||
BASE_URL = app.config['BASE_URL']
|
BASE_URL = app.config.get('BASE_URL')
|
||||||
BACKUP_TIME = app.config['BACKUP_TIME']
|
BACKUP_TIME = app.config.get('BACKUP_TIME')
|
||||||
|
|
||||||
##################################################################################################
|
##################################################################################################
|
||||||
|
|
||||||
@@ -48,6 +50,7 @@ def profil_img(user, img) :
|
|||||||
@login_required
|
@login_required
|
||||||
def profile() :
|
def profile() :
|
||||||
user='%s' % escape(session['username'])
|
user='%s' % escape(session['username'])
|
||||||
|
check_and_create(os.path.join(DOSSIER_PERSO, user,'profile'))
|
||||||
conn = sqlite3.connect(DATABASE) # 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 = conn.cursor() # Création de l'objet "curseur"
|
||||||
cursor.execute("""SELECT avatar, nom, prenom, age, Mail_rescue FROM users WHERE name=?""", (user,))
|
cursor.execute("""SELECT avatar, nom, prenom, age, Mail_rescue FROM users WHERE name=?""", (user,))
|
||||||
@@ -65,37 +68,38 @@ def profile() :
|
|||||||
f = request.files['fic']
|
f = request.files['fic']
|
||||||
|
|
||||||
|
|
||||||
if request.form['theme'] != "Default":
|
if request.form['theme']:
|
||||||
copy( "static/vendors/picocss/pico.fluid.classless."+request.form['theme']+".min.css",
|
copy( "static/vendors/picocss/pico.fluid.classless."+request.form['theme']+".min.css",
|
||||||
DOSSIER_PERSO+ user +'/theme.min.css' )
|
os.path.join(DOSSIER_PERSO, user ,'theme.min.css') )
|
||||||
|
|
||||||
if request.form['nom']:
|
if request.form['nom']:
|
||||||
profil_user['nom'] = request.form['nom']
|
profil_user['nom'] = str(request.form['nom'])
|
||||||
if request.form['prenom']:
|
if request.form['prenom']:
|
||||||
profil_user['prenom'] = request.form['prenom']
|
profil_user['prenom'] = str(request.form['prenom'])
|
||||||
if request.form['age']:
|
if request.form['age']:
|
||||||
profil_user['age'] = request.form['age']
|
profil_user['age'] = str(request.form['age'])
|
||||||
if '@' in request.form['mail_rescue']:
|
|
||||||
if len(request.form['mail_rescue']) > 4:
|
if request.form['mail_rescue'] :
|
||||||
profil_user['mail_rescue'] = request.form['mail_rescue']
|
new_mail_rescue = str(request.form['mail_rescue'])
|
||||||
|
if valid_email(new_mail_rescue):
|
||||||
|
profil_user['mail_rescue']=new_mail_rescue
|
||||||
else:
|
else:
|
||||||
flash(u'Adresse de courriel invalide', 'error')
|
flash(u'Adresse de courriel invalide', 'error')
|
||||||
else:
|
|
||||||
flash(u'Adresse de courriel de secour invalide', 'error')
|
|
||||||
if f: # On vérifie qu'un fichier a bien été envoyé
|
if f: # On vérifie qu'un fichier a bien été envoyé
|
||||||
nom = secure_filename(f.filename)
|
nom = secure_filename(f.filename)
|
||||||
f.save(DOSSIER_PERSO + user + '/profile/' + nom)
|
f.save(os.path.join(DOSSIER_PERSO, user, 'profile', nom))
|
||||||
image = DOSSIER_PERSO + user + '/profile/' + nom
|
image = os.path.join(DOSSIER_PERSO, user, 'profile', nom)
|
||||||
with Image.open(image) as img:
|
with Image.open(image) as img:
|
||||||
img.thumbnail((300,200))
|
img.thumbnail((300,200))
|
||||||
img.save( DOSSIER_PERSO + user + '/profile/' + nom)
|
img.save(os.path.join(DOSSIER_PERSO, user, 'profile', nom))
|
||||||
filename = nom
|
filename = nom
|
||||||
conn = sqlite3.connect(DATABASE) # 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 = conn.cursor() # Création de l'objet "curseur"
|
||||||
cursor.execute("UPDATE users SET avatar=? WHERE name=?",
|
cursor.execute("UPDATE users SET avatar=? WHERE name=?",
|
||||||
(filename, user))
|
(filename, user))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
cursor = conn.cursor() # Création de l'objet "curseur"
|
|
||||||
conn.close()
|
conn.close()
|
||||||
flash(u'Image de profil mise à jour', 'success')
|
flash(u'Image de profil mise à jour', 'success')
|
||||||
|
|
||||||
@@ -106,7 +110,7 @@ def profile() :
|
|||||||
(profil_user['nom'], profil_user['prenom'], profil_user['age'], profil_user['mail_rescue'],
|
(profil_user['nom'], profil_user['prenom'], profil_user['age'], profil_user['mail_rescue'],
|
||||||
user))
|
user))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
flash(u'Le profil a été mis à jour', 'succes')
|
flash(u'Le profil a été mis à jour', 'success')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -192,7 +196,7 @@ def change_passwd() :
|
|||||||
if not(account['totp']):
|
if not(account['totp']):
|
||||||
account['totp'] = random_base32()
|
account['totp'] = random_base32()
|
||||||
img = qrcode.make('otpauth://totp/'+BASE_URL+'?secret='+account['totp'])
|
img = qrcode.make('otpauth://totp/'+BASE_URL+'?secret='+account['totp'])
|
||||||
img.save(DOSSIER_PERSO + user + "/totp.png")
|
img.save(os.path.join(DOSSIER_PERSO, user, "totp.png"))
|
||||||
shared_key_validate = False
|
shared_key_validate = False
|
||||||
|
|
||||||
return render_template('mypassword.html',
|
return render_template('mypassword.html',
|
||||||
@@ -299,7 +303,7 @@ def set_totp():
|
|||||||
cursor.execute("""UPDATE users SET totp=? WHERE name=?""", (shared_key, user,))
|
cursor.execute("""UPDATE users SET totp=? WHERE name=?""", (shared_key, user,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
img = qrcode.make('otpauth://totp/'+BASE_URL+'?secret='+shared_key)
|
img = qrcode.make('otpauth://totp/'+BASE_URL+'?secret='+shared_key)
|
||||||
img.save(DOSSIER_PERSO + user + "/totp.png")
|
img.save(os.path.join(DOSSIER_PERSO, user, "totp.png"))
|
||||||
flash(u'Votre mot de passe à usage unique est configuré et actif.', 'success')
|
flash(u'Votre mot de passe à usage unique est configuré et actif.', 'success')
|
||||||
else:
|
else:
|
||||||
flash(u'Le code de validation totp n\'est pas valide.', 'error')
|
flash(u'Le code de validation totp n\'est pas valide.', 'error')
|
||||||
@@ -327,8 +331,9 @@ def totp_qrcode():
|
|||||||
os.path.join(DOSSIER_PERSO, user, "totp.png"), "totp.png")
|
os.path.join(DOSSIER_PERSO, user, "totp.png"), "totp.png")
|
||||||
|
|
||||||
|
|
||||||
@profil.route('/deltoken-password-lost/<token>', methods=['GET','POST'] )
|
@profil.route('/deltoken-password-lost/<token>', methods=['GET'] )
|
||||||
def deltoken_passwd_lost(token) :
|
def deltoken_passwd_lost(token) :
|
||||||
|
token = escape(token)
|
||||||
if valid_token_register(token, "Lost password"):
|
if valid_token_register(token, "Lost password"):
|
||||||
user = get_user_by_token(token, "Lost password")
|
user = get_user_by_token(token, "Lost password")
|
||||||
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée
|
||||||
@@ -347,100 +352,108 @@ def deltoken_passwd_lost(token) :
|
|||||||
@profil.route('/invitation/', methods=['GET'])
|
@profil.route('/invitation/', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def invitation():
|
def invitation():
|
||||||
UTILISATEUR='%s' % escape(session['username'])
|
user='%s' % escape(session['username'])
|
||||||
conn = sqlite3.connect(DATABASE) # 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 = conn.cursor() # Création de l'objet "curseur"
|
||||||
cursor.execute("""SELECT Token, invitations FROM users WHERE name=?""", (UTILISATEUR,))
|
cursor.execute("""SELECT Token, invitations FROM users WHERE name=?""", (user,))
|
||||||
tmp = cursor.fetchone()
|
tmp = cursor.fetchone()
|
||||||
token = tmp[0]
|
token = tmp[0]
|
||||||
if token:
|
nb_invitations = tmp[1]
|
||||||
url_invitation = BASE_URL + 'inscription/' + token
|
if token and nb_invitations > 0:
|
||||||
|
url_invitation = BASE_URL + '/inscription/' + token
|
||||||
|
img = qrcode.make(url_invitation)
|
||||||
|
img.save(os.path.join(DOSSIER_PERSO, user, "invitation.png"))
|
||||||
else:
|
else:
|
||||||
url_invitation = ""
|
url_invitation = ""
|
||||||
invitations_count = tmp[1]
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return render_template('invitation.html',
|
return render_template('invitation.html',
|
||||||
section='Profil',
|
section='Profil',
|
||||||
nb_invitation=invitations_count,
|
nb_invitation=nb_invitations,
|
||||||
token=token,
|
token=token,
|
||||||
url_invitation=url_invitation)
|
url_invitation=url_invitation)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@profil.route('/invitation.png', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def invitation_qrcode():
|
||||||
|
user='%s' % escape(session['username'])
|
||||||
|
return send_file(
|
||||||
|
os.path.join(DOSSIER_PERSO, user, "invitation.png"))
|
||||||
|
|
||||||
@profil.route('/gen_token/', methods=['GET'])
|
@profil.route('/gen_token/', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def generate_token():
|
def generate_token():
|
||||||
UTILISATEUR='%s' % escape(session['username'])
|
user='%s' % escape(session['username'])
|
||||||
conn = sqlite3.connect(DATABASE) # 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 = conn.cursor() # Création de l'objet "curseur"
|
||||||
|
cursor.execute("""SELECT invitations FROM users WHERE name=?""", (user,))
|
||||||
|
tmp = cursor.fetchone()
|
||||||
|
token = tmp[0]
|
||||||
token = gen_token("Invitation")
|
token = gen_token("Invitation")
|
||||||
cursor.execute("UPDATE users SET Token=? WHERE name=?",
|
cursor.execute("UPDATE users SET Token=? WHERE name=?",
|
||||||
(token, UTILISATEUR))
|
(token, user))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
return redirect(BASE_URL+'invitation/')
|
return redirect(BASE_URL+'/invitation/')
|
||||||
|
|
||||||
|
|
||||||
@profil.route( '/delete_me/', methods=['GET','POST'])
|
@profil.route( '/delete_me/', methods=['GET','POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def delete_account():
|
def delete_account():
|
||||||
UTILISATEUR='%s'% escape(session['username'])
|
user='%s'% escape(session['username'])
|
||||||
resp = render_template('delete_account.html', time_backup=BACKUP_TIME)
|
resp = render_template('delete_account.html', time_backup=BACKUP_TIME)
|
||||||
if request.method == 'POST' :
|
if request.method == 'POST' :
|
||||||
conn = sqlite3.connect(DATABASE) # 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 = conn.cursor() # Création de l'objet "curseur"
|
||||||
cursor.execute("""SELECT passwd FROM users WHERE name=?""", (UTILISATEUR,))
|
cursor.execute("""SELECT passwd FROM users WHERE name=?""", (user,))
|
||||||
passwd = cursor.fetchone()[0]
|
passwd = cursor.fetchone()[0]
|
||||||
cursor.execute("""SELECT mail FROM users WHERE name=?""", (UTILISATEUR,))
|
cursor.execute("""SELECT mail FROM users WHERE name=?""", (user,))
|
||||||
mail = cursor.fetchone()[0]
|
mail = cursor.fetchone()[0]
|
||||||
conn.close()
|
conn.close()
|
||||||
password = request.form['passwd']
|
password = str(request.form['passwd'])
|
||||||
if bcrypt.check_password_hash(passwd, password) is True:
|
if bcrypt.check_password_hash(passwd, password) is True:
|
||||||
not_error = True
|
not_error = True
|
||||||
|
# Delete mail account
|
||||||
if MAIL_SERVER:
|
if MAIL_SERVER:
|
||||||
try:
|
try:
|
||||||
cmd = SETUID + ' set_mail_passwd del ' + '"'+mail+'"'
|
cmd = subprocess.run([SETUID, 'set_mail_passwd','del',mail])
|
||||||
print(cmd)
|
|
||||||
os.system(cmd)
|
|
||||||
except:
|
except:
|
||||||
not_error = False
|
not_error = False
|
||||||
flash(u'Erreur lors de la suppression de votre compte Mail.', 'error')
|
flash(u'Erreur lors de la suppression de votre compte Mail.', 'error')
|
||||||
|
|
||||||
|
|
||||||
|
# Delete the XMPP account
|
||||||
if XMPP_SERVER:
|
if XMPP_SERVER:
|
||||||
try:
|
try:
|
||||||
tmp = mail.split('@')
|
cmd = subprocess.run([SETUID,'prosodyctl', 'deluser', mail])
|
||||||
cmd = SETUID+ ' prosodyctl deluser ' "'"+tmp[0]+"' " + "'"+tmp[1]+"'"
|
print(str(cmd))
|
||||||
os.system(cmd)
|
|
||||||
except:
|
except:
|
||||||
not_error = False
|
not_error = False
|
||||||
flash(u'Erreur lors de la suppression de votre compte XMPP.', 'error')
|
flash(u'Erreur lors de la suppression de votre compte XMPP.', 'error')
|
||||||
|
|
||||||
|
# Delete files
|
||||||
|
try:
|
||||||
|
cmd = subprocess.run(['rm', '-r', DATAS_USER + '/' + user])
|
||||||
|
print(str(cmd))
|
||||||
|
if cmd.returncode != 0:
|
||||||
|
raise TypeError("Remove directory error")
|
||||||
|
except:
|
||||||
|
flash(u'Erreur lors de la suppression de votre dossier utilisateur.', 'error')
|
||||||
|
not_error = False
|
||||||
|
|
||||||
|
|
||||||
if not_error:
|
if not_error:
|
||||||
try:
|
conn = sqlite3.connect(DATABASE)
|
||||||
cmd = 'rm -r ' + DATAS_USER + '/' + UTILISATEUR
|
cursor = conn.cursor()
|
||||||
if os.system(cmd) != 0:
|
cursor.execute("""DELETE FROM users WHERE name=?""", (user,))
|
||||||
raise TypeError("Remove directory error")
|
cursor.execute("""DELETE FROM Blog_posts WHERE author=?""", (user,))
|
||||||
except:
|
conn.commit()
|
||||||
flash(u'Erreur lors de la suppression de votre dossier utilisateur.', 'error')
|
conn.close()
|
||||||
|
flash(u'Désinscription réalisé avec succés, y\'a plus rien !', 'success')
|
||||||
|
resp = redirect(url_for('loginlogout.logout'))
|
||||||
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:
|
else:
|
||||||
flash(u'Mauvais mot de passe', 'error')
|
flash(u'Mauvais mot de passe', 'error')
|
||||||
|
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|||||||
7
wsgi.py
7
wsgi.py
@@ -1,6 +1,11 @@
|
|||||||
from gevent.pywsgi import WSGIServer
|
from gevent.pywsgi import WSGIServer
|
||||||
from pywallter import create_app
|
from pywallter import create_app
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app = create_app()
|
app = create_app()
|
||||||
http_server = WSGIServer(("127.0.0.1", 8000), app)
|
app.config.from_pyfile('config.py')
|
||||||
|
|
||||||
|
|
||||||
|
http_server = WSGIServer((app.config['HOST'], int(app.config['PORT']) ), app)
|
||||||
http_server.serve_forever()
|
http_server.serve_forever()
|
||||||
|
|||||||
Reference in New Issue
Block a user