Compare commits
6 Commits
feat/pytho
...
master
Author | SHA1 | Date | |
---|---|---|---|
3b5d01d5df | |||
3a3c4f4d0c | |||
898d6a652d | |||
3bf952b57f | |||
70442f6464 | |||
33f793fcbe |
@@ -1,5 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
from lib.user import create_users_from_file
|
|
||||||
|
|
||||||
create_users_from_file()
|
|
@@ -1,15 +0,0 @@
|
|||||||
DOCKERS_ENV = "/kaz/config/dockers.env"
|
|
||||||
SECRETS = "/kaz/secret/env-{serv}"
|
|
||||||
|
|
||||||
def getDockersConfig(key):
|
|
||||||
with open(DOCKERS_ENV) as config:
|
|
||||||
for line in config:
|
|
||||||
if line.startswith(f"{key}="):
|
|
||||||
return line.split("=", 1)[1].split("#")[0].strip()
|
|
||||||
|
|
||||||
def getSecretConfig(serv, key):
|
|
||||||
with open(SECRETS.format(serv=serv)) as config:
|
|
||||||
for line in config:
|
|
||||||
if line.startswith(f"{key}="):
|
|
||||||
return line.split("=", 2)[1].split("#")[0].strip()
|
|
||||||
|
|
101
bin/lib/ldap.py
101
bin/lib/ldap.py
@@ -1,101 +0,0 @@
|
|||||||
import ldap
|
|
||||||
from passlib.hash import sha512_crypt
|
|
||||||
from email_validator import validate_email, EmailNotValidError
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
from .config import getDockersConfig, getSecretConfig
|
|
||||||
|
|
||||||
class Ldap:
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.ldap_connection = None
|
|
||||||
self.ldap_root = getDockersConfig("ldap_root")
|
|
||||||
self.ldap_admin_username = getSecretConfig("ldapServ", "LDAP_ADMIN_USERNAME")
|
|
||||||
self.ldap_admin_password = getSecretConfig("ldapServ", "LDAP_ADMIN_PASSWORD")
|
|
||||||
cmd="docker inspect -f '{{.NetworkSettings.Networks.ldapNet.IPAddress}}' ldapServ"
|
|
||||||
self.ldap_host = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT).strip().decode()
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
self.ldap_connection = ldap.initialize(f"ldap://{self.ldap_host}")
|
|
||||||
self.ldap_connection.simple_bind_s("cn={},{}".format(self.ldap_admin_username, self.ldap_root), self.ldap_admin_password)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, tp, e, traceback):
|
|
||||||
self.ldap_connection.unbind_s()
|
|
||||||
|
|
||||||
|
|
||||||
def get_email(self, email):
|
|
||||||
"""
|
|
||||||
Vérifier si un utilisateur avec cet email existe dans le LDAP soit comme mail principal soit comme alias
|
|
||||||
"""
|
|
||||||
# Créer une chaîne de filtre pour rechercher dans les champs "cn" et "mailAlias"
|
|
||||||
filter_str = "(|(cn={})(mailAlias={}))".format(email, email)
|
|
||||||
result = self.ldap_connection.search_s("ou=users,{}".format(self.ldap_root), ldap.SCOPE_SUBTREE, filter_str)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def delete_user(self, email):
|
|
||||||
"""
|
|
||||||
Supprimer un utilisateur du LDAP par son adresse e-mail
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# Recherche de l'utilisateur
|
|
||||||
result = self.ldap_connection.search_s("ou=users,{}".format(self.ldap_root), ldap.SCOPE_SUBTREE, "(cn={})".format(email))
|
|
||||||
|
|
||||||
if not result:
|
|
||||||
return False # Utilisateur non trouvé
|
|
||||||
|
|
||||||
# Récupération du DN de l'utilisateur
|
|
||||||
dn = result[0][0]
|
|
||||||
|
|
||||||
# Suppression de l'utilisateur
|
|
||||||
self.ldap_connection.delete_s(dn)
|
|
||||||
return True # Utilisateur supprimé avec succès
|
|
||||||
|
|
||||||
except ldap.NO_SUCH_OBJECT:
|
|
||||||
return False # Utilisateur non trouvé
|
|
||||||
except ldap.LDAPError as e:
|
|
||||||
return False # Erreur lors de la suppression
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_user(self, email, prenom, nom, password, email_secours, quota):
|
|
||||||
"""
|
|
||||||
Créer une nouvelle entrée dans le LDAP pour un nouvel utilisateur. QUESTION: A QUOI SERVENT PRENOM/NOM/IDENT_KAZ DANS LE LDAP ? POURQUOI 3 QUOTA ?
|
|
||||||
"""
|
|
||||||
password_chiffre = sha512_crypt.hash(password)
|
|
||||||
|
|
||||||
if not validate_email(email) or not validate_email(email_secours):
|
|
||||||
return False
|
|
||||||
|
|
||||||
if self.get_email(email):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Construire le DN
|
|
||||||
dn = f"cn={email},ou=users,{self.ldap_root}"
|
|
||||||
|
|
||||||
mod_attrs = [
|
|
||||||
('objectClass', [b'inetOrgPerson', b'PostfixBookMailAccount', b'nextcloudAccount', b'kaznaute']),
|
|
||||||
('sn', f'{prenom} {nom}'.encode('utf-8')),
|
|
||||||
('mail', email.encode('utf-8')),
|
|
||||||
('mailEnabled', b'TRUE'),
|
|
||||||
('mailGidNumber', b'5000'),
|
|
||||||
('mailHomeDirectory', f"/var/mail/{email.split('@')[1]}/{email.split('@')[0]}/".encode('utf-8')),
|
|
||||||
('mailQuota', f'{quota}G'.encode('utf-8')),
|
|
||||||
('mailStorageDirectory', f"maildir:/var/mail/{email.split('@')[1]}/{email.split('@')[0]}/".encode('utf-8')),
|
|
||||||
('mailUidNumber', b'5000'),
|
|
||||||
('mailDeSecours', email_secours.encode('utf-8')),
|
|
||||||
('identifiantKaz', f'{prenom.lower()}.{nom.lower()}'.encode('utf-8')),
|
|
||||||
('quota', str(quota).encode('utf-8')),
|
|
||||||
('nextcloudEnabled', b'TRUE'),
|
|
||||||
('nextcloudQuota', f'{quota} GB'.encode('utf-8')),
|
|
||||||
('mobilizonEnabled', b'TRUE'),
|
|
||||||
('agoraEnabled', b'TRUE'),
|
|
||||||
('userPassword', f'{{CRYPT}}{password_chiffre}'.encode('utf-8')),
|
|
||||||
('cn', email.encode('utf-8'))
|
|
||||||
]
|
|
||||||
|
|
||||||
self.ldap_connection.add_s(dn, mod_attrs)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
@@ -1,134 +0,0 @@
|
|||||||
import subprocess
|
|
||||||
|
|
||||||
from .config import getDockersConfig, getSecretConfig
|
|
||||||
|
|
||||||
mattermost_user = getSecretConfig("mattermostServ", "MM_ADMIN_USER")
|
|
||||||
mattermost_pass = getSecretConfig("mattermostServ", "MM_ADMIN_PASSWORD")
|
|
||||||
mattermost_url = f"https://{getDockersConfig('matterHost')}.{getDockersConfig('domain')}"
|
|
||||||
mmctl = "docker exec -i mattermostServ bin/mmctl"
|
|
||||||
|
|
||||||
class Mattermost:
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
self.authenticate()
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, tp, e, traceback):
|
|
||||||
self.logout()
|
|
||||||
|
|
||||||
|
|
||||||
def authenticate(self):
|
|
||||||
# Authentification sur MM
|
|
||||||
cmd = f"{mmctl} auth login {mattermost_url} --name local-server --username {mattermost_user} --password {mattermost_pass}"
|
|
||||||
subprocess.run(cmd, shell=True, stderr=subprocess.STDOUT, check=True)
|
|
||||||
|
|
||||||
|
|
||||||
def logout(self):
|
|
||||||
# Authentification sur MM
|
|
||||||
cmd = f"{mmctl} auth clean"
|
|
||||||
subprocess.run(cmd, shell=True, stderr=subprocess.STDOUT, check=True)
|
|
||||||
|
|
||||||
def post_message(self, message, equipe="kaz", canal="creation-comptes"):
|
|
||||||
"""
|
|
||||||
Envoyer un message dans une Equipe/Canal de MM
|
|
||||||
"""
|
|
||||||
cmd = f"{mmctl} post create {equipe}:{canal} --message \"{message}\""
|
|
||||||
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
|
||||||
return output.decode()
|
|
||||||
|
|
||||||
|
|
||||||
def get_user(self, user):
|
|
||||||
"""
|
|
||||||
Le user existe t-il sur MM ?
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
cmd = f"{mmctl} user search {user} --json"
|
|
||||||
user_list_output = subprocess.check_output(cmd, shell=True)
|
|
||||||
return True # Le nom d'utilisateur existe
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def create_user(self, user, email, password):
|
|
||||||
"""
|
|
||||||
Créer un utilisateur sur MM
|
|
||||||
"""
|
|
||||||
cmd = f"{mmctl} user create --email {email} --username {user} --password {password}"
|
|
||||||
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
|
||||||
return output.decode()
|
|
||||||
|
|
||||||
|
|
||||||
def delete_user(self, email):
|
|
||||||
"""
|
|
||||||
Supprimer un utilisateur sur MM
|
|
||||||
"""
|
|
||||||
cmd = f"{mmctl} user delete {email} --confirm"
|
|
||||||
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
|
||||||
return output.decode()
|
|
||||||
|
|
||||||
|
|
||||||
def update_password(self, email, new_password):
|
|
||||||
"""
|
|
||||||
Changer un password pour un utilisateur de MM
|
|
||||||
"""
|
|
||||||
cmd = f"{mmctl} user change-password {email} --password {new_password}"
|
|
||||||
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
|
||||||
return output.decode()
|
|
||||||
|
|
||||||
|
|
||||||
def add_user_to_team(self, email, equipe):
|
|
||||||
"""
|
|
||||||
Affecte un utilisateur à une équipe MM
|
|
||||||
"""
|
|
||||||
cmd = f"{mmctl} team users add {equipe} {email}"
|
|
||||||
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
|
||||||
return output.decode()
|
|
||||||
|
|
||||||
|
|
||||||
def add_user_to_channel(self, email, equipe, canal):
|
|
||||||
"""
|
|
||||||
Affecte un utilisateur à un canal MM
|
|
||||||
"""
|
|
||||||
cmd = f'{mmctl} channel users add {equipe}:{canal} {email}'
|
|
||||||
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
|
||||||
return output.decode()
|
|
||||||
|
|
||||||
|
|
||||||
def get_teams(self):
|
|
||||||
"""
|
|
||||||
Lister les équipes sur MM
|
|
||||||
"""
|
|
||||||
cmd = f"{mmctl} team list --disable-pager"
|
|
||||||
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
|
||||||
data_list = output.decode("utf-8").strip().split('\n')
|
|
||||||
data_list.pop()
|
|
||||||
return data_list
|
|
||||||
|
|
||||||
|
|
||||||
def create_team(self, equipe, email):
|
|
||||||
"""
|
|
||||||
Créer une équipe sur MM et affecter un admin si email est renseigné (set admin marche pô)
|
|
||||||
"""
|
|
||||||
|
|
||||||
#DANGER: l'option --email ne rend pas le user admin de l'équipe comme c'est indiqué dans la doc :(
|
|
||||||
cmd = f"{mmctl} team create --name {equipe} --display-name {equipe} --private --email {email}"
|
|
||||||
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
|
||||||
|
|
||||||
#Workaround: on récup l'id du user et de l'équipe pour affecter le rôle "scheme_admin": true, "scheme_user": true avec l'api MM classique.
|
|
||||||
#TODO:
|
|
||||||
|
|
||||||
return output.decode()
|
|
||||||
|
|
||||||
|
|
||||||
def delete_team(self, equipe):
|
|
||||||
"""
|
|
||||||
Supprimer une équipe sur MM
|
|
||||||
"""
|
|
||||||
|
|
||||||
cmd = f"{mmctl} team delete {equipe} --confirm"
|
|
||||||
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
|
||||||
return output.decode()
|
|
||||||
|
|
@@ -1,134 +0,0 @@
|
|||||||
import re
|
|
||||||
import requests
|
|
||||||
|
|
||||||
from .config import getDockersConfig, getSecretConfig
|
|
||||||
|
|
||||||
paheko_ident = getDockersConfig("paheko_API_USER")
|
|
||||||
paheko_pass = getDockersConfig("paheko_API_PASSWORD")
|
|
||||||
paheko_auth = (paheko_ident, paheko_pass)
|
|
||||||
paheko_url = f"https://kaz-paheko.{getDockersConfig('domain')}"
|
|
||||||
|
|
||||||
class Paheko:
|
|
||||||
def get_categories(self):
|
|
||||||
"""
|
|
||||||
Récupérer les catégories Paheko avec le compteur associé
|
|
||||||
"""
|
|
||||||
api_url = paheko_url + '/api/user/categories'
|
|
||||||
|
|
||||||
response = requests.get(api_url, auth=paheko_auth)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
data = response.json()
|
|
||||||
return data
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_users_in_categorie(self,categorie):
|
|
||||||
"""
|
|
||||||
Afficher les membres d'une catégorie Paheko
|
|
||||||
"""
|
|
||||||
if not categorie.isdigit():
|
|
||||||
return 'Id de category non valide', 400
|
|
||||||
|
|
||||||
api_url = paheko_url + '/api/user/category/'+categorie+'.json'
|
|
||||||
|
|
||||||
response = requests.get(api_url, auth=paheko_auth)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
data = response.json()
|
|
||||||
return data
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_user(self,ident):
|
|
||||||
"""
|
|
||||||
Afficher un membre de Paheko par son email kaz ou son numéro ou le non court de l'orga
|
|
||||||
"""
|
|
||||||
|
|
||||||
emailmatchregexp = re.compile(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
|
|
||||||
|
|
||||||
if emailmatchregexp.match(ident):
|
|
||||||
data = { "sql": f"select * from users where email='{ident}' or alias = '{ident}'" }
|
|
||||||
api_url = paheko_url + '/api/sql/'
|
|
||||||
response = requests.post(api_url, auth=paheko_auth, data=data)
|
|
||||||
#TODO: if faut Rechercher count et vérifier que = 1 et supprimer le count=1 dans la réponse
|
|
||||||
elif ident.isdigit():
|
|
||||||
api_url = paheko_url + '/api/user/'+ident
|
|
||||||
response = requests.get(api_url, auth=paheko_auth)
|
|
||||||
else:
|
|
||||||
nomorga = re.sub(r'\W+', '', ident) # on vire les caractères non alphanumérique
|
|
||||||
data = { "sql": f"select * from users where admin_orga=1 and nom_orga='{nomorga}'" }
|
|
||||||
api_url = paheko_url + '/api/sql/'
|
|
||||||
response = requests.post(api_url, auth=paheko_auth, data=data)
|
|
||||||
#TODO:if faut Rechercher count et vérifier que = 1 et supprimer le count=1 dans la réponse
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
data = response.json()
|
|
||||||
if data["count"] == 1:
|
|
||||||
return data["results"][0]
|
|
||||||
elif data["count"] == 0:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return data["results"]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def set_user(self,ident,field,new_value):
|
|
||||||
"""
|
|
||||||
Modifie la valeur d'un champ d'un membre paheko (ident= numéro paheko ou email kaz)
|
|
||||||
"""
|
|
||||||
|
|
||||||
#récupérer le numero paheko si on fournit un email kaz
|
|
||||||
emailmatchregexp = re.compile(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
|
|
||||||
if emailmatchregexp.match(ident):
|
|
||||||
data = { "sql": f"select id from users where email='{ident}'" }
|
|
||||||
api_url = paheko_url + '/api/sql/'
|
|
||||||
response = requests.post(api_url, auth=paheko_auth, data=data)
|
|
||||||
if response.status_code == 200:
|
|
||||||
#on extrait l'id de la réponse
|
|
||||||
data = response.json()
|
|
||||||
if data['count'] == 0:
|
|
||||||
print("email non trouvé")
|
|
||||||
return None
|
|
||||||
elif data['count'] > 1:
|
|
||||||
print("trop de résultat")
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
#OK
|
|
||||||
ident = data['results'][0]['id']
|
|
||||||
else:
|
|
||||||
print("pas de résultat")
|
|
||||||
return None
|
|
||||||
elif not ident.isdigit():
|
|
||||||
print("Identifiant utilisateur invalide")
|
|
||||||
return None
|
|
||||||
|
|
||||||
regexp = re.compile("[^a-zA-Z0-9 \\r\\n\\t" + re.escape(string.punctuation) + "]")
|
|
||||||
valeur = regexp.sub('',new_value) # mouais, il faudrait être beaucoup plus précis ici en fonction des champs qu'on accepte...
|
|
||||||
|
|
||||||
champ = re.sub(r'\W+','',field) # pas de caractères non alphanumériques ici, dans l'idéal, c'est à choisir dans une liste plutot
|
|
||||||
|
|
||||||
api_url = paheko_url + '/api/user/'+str(ident)
|
|
||||||
payload = {champ: valeur}
|
|
||||||
response = requests.post(api_url, auth=paheko_auth, data=payload)
|
|
||||||
return response.json()
|
|
||||||
|
|
||||||
|
|
||||||
def get_users_with_action(self, action):
|
|
||||||
"""
|
|
||||||
retourne tous les membres de paheko avec une action à mener (création du compte kaz / modification...)
|
|
||||||
"""
|
|
||||||
|
|
||||||
api_url = paheko_url + '/api/sql/'
|
|
||||||
payload = { "sql": f"select * from users where action_auto='{action}'" }
|
|
||||||
response = requests.post(api_url, auth=paheko_auth, data=payload)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
return response.json()
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
@@ -1,40 +0,0 @@
|
|||||||
import subprocess
|
|
||||||
from email_validator import validate_email, EmailNotValidError
|
|
||||||
|
|
||||||
from .config import getDockersConfig, getSecretConfig
|
|
||||||
|
|
||||||
sympa_user = getSecretConfig("sympaServ", "SOAP_USER")
|
|
||||||
sympa_pass = getSecretConfig("sympaServ", "SOAP_PASSWORD")
|
|
||||||
sympa_listmaster = getSecretConfig("sympaServ", "ADMINEMAIL")
|
|
||||||
sympa_url = f"https://{getDockersConfig('sympaHost')}.{getDockersConfig('domain')}"
|
|
||||||
sympa_soap = "docker exec -i sympaServ /usr/lib/sympa/bin/sympa_soap_client.pl"
|
|
||||||
sympa_domain = getDockersConfig('domain_sympa')
|
|
||||||
sympa_liste_info = "infos"
|
|
||||||
|
|
||||||
|
|
||||||
# docker exec -i sympaServ /usr/lib/sympa/bin/sympa_soap_client.pl --soap_url=${httpProto}://${URL_LISTE}/sympasoap --trusted_application=${sympa_SOAP_USER} --trusted_application_password=${sympa_SOAP_PASSWORD} --proxy_vars=\"USER_EMAIL=${LISTMASTER}\" --service=add --service_parameters=\"${NL_LIST},${EMAIL_SOUHAITE}\"" | tee -a "${CMD_SYMPA}"
|
|
||||||
|
|
||||||
class Sympa:
|
|
||||||
|
|
||||||
def _execute_sympa_command(self, email, liste, service):
|
|
||||||
if validate_email(email) and validate_email(liste):
|
|
||||||
cmd = f'{sympa_soap} --soap_url={sympa_url}/sympasoap --trusted_application={sympa_user} --trusted_application_password={sympa_pass} --proxy_vars=USER_EMAIL={sympa_listmaster} --service={service} --service_parameters="{liste},{email}" && echo $?'
|
|
||||||
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
|
||||||
return output.decode()
|
|
||||||
|
|
||||||
def add_email_to_list(self, email, liste=sympa_liste_info):
|
|
||||||
"""
|
|
||||||
Ajouter un email dans une liste sympa
|
|
||||||
"""
|
|
||||||
output = self._execute_sympa_command(email, f"{liste}@{sympa_domain}", 'add')
|
|
||||||
return output
|
|
||||||
|
|
||||||
def delete_email_from_list(self, email, liste=sympa_liste_info):
|
|
||||||
"""
|
|
||||||
Supprimer un email dans une liste sympa
|
|
||||||
"""
|
|
||||||
output = self._execute_sympa_command(email, f"{liste}@{sympa_domain}", 'del')
|
|
||||||
return output
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -1,8 +0,0 @@
|
|||||||
import jinja2
|
|
||||||
|
|
||||||
templateLoader = jinja2.FileSystemLoader(searchpath="../templates")
|
|
||||||
templateEnv = jinja2.Environment(loader=templateLoader)
|
|
||||||
|
|
||||||
def render_template(filename, args):
|
|
||||||
template = templateEnv.get_template(filename)
|
|
||||||
return template.render(args)
|
|
213
bin/lib/user.py
213
bin/lib/user.py
@@ -1,213 +0,0 @@
|
|||||||
from email_validator import validate_email, EmailNotValidError
|
|
||||||
from glob import glob
|
|
||||||
import tempfile
|
|
||||||
import subprocess
|
|
||||||
import re
|
|
||||||
from email.mime.text import MIMEText
|
|
||||||
from email.mime.multipart import MIMEMultipart
|
|
||||||
import smtplib
|
|
||||||
|
|
||||||
from .paheko import Paheko
|
|
||||||
from .ldap import Ldap
|
|
||||||
from .mattermost import Mattermost
|
|
||||||
from .sympa import Sympa
|
|
||||||
from .template import render_template
|
|
||||||
from .config import getDockersConfig, getSecretConfig
|
|
||||||
|
|
||||||
DEFAULT_FILE = "/kaz/tmp/createUser.txt"
|
|
||||||
|
|
||||||
webmail_url = f"https://webmail.{getDockersConfig('domain')}"
|
|
||||||
mattermost_url = f"https://agora.{getDockersConfig('domain')}"
|
|
||||||
mdp_url = f"https://mdp.{getDockersConfig('domain')}"
|
|
||||||
sympa_url = f"https://listes.{getDockersConfig('domain')}"
|
|
||||||
site_url = f"https://{getDockersConfig('domain')}"
|
|
||||||
cloud_url = f"https://cloud.{getDockersConfig('domain')}"
|
|
||||||
|
|
||||||
|
|
||||||
def _generate_password(self):
|
|
||||||
cmd="apg -n 1 -m 10 -M NCL -d"
|
|
||||||
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
|
||||||
new_password="_"+output.decode("utf-8")+"_"
|
|
||||||
return new_password
|
|
||||||
|
|
||||||
|
|
||||||
def create_user(email, email_secours, admin_orga, nom_orga, quota_disque, nom, prenom, nc_orga, garradin_orga, wp_orga, agora_orga, wiki_orga, nc_base, groupe_nc_base, equipe_agora, password=None):
|
|
||||||
email = email.lower()
|
|
||||||
|
|
||||||
with Ldap() as ldap:
|
|
||||||
# est-il déjà dans le ldap ? (mail ou alias)
|
|
||||||
if ldap.get_email(email):
|
|
||||||
print(f"ERREUR 1: {email} déjà existant dans ldap. on arrête tout")
|
|
||||||
return None
|
|
||||||
|
|
||||||
#test nom orga
|
|
||||||
if admin_orga == 1:
|
|
||||||
if nom_orga is None:
|
|
||||||
print(f"ERREUR 0 sur paheko: {email} : nom_orga vide, on arrête tout")
|
|
||||||
return
|
|
||||||
if not bool(re.match(r'^[a-z0-9-]+$', nom_orga)):
|
|
||||||
print(f"ERREUR 0 sur paheko: {email} : nom_orga ({tab['nom_orga']}) incohérent (minuscule/chiffre/-), on arrête tout")
|
|
||||||
return
|
|
||||||
|
|
||||||
#test email_secours
|
|
||||||
email_secours = email_secours.lower()
|
|
||||||
if not validate_email(email_secours):
|
|
||||||
print("Mauvais email de secours")
|
|
||||||
return
|
|
||||||
|
|
||||||
#test quota
|
|
||||||
quota = quota_disque
|
|
||||||
if not quota.isdigit():
|
|
||||||
print(f"ERREUR 2: quota non numérique : {quota}, on arrête tout")
|
|
||||||
return
|
|
||||||
|
|
||||||
#on génère un password
|
|
||||||
password = password or _generate_password()
|
|
||||||
|
|
||||||
#on créé dans le ldap
|
|
||||||
#à quoi servent prenom/nom dans le ldap ?
|
|
||||||
data = {
|
|
||||||
"prenom": prenom,
|
|
||||||
"nom": nom,
|
|
||||||
"password": password,
|
|
||||||
"email_secours": email_secours,
|
|
||||||
"quota": quota
|
|
||||||
}
|
|
||||||
if not ldap.create_user(email, **data):
|
|
||||||
print("Erreur LDAP")
|
|
||||||
return
|
|
||||||
|
|
||||||
with Mattermost() as mm:
|
|
||||||
#on créé dans MM
|
|
||||||
user = email.split('@')[0]
|
|
||||||
mm.create_user(user, email, password)
|
|
||||||
mm.add_user_to_team(email, "kaz")
|
|
||||||
|
|
||||||
#et aux 2 canaux de base
|
|
||||||
mm.add_user_to_channel(email, "kaz", "une-question--un-soucis")
|
|
||||||
mm.add_user_to_channel(email, "kaz", "cafe-du-commerce--ouvert-2424h")
|
|
||||||
|
|
||||||
#on créé une nouvelle équipe ds MM si besoin
|
|
||||||
if admin_orga == 1:
|
|
||||||
mm.create_team(nom_orga, email)
|
|
||||||
#BUG: créer la nouvelle équipe n'a pas rendu l'email admin, on le rajoute comme membre simple
|
|
||||||
mm.add_user_to_team(email, nom_orga)
|
|
||||||
|
|
||||||
|
|
||||||
#on inscrit email et email_secours à la nl sympa_liste_info
|
|
||||||
sympa = Sympa()
|
|
||||||
sympa.add_email_to_list(email)
|
|
||||||
sympa.add_email_to_list(email_secours)
|
|
||||||
|
|
||||||
#on construit/envoie le mail
|
|
||||||
context = {
|
|
||||||
'ADMIN_ORGA': admin_orga,
|
|
||||||
'NOM': f"{prenom} {nom}",
|
|
||||||
'EMAIL_SOUHAITE': email,
|
|
||||||
'PASSWORD': password,
|
|
||||||
'QUOTA': quota_disque,
|
|
||||||
'URL_WEBMAIL': webmail_url,
|
|
||||||
'URL_AGORA': mattermost_url,
|
|
||||||
'URL_MDP': mdp_url,
|
|
||||||
'URL_LISTE': sympa_url,
|
|
||||||
'URL_SITE': site_url,
|
|
||||||
'URL_CLOUD': cloud_url,
|
|
||||||
}
|
|
||||||
|
|
||||||
html = render_template("email_inscription.html", context)
|
|
||||||
raw = render_template("email_inscription.txt", context)
|
|
||||||
|
|
||||||
message = MIMEMultipart()
|
|
||||||
message["Subject"] = "KAZ: confirmation d'inscription !"
|
|
||||||
message["From"] = f"contact@{getDockersConfig('domain')}"
|
|
||||||
message["To"] = f"{email}, {email_secours}"
|
|
||||||
message.attach(MIMEText(raw, "plain"))
|
|
||||||
message.attach(MIMEText(html, "html"))
|
|
||||||
|
|
||||||
with smtplib.SMTP(f"mail.{getDockersConfig('domain')}", 25) as server:
|
|
||||||
server.sendmail(f"contact@{getDockersConfig('domain')}", [email,email_secours], message.as_string())
|
|
||||||
|
|
||||||
#on met le flag paheko action à Aucune
|
|
||||||
paheko = Paheko()
|
|
||||||
try:
|
|
||||||
paheko.set_user(email, "action_auto", "Aucune")
|
|
||||||
except:
|
|
||||||
print(f"Erreur paheko pour remettre action_auto = Aucune pour {email}")
|
|
||||||
|
|
||||||
#on post sur MM pour dire ok
|
|
||||||
with Mattermost() as mm:
|
|
||||||
msg=f"**POST AUTO** Inscription réussie pour {email} avec le secours {email_secours} Bisou!"
|
|
||||||
mm.post_message(message=msg)
|
|
||||||
|
|
||||||
|
|
||||||
def create_waiting_users():
|
|
||||||
"""
|
|
||||||
Créé les kaznautes en attente: inscription sur MM / Cloud / email + msg sur MM + email à partir de action="a créer" sur paheko
|
|
||||||
"""
|
|
||||||
#verrou pour empêcher de lancer en même temps la même api
|
|
||||||
prefixe="create_user_lock_"
|
|
||||||
if glob(f"{tempfile.gettempdir()}/{prefixe}*"):
|
|
||||||
print("Lock présent")
|
|
||||||
return None
|
|
||||||
lock_file = tempfile.NamedTemporaryFile(prefix=prefixe,delete=True)
|
|
||||||
|
|
||||||
#qui sont les kaznautes à créer ?
|
|
||||||
paheko = Paheko()
|
|
||||||
liste_kaznautes = paheko.get_users_with_action("A créer")
|
|
||||||
|
|
||||||
if liste_kaznautes:
|
|
||||||
count=liste_kaznautes['count']
|
|
||||||
if count==0:
|
|
||||||
print("aucun nouveau kaznaute à créer")
|
|
||||||
return
|
|
||||||
|
|
||||||
#au moins un kaznaute à créer
|
|
||||||
for tab in liste_kaznautes['results']:
|
|
||||||
create_user(**tab)
|
|
||||||
|
|
||||||
print("fin des inscriptions")
|
|
||||||
|
|
||||||
|
|
||||||
def create_users_from_file(file=DEFAULT_FILE):
|
|
||||||
"""
|
|
||||||
Créé les kaznautes en attente: inscription sur MM / Cloud / email + msg sur MM + email à partir du ficher
|
|
||||||
"""
|
|
||||||
#verrou pour empêcher de lancer en même temps la même api
|
|
||||||
prefixe="create_user_lock_"
|
|
||||||
if glob(f"{tempfile.gettempdir()}/{prefixe}*"):
|
|
||||||
print("Lock présent")
|
|
||||||
return None
|
|
||||||
lock_file = tempfile.NamedTemporaryFile(prefix=prefixe,delete=True)
|
|
||||||
|
|
||||||
#qui sont les kaznautes à créer ?
|
|
||||||
liste_kaznautes = []
|
|
||||||
with open(file) as lines:
|
|
||||||
for line in lines:
|
|
||||||
line = line.strip()
|
|
||||||
if not line.startswith("#") and line != "":
|
|
||||||
user_data = line.split(';')
|
|
||||||
user_dict = {
|
|
||||||
"nom": user_data[0],
|
|
||||||
"prenom": user_data[1],
|
|
||||||
"email": user_data[2],
|
|
||||||
"email_secours": user_data[3],
|
|
||||||
"nom_orga": user_data[4],
|
|
||||||
"admin_orga": user_data[5],
|
|
||||||
"nc_orga": user_data[6],
|
|
||||||
"garradin_orga": user_data[7],
|
|
||||||
"wp_orga": user_data[8],
|
|
||||||
"agora_orga": user_data[9],
|
|
||||||
"wiki_orga": user_data[10],
|
|
||||||
"nc_base": user_data[11],
|
|
||||||
"groupe_nc_base": user_data[12],
|
|
||||||
"equipe_agora": user_data[13],
|
|
||||||
"quota_disque": user_data[14],
|
|
||||||
"password": user_data[15],
|
|
||||||
}
|
|
||||||
liste_kaznautes.append(user_dict)
|
|
||||||
|
|
||||||
if liste_kaznautes:
|
|
||||||
for tab in liste_kaznautes:
|
|
||||||
create_user(**tab)
|
|
||||||
|
|
||||||
print("fin des inscriptions")
|
|
@@ -1,82 +0,0 @@
|
|||||||
body {
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.email-content {
|
|
||||||
background-color: #f0f0f0; /* Light gray background */
|
|
||||||
margin: 20px auto;
|
|
||||||
padding: 20px;
|
|
||||||
border: 1px solid #dddddd;
|
|
||||||
max-width: 600px;
|
|
||||||
width: 90%; /* This makes the content take 90% width of its container */
|
|
||||||
text-align: left; /* Remove text justification */
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
background-color: #E16969;
|
|
||||||
color: white;
|
|
||||||
text-align: center;
|
|
||||||
height: 50px; /* Fixed height for header */
|
|
||||||
line-height: 50px; /* Vertically center the text */
|
|
||||||
width: 100%; /* Make header full width */
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
background-color: #E16969;
|
|
||||||
color: white;
|
|
||||||
text-align: center;
|
|
||||||
height: 50px; /* Fixed height for footer */
|
|
||||||
line-height: 50px; /* Vertically center the text */
|
|
||||||
width: 100%; /* Make footer full width */
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-container {
|
|
||||||
position: relative; /* Pour positionner le logo et le texte dans le header */
|
|
||||||
height: 50px; /* Hauteur maximale du header */
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
position: absolute; /* Pour positionner le logo */
|
|
||||||
max-height: 100%; /* Taille maximale du logo égale à la hauteur du header */
|
|
||||||
top: 0; /* Aligner le logo en haut */
|
|
||||||
left: 0; /* Aligner le logo à gauche */
|
|
||||||
margin-right: 10px; /* Marge à droite du logo */
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-container h1, .footer-container p {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-container p {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-container a {
|
|
||||||
color: #FFFFFF; /* White color for links in footer */
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-container a:hover {
|
|
||||||
text-decoration: underline; /* Optional: add underline on hover */
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #E16969; /* Same color as header/footer background for all other links */
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
text-decoration: underline; /* Optional: add underline on hover */
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
color: #E16969;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
@@ -1,9 +0,0 @@
|
|||||||
<footer>
|
|
||||||
<div class="footer-container">
|
|
||||||
<p>
|
|
||||||
Ici, on prend soin de vos données et on ne les vend pas !
|
|
||||||
<br>
|
|
||||||
<a href="https://kaz.bzh">https://kaz.bzh</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
@@ -1,6 +0,0 @@
|
|||||||
<header>
|
|
||||||
<div class="header-container">
|
|
||||||
<img class="logo" src="https://kaz-cloud.kaz.bzh/apps/theming/image/logo?v=33" alt="KAZ Logo">
|
|
||||||
<h1>Kaz : Le numérique sobre, libre, éthique et local</h1>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
@@ -1,94 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Email d'inscription'</title>
|
|
||||||
<style>
|
|
||||||
{% include 'email.css' %}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
{% include 'email_header.html' %}
|
|
||||||
|
|
||||||
<div class="email-content">
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Bonjour {{NOM}}!<br><br>
|
|
||||||
|
|
||||||
Bienvenue chez KAZ!<br><br>
|
|
||||||
|
|
||||||
Vous disposez de :
|
|
||||||
<ul>
|
|
||||||
<li>une messagerie classique : <a href={{URL_WEBMAIL}}>{{URL_WEBMAIL}}</a></li>
|
|
||||||
<li>une messagerie instantanée pour discuter au sein d'équipes : <a href={{URL_AGORA}}>{{URL_AGORA}}</a></li>
|
|
||||||
</ul>
|
|
||||||
Votre email et identifiant pour ces services : {{EMAIL_SOUHAITE}}<br>
|
|
||||||
Le mot de passe : <b>{{PASSWORD}}</b><br><br>
|
|
||||||
|
|
||||||
Pour changer votre mot de passe de messagerie, c'est ici: <a href={{URL_MDP}}>{{URL_MDP}}</a><br>
|
|
||||||
Si vous avez perdu votre mot de passe, c'est ici: <a href={{URL_MDP}}/?action=sendtoken>{{URL_MDP}}/?action=sendtoken</a><br><br>
|
|
||||||
|
|
||||||
Vous pouvez accéder à votre messagerie classique:
|
|
||||||
<ul>
|
|
||||||
<li>soit depuis votre webmail : <a href={{URL_WEBMAIL}}>{{URL_WEBMAIL}}</a></li>
|
|
||||||
<li>soit depuis votre bureau virtuel : <a href={{URL_CLOUD}}>{{URL_CLOUD}}</a></li>
|
|
||||||
<li>soit depuis un client de messagerie comme thunderbird<br>
|
|
||||||
</ul>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{% if ADMIN_ORGA == '1' %}
|
|
||||||
<p>
|
|
||||||
En tant qu'association/famille/société. Vous avez la possibilité d'ouvrir, quand vous le voulez, des services kaz, il vous suffit de nous le demander.<br><br>
|
|
||||||
|
|
||||||
Pourquoi n'ouvrons-nous pas tous les services tout de suite ? parce que nous aimons la sobriété et que nous préservons notre espace disque ;)<br>
|
|
||||||
A quoi sert d'avoir un site web si on ne l'utilise pas, n'est-ce pas ?<br><br>
|
|
||||||
|
|
||||||
Par retour de mail, dites-nous de quoi vous avez besoin tout de suite entre:
|
|
||||||
<ul>
|
|
||||||
<li>une comptabilité : un service de gestion adhérents/clients</li>
|
|
||||||
<li>un site web de type WordPress</li>
|
|
||||||
<li>un cloud : bureau virtuel pour stocker des fichiers/calendriers/contacts et partager avec vos connaissances</li>
|
|
||||||
</ul>
|
|
||||||
Une fois que vous aurez répondu à ce mail, votre demande sera traitée manuellement.
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Vous avez quelques docs intéressantes sur le wiki de kaz:
|
|
||||||
<ul>
|
|
||||||
<li>Migrer son site internet wordpress vers kaz : <a href="https://wiki.kaz.bzh/wordpress/start#migrer_son_site_wordpress_vers_kaz">https://wiki.kaz.bzh/wordpress/start#migrer_son_site_wordpress_vers_kaz</a></li>
|
|
||||||
<li>Migrer sa messagerie vers kaz : <a href="https://wiki.kaz.bzh/messagerie/gmail/start">https://wiki.kaz.bzh/messagerie/gmail/start</a></li>
|
|
||||||
<li>Démarrer simplement avec son cloud : <a href="https://wiki.kaz.bzh/nextcloud/start">https://wiki.kaz.bzh/messagerie/gmail/start</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Votre quota est de {{QUOTA}}GB. Si vous souhaitez plus de place pour vos fichiers ou la messagerie, faites-nous signe !<br><br>
|
|
||||||
|
|
||||||
Pour accéder à la messagerie instantanée et communiquer avec les membres de votre équipe ou ceux de kaz : <a href={{URL_AGORA}}/login>{{URL_AGORA}}/login</a><br>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{% if ADMIN_ORGA == '1' %}
|
|
||||||
<p>
|
|
||||||
Comme administrateur de votre organisation, vous pouvez créer des listes de diffusion en vous rendant sur <a href={{URL_LISTE}}>{{URL_LISTE}}</a><br>
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Enfin, vous disposez de tous les autres services KAZ où l'authentification n'est pas nécessaire : <a href={{URL_SITE}}>{{URL_SITE}}</a><br><br>
|
|
||||||
|
|
||||||
En cas de soucis, n'hésitez pas à poser vos questions sur le canal 'Une question ? un soucis' de l'agora dispo ici : <a href={{URL_AGORA}}>{{URL_AGORA}}</a><br><br>
|
|
||||||
|
|
||||||
Si vous avez besoin d'accompagnement pour votre site, votre cloud, votre compta, votre migration de messagerie,...<br>nous proposons des formations mensuelles gratuites. Si vous souhaitez être accompagné par un professionnel, nous pouvons vous donner une liste de pros, référencés par KAZ.<br><br>
|
|
||||||
|
|
||||||
À bientôt 😉<br><br>
|
|
||||||
|
|
||||||
La collégiale de KAZ.<br>
|
|
||||||
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div> <!-- <div class="email-content"> -->
|
|
||||||
|
|
||||||
{% include 'email_footer.html' %}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -1,70 +0,0 @@
|
|||||||
Bonjour {{NOM}}!
|
|
||||||
|
|
||||||
Bienvenue chez KAZ!<br><br>
|
|
||||||
|
|
||||||
Vous disposez de :
|
|
||||||
<ul>
|
|
||||||
<li>une messagerie classique : <a href={{URL_WEBMAIL}}>{{URL_WEBMAIL}}</a></li>
|
|
||||||
<li>une messagerie instantanée pour discuter au sein d'équipes : <a href={{URL_AGORA}}>{{URL_AGORA}}</a></li>
|
|
||||||
</ul>
|
|
||||||
Votre email et identifiant pour ces services : {{EMAIL_SOUHAITE}}<br>
|
|
||||||
Le mot de passe : <b>{{PASSWORD}}</b><br><br>
|
|
||||||
|
|
||||||
Pour changer votre mot de passe de messagerie, c'est ici: <a href={{URL_MDP}}>{{URL_MDP}}</a><br>
|
|
||||||
Si vous avez perdu votre mot de passe, c'est ici: <a href={{URL_MDP}}/?action=sendtoken>{{URL_MDP}}/?action=sendtoken</a><br><br>
|
|
||||||
|
|
||||||
Vous pouvez accéder à votre messagerie classique:
|
|
||||||
<ul>
|
|
||||||
<li>soit depuis votre webmail : <a href={{URL_WEBMAIL}}>{{URL_WEBMAIL}}</a></li>
|
|
||||||
<li>soit depuis votre bureau virtuel : <a href={{URL_CLOUD}}>{{URL_CLOUD}}</a></li>
|
|
||||||
<li>soit depuis un client de messagerie comme thunderbird<br>
|
|
||||||
</ul>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{% if ADMIN_ORGA == '1' %}
|
|
||||||
<p>
|
|
||||||
En tant qu'association/famille/société. Vous avez la possibilité d'ouvrir, quand vous le voulez, des services kaz, il vous suffit de nous le demander.<br><br>
|
|
||||||
|
|
||||||
Pourquoi n'ouvrons-nous pas tous les services tout de suite ? parce que nous aimons la sobriété et que nous préservons notre espace disque ;)<br>
|
|
||||||
A quoi sert d'avoir un site web si on ne l'utilise pas, n'est-ce pas ?<br><br>
|
|
||||||
|
|
||||||
Par retour de mail, dites-nous de quoi vous avez besoin tout de suite entre:
|
|
||||||
<ul>
|
|
||||||
<li>une comptabilité : un service de gestion adhérents/clients</li>
|
|
||||||
<li>un site web de type WordPress</li>
|
|
||||||
<li>un cloud : bureau virtuel pour stocker des fichiers/calendriers/contacts et partager avec vos connaissances</li>
|
|
||||||
</ul>
|
|
||||||
Une fois que vous aurez répondu à ce mail, votre demande sera traitée manuellement.
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Vous avez quelques docs intéressantes sur le wiki de kaz:
|
|
||||||
<ul>
|
|
||||||
<li>Migrer son site internet wordpress vers kaz : <a href="https://wiki.kaz.bzh/wordpress/start#migrer_son_site_wordpress_vers_kaz">https://wiki.kaz.bzh/wordpress/start#migrer_son_site_wordpress_vers_kaz</a></li>
|
|
||||||
<li>Migrer sa messagerie vers kaz : <a href="https://wiki.kaz.bzh/messagerie/gmail/start">https://wiki.kaz.bzh/messagerie/gmail/start</a></li>
|
|
||||||
<li>Démarrer simplement avec son cloud : <a href="https://wiki.kaz.bzh/nextcloud/start">https://wiki.kaz.bzh/messagerie/gmail/start</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Votre quota est de {{QUOTA}}GB. Si vous souhaitez plus de place pour vos fichiers ou la messagerie, faites-nous signe !<br><br>
|
|
||||||
|
|
||||||
Pour accéder à la messagerie instantanée et communiquer avec les membres de votre équipe ou ceux de kaz : <a href={{URL_AGORA}}/login>{{URL_AGORA}}/login</a><br>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{% if ADMIN_ORGA == '1' %}
|
|
||||||
<p>
|
|
||||||
Comme administrateur de votre organisation, vous pouvez créer des listes de diffusion en vous rendant sur <a href={{URL_LISTE}}>{{URL_LISTE}}</a><br>
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Enfin, vous disposez de tous les autres services KAZ où l'authentification n'est pas nécessaire : <a href={{URL_SITE}}>{{URL_SITE}}</a><br><br>
|
|
||||||
|
|
||||||
En cas de soucis, n'hésitez pas à poser vos questions sur le canal 'Une question ? un soucis' de l'agora dispo ici : <a href={{URL_AGORA}}>{{URL_AGORA}}</a><br><br>
|
|
||||||
|
|
||||||
Si vous avez besoin d'accompagnement pour votre site, votre cloud, votre compta, votre migration de messagerie,...<br>nous proposons des formations mensuelles gratuites. Si vous souhaitez être accompagné par un professionnel, nous pouvons vous donner une liste de pros, référencés par KAZ.<br><br>
|
|
||||||
|
|
||||||
À bientôt 😉<br><br>
|
|
||||||
|
|
||||||
La collégiale de KAZ.<br>
|
|
||||||
|
|
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: roundcube/roundcubemail:1.6.9-apache
|
image: roundcube/roundcubemail
|
||||||
container_name: ${roundcubeServName}
|
container_name: ${roundcubeServName}
|
||||||
restart: ${restartPolicy}
|
restart: ${restartPolicy}
|
||||||
depends_on:
|
depends_on:
|
||||||
|
@@ -226,13 +226,13 @@ networks:
|
|||||||
}}
|
}}
|
||||||
{{peertube
|
{{peertube
|
||||||
peertubeNet:
|
peertubeNet:
|
||||||
external:true
|
external: true
|
||||||
name:peertubeNet
|
name: peertubeNet
|
||||||
}}
|
}}
|
||||||
{{spip
|
{{spip
|
||||||
spipNet:
|
spipNet:
|
||||||
external:true
|
external: true
|
||||||
name:spipNet
|
name: spipNet
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -147,8 +147,8 @@ sympa_MYSQL_DATABASE="sympa"
|
|||||||
sympa_MYSQL_USER="sympa"
|
sympa_MYSQL_USER="sympa"
|
||||||
sympa_MYSQL_PASSWORD="--clean_val--"
|
sympa_MYSQL_PASSWORD="--clean_val--"
|
||||||
|
|
||||||
sympa_KEY="/etc/letsencrypt/live/${domain}/privkey.pem"
|
sympa_KEY="/etc/ssl/private/listes.key"
|
||||||
sympa_CERT="/etc/letsencrypt/live/${domain}/fullchain.pem"
|
sympa_CERT="/etc/ssl/certs/listes.pem"
|
||||||
sympa_LISTMASTERS="listmaster@${domain_sympa}"
|
sympa_LISTMASTERS="listmaster@${domain_sympa}"
|
||||||
sympa_ADMINEMAIL="listmaster@${domain_sympa}"
|
sympa_ADMINEMAIL="listmaster@${domain_sympa}"
|
||||||
sympa_SOAP_USER="sympa"
|
sympa_SOAP_USER="sympa"
|
||||||
|
Reference in New Issue
Block a user