first commit symfony 6

This commit is contained in:
Arnaud Fornerot 2022-07-25 17:16:08 +02:00
parent 2bba3d5695
commit 8181ca1c39
53 changed files with 754 additions and 116 deletions

6
.env
View File

@ -58,6 +58,8 @@ LDAP_GROUPMEMBER=memberuid # Attribut stockant les membres d'un groupe
LDAP_GROUPMEMBERISDN=0 # LDAP_GROUPMEMBER stocke un uid ou un dn ? 0/1
LDAP_FILTERGROUP=(cn=*) # requete ldap pour rechercher les groupes
LDAP_FILTERUSER=(uid=*) # requete ldap pour rechercher les users
LDAP_AUTOSUBMIT=1 # if APP_AUTH = LDAP autocréer les users non existant
LDAP_AUTOUPDATE=1 # if APP_AUTH = LDAP automodifier les users existant
# If APP_AUTH = CAS
CAS_HOST=
@ -70,6 +72,8 @@ CAS_FIRSTNAME=firstname
CAS_AVATAR=
CAS_NIVEAU01=
CAS_GROUP=
CAS_AUTOSUBMIT=1 # if APP_AUTH = CAS autocréer les users non existant
CAS_AUTOUPDATE=1 # if APP_AUTH = CAS automodifier les users existant
# If APP_AUTH = OPENID
OAUTH_CLIENTID=
@ -85,6 +89,8 @@ OAUTH_FIRSTNAME=firstname
OAUTH_AVATAR=
OAUTH_NIVEAU01=
OAUTH_GROUP=
OAUTH_AUTOSUBMIT=1 # if APP_AUTH = OPENID autocréer les users non existant
OAUTH_AUTOUPDATE=1 # if APP_AUTH = OPENID automodifier les users existant
# IF APP_SYNCHRO=NINE2NINE
NINE_URL=

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"esbonio.sphinx.confDir": ""
}

View File

@ -2,6 +2,7 @@ $(document).ready(function() {
$.extend( $.fn.dataTable.defaults, {
responsive: true,
"iDisplayLength": 1000,
"scrollX": true,
"oLanguage": {
"sThousands": " ",
"sProcessing": "Traitement en cours...",

View File

@ -20,6 +20,11 @@ body {
background-color: var(--colorbgbodydark);
}
.table,
.table-hover > tbody > tr:hover > *,
.table-striped > tbody > tr:nth-of-type(odd) > * {
color: var(--colorftbodylight);
}
/* FONT */
body {
@ -28,6 +33,7 @@ body {
h1, h2, h3, .navbar-brand, .card-header, .modal-header h4, .widgetheader .title {
font-family: var(--fonttitle);
color: var(--colorfttitlelight);
}
h1 { font-size: var(--fontsizeh1); }

View File

@ -46,16 +46,27 @@ app_logout:
app_redirect:
path: /user/redirect/{route}/{id}
controller: App\Controller\SecurityController:Security::redirecturl
controller: App\Controller\SecurityController::redirecturl
defaults: { access: user }
app_noperm:
path: /noperm
controller: App\Controller\SecurityController::noperm
#== Websocket====================================================================================================
#-- Access user
app_publish_sample:
path: /user/publish/sample/{id}
controller: App\Controller\PublishController::sample
defaults: { access: user }
app_publish:
path: /user/publish/{channel}/{id}
controller: App\Controller\PublishController::publish
defaults: { access: user }
#== Config ======================================================================================================
#-- Access admin
app_admin_config:
@ -88,6 +99,19 @@ app_admin_config_logo:
controller: App\Controller\ConfigController::logo
defaults: { access: admin }
#== Theme ================================================================================================================
#-- Access admin
app_admin_theme:
path: /admin/theme
controller: App\Controller\ThemeController::list
defaults: { access: admin }
app_admin_theme_select:
path: /admin/theme/select/{name}
controller: App\Controller\ThemeController::select
defaults: { name: "", access: admin }
#== API ==================================================================================================================
#-- Access visiteur
app_rest:

View File

@ -51,6 +51,8 @@ parameters:
ldapGroupmemberisdn: '%env(resolve:LDAP_GROUPMEMBERISDN)%'
ldapFiltergroup: '%env(resolve:LDAP_FILTERGROUP)%'
ldapFilteruser: '%env(resolve:LDAP_FILTERUSER)%'
ldapAutosubmit: '%env(resolve:LDAP_AUTOSUBMIT)%'
ldapAutoupdate: '%env(resolve:LDAP_AUTOUPDATE)%'
casHost: '%env(resolve:CAS_HOST)%'
casPort: '%env(resolve:CAS_PORT)%'
@ -62,6 +64,8 @@ parameters:
casAvatar: '%env(resolve:CAS_AVATAR)%'
casNiveau01: '%env(resolve:CAS_NIVEAU01)%'
casGroup: '%env(resolve:CAS_GROUP)%'
casAutosubmit: '%env(resolve:CAS_AUTOSUBMIT)%'
casAutoupdate: '%env(resolve:CAS_AUTOUPDATE)%'
oauthClientid: '%env(resolve:OAUTH_CLIENTID)%'
oauthClientsecret: '%env(resolve:OAUTH_CLIENTSECRET)%'
@ -76,6 +80,8 @@ parameters:
oauthAvatar: '%env(resolve:OAUTH_AVATAR)%'
oauthNiveau01: '%env(resolve:OAUTH_NIVEAU01)%'
oauthGroup: '%env(resolve:OAUTH_GROUP)%'
oauthAutosubmit: '%env(resolve:OAUTH_AUTOSUBMIT)%'
oauthAutoupdate: '%env(resolve:OAUTH_AUTOUPDATE)%'
nineUrl: '%env(resolve:NINE_URL)%'
nineSecret: '%env(resolve:NINE_SECRET)%'

BIN
public/themes/look.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
public/themes/look.xcf Normal file

Binary file not shown.

View File

@ -0,0 +1,3 @@
name: Nineblue
author: Arnaud Fornerot
version: 1.0

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,47 @@
:root{
--colorbgbodydark: #038aff;
--colorfttitlelight: #038aff;
--colorbgbodydark-darker: #082169;
--colorfttitlelight-darker: #082169;
--colorbgbodydark-rgb: 58,83,155;
/* Vous pouvez forcer l'ensemble de ces variables ou laisser la valeur par défaut
--colorbgbodylight: #;
--colorbgbodydark: #;
--colorfttitlelight: #;
--colorfttitledark: #;
--colorftbodylight: #;
--colorftbodydark: #;
--fontbody: "";
--fonttitle: "";
--fontsizeh1: px;
--fontsizeh2: px;
--fontsizeh3: px;
--fontsizeh4: px;
--colorbgbodylight-darker: #;
--colorfttitlelight-darker: #;
--colorbgbodydark-darker: #;
--colorbgbodydark-rgb: R,V,G
*/
}
/* Puis sur classer l'ensemble de la feuille de style */

View File

@ -0,0 +1,3 @@
name: Ninedark
author: Arnaud Fornerot
version: 1.0

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -0,0 +1,48 @@
:root{
--colorbgbodydark: #2e3131;
--colorfttitlelight: #2e3131;
--colorfttitlelight-darker: #95a5a6;
--colorbgbodydark-darker: #000000;
--colorfttitlelight-darker: #000000;
--colorbgbodydark-rgb: 46,49,49;
/* Vous pouvez forcer l'ensemble de ces variables ou laisser la valeur par défaut
--colorbgbodylight: #;
--colorbgbodydark: #;
--colorfttitlelight: #;
--colorfttitledark: #;
--colorftbodylight: #;
--colorftbodydark: #;
--fontbody: "";
--fonttitle: "";
--fontsizeh1: px;
--fontsizeh2: px;
--fontsizeh3: px;
--fontsizeh4: px;
--colorbgbodylight-darker: #;
--colorfttitlelight-darker: #;
--colorbgbodydark-darker: #;
--colorbgbodydark-rgb: R,V,G
*/
}
/* Puis sur classer l'ensemble de la feuille de style */

View File

@ -0,0 +1,3 @@
name: Ninefulldark
author: Arnaud Fornerot
version: 1.0

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,73 @@
:root{
--colorbgbodydark: #2e3131;
--colorbgbodylight: #2e3131;
--colorfttitledark: #ffffff;
--colorfttitlelight: #ffffff;
--colorftbodylight: #ffffff;
--colorfttitlelight: #ffffff;
--colorfttitledark-darker: #95a5a6;
--colorfttitlelight-darker: #95a5a6;
--colorbgbodydark-rgb: 46,49,49;
/* Vous pouvez forcer l'ensemble de ces variables ou laisser la valeur par défaut
--colorbgbodylight: #;
--colorbgbodydark: #;
--colorfttitlelight: #;
--colorfttitledark: #;
--colorftbodylight: #;
--colorftbodydark: #;
--fontbody: "";
--fonttitle: "";
--fontsizeh1: px;
--fontsizeh2: px;
--fontsizeh3: px;
--fontsizeh4: px;
--colorbgbodylight-darker: #;
--colorfttitlelight-darker: #;
--colorbgbodydark-darker: #;
--colorbgbodydark-rgb: R,V,G
*/
}
/* Puis sur classer l'ensemble de la feuille de style */
.modal-content {
background-color: var(--colorbgbodydark);
}
.card-header {
color: var(--colorbgbodydark);
}
.card-body {
color: var(--colorbgbodydark);
}
.card-body .table,
.card-body .table-hover > tbody > tr:hover > *,
.card-body .table-striped > tbody > tr:nth-of-type(odd) > * {
color: var(--colorbgbodydark);
}
.card-body .table a {
color: var(--colorbgbodydark);
}
.card-body .table a:hover {
color: var(--colorfttitlelight-darker);
}

View File

@ -0,0 +1,3 @@
name: Ninegray
author: Arnaud Fornerot
version: 1.0

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -0,0 +1,47 @@
:root{
--colorbgbodydark: #6c7a89;
--colorfttitlelight: #6c7a89;
--colorbgbodydark-darker: #3a4857;
--colorfttitlelight-darker: #3a4857;
--colorbgbodydark-rgb: 108,122,137;
/* Vous pouvez forcer l'ensemble de ces variables ou laisser la valeur par défaut
--colorbgbodylight: #;
--colorbgbodydark: #;
--colorfttitlelight: #;
--colorfttitledark: #;
--colorftbodylight: #;
--colorftbodydark: #;
--fontbody: "";
--fonttitle: "";
--fontsizeh1: px;
--fontsizeh2: px;
--fontsizeh3: px;
--fontsizeh4: px;
--colorbgbodylight-darker: #;
--colorfttitlelight-darker: #;
--colorbgbodydark-darker: #;
--colorbgbodydark-rgb: R,V,G
*/
}
/* Puis sur classer l'ensemble de la feuille de style */

View File

@ -0,0 +1,3 @@
name: Ninegreen
author: Arnaud Fornerot
version: 1.0

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,43 @@
:root{
--colorfttitlelight: #1e824c;
--colorbgbodydark: #1e824c;
--colorbgbodydark-darker: #00501a;
--colorfttitlelight-darker: #00501a;
--colorbgbodydark-rgb: 30,130,76;
/* Vous pouvez forcer l'ensemble de ces variables ou laisser la valeur par défaut
--colorbgbodylight: #;
--colorbgbodydark: #;
--colorfttitlelight: #;
--colorfttitledark: #;
--colorftbodylight: #;
--colorftbodydark: #;
--fontbody: "";
--fonttitle: "";
--fontsizeh1: px;
--fontsizeh2: px;
--fontsizeh3: px;
--fontsizeh4: px;
--colorbgbodylight-darker: #;
--colorfttitlelight-darker: #;
--colorbgbodydark-darker: #;
--colorbgbodydark-rgb: R,V,G
*/
}
/* Puis sur classer l'ensemble de la feuille de style */

View File

@ -0,0 +1,3 @@
name: Nineorange
author: Arnaud Fornerot
version: 1.0

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -0,0 +1,47 @@
:root{
--colorbgbodydark: #f15a22;
--colorfttitlelight: #f15a22;
--colorbgbodydark-darker: #bf2800;
--colorfttitlelight-darker: #bf2800;
--colorbgbodydark-rgb: 241,90,34;
/* Vous pouvez forcer l'ensemble de ces variables ou laisser la valeur par défaut
--colorbgbodylight: #;
--colorbgbodydark: #;
--colorfttitlelight: #;
--colorfttitledark: #;
--colorftbodylight: #;
--colorftbodydark: #;
--fontbody: "";
--fonttitle: "";
--fontsizeh1: px;
--fontsizeh2: px;
--fontsizeh3: px;
--fontsizeh4: px;
--colorbgbodylight-darker: #;
--colorfttitlelight-darker: #;
--colorbgbodydark-darker: #;
--colorbgbodydark-rgb: R,V,G
*/
}
/* Puis sur classer l'ensemble de la feuille de style */

View File

@ -0,0 +1,3 @@
name: Ninered
author: Arnaud Fornerot
version: 1.0

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -0,0 +1,47 @@
:root{
--colorbgbodydark: #96281b;
--colorfttitlelight: #96281b;
--colorbgbodydark-darker: #640000;
--colorfttitlelight-darker: #640000;
--colorbgbodydark-rgb: 150,40,27;
/* Vous pouvez forcer l'ensemble de ces variables ou laisser la valeur par défaut
--colorbgbodylight: #;
--colorbgbodydark: #;
--colorfttitlelight: #;
--colorfttitledark: #;
--colorftbodylight: #;
--colorftbodydark: #;
--fontbody: "";
--fonttitle: "";
--fontsizeh1: px;
--fontsizeh2: px;
--fontsizeh3: px;
--fontsizeh4: px;
--colorbgbodylight-darker: #;
--colorfttitlelight-darker: #;
--colorbgbodydark-darker: #;
--colorbgbodydark-rgb: R,V,G
*/
}
/* Puis sur classer l'ensemble de la feuille de style */

View File

@ -0,0 +1,3 @@
name: Nineyellow
author: Arnaud Fornerot
version: 1.0

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -0,0 +1,47 @@
:root{
--colorbgbodydark: #f7ca18;
--colorfttitlelight: #c59800;
--colorbgbodydark-darker: #c59800;
--colorfttitlelight-darker: #584403;
--colorbgbodydark-rgb: 247,202,24;
/* Vous pouvez forcer l'ensemble de ces variables ou laisser la valeur par défaut
--colorbgbodylight: #;
--colorbgbodydark: #;
--colorfttitlelight: #;
--colorfttitledark: #;
--colorftbodylight: #;
--colorftbodydark: #;
--fontbody: "";
--fonttitle: "";
--fontsizeh1: px;
--fontsizeh2: px;
--fontsizeh3: px;
--fontsizeh4: px;
--colorbgbodylight-darker: #;
--colorfttitlelight-darker: #;
--colorbgbodydark-darker: #;
--colorbgbodydark-rgb: R,V,G
*/
}
/* Puis sur classer l'ensemble de la feuille de style */

View File

@ -9,11 +9,26 @@ use Symfony\Component\Mercure\Update;
class PublishController extends AbstractController
{
public function sample($id){
return $this->render('Home/publishsample.html.twig',[
'id'=>$id
]);
}
public function publish($channel, $id, Request $request, HubInterface $hub): Response
{
$ret=$request->get("msg");
$ret["from"]=[];
$ret["from"]["id"]="tot";
$ret["from"]["id"]=$this->getUser()->getId();
$ret["from"]["username"]=$this->getUser()->getUsername();
$ret["from"]["displayname"]=$this->getUser()->getDisplayname();
if(stripos($this->getUser()->getAvatar(),"http")===0)
$ret["from"]["avatar"]=$this->getUser()->getAvatar();
else
$ret["from"]["avatar"]=$this->getParameter('appAlias')."uploads/avatar/".$this->getUser()->getAvatar();
$update = new Update(
$channel."-".$id,
json_encode(

View File

@ -36,6 +36,14 @@ class SecurityController extends AbstractController
$this->apiservice = $apiservice;
}
public function noperm(Request $request)
{
return $this->render('Home/noperm.html.twig',[
"useheader"=>true,
"usemenu"=>false,
]);
}
public function login(Request $request, AuthenticationUtils $authenticationUtils,ManagerRegistry $em)
{
switch($this->getParameter("appAuth")) {
@ -111,21 +119,24 @@ class SecurityController extends AbstractController
if(isset($attributes[$this->getParameter('casAvatar')]))
$avatar = $attributes[$this->getParameter('casAvatar')];
// Génération auto des niveau01s et des groupes en fonction des attributs sso
$this->submitSSONiveau01($attributes,$em);
$this->submitSSOGroup($attributes,$em);
// Rechercher l'utilisateur
$user = $em->getRepository('App\Entity\User')->findOneBy(array("username"=>$username));
if (!$user) {
if(!$this->getParameter("casAutosubmit")) return $this->redirect($this->generateUrl('app_noperm'));
$this->submitSSONiveau01($attributes,$em);
$this->submitSSOGroup($attributes,$em);
$niveau01=$em->getRepository('App\Entity\Niveau01')->calculateSSONiveau01($attributes);
$user=$this->submituser($username,$firstname,$lastname,$email,$password,$niveau01,$em);
$user=$em->getRepository('App\Entity\Group')->calculateSSOGroup($user,$attributes);
}
else
elseif($this->getParameter("casAutoupdate")) {
$this->submitSSONiveau01($attributes,$em);
$this->submitSSOGroup($attributes,$em);
$this->updateuser($user,$firstname,$lastname,$email,$avatar,$em);
$user=$em->getRepository('App\Entity\Group')->calculateSSOGroup($user,$attributes);
}
// On calcule les groupes de l'utilisateur
$user=$em->getRepository('App\Entity\Group')->calculateSSOGroup($user,$attributes);
// Autoconnexion
@ -154,7 +165,6 @@ class SecurityController extends AbstractController
$username=$request->get('login')["username"];
$password=$request->get('login')["password"];
$appMasteridentity=$this->getParameter("appMasteridentity");
// Récupération de la cible de navigation
$redirect = $request->getSession()->get("_security.main.target_path");
@ -186,10 +196,11 @@ class SecurityController extends AbstractController
$user = $em->getRepository('App\Entity\User')->findOneBy(array("username"=>$username));
if (!$user) {
if(!$this->getParameter("ldapAutosubmit")) return $this->redirect($this->generateUrl('app_noperm'));
$niveau01=$em->getRepository('App\Entity\Niveau01')->calculateLDAPNiveau01($username);
$user=$this->submituser($username,$firstname,$lastname,$email,$avatar,$niveau01,$em);
}
else {
elseif($this->getParameter("ldapAutoupdate")) {
$this->updateuser($user,$firstname,$lastname,$email,$avatar,$em);
}
@ -267,21 +278,22 @@ class SecurityController extends AbstractController
if(isset($attributes[$this->getParameter('oauthAvatar')]))
$avatar = $attributes[$this->getParameter('oauthAvatar')];
// Génération auto des niveau01s et des groupes en fonction des attributs sso
$this->submitSSONiveau01($attributes,$em);
$this->submitSSOGroup($attributes,$em);
// Rechercher l'utilisateur
$user = $em->getRepository('App\Entity\User')->findOneBy(array("username"=>$username));
if (!$user) {
if(!$this->getParameter("oauthAutosubmit")) return $this->redirect($this->generateUrl('app_noperm'));
$this->submitSSONiveau01($attributes,$em);
$this->submitSSOGroup($attributes,$em);
$niveau01=$em->getRepository('App\Entity\Niveau01')->calculateSSONiveau01($attributes);
$user=$this->submituser($username,$firstname,$lastname,$email,$avatar,$niveau01,$em);
}
else
elseif($this->getParameter("oauthAutoupdate")) {
$this->submitSSONiveau01($attributes,$em);
$this->submitSSOGroup($attributes,$em);
$this->updateuser($user,$firstname,$lastname,$email,$avatar,$em);
// On calcule les groupes de l'utilisateur
$user=$em->getRepository('App\Entity\Group')->calculateSSOGroup($user,$attributes);
$user=$em->getRepository('App\Entity\Group')->calculateSSOGroup($user,$attributes);
}
// Autoconnexion
return $this->autoconnexion($user,$redirect,$request);

View File

@ -0,0 +1,55 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Yaml\Yaml;
use Doctrine\Persistence\ManagerRegistry;
class ThemeController extends AbstractController
{
public function list(Request $request)
{
$finder = new Finder();
$dir = $this->getParameter('kernel.project_dir')."/public/themes";
$url=$this->getParameter('appAlias')."themes";
$finder->in($dir)->directories()->depth('== 0');
$themes=[];
$themes[""]["dir"]="";
$themes[""]["url"]=$url;
$themes[""]["name"]="Thème par défaut";
foreach ($finder as $file) {
$key=$file->getRelativePathname();
$themes[$key]["dir"]=$key;
$themes[$key]["url"]=$url."/".$key;
$yml=Yaml::parseFile($dir.'/'.$key.'/info.yml');
$themes[$key]["name"]=$yml["name"];
}
$current=$request->getSession()->get("apptheme");
$currentheme=$themes[$current];
unset($themes[$current]);
return $this->render('Theme/list.html.twig',[
'useheader' => true,
'usesidebar' => true,
'currentheme' => $currentheme,
'themes' => $themes
]);
}
public function select($name,Request $request,ManagerRegistry $em)
{
$config=$em->getRepository("App\Entity\Config")->findoneBy(["id"=>"apptheme"]);
$config->setValue($name);
$em->getManager()->flush();
return $this->redirectToRoute("app_admin_theme");
}
}

View File

@ -1,9 +1,10 @@
<?php
namespace App\Twig;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Ramsey\Uuid\Uuid;
class AppExtension extends AbstractExtension
{
@ -16,6 +17,14 @@ class AppExtension extends AbstractExtension
];
}
public function getFunctions()
{
return [
new TwigFunction('uniqueId', [$this, 'getUniqueId']),
];
}
public function urlavatar($avatar)
{
if(stripos($avatar,"http")===0)
@ -24,6 +33,10 @@ class AppExtension extends AbstractExtension
return $this->container->getParameter("appAlias")."uploads/avatar/".$avatar;
}
public function getUniqueId() {
return str_replace("-","",Uuid::uuid4());
}
public function setContainer($container)
{
$this->container = $container;

View File

@ -2,81 +2,16 @@
{% block body %}
{% if app.user %}
<button class="btn btn-primary" onClick="send()">Send</button>
<div id="chat"></div>
<div class="row">
<div class="col col-md6">
<h3>Chat #1</h3>
{{ render(path("app_publish_sample",{id:1})) }}
</div>
<div class="col col-md6">
<h3>Chat #2</h3>
{{ render(path("app_publish_sample",{id:2})) }}
</div>
</div>
{% endif %}
{% endblock %}
{% block localscript %}
{% if app.user %}
<script>
function connect() {
channel="chat";
id=1;
const eventSource = new EventSource("{{ mercure('chat-1')|escape('js') }}");
eventSource.onopen = function(e) {
console.log("== ONOPEN");
sendMessage(channel,id,{command: "alive"});
};
eventSource.onclose = function(e) {
console.log("== ONCLOSE");
sendMessage(channel,id,{command: "dead"});
setTimeout(function() { connect(); }, 1000);
};
eventSource.onmessage = event => {
data=JSON.parse(event.data);
ret=data.ret;
console.log("== ONMESSAGE = "+ret.command);
console.log(ret);
switch (ret.command) {
case "alive":
sendMessage(channel,id,{command: "meto"});
break;
case "meto":
break;
case "dead":
break;
case "push":
$("#chat").prepend('<div class="card mt-3"><div class="card-body">'+ret.message+'</div></div>');
break;
}
}
$(window).on("beforeunload", function() {
sendMessage(channel,id,{command: "dead"});
})
}
connect();
function sendMessage(channel,id,msg) {
url="{{path("app_publish",{channel:'xxx',id:'yyy'})}}";
url=url.replace('xxx',channel);
url=url.replace('yyy',id);
$.ajax({
method: "POST",
url: url,
data: {
msg: msg
},
success: function(data, dataType)
{
},
});
}
function send() {
sendMessage('chat',1,{command: "push", message:"pouet"});
}
</script>
{% endif %}
{% endblock %}

View File

@ -1,17 +1,9 @@
{% extends "base.html.twig" %}
{% block localstyle %}
<style>
label {
color: var(--colorftbodylight);
}
</style>
{% endblock %}
{% block body %}
<div style="text-align:center">
<img src="{{ appAlias }}uploads/logo/{{ app.session.get('logolight') }}" style="height:120px;margin-top:10px;margin-bottom:20px;">
<h1 style="border:none">{{appName}}</h1>
<h1 style="border:none">{{app.session.get('appname')}}</h1>
{{ form_start(form, {'action': path('app_loginldapcheck'), 'method': 'POST'}) }}
<div class="card homecard mb-3" style="width:400px; margin:auto; text-align: left;">
<div class="card-body">

View File

@ -1,17 +1,11 @@
{% extends "base.html.twig" %}
{% block localstyle %}
<style>
label {
color: var(--colorftbodylight);
}
</style>
{% endblock %}
{% block body %}
<div style="text-align:center">
<img src="{{ appAlias }}uploads/logo/{{ app.session.get('logolight') }}" style="height:120px;margin-top:10px;margin-bottom:20px;">
<h1 style="border:none">{{appName}}</h1>
<h1 style="border:none">{{app.session.get('appname')}}</h1>
<form action="{{ path('app_login') }}" method="post">
<div class="card homecard mb-3" style="width:400px; margin:auto">
<div class="card-body">

View File

@ -0,0 +1,20 @@
{% extends "base.html.twig" %}
{% block body %}
Vous avez pu vous connecter à {{ app.session.get('appname') }} mais vous n'avez aucun compte sur l'application.<br>
Contacter votre administrateur si vous souhaitez y accéder.<br><br>
Vous allez être déconnectés d'ici quelques secondes.
{% endblock %}
{% block localscript %}
<script>
$(document).ready(function() {
// Redirection vers la mire d'authentification
setTimeout(function(){
window.location.href="{{ path("app_logout") }}";
}, 6000);
});
</script>
{% endblock %}

View File

@ -0,0 +1,95 @@
{% if app.user %}
{% set idwidget=uniqueId() %}
<div id="chat{{idwidget}}">
<textarea class="form-control mb-2" id="pushmessage" rows="3"></textarea>
<button class="btn btn-primary" onClick="send{{idwidget}}()" class="mt-2">Send</button>
<div id="aliveusers" class="mt-3 mb-3"></div>
<div id="chat"></div>
</div>
<script>
function connect{{idwidget}}() {
channel="chat";
id{{idwidget}}={{id}};
const eventSource = new EventSource("{{ mercure('chat-'~id)|escape('js') }}");
eventSource.onopen = function(e) {
console.log("== ONOPEN");
sendMessage{{idwidget}}(channel,id{{idwidget}},{command: "alive"});
};
eventSource.onclose = function(e) {
console.log("== ONCLOSE");
sendMessage{{idwidget}}(channel,id,{command: "dead"});
setTimeout(function() { connect{{idwidget}}(); }, 5000);
};
eventSource.onmessage = event => {
data=JSON.parse(event.data);
ret=data.ret;
console.log("== ONMESSAGE = "+ret.command);
console.log(ret);
switch (ret.command) {
case "alive":
sendMessage{{idwidget}}(channel,id{{idwidget}},{command: "meto"});
break;
case "meto":
if(!$("#chat{{idwidget}} #aliveuser"+ret.from.id).length) {
html='<img id="aliveuser'+ret.from.id+'" src="'+ret.from.avatar+'" title="'+ret.from.displayname+'"class="avatar me-1">';
$("#chat{{idwidget}} #aliveusers").append(html);
}
break;
case "dead":
sendMessage{{idwidget}}(channel,id{{idwidget}},{command: "alive"});
if($("#aliveuser"+ret.from.id).length) {
$("#aliveuser"+ret.from.id).remove();
}
break;
case "push":
html ='<div class="card mt-1"><div class="card-body d-flex">';
html+='<img id="msguser'+ret.from.id+'" src="'+ret.from.avatar+'" title="'+ret.from.displayname+'"class="avatar me-1">';
html+='<div class="ps-2"><small>'+ret.message.replace(/\n/g,"<br>")+'</small></div>';
html+='</div></div>';
$("#chat{{idwidget}} #chat").prepend(html);
break;
}
}
$(window).on("beforeunload", function() {
sendMessage{{idwidget}}(channel,id{{idwidget}},{command: "dead"});
})
}
connect{{idwidget}}();
function sendMessage{{idwidget}}(channel,id,msg) {
url="{{path("app_publish",{channel:'xxx',id:'yyy'})}}";
url=url.replace('xxx',channel);
url=url.replace('yyy',id{{idwidget}});
$.ajax({
method: "POST",
url: url,
data: {
msg: msg
},
success: function(data, dataType)
{
},
});
}
function send{{idwidget}}() {
if($("#chat{{idwidget}} #pushmessage").val()) {
sendMessage{{idwidget}}('chat',1,{command: "push", message:$("#chat{{idwidget}} #pushmessage").val()});
$("#chat{{idwidget}} #pushmessage").val("");
}
}
</script>
{% endif %}

View File

@ -9,6 +9,12 @@
route: 'app_admin_config',
name: 'Général',
},
{
icon: 'fas fa-paint-brush',
route: 'app_admin_theme',
name: 'Thème',
},
]
},
{

View File

@ -0,0 +1,29 @@
{% extends 'base.html.twig' %}
{% block body %}
<h1>Thèmes</h1>
<h2>Thème en cours</h2>
<div class="text-center" style="width:330px">
<img src="{{currentheme.url}}/look.png" style="width:100%; background-color: {{app.session.get('colorbgbodydark') }}"><br>
{{currentheme.name}}
</div>
<h2 class="mt-5">Thèmes disponibles</h2>
<div>
{% for theme in themes %}
<div class="text-center mb-4" style="width:330px; display: inline-block">
<img src="{{theme.url}}/look.png" style="height:170px; background-color: {{app.session.get('colorbgbodydark') }}"><br>
{{theme.name}}<br>
<a href="{{ path("app_admin_theme_select",{"name":theme.dir}) }}" class="btn btn-primary" role="button">Sélectionner</a>
</div>
{% endfor %}
</div>
{% endblock %}

View File

@ -14,7 +14,7 @@
</div>
<div class="card-body">
<table class="table table-striped table-bordered table-hover" id="dataTables" style="width:100%; font-size:11px;">
<table class="table table-striped table-bordered table-hover wrap" id="dataTables" style="width:100%; font-size:11px;">
<thead>
<tr>
{% if access=="admin" or access=="modo"%}
@ -44,7 +44,6 @@
$(document).ready(function() {
$('#dataTables').DataTable({
columnDefs: [ { "targets": 'no-sort', "orderable": false },{ "targets": 'no-visible', "visible": false } ],
responsive: true,
iDisplayLength: 100,
processing: true,
serverSide: true,

View File

@ -12,6 +12,10 @@
<script src="{{ asset('bundles/tetranzselect2entity/js/select2entity.js') }}"></script>
{{ include('Include/style.css.twig') }}
{% if not app.session.get("apptheme") is empty %}
<link href="{{ appAlias }}themes/{{ app.session.get("apptheme") }}/style.css" rel="stylesheet" media="screen" />
{% endif %}
{% block localstyle %}{% endblock %}
</head>