code cosmetic (warnings pylint)
This commit is contained in:
parent
5d527edb71
commit
6edecb6659
@ -41,8 +41,9 @@ from xml.etree import ElementTree
|
|||||||
import flask
|
import flask
|
||||||
from flask import g, url_for, request, current_app, flash
|
from flask import g, url_for, request, current_app, flash
|
||||||
from flask import redirect, render_template
|
from flask import redirect, render_template
|
||||||
|
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
from flask_wtf import FlaskForm
|
||||||
|
|
||||||
from wtforms import HiddenField, PasswordField, StringField, SubmitField
|
from wtforms import HiddenField, PasswordField, StringField, SubmitField
|
||||||
from wtforms.validators import DataRequired, Email, ValidationError, EqualTo
|
from wtforms.validators import DataRequired, Email, ValidationError, EqualTo
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ from app.decorators import (
|
|||||||
permission_required,
|
permission_required,
|
||||||
)
|
)
|
||||||
|
|
||||||
from app.scodoc import html_sco_header, sco_import_users, sco_excel, sco_roles_default
|
from app.scodoc import html_sco_header, sco_import_users, sco_roles_default
|
||||||
from app.scodoc import sco_users
|
from app.scodoc import sco_users
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc import sco_xml
|
from app.scodoc import sco_xml
|
||||||
@ -72,13 +73,14 @@ from app.scodoc.sco_import_users import generate_password
|
|||||||
from app.scodoc.sco_permissions_check import can_handle_passwd
|
from app.scodoc.sco_permissions_check import can_handle_passwd
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
||||||
from app.views import users_bp as bp
|
from app.views import users_bp as bp
|
||||||
from flask_wtf import FlaskForm
|
|
||||||
|
|
||||||
_ = lambda x: x # sans babel
|
_ = lambda x: x # sans babel
|
||||||
_l = _
|
_l = _
|
||||||
|
|
||||||
|
|
||||||
class ChangePasswordForm(FlaskForm):
|
class ChangePasswordForm(FlaskForm):
|
||||||
|
"""formulaire changement mot de passe et mail"""
|
||||||
|
|
||||||
user_name = HiddenField()
|
user_name = HiddenField()
|
||||||
old_password = PasswordField(_l("Identifiez-vous"))
|
old_password = PasswordField(_l("Identifiez-vous"))
|
||||||
new_password = PasswordField(_l("Nouveau mot de passe de l'utilisateur"))
|
new_password = PasswordField(_l("Nouveau mot de passe de l'utilisateur"))
|
||||||
@ -102,6 +104,7 @@ class ChangePasswordForm(FlaskForm):
|
|||||||
cancel = SubmitField("Annuler")
|
cancel = SubmitField("Annuler")
|
||||||
|
|
||||||
def validate_email(self, email):
|
def validate_email(self, email):
|
||||||
|
"vérifie que le mail est unique"
|
||||||
user = User.query.filter_by(email=email.data.strip()).first()
|
user = User.query.filter_by(email=email.data.strip()).first()
|
||||||
if user is not None and self.user_name.data != user.user_name:
|
if user is not None and self.user_name.data != user.user_name:
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
@ -109,8 +112,9 @@ class ChangePasswordForm(FlaskForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def validate_new_password(self, new_password):
|
def validate_new_password(self, new_password):
|
||||||
|
"vérifie que le mot de passe est acceptable"
|
||||||
if new_password.data != "" and not is_valid_password(new_password.data):
|
if new_password.data != "" and not is_valid_password(new_password.data):
|
||||||
raise ValidationError(f"Mot de passe trop simple, recommencez")
|
raise ValidationError("Mot de passe trop simple, recommencez")
|
||||||
|
|
||||||
def validate_old_password(self, old_password):
|
def validate_old_password(self, old_password):
|
||||||
if not current_user.check_password(old_password.data):
|
if not current_user.check_password(old_password.data):
|
||||||
@ -129,6 +133,7 @@ class Mode(IntEnum):
|
|||||||
@permission_required(Permission.ScoUsersView)
|
@permission_required(Permission.ScoUsersView)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def index_html(all_depts=False, with_inactives=False, format="html"):
|
def index_html(all_depts=False, with_inactives=False, format="html"):
|
||||||
|
"Page accueil utilisateur: tableau avec liste des comptes"
|
||||||
return sco_users.index_html(
|
return sco_users.index_html(
|
||||||
all_depts=all_depts,
|
all_depts=all_depts,
|
||||||
with_inactives=with_inactives,
|
with_inactives=with_inactives,
|
||||||
@ -136,15 +141,6 @@ def index_html(all_depts=False, with_inactives=False, format="html"):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/user_info")
|
|
||||||
@scodoc
|
|
||||||
@permission_required(Permission.ScoUsersView)
|
|
||||||
@scodoc7func
|
|
||||||
def user_info(user_name, format="json"):
|
|
||||||
info = sco_users.user_info(user_name)
|
|
||||||
return scu.sendResult(info, name="user", format=format)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/create_user_form", methods=["GET", "POST"])
|
@bp.route("/create_user_form", methods=["GET", "POST"])
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoUsersAdmin)
|
@permission_required(Permission.ScoUsersAdmin)
|
||||||
@ -173,7 +169,7 @@ def create_user_form(user_name=None, edit=0, all_roles=False):
|
|||||||
if not the_user:
|
if not the_user:
|
||||||
raise ScoValueError("utilisateur inexistant")
|
raise ScoValueError("utilisateur inexistant")
|
||||||
initvalues = the_user.to_dict()
|
initvalues = the_user.to_dict()
|
||||||
H.append("<h2>Modification de l'utilisateur %s</h2>" % user_name)
|
H.append(f"<h2>Modification de l'utilisateur {user_name}</h2>")
|
||||||
else:
|
else:
|
||||||
H.append("<h2>Création d'un utilisateur</h2>")
|
H.append("<h2>Création d'un utilisateur</h2>")
|
||||||
|
|
||||||
@ -196,9 +192,9 @@ def create_user_form(user_name=None, edit=0, all_roles=False):
|
|||||||
]
|
]
|
||||||
# Départements auxquels ont peut associer des rôles via ce dialogue:
|
# Départements auxquels ont peut associer des rôles via ce dialogue:
|
||||||
# si SuperAdmin, tous les rôles standards dans tous les départements
|
# si SuperAdmin, tous les rôles standards dans tous les départements
|
||||||
# sinon, les départements dans lesquels l'utilisateur a le droit
|
# sinon, les départements dans lesquels l'utilisateur a la permission ScoUsersAdmin
|
||||||
if is_super_admin:
|
if is_super_admin:
|
||||||
log("create_user_form called by %s (super admin)" % (current_user.user_name,))
|
log(f"create_user_form called by {current_user.user_name} (super admin)")
|
||||||
administrable_dept_acronyms = [d.acronym for d in Departement.query.all()]
|
administrable_dept_acronyms = [d.acronym for d in Departement.query.all()]
|
||||||
else:
|
else:
|
||||||
# Si on n'est pas SuperAdmin, liste les départements dans lesquels on a la
|
# Si on n'est pas SuperAdmin, liste les départements dans lesquels on a la
|
||||||
@ -266,8 +262,8 @@ def create_user_form(user_name=None, edit=0, all_roles=False):
|
|||||||
f"{dept or '<em>tout dépt.</em>'}: {r.name}" for (r, dept) in displayed_roles
|
f"{dept or '<em>tout dépt.</em>'}: {r.name}" for (r, dept) in displayed_roles
|
||||||
]
|
]
|
||||||
disabled_roles = {} # pour désactiver les roles que l'on ne peut pas éditer
|
disabled_roles = {} # pour désactiver les roles que l'on ne peut pas éditer
|
||||||
for i in range(len(displayed_roles_strings)):
|
for i, role_string in enumerate(displayed_roles_strings):
|
||||||
if displayed_roles_strings[i] not in editable_roles_strings:
|
if role_string not in editable_roles_strings:
|
||||||
disabled_roles[i] = True
|
disabled_roles[i] = True
|
||||||
descr = [
|
descr = [
|
||||||
("edit", {"input_type": "hidden", "default": edit}),
|
("edit", {"input_type": "hidden", "default": edit}),
|
||||||
@ -418,8 +414,7 @@ def create_user_form(user_name=None, edit=0, all_roles=False):
|
|||||||
"d",
|
"d",
|
||||||
{
|
{
|
||||||
"input_type": "separator",
|
"input_type": "separator",
|
||||||
"title": "L'utilisateur appartient au département %s"
|
"title": f"L'utilisateur appartient au département {auth_dept}",
|
||||||
% auth_dept,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -429,8 +424,7 @@ def create_user_form(user_name=None, edit=0, all_roles=False):
|
|||||||
"d",
|
"d",
|
||||||
{
|
{
|
||||||
"input_type": "separator",
|
"input_type": "separator",
|
||||||
"title": "L'utilisateur sera crée dans le département %s"
|
"title": f"L'utilisateur sera crée dans le département {auth_dept}",
|
||||||
% auth_dept,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -469,7 +463,7 @@ def create_user_form(user_name=None, edit=0, all_roles=False):
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
vals = scu.get_request_args()
|
vals = scu.get_request_args()
|
||||||
if "tf_submitted" in vals and not "roles" in vals:
|
if "tf_submitted" in vals and "roles" not in vals:
|
||||||
vals["roles"] = []
|
vals["roles"] = []
|
||||||
if "tf_submitted" in vals:
|
if "tf_submitted" in vals:
|
||||||
# Ajoute roles existants mais non modifiables (disabled dans le form)
|
# Ajoute roles existants mais non modifiables (disabled dans le form)
|
||||||
@ -507,13 +501,15 @@ def create_user_form(user_name=None, edit=0, all_roles=False):
|
|||||||
user_name = vals["user_name"]
|
user_name = vals["user_name"]
|
||||||
# ce login existe ?
|
# ce login existe ?
|
||||||
err = None
|
err = None
|
||||||
users = sco_users._user_list(user_name)
|
existing_user = User.query.filter_by(user_name=user_name)
|
||||||
if edit and not users: # safety net, le user_name ne devrait pas changer
|
if (
|
||||||
err = "identifiant %s inexistant" % user_name
|
edit and existing_user is None
|
||||||
if not edit and users:
|
): # safety net, le user_name ne devrait pas changer
|
||||||
err = "identifiant %s déjà utilisé" % user_name
|
err = f"identifiant {user_name} inexistant"
|
||||||
|
if not edit and existing_user is not None:
|
||||||
|
err = f"identifiant %{user_name} déjà utilisé"
|
||||||
if err:
|
if err:
|
||||||
H.append(tf_error_message("""Erreur: %s""" % err))
|
H.append(tf_error_message(f"""Erreur: {err}"""))
|
||||||
return "\n".join(H) + "\n" + tf[1] + F
|
return "\n".join(H) + "\n" + tf[1] + F
|
||||||
ok, msg = sco_users.check_modif_user(
|
ok, msg = sco_users.check_modif_user(
|
||||||
edit,
|
edit,
|
||||||
@ -570,15 +566,20 @@ def create_user_form(user_name=None, edit=0, all_roles=False):
|
|||||||
vals["roles_string"] = ",".join(roles)
|
vals["roles_string"] = ",".join(roles)
|
||||||
|
|
||||||
# ok, edit
|
# ok, edit
|
||||||
log("sco_users: editing %s by %s" % (user_name, current_user.user_name))
|
log(f"sco_users: editing {user_name} by {current_user.user_name}")
|
||||||
log("sco_users: previous_values=%s" % initvalues)
|
log(f"sco_users: previous_values={initvalues}")
|
||||||
log("sco_users: new_values=%s" % vals)
|
log(f"sco_users: new_values={vals}")
|
||||||
sco_users.user_edit(user_name, vals)
|
sco_users.user_edit(user_name, vals)
|
||||||
|
flash(f"Utilisateur {user_name} modifié")
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
"user_info_page?user_name=%s&head_message=Utilisateur %s modifié"
|
url_for(
|
||||||
% (user_name, user_name)
|
"users.user_info_page",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
user_name=user_name,
|
||||||
)
|
)
|
||||||
else: # creation utilisateur
|
)
|
||||||
|
|
||||||
|
else: # création utilisateur
|
||||||
vals["roles_string"] = ",".join(vals["roles"])
|
vals["roles_string"] = ",".join(vals["roles"])
|
||||||
# check identifiant
|
# check identifiant
|
||||||
if not re.match(r"^[a-zA-Z0-9@\\\-_\\\.]+$", vals["user_name"]):
|
if not re.match(r"^[a-zA-Z0-9@\\\-_\\\.]+$", vals["user_name"]):
|
||||||
@ -623,8 +624,7 @@ def create_user_form(user_name=None, edit=0, all_roles=False):
|
|||||||
raise ScoValueError("département invalide")
|
raise ScoValueError("département invalide")
|
||||||
# ok, go
|
# ok, go
|
||||||
log(
|
log(
|
||||||
"sco_users: new_user %s by %s"
|
f"""sco_users: new_user {vals["user_name"]} by {current_user.user_name}"""
|
||||||
% (vals["user_name"], current_user.user_name)
|
|
||||||
)
|
)
|
||||||
the_user = User()
|
the_user = User()
|
||||||
the_user.from_dict(vals, new_user=True)
|
the_user.from_dict(vals, new_user=True)
|
||||||
@ -678,7 +678,8 @@ def import_users_form():
|
|||||||
H = [
|
H = [
|
||||||
head,
|
head,
|
||||||
"""<h2>Téléchargement d'une nouvelle liste d'utilisateurs</h2>
|
"""<h2>Téléchargement d'une nouvelle liste d'utilisateurs</h2>
|
||||||
<p style="color: red">A utiliser pour importer de <b>nouveaux</b> utilisateurs (enseignants ou secrétaires)
|
<p style="color: red">A utiliser pour importer de <b>nouveaux</b>
|
||||||
|
utilisateurs (enseignants ou secrétaires)
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
L'opération se déroule en deux étapes. Dans un premier temps,
|
L'opération se déroule en deux étapes. Dans un premier temps,
|
||||||
@ -690,7 +691,7 @@ def import_users_form():
|
|||||||
</p>
|
</p>
|
||||||
""",
|
""",
|
||||||
]
|
]
|
||||||
help = """<p class="help">
|
help_msg = """<p class="help">
|
||||||
Lors de la creation des utilisateurs, les opérations suivantes sont effectuées:
|
Lors de la creation des utilisateurs, les opérations suivantes sont effectuées:
|
||||||
</p>
|
</p>
|
||||||
<ol class="help">
|
<ol class="help">
|
||||||
@ -727,27 +728,33 @@ def import_users_form():
|
|||||||
submitlabel="Télécharger",
|
submitlabel="Télécharger",
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + "</li></ol>" + help + F
|
return "\n".join(H) + tf[1] + "</li></ol>" + help_msg + F
|
||||||
elif tf[0] == -1:
|
elif tf[0] == -1:
|
||||||
return flask.redirect(url_for("scolar.index_html", docodc_dept=g.scodoc_dept))
|
return flask.redirect(url_for("scolar.index_html", docodc_dept=g.scodoc_dept))
|
||||||
else:
|
|
||||||
# IMPORT
|
# IMPORT
|
||||||
ok, diag, nb_created = sco_import_users.import_excel_file(
|
ok, diags, nb_created = sco_import_users.import_excel_file(
|
||||||
tf[2]["xlsfile"], tf[2]["force"]
|
tf[2]["xlsfile"], tf[2]["force"]
|
||||||
)
|
)
|
||||||
H = [html_sco_header.sco_header(page_title="Import utilisateurs")]
|
H = [html_sco_header.sco_header(page_title="Import utilisateurs")]
|
||||||
H.append("<ul>")
|
H.append("<ul>")
|
||||||
for d in diag:
|
for diag in diags:
|
||||||
H.append("<li>%s</li>" % d)
|
H.append(f"<li>{diag}</li>")
|
||||||
H.append("</ul>")
|
H.append("</ul>")
|
||||||
if ok:
|
if ok:
|
||||||
dest = url_for("users.index_html", scodoc_dept=g.scodoc_dept, all_depts=1)
|
dest_url = url_for("users.index_html", scodoc_dept=g.scodoc_dept, all_depts=1)
|
||||||
H.append("<p>Ok, Import terminé (%s utilisateurs créés)!</p>" % nb_created)
|
H.append(
|
||||||
H.append('<p><a class="stdlink" href="%s">Continuer</a></p>' % dest)
|
f"""<p>Ok, Import terminé ({nb_created} utilisateurs créés)!</p>
|
||||||
|
<p><a class="stdlink" href="{dest_url}">Continuer</a></p>
|
||||||
|
"""
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
dest = url_for("users.import_users_form", scodoc_dept=g.scodoc_dept)
|
dest_url = url_for("users.import_users_form", scodoc_dept=g.scodoc_dept)
|
||||||
H.append("<p>Erreur, importation annulée !</p>")
|
H.append(
|
||||||
H.append('<p><a class="stdlink" href="%s">Continuer</a></p>' % dest)
|
f"""<p>Erreur, importation annulée !</p>
|
||||||
|
<p><a class="stdlink" href="{dest_url}">Continuer</a></p>
|
||||||
|
"""
|
||||||
|
)
|
||||||
return "\n".join(H) + html_sco_header.sco_footer()
|
return "\n".join(H) + html_sco_header.sco_footer()
|
||||||
|
|
||||||
|
|
||||||
@ -759,11 +766,9 @@ def user_info_page(user_name=None):
|
|||||||
"""Display page of info about given user.
|
"""Display page of info about given user.
|
||||||
If user_name not specified, user current_user
|
If user_name not specified, user current_user
|
||||||
"""
|
"""
|
||||||
from app.scodoc.sco_permissions_check import can_handle_passwd
|
|
||||||
|
|
||||||
if user_name is not None: # scodoc7func converti en int !
|
if user_name is not None: # scodoc7func converti en int !
|
||||||
user_name = str(user_name)
|
user_name = str(user_name)
|
||||||
# peut on divulguer ces infos ?
|
# peut-on divulguer ces infos ?
|
||||||
if not can_handle_passwd(current_user, allow_admindepts=True):
|
if not can_handle_passwd(current_user, allow_admindepts=True):
|
||||||
raise AccessDenied("Vous n'avez pas la permission de voir cette page")
|
raise AccessDenied("Vous n'avez pas la permission de voir cette page")
|
||||||
|
|
||||||
@ -877,26 +882,29 @@ def change_password(user_name, password, password2):
|
|||||||
if not can_handle_passwd(u):
|
if not can_handle_passwd(u):
|
||||||
# access denied
|
# access denied
|
||||||
log(
|
log(
|
||||||
"change_password: access denied (authuser=%s, user_name=%s)"
|
f"change_password: access denied (authuser={current_user}, user_name={user_name})"
|
||||||
% (current_user, user_name)
|
|
||||||
)
|
)
|
||||||
raise AccessDenied("vous n'avez pas la permission de changer ce mot de passe")
|
raise AccessDenied("vous n'avez pas la permission de changer ce mot de passe")
|
||||||
H = []
|
H = []
|
||||||
F = html_sco_header.sco_footer()
|
F = html_sco_header.sco_footer()
|
||||||
# check password
|
# check password
|
||||||
|
dest_url = url_for(
|
||||||
|
"users.form_change_password", scodoc_dept=g.scodoc_dept, user_name=user_name
|
||||||
|
)
|
||||||
if password != password2:
|
if password != password2:
|
||||||
H.append(
|
H.append(
|
||||||
"""<p>Les deux mots de passes saisis sont différents !</p>
|
f"""<p>Les deux mots de passes saisis sont différents !</p>
|
||||||
<p><a href="form_change_password?user_name=%s" class="stdlink">Recommencer</a></p>"""
|
<p><a href="{dest_url}" class="stdlink">Recommencer</a></p>
|
||||||
% user_name
|
"""
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if not is_valid_password(password):
|
if not is_valid_password(password):
|
||||||
H.append(
|
H.append(
|
||||||
"""<p><b>ce mot de passe n\'est pas assez compliqué !</b><br/>(oui, il faut un mot de passe vraiment compliqué !)</p>
|
f"""<p><b>ce mot de passe n'est pas assez compliqué !</b>
|
||||||
<p><a href="form_change_password?user_name=%s" class="stdlink">Recommencer</a></p>
|
<br/>(oui, il faut un mot de passe vraiment compliqué !)
|
||||||
|
</p>
|
||||||
|
<p><a href="{dest_url}" class="stdlink">Recommencer</a></p>
|
||||||
"""
|
"""
|
||||||
% user_name
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# ok, strong password
|
# ok, strong password
|
||||||
@ -907,21 +915,26 @@ def change_password(user_name, password, password2):
|
|||||||
# ici page simplifiee car on peut ne plus avoir
|
# ici page simplifiee car on peut ne plus avoir
|
||||||
# le droit d'acceder aux feuilles de style
|
# le droit d'acceder aux feuilles de style
|
||||||
H.append(
|
H.append(
|
||||||
"<h2>Changement effectué !</h2><p>Ne notez pas ce mot de passe, mais mémorisez le !</p><p>Rappel: il est <b>interdit</b> de communiquer son mot de passe à un tiers, même si c'est un collègue de confiance !</p><p><b>Si vous n'êtes pas administrateur, le système va vous redemander votre login et nouveau mot de passe au prochain accès.</b></p>"
|
"""<h2>Changement effectué !</h2>
|
||||||
|
<p>Ne notez pas ce mot de passe, mais mémorisez le !</p>
|
||||||
|
<p>Rappel: il est <b>interdit</b> de communiquer son mot de passe à
|
||||||
|
un tiers, même si c'est un collègue de confiance !</p>
|
||||||
|
<p><b>Si vous n'êtes pas administrateur, le système va vous redemander
|
||||||
|
votre login et nouveau mot de passe au prochain accès.</b>
|
||||||
|
</p>"""
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
"""<?xml version="1.0" encoding="%s"?>
|
f"""<?xml version="1.0" encoding="{scu.SCO_ENCODING}"?>
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Mot de passe changé</title>
|
<title>Mot de passe changé</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=%s" />
|
<meta http-equiv="Content-Type" content="text/html; charset={scu.SCO_ENCODING}" />
|
||||||
<body><h1>Mot de passe changé !</h1>
|
<body><h1>Mot de passe changé !</h1>
|
||||||
"""
|
"""
|
||||||
% (scu.SCO_ENCODING, scu.SCO_ENCODING)
|
|
||||||
+ "\n".join(H)
|
+ "\n".join(H)
|
||||||
+ '<a href="%s" class="stdlink">Continuer</a></body></html>'
|
+ f'<a href="{scu.ScoURL()}" class="stdlink">Continuer</a></body></html>'
|
||||||
% scu.ScoURL()
|
|
||||||
)
|
)
|
||||||
return html_sco_header.sco_header() + "\n".join(H) + F
|
return html_sco_header.sco_header() + "\n".join(H) + F
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user