added "create user" functionality (#37)
* added "create user" functionality #5 * improved user admin views * added Role constraint and validator
This commit is contained in:
@@ -1,35 +1,12 @@
|
||||
<?xml version="1.0"?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" target-language="de" datatype="plaintext" original="file.ext">
|
||||
<file source-language="en" target-language="de" datatype="plaintext" original="not.available">
|
||||
<body>
|
||||
<trans-unit id="post.blank_summary">
|
||||
<source>post.blank_summary</source>
|
||||
<target>Gib deinem Beitrag eine Zusammenfassung!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="post.blank_content">
|
||||
<source>post.blank_content</source>
|
||||
<target>Dein Beitrag sollte einen Inhalt haben!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="post.too_short_content">
|
||||
<source>post.too_short_content</source>
|
||||
<target>Der Beitragsinhalt ist zu kurz (mindestens {{ limit }} Zeichen)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="comment.blank">
|
||||
<source>comment.blank</source>
|
||||
<target>Bitte gib einen Kommentar ein!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="comment.too_short">
|
||||
<source>comment.too_short</source>
|
||||
<target>Der Kommentar ist zu kurz (mindestens {{ limit }} Zeichen)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="comment.too_long">
|
||||
<source>comment.too_long</source>
|
||||
<target>Der Kommentar ist zu lang (maximal {{ limit }} Zeichen)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="comment.is_spam">
|
||||
<source>comment.is_spam</source>
|
||||
<target>Der Inhalt des Kommentars wird als Spam eingestuft.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="This value is not a valid role.">
|
||||
<source>This value is not a valid role.</source>
|
||||
<target>Dieser Wert ist keine gültige Rolle.</target>
|
||||
</trans-unit>
|
||||
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
@@ -17,17 +17,21 @@
|
||||
'label.active': '',
|
||||
'label.roles': '',
|
||||
'label.actions': '',
|
||||
}) }}
|
||||
}, null, {'plus-square': path('admin_user_create')}) }}
|
||||
|
||||
{% for entry in entries %}
|
||||
<tr>
|
||||
<td class="hidden-xs">{{ entry.id }}</td>
|
||||
<td>{{ entry.alias }}</td>
|
||||
<td>{{ entry.alias|default(entry.username) }}</td>
|
||||
<td class="hidden-xs">{{ entry.username }}</td>
|
||||
<td class="hidden-xs hidden-sm">{{ entry.email }}</td>
|
||||
<td class="hidden-xs">{{ entry.title }}</td>
|
||||
<td>{{ widgets.label_visible(entry.active) }}</td>
|
||||
<td>{{ entry.roles|join(',')|trans }}</td>
|
||||
<td>
|
||||
{% for role in entry.roles %}
|
||||
{{ widgets.label_role(role) }}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
{{ widgets.button_group({
|
||||
'edit': path('user_profile', {'username' : entry.username}),
|
||||
|
||||
12
app/Resources/views/admin/user_edit.html.twig
Normal file
12
app/Resources/views/admin/user_edit.html.twig
Normal file
@@ -0,0 +1,12 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block page_title %}{{ 'admin_user.title'|trans }}{% endblock %}
|
||||
{% block page_subtitle %}{{ 'admin_user.subtitle'|trans }}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{{ include('default/_form.html.twig', {
|
||||
'title': 'create'|trans,
|
||||
'form': form,
|
||||
'back': path('admin_user')
|
||||
}) }}
|
||||
{% endblock %}
|
||||
@@ -12,6 +12,11 @@
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro label_role(role) %}
|
||||
{% import _self as macro %}
|
||||
{{ macro.label(role, 'primary') }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro label_project(project) %}
|
||||
{% import _self as macro %}
|
||||
{{ macro.label(project.name, 'primary') }}
|
||||
|
||||
@@ -11,13 +11,15 @@
|
||||
|
||||
namespace AppBundle\Controller\Admin;
|
||||
|
||||
use AppBundle\Controller\AbstractController;
|
||||
use AppBundle\Entity\User;
|
||||
use AppBundle\Form\UserCreateType;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Controller used to manage users in the admin part of the site.
|
||||
@@ -27,7 +29,7 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||
*
|
||||
* @author Kevin Papst <kevin@kevinpapst.de>
|
||||
*/
|
||||
class UserController extends Controller
|
||||
class UserController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @Route("/", defaults={"page": 1}, name="admin_user")
|
||||
@@ -42,4 +44,58 @@ class UserController extends Controller
|
||||
|
||||
return $this->render('admin/user.html.twig', ['entries' => $entries]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/create", name="admin_user_create")
|
||||
* @Method({"GET", "POST"})
|
||||
*/
|
||||
public function createAction(Request $request)
|
||||
{
|
||||
$user = new User();
|
||||
$editForm = $this->createEditForm($user);
|
||||
|
||||
$editForm->handleRequest($request);
|
||||
|
||||
if ($editForm->isSubmitted() && $editForm->isValid()) {
|
||||
$password = $this->get('security.password_encoder')
|
||||
->encodePassword($user, $user->getPlainPassword());
|
||||
$user->setPassword($password);
|
||||
$user->setRoles([User::DEFAULT_ROLE]);
|
||||
|
||||
$entityManager = $this->getDoctrine()->getManager();
|
||||
$entityManager->persist($user);
|
||||
$entityManager->flush();
|
||||
|
||||
$this->flashSuccess('action.updated_successfully');
|
||||
|
||||
return $this->redirectToRoute(
|
||||
'user_profile_edit', ['username' => $user->getUsername()]
|
||||
);
|
||||
}
|
||||
|
||||
return $this->render(
|
||||
'admin/user_edit.html.twig',
|
||||
[
|
||||
'user' => $user,
|
||||
'form' => $editForm->createView()
|
||||
]
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @return \Symfony\Component\Form\FormInterface
|
||||
*/
|
||||
private function createEditForm(User $user)
|
||||
{
|
||||
return $this->createForm(
|
||||
UserCreateType::class,
|
||||
$user,
|
||||
[
|
||||
'action' => $this->generateUrl('admin_user_create'),
|
||||
'method' => 'POST'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,19 +2,28 @@
|
||||
|
||||
namespace AppBundle\Entity;
|
||||
|
||||
use AppBundle\Validator\Constraints as KimaiAssert;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
|
||||
/**
|
||||
* User
|
||||
*
|
||||
* @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
|
||||
* @ORM\Table(name="users", uniqueConstraints={@ORM\UniqueConstraint(name="name", columns={"name"})})
|
||||
* @ORM\Table(name="users", uniqueConstraints={@ORM\UniqueConstraint(name="name", columns={"name"}), @ORM\UniqueConstraint(name="mail", columns={"mail"})})
|
||||
* @UniqueEntity("username")
|
||||
* @UniqueEntity("email")
|
||||
*
|
||||
* @author Kevin Papst <kevin@kevinpapst.de>
|
||||
*/
|
||||
class User implements UserInterface
|
||||
{
|
||||
|
||||
const DEFAULT_ROLE = 'ROLE_USER';
|
||||
const DEFAULT_LANGUAGE = 'de';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
@@ -27,7 +36,7 @@ class User implements UserInterface
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(name="name", type="string", length=160, nullable=false, unique=true)
|
||||
* @ORM\Column(name="name", type="string", length=60, nullable=false, unique=true)
|
||||
* @Assert\NotBlank()
|
||||
* @Assert\Length(min=6, max=160)
|
||||
*/
|
||||
@@ -60,7 +69,8 @@ class User implements UserInterface
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(name="alias", type="string", length=160, nullable=true)
|
||||
* @ORM\Column(name="alias", type="string", length=60, nullable=true)
|
||||
* @Assert\Length(max=160)
|
||||
*/
|
||||
private $alias;
|
||||
|
||||
@@ -68,13 +78,15 @@ class User implements UserInterface
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(name="language", type="string", length=5, nullable=true)
|
||||
* @Assert\Language()
|
||||
*/
|
||||
private $language = 'de';
|
||||
private $language = self::DEFAULT_LANGUAGE;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*
|
||||
* @ORM\Column(name="active", type="boolean", nullable=false)
|
||||
* @Assert\NotNull()
|
||||
*/
|
||||
private $active = true;
|
||||
|
||||
@@ -103,6 +115,7 @@ class User implements UserInterface
|
||||
* @var string[]
|
||||
*
|
||||
* @ORM\Column(type="json_array")
|
||||
* @KimaiAssert\Role()
|
||||
*/
|
||||
private $roles = [];
|
||||
|
||||
@@ -166,7 +179,7 @@ class User implements UserInterface
|
||||
*/
|
||||
public function setActive($active)
|
||||
{
|
||||
$this->active = $active;
|
||||
$this->active = (bool) $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -305,10 +318,12 @@ class User implements UserInterface
|
||||
|
||||
/**
|
||||
* @param string $language
|
||||
* @return $this
|
||||
*/
|
||||
public function setLanguage($language)
|
||||
{
|
||||
$this->language = $language;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
56
src/AppBundle/Form/UserCreateType.php
Normal file
56
src/AppBundle/Form/UserCreateType.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai package.
|
||||
*
|
||||
* (c) Kevin Papst <kevin@kevinpapst.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AppBundle\Form;
|
||||
|
||||
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* Defines the form used to create Users.
|
||||
*
|
||||
* @author Kevin Papst <kevin@kevinpapst.de>
|
||||
*/
|
||||
class UserCreateType extends UserEditType
|
||||
{
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('username', null, [
|
||||
'label' => 'label.username',
|
||||
'required' => true
|
||||
])
|
||||
->add('plainPassword', RepeatedType::class, [
|
||||
'required' => true,
|
||||
'type' => PasswordType::class,
|
||||
'first_options' => array('label' => 'security.label.password'),
|
||||
'second_options' => array('label' => 'security.label.password_repeat'),
|
||||
]);
|
||||
|
||||
parent::buildForm($builder, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'class' => 'AppBundle:User',
|
||||
]);
|
||||
}
|
||||
}
|
||||
31
src/AppBundle/Validator/Constraints/Role.php
Normal file
31
src/AppBundle/Validator/Constraints/Role.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai package.
|
||||
*
|
||||
* (c) Kevin Papst <kevin@kevinpapst.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AppBundle\Validator\Constraints;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
|
||||
*
|
||||
* @author Kevin Papst <kevin@kevinpapst.de>
|
||||
*/
|
||||
class Role extends Constraint
|
||||
{
|
||||
const ROLE_ERROR = 'xd5hffg-dsfef3-426a-83d7-1f2d33hs5d84';
|
||||
|
||||
protected static $errorNames = array(
|
||||
self::ROLE_ERROR => 'ROLE_ERROR',
|
||||
);
|
||||
|
||||
public $message = 'This value is not a valid role.';
|
||||
}
|
||||
50
src/AppBundle/Validator/Constraints/RoleValidator.php
Normal file
50
src/AppBundle/Validator/Constraints/RoleValidator.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai package.
|
||||
*
|
||||
* (c) Kevin Papst <kevin@kevinpapst.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AppBundle\Validator\Constraints;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||
|
||||
/**
|
||||
* @author Kevin Papst <kevin@kevinpapst.de>
|
||||
*/
|
||||
class RoleValidator extends ConstraintValidator
|
||||
{
|
||||
|
||||
protected $allowedRoles = ['ROLE_CUSTOMER', 'ROLE_USER', 'ROLE_TEAMLEAD', 'ROLE_ADMIN', 'ROLE_SUPER_ADMIN'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($value, Constraint $constraint)
|
||||
{
|
||||
if (!$constraint instanceof Role) {
|
||||
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Role');
|
||||
}
|
||||
|
||||
$roles = $value;
|
||||
|
||||
if (!is_array($roles)) {
|
||||
$roles = [$roles];
|
||||
}
|
||||
|
||||
foreach($roles as $role) {
|
||||
if (!is_string($role) || !in_array($role, $this->allowedRoles)) {
|
||||
$this->context->buildViolation($constraint->message)
|
||||
->setParameter('{{ value }}', $this->formatValue($role))
|
||||
->setCode(Role::ROLE_ERROR)
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user