Passed
Push — master ( 23587f...1016f0 )
by Jan
04:38 queued 10s
created

UserController::userSettings()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 82
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 41
c 1
b 0
f 0
nc 7
nop 3
dl 0
loc 82
rs 8.3306

1 Method

Rating   Name   Duplication   Size   Complexity  
A UserController::getGravatar() 0 18 4

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
4
 *
5
 * Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
20
 */
21
22
namespace App\Controller;
23
24
use App\Entity\Attachments\AttachmentType;
25
use App\Entity\Attachments\UserAttachment;
26
use App\Entity\UserSystem\User;
27
use App\Form\Permissions\PermissionsType;
28
use App\Form\TFAGoogleSettingsType;
29
use App\Form\UserAdminForm;
30
use App\Form\UserSettingsType;
31
use App\Services\EntityExporter;
32
use App\Services\EntityImporter;
33
use App\Services\StructuralElementRecursionHelper;
34
use App\Services\TFA\BackupCodeManager;
35
use Doctrine\ORM\EntityManagerInterface;
36
use \Exception;
37
use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticator;
38
use Symfony\Component\Asset\Packages;
39
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
40
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
41
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
42
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
43
use Symfony\Component\Form\Extension\Core\Type\TextType;
44
use Symfony\Component\HttpFoundation\Request;
45
use Symfony\Component\HttpFoundation\Response;
46
use Symfony\Component\Routing\Annotation\Route;
47
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
48
use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
49
use Symfony\Component\Serializer\SerializerInterface;
50
use Symfony\Component\Validator\Constraints\Length;
51
52
/**
53
 * @Route("/user")
54
 * Class UserController
55
 */
56
class UserController extends AdminPages\BaseAdminController
57
{
58
    protected $entity_class = User::class;
59
    protected $twig_template = 'AdminPages/UserAdmin.html.twig';
60
    protected $form_class = UserAdminForm::class;
61
    protected $route_base = 'user';
62
    protected $attachment_class = UserAttachment::class;
63
64
    /**
65
     * @Route("/{id}/edit", requirements={"id"="\d+"}, name="user_edit")
66
     * @Route("/{id}/", requirements={"id"="\d+"})
67
     */
68
    public function edit(User $entity, Request $request, EntityManagerInterface $em)
69
    {
70
        //Handle 2FA disabling
71
72
        if($request->request->has('reset_2fa')) {
73
            //Check if the admin has the needed permissions
74
            $this->denyAccessUnlessGranted('set_password', $entity);
75
            if ($this->isCsrfTokenValid('reset_2fa'.$entity->getId(), $request->request->get('_token'))) {
76
                //Disable Google authenticator
77
                $entity->setGoogleAuthenticatorSecret(null);
78
                $entity->setBackupCodes([]);
79
                //Remove all U2F keys
80
                foreach($entity->getU2FKeys() as $key) {
81
                    $em->remove($key);
82
                }
83
                //Invalidate trusted devices
84
                $entity->invalidateTrustedDeviceTokens();
85
                $em->flush();
86
87
                $this->addFlash('success', 'user.edit.reset_success');
88
            } else {
89
                $this->addFlash('danger', 'csfr_invalid');
90
            }
91
        }
92
93
        return $this->_edit($entity, $request, $em);
94
    }
95
96
    /**
97
     * @Route("/new", name="user_new")
98
     * @Route("/")
99
     *
100
     * @return Response
101
     */
102
    public function new(Request $request, EntityManagerInterface $em, EntityImporter $importer)
103
    {
104
        return $this->_new($request, $em, $importer);
105
    }
106
107
    /**
108
     * @Route("/{id}", name="user_delete", methods={"DELETE"}, requirements={"id"="\d+"})
109
     */
110
    public function delete(Request $request, User $entity, StructuralElementRecursionHelper $recursionHelper)
111
    {
112
        if (User::ID_ANONYMOUS === $entity->getID()) {
113
            throw new \InvalidArgumentException('You can not delete the anonymous user! It is needed for permission checking without a logged in user');
114
        }
115
116
        return $this->_delete($request, $entity, $recursionHelper);
117
    }
118
119
    /**
120
     * @Route("/export", name="user_export_all")
121
     *
122
     * @param SerializerInterface $serializer
123
     *
124
     * @return Response
125
     */
126
    public function exportAll(EntityManagerInterface $em, EntityExporter $exporter, Request $request)
127
    {
128
        return $this->_exportAll($em, $exporter, $request);
129
    }
130
131
    /**
132
     * @Route("/{id}/export", name="user_export")
133
     *
134
     * @param AttachmentType $entity
135
     *
136
     * @return Response
137
     */
138
    public function exportEntity(User $entity, EntityExporter $exporter, Request $request)
139
    {
140
        return $this->_exportEntity($entity, $exporter, $request);
141
    }
142
143
    /**
144
     * @Route("/info", name="user_info_self")
145
     * @Route("/{id}/info")
146
     */
147
    public function userInfo(?User $user, Packages $packages)
148
    {
149
        //If no user id was passed, then we show info about the current user
150
        if (null === $user) {
151
            $user = $this->getUser();
152
153
        } else {
154
            //Else we must check, if the current user is allowed to access $user
155
            $this->denyAccessUnlessGranted('read', $user);
156
        }
157
158
        if ($this->getParameter('use_gravatar')) {
159
            $avatar = $this->getGravatar($user->getEmail(), 200, 'identicon');
160
        } else {
161
            $avatar = $packages->getUrl('/img/default_avatar.png');
162
        }
163
164
        //Show permissions to user
165
        $builder = $this->createFormBuilder()->add('permissions', PermissionsType::class, [
166
            'mapped' => false,
167
            'disabled' => true,
168
            'inherit' => true,
169
            'data' => $user,
170
        ]);
171
172
        return $this->render('Users/user_info.html.twig', [
173
            'user' => $user,
174
            'avatar' => $avatar,
175
            'form' => $builder->getForm()->createView(),
176
        ]);
177
    }
178
179
    /**
180
     * Get either a Gravatar URL or complete image tag for a specified email address.
181
     *
182
     * @param string $email The email address
183
     * @param string $s     Size in pixels, defaults to 80px [ 1 - 2048 ]
184
     * @param string $d     Default imageset to use [ 404 | mm | identicon | monsterid | wavatar ]
185
     * @param string $r     Maximum rating (inclusive) [ g | pg | r | x ]
186
     * @param bool   $img   True to return a complete IMG tag False for just the URL
187
     * @param array  $atts  Optional, additional key/value attributes to include in the IMG tag
188
     *
189
     * @return string containing either just a URL or a complete image tag
190
     * @source https://gravatar.com/site/implement/images/php/
191
     */
192
    public function getGravatar(?string $email, int $s = 80, string $d = 'mm', string $r = 'g', bool $img = false, array $atts = [])
193
    {
194
        if (null === $email) {
195
            return '';
196
        }
197
198
        $url = 'https://www.gravatar.com/avatar/';
199
        $url .= md5(strtolower(trim($email)));
200
        $url .= "?s=$s&d=$d&r=$r";
201
        if ($img) {
202
            $url = '<img src="'.$url.'"';
203
            foreach ($atts as $key => $val) {
204
                $url .= ' '.$key.'="'.$val.'"';
205
            }
206
            $url .= ' />';
207
        }
208
209
        return $url;
210
    }
211
}
212