svg
This commit is contained in:
parent
38239d4b02
commit
b5f7aa4b0a
@ -10,6 +10,7 @@
|
||||
"friendsofsymfony/rest-bundle": "^2.7",
|
||||
"jasig/phpcas": "^1.3",
|
||||
"knplabs/knp-snappy-bundle": "^1.7",
|
||||
"mashape/unirest-php": "^3.0",
|
||||
"nategood/httpful": "^0.3.2",
|
||||
"nelmio/api-doc-bundle": "^3.6",
|
||||
"oneup/uploader-bundle": "^2.2",
|
||||
|
48
src/nineskeletor-1.0/composer.lock
generated
48
src/nineskeletor-1.0/composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "1be2a2e3a398eb23cd3c3e26bc75c090",
|
||||
"content-hash": "75b3e8bc9bb37c5b0331d03affa7fa45",
|
||||
"packages": [
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
@ -1687,6 +1687,52 @@
|
||||
],
|
||||
"time": "2019-12-30T16:19:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mashape/unirest-php",
|
||||
"version": "v3.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Mashape/unirest-php.git",
|
||||
"reference": "842c0f242dfaaf85f16b72e217bf7f7c19ab12cb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Mashape/unirest-php/zipball/842c0f242dfaaf85f16b72e217bf7f7c19ab12cb",
|
||||
"reference": "842c0f242dfaaf85f16b72e217bf7f7c19ab12cb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"codeclimate/php-test-reporter": "0.1.*",
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-json": "Allows using JSON Bodies for sending and parsing requests"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Unirest\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Unirest PHP",
|
||||
"homepage": "https://github.com/Mashape/unirest-php",
|
||||
"keywords": [
|
||||
"client",
|
||||
"curl",
|
||||
"http",
|
||||
"https",
|
||||
"rest"
|
||||
],
|
||||
"time": "2016-08-11T17:49:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "1.25.4",
|
||||
|
@ -11,3 +11,4 @@ twig:
|
||||
appAuth: '%appAuth%'
|
||||
appName: '%appName%'
|
||||
appCron: '%appCron%'
|
||||
appMasteridentity: '%appMasteridentity'
|
||||
|
@ -72,18 +72,10 @@ app_user:
|
||||
path: /admin/user
|
||||
defaults: { _controller: App\Controller\UserController:list }
|
||||
|
||||
app_user_submit:
|
||||
path: /admin/user/submit
|
||||
defaults: { _controller: App\Controller\UserController:submit }
|
||||
|
||||
app_user_update:
|
||||
path: /admin/user/update/{id}
|
||||
defaults: { _controller: App\Controller\UserController:update }
|
||||
|
||||
app_user_delete:
|
||||
path: /admin/user/delete/{id}
|
||||
defaults: { _controller: App\Controller\UserController:delete }
|
||||
|
||||
app_user_select:
|
||||
path: /user/user/select
|
||||
defaults: { _controller: App\Controller\UserController:select }
|
||||
|
@ -7,6 +7,7 @@ parameters:
|
||||
appEnv: '%env(resolve:APP_ENV)%'
|
||||
appSecret: '%env(resolve:APP_SECRET)%'
|
||||
|
||||
appWeburl: '%env(resolve:APP_WEBURL)%'
|
||||
appAuth: '%env(resolve:APP_AUTH)%'
|
||||
appAlias: '%env(resolve:APP_ALIAS)%'
|
||||
appName: '%env(resolve:APP_NAME)%'
|
||||
@ -60,7 +61,7 @@ services:
|
||||
# this creates a service per class whose id is the fully-qualified class name
|
||||
App\:
|
||||
resource: '../src/*'
|
||||
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
|
||||
exclude: '../src/{DependencyInjection,Twig,Entity,Migrations,Tests,Kernel.php}'
|
||||
|
||||
# controllers are imported separately to make sure services can be injected
|
||||
# as action arguments even if you don't extend any base controller class
|
||||
@ -106,3 +107,10 @@ services:
|
||||
public: true
|
||||
class: App\Service\mailService
|
||||
arguments: ["@mailer", "@twig"]
|
||||
|
||||
app.twig.extension:
|
||||
class: App\Twig\AppExtension
|
||||
calls:
|
||||
- [setContainer, ["@service_container"]]
|
||||
tags:
|
||||
- { name: twig.extension }
|
@ -356,7 +356,17 @@ class SynchroUsersCommand extends Command
|
||||
$this->writeln('== GROUPS ============================================');
|
||||
$groups=$this->em->getRepository("App:Group")->findAll();
|
||||
foreach($groups as $group) {
|
||||
if($group->getIdexternal()) {
|
||||
$this->writeln(" - Suppression dans Bundle >> ".$group->getName());
|
||||
if(!$simulate) {
|
||||
$this->em->remove($group);
|
||||
$this->em->flush();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(!$group->getLdapfilter()) continue;
|
||||
|
||||
if(!in_array($group->getId(),$this->ldapgroups)) {
|
||||
$this->writeln(" - Suppression dans Bundle >> ".$group->getName());
|
||||
if(!$simulate) {
|
||||
@ -383,13 +393,21 @@ class SynchroUsersCommand extends Command
|
||||
$this->writeln('== SYNCHONISATION NINEGATE TO BUNDLE ================');
|
||||
$this->writeln('=====================================================');
|
||||
|
||||
$appmasterurl = $this->getParameter("appmasterurl");
|
||||
if(stripos($appmasterurl,"/")===0)
|
||||
$url="https://".$this->getParameter("appWeburl").$appmasterurl;
|
||||
$appmasterurl = $this->container->getParameter("appMasterurl");
|
||||
$appmasterkey = $this->container->getParameter("appMasterkey");
|
||||
|
||||
// Déclaration du proxy
|
||||
if(stripos($appmasterurl,"/")===0) {
|
||||
$url="https://".$this->container->getParameter("appWeburl").$appmasterurl;
|
||||
}
|
||||
else
|
||||
$url=$masterurl;
|
||||
$url=$appmasterurl;
|
||||
|
||||
$indomaine = (stripos($url,$this->getParameter("appWeburl"))!==false);
|
||||
$indomaine = (stripos($url,$this->container->getParameter("appWeburl"))!==false);
|
||||
|
||||
|
||||
$url="http://172.27.7.67/ninegate";
|
||||
$indomaine=true;
|
||||
|
||||
// Recherche des élèments de masterIdentify
|
||||
$headers = ['Accept' => 'application/json'];
|
||||
@ -397,16 +415,169 @@ class SynchroUsersCommand extends Command
|
||||
|
||||
/* si hor domaine on utilise le proxy si proxy il y a */
|
||||
if(!$indomaine) {
|
||||
$PROXYactivate = $em->getRepository("CadolesCoreBundle:Config")->find("PROXYactivate")->getValue();
|
||||
if($PROXYactivate) {
|
||||
$PROXYserver = $em->getRepository("CadolesCoreBundle:Config")->find("PROXYserver")->getValue();
|
||||
$PROXYport = $em->getRepository("CadolesCoreBundle:Config")->find("PROXYport")->getValue();
|
||||
\Unirest\Request::proxy($PROXYserver, $PROXYport, CURLPROXY_HTTP, true);
|
||||
$proxyUse = $this->container->getParameter("proxyUser");
|
||||
if($proxyUse) {
|
||||
$proxyHost = $this->container->getParameter("proxyHost");
|
||||
$proxyPort = $this->container->getParameter("proxyPort");
|
||||
\Unirest\Request::proxy($proxyHost, $proxyPort, CURLPROXY_HTTP, true);
|
||||
}
|
||||
}
|
||||
|
||||
$this->writeln('');
|
||||
$this->writeln('== GROUPS ============================================');
|
||||
|
||||
// Récupération des informations groups issus du masteridentity
|
||||
$response = \Unirest\Request::get($url.'/rest/groups/'.$appmasterkey,$headers,$query);
|
||||
$lstgroups=[];
|
||||
if($response->code="200" && is_object($response->body)) {
|
||||
$apigroups=$response->body;
|
||||
foreach($apigroups as $apigroup) {
|
||||
array_push($lstgroups,$apigroup->id);
|
||||
|
||||
$group=$this->em->getRepository("App:Group")->findOneBy(["idexternal"=>$apigroup->id]);
|
||||
$this->writeln(" - ".$apigroup->name);
|
||||
if(!$simulate) {
|
||||
if(!$group) {
|
||||
$group = new Group();
|
||||
$group->setIdexternal($apigroup->id);
|
||||
}
|
||||
|
||||
$group->setName($apigroup->name);
|
||||
|
||||
$this->em->persist($group);
|
||||
$this->em->flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
else die("Erreur de communication");
|
||||
|
||||
$this->writeln('');
|
||||
$this->writeln('== USERS ============================================');
|
||||
|
||||
// Récupération des informations utilisateurs issus du masteridentity
|
||||
$response = \Unirest\Request::get($url.'/rest/user/'.$masterapikey.'/'.$user->getUsername(),$headers,$query);
|
||||
$response = \Unirest\Request::get($url.'/rest/users/'.$appmasterkey,$headers,$query);
|
||||
$lstusers=[];
|
||||
if($response->code="200"&&is_object($response->body)) {
|
||||
$apiusers=$response->body;
|
||||
foreach($apiusers as $apiuser) {
|
||||
array_push($lstusers,$apiuser->username);
|
||||
|
||||
$user=$this->em->getRepository("App:User")->findOneBy(["username"=>$apiuser->username]);
|
||||
$this->writeln(" - ".$apiuser->username);
|
||||
if(!$simulate) {
|
||||
if(!$user) {
|
||||
$user = new User();
|
||||
|
||||
$user->setUsername($apiuser->username);
|
||||
$user->setPassword("NOPASSWORD");
|
||||
}
|
||||
|
||||
$user->setLastname($apiuser->lastname);
|
||||
$user->setFirstname($apiuser->firstname);
|
||||
$user->setEmail($apiuser->email);
|
||||
$user->setAvatar($apiuser->avatar);
|
||||
|
||||
$this->em->persist($user);
|
||||
$this->em->flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
else die("Erreur de communication");
|
||||
|
||||
$this->writeln('');
|
||||
$this->writeln('== USERS GROUP ======================================');
|
||||
|
||||
$groups=$this->em->getRepository('App:Group')->findAll();
|
||||
$tabgroups = json_decode(json_encode($apigroups), true);
|
||||
foreach($groups as $group) {
|
||||
if(!$group->getIdexternal()) continue;
|
||||
|
||||
$this->writeln($group->getName());
|
||||
|
||||
$usergroups = $tabgroups[$group->getIdexternal()]["users"];
|
||||
$tbusers=[];
|
||||
foreach($usergroups as $user) {
|
||||
array_push($tbusers,$user["username"]);
|
||||
|
||||
// On recherche le user en question
|
||||
$user=$this->em->getRepository("App:User")->findOneBy(["username"=>$user["username"]]);
|
||||
if($user) {
|
||||
$this->writeln(" - Rattachement ".$user->getUsername());
|
||||
|
||||
if(!$simulate) {
|
||||
if(!$group->getUsers()->contains($user)) {
|
||||
$group->addUser($user);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach($group->getUsers() as $user) {
|
||||
if(!in_array($user->getUsername(),$tbusers)) {
|
||||
$this->writeln(" - Détachement ".$user->getUsername());
|
||||
if(!$simulate) {
|
||||
$group->removeUser($user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->em->persist($group);
|
||||
$this->em->flush();
|
||||
|
||||
}
|
||||
|
||||
$this->writeln('');
|
||||
$this->writeln('=====================================================');
|
||||
$this->writeln('== SYNCHONISATION BUNDLE TO NINEGATE ================');
|
||||
$this->writeln('=====================================================');
|
||||
|
||||
|
||||
$this->writeln('');
|
||||
$this->writeln('== USERS ============================================');
|
||||
|
||||
// Pour chaque utilisateur de la base
|
||||
$users=$this->em->getRepository("App:User")->findAll();
|
||||
foreach($users as $user) {
|
||||
if(!in_array($user->getUsername(),$lstusers)) {
|
||||
if($user->getUsername()=="admin")
|
||||
$this->writeln(" - Ne jamais supprimer >> ".$user->getUsername());
|
||||
else {
|
||||
$this->writeln(" - Suppression dans Bundle >> ".$user->getUsername());
|
||||
if(!$simulate) {
|
||||
$this->em->remove($user);
|
||||
$this->em->flush();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->writeln('');
|
||||
$this->writeln('== GROUPS ============================================');
|
||||
$groups=$this->em->getRepository("App:Group")->findAll();
|
||||
foreach($groups as $group) {
|
||||
if($group->getLdapfilter()) {
|
||||
$this->writeln(" - Suppression dans Bundle >> ".$group->getName());
|
||||
if(!$simulate) {
|
||||
$this->em->remove($group);
|
||||
$this->em->flush();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(!$group->getIdexternal()) continue;
|
||||
|
||||
if(!in_array($group->getIdexternal(),$lstgroups)) {
|
||||
$this->writeln(" - Suppression dans Bundle >> ".$group->getName());
|
||||
if(!$simulate) {
|
||||
$this->em->remove($group);
|
||||
$this->em->flush();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->writeln('');
|
||||
|
||||
}
|
||||
|
||||
|
@ -29,45 +29,6 @@ class UserController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
public function submit(Request $request)
|
||||
{
|
||||
// Initialisation de l'enregistrement
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$data = new Entity();
|
||||
|
||||
// Création du formulaire
|
||||
$form = $this->createForm(Form::class,$data,array("mode"=>"submit","appAuth"=>$this->getParameter("appAuth")));
|
||||
|
||||
// Récupération des data du formulaire
|
||||
$form->handleRequest($request);
|
||||
|
||||
// Sur erreur
|
||||
$this->getErrorForm(null,$form,$request,$data,"submit");
|
||||
|
||||
// Sur validation
|
||||
if ($form->get('submit')->isClicked() && $form->isValid()) {
|
||||
if($this->getParameter("appAuth")!="MYSQL") {
|
||||
$data->setPassword("nopassword");
|
||||
}
|
||||
|
||||
$data = $form->getData();
|
||||
$em->persist($data);
|
||||
$em->flush();
|
||||
|
||||
// Retour à la liste
|
||||
return $this->redirectToRoute($this->route);
|
||||
}
|
||||
|
||||
// Affichage du formulaire
|
||||
return $this->render($this->render.'edit.html.twig', [
|
||||
'useheader' => true,
|
||||
'usesidebar' => true,
|
||||
$this->data => $data,
|
||||
'mode' => 'submit',
|
||||
'form' => $form->createView()
|
||||
]);
|
||||
}
|
||||
|
||||
public function update($id,Request $request)
|
||||
{
|
||||
// Initialisation de l'enregistrement
|
||||
@ -152,25 +113,6 @@ class UserController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
public function delete($id,Request $request)
|
||||
{
|
||||
// Initialisation de l'enregistrement
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$data=$em->getRepository($this->entity)->find($id);
|
||||
|
||||
// Controle avant suppression
|
||||
$error=false;
|
||||
if($error)
|
||||
return $this->redirectToRoute($this->route."_update",["id"=>$id]);
|
||||
else {
|
||||
$em->remove($data);
|
||||
$em->flush();
|
||||
|
||||
// Retour à la liste
|
||||
return $this->redirectToRoute($this->route);
|
||||
}
|
||||
}
|
||||
|
||||
public function select(Request $request)
|
||||
{
|
||||
// S'assurer que c'est un appel ajax
|
||||
|
@ -12,7 +12,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
* Group
|
||||
*
|
||||
* @ORM\Entity(repositoryClass="App\Repository\GroupRepository")
|
||||
* @ORM\Table(name="groupe",uniqueConstraints={@ORM\UniqueConstraint(name="name", columns={"name"})}))
|
||||
* @ORM\Table(name="groupe", uniqueConstraints={@ORM\UniqueConstraint(name="name", columns={"name"})}, indexes={@ORM\Index(name="idexternal", columns={"idexternal"})} )
|
||||
* @UniqueEntity("name", message="Ce nom de groupe existe dèja")
|
||||
*/
|
||||
class Group
|
||||
@ -35,6 +35,11 @@ class Group
|
||||
*/
|
||||
private $ldapfilter;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", nullable=true)
|
||||
*/
|
||||
private $idexternal;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity="User", mappedBy="groups")
|
||||
*/
|
||||
@ -102,4 +107,16 @@ class Group
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIdexternal(): ?string
|
||||
{
|
||||
return $this->idexternal;
|
||||
}
|
||||
|
||||
public function setIdexternal(?string $idexternal): self
|
||||
{
|
||||
$this->idexternal = $idexternal;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
@ -66,7 +66,7 @@ class User implements UserInterface, \Serializable
|
||||
private $displayname;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=60, nullable=true, options={"default" : 0})
|
||||
* @ORM\Column(type="string", length=200, nullable=true, options={"default" : 0})
|
||||
*/
|
||||
private $avatar;
|
||||
|
||||
@ -91,9 +91,10 @@ class User implements UserInterface, \Serializable
|
||||
private $groups;
|
||||
|
||||
|
||||
public function __construct()
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
$this->groups = new ArrayCollection();
|
||||
|
||||
}
|
||||
|
||||
public function getUsername(): ?string
|
||||
|
@ -37,22 +37,11 @@ class UserType extends AbstractType
|
||||
$builder->add('username',
|
||||
TextType::class, [
|
||||
"label" =>"Login",
|
||||
"disabled" => ($options["mode"]=="submit"?false:true),
|
||||
"disabled" => true,
|
||||
"attr" => ["autocomplete" => "off"],
|
||||
]
|
||||
);
|
||||
|
||||
if($options["appAuth"]=="MYSQL"&&$options["mode"]!="profil") {
|
||||
$builder->add('password',
|
||||
RepeatedType::class, [
|
||||
"type" => PasswordType::class,
|
||||
"required" => ($options["mode"]=="submit"?true:false),
|
||||
"first_options" => ["label" => "Mot de Passe", "attr" => ["class" => " no-print", "autocomplete" => "new-password"]],
|
||||
"second_options" => ["label" => "Confirmer Mot de Passe", "attr" => ["class" => "no-print"]],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if($options["mode"]!="profil") {
|
||||
$choices=[];
|
||||
$choices['Administrateur']='ROLE_ADMIN';
|
||||
@ -67,23 +56,47 @@ class UserType extends AbstractType
|
||||
'expanded' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$builder->add('groups',
|
||||
Select2EntityType::class, [
|
||||
"label" => "Groupes",
|
||||
"disabled" => false,
|
||||
"required" => false,
|
||||
"multiple" => true,
|
||||
"remote_route" => "app_group_select",
|
||||
"class" => "App:Group",
|
||||
"primary_key" => "id",
|
||||
"text_property" => "name",
|
||||
"minimum_input_length" => 0,
|
||||
"page_limit" => 100,
|
||||
"allow_clear" => true,
|
||||
"delay" => 250,
|
||||
"cache" => false,
|
||||
"cache_timeout" => 60000,
|
||||
"language" => "fr",
|
||||
"placeholder" => "Selectionner des Groupes",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$builder->add('lastname',
|
||||
TextType::class, [
|
||||
"label" =>"Nom",
|
||||
"disabled" => true,
|
||||
]
|
||||
);
|
||||
|
||||
$builder->add('firstname',
|
||||
TextType::class, [
|
||||
"label" =>"Prénom",
|
||||
"required" => false ]
|
||||
"required" => false,
|
||||
"disabled" => true, ]
|
||||
);
|
||||
|
||||
$builder->add('email',
|
||||
EmailType::class, [
|
||||
"label" =>"Email",
|
||||
"disabled" => true,
|
||||
]
|
||||
);
|
||||
|
||||
@ -94,26 +107,6 @@ class UserType extends AbstractType
|
||||
]
|
||||
);
|
||||
|
||||
$builder->add('groups',
|
||||
Select2EntityType::class, [
|
||||
"label" => "Groupes",
|
||||
"disabled" => false,
|
||||
"required" => false,
|
||||
"multiple" => true,
|
||||
"remote_route" => "app_group_select",
|
||||
"class" => "App:Group",
|
||||
"primary_key" => "id",
|
||||
"text_property" => "name",
|
||||
"minimum_input_length" => 0,
|
||||
"page_limit" => 100,
|
||||
"allow_clear" => true,
|
||||
"delay" => 250,
|
||||
"cache" => false,
|
||||
"cache_timeout" => 60000,
|
||||
"language" => "fr",
|
||||
"placeholder" => "Selectionner des Groupes",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
|
30
src/nineskeletor-1.0/src/Twig/AppExtension.php
Normal file
30
src/nineskeletor-1.0/src/Twig/AppExtension.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace App\Twig;
|
||||
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
class AppExtension extends AbstractExtension
|
||||
{
|
||||
protected $container;
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
new TwigFilter('urlavatar', [$this, 'urlAvatar']),
|
||||
];
|
||||
}
|
||||
|
||||
public function urlAvatar($avatar)
|
||||
{
|
||||
if(stripos($avatar,"http")===0)
|
||||
return $avatar;
|
||||
else
|
||||
return "/".$this->container->getParameter("appAlias")."/uploads/avatar/".$avatar;
|
||||
}
|
||||
|
||||
public function setContainer($container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user