Compare commits
13 Commits
577dee227d
...
c6d4a871fa
Author | SHA1 | Date | |
---|---|---|---|
c6d4a871fa | |||
9f23dfa0eb | |||
f12f9dda12 | |||
b2972fec3e | |||
18c7c33ffb | |||
68236e1571 | |||
fe47746c1f | |||
edfe6936f5 | |||
ea322dc2ac | |||
8d97ab0345 | |||
133d99d297 | |||
96abea4198 | |||
368b4fbcd3 |
BIN
assets/img/pinpoints/black-pinpoint-icon.png
Normal file
BIN
assets/img/pinpoints/black-pinpoint-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
BIN
assets/img/pinpoints/blue-pinpoint-icon.png
Normal file
BIN
assets/img/pinpoints/blue-pinpoint-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
assets/img/pinpoints/green-pinpoint-icon.png
Normal file
BIN
assets/img/pinpoints/green-pinpoint-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
assets/img/pinpoints/red-pinpoint-icon.png
Normal file
BIN
assets/img/pinpoints/red-pinpoint-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
assets/img/pinpoints/yellow-pinpoint-icon.png
Normal file
BIN
assets/img/pinpoints/yellow-pinpoint-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
@ -14,6 +14,7 @@
|
||||
"doctrine/orm": "^3.3",
|
||||
"phpdocumentor/reflection-docblock": "^5.4",
|
||||
"phpstan/phpdoc-parser": "^1.33",
|
||||
"symfony-cmf/slugifier-api": "^2.1",
|
||||
"symfony/asset": "7.2.*",
|
||||
"symfony/asset-mapper": "7.2.*",
|
||||
"symfony/console": "7.2.*",
|
||||
|
@ -79,4 +79,7 @@ return [
|
||||
'underscore' => [
|
||||
'version' => '1.5.2',
|
||||
],
|
||||
'chartjs' => [
|
||||
'version' => '0.3.24',
|
||||
],
|
||||
];
|
||||
|
@ -12,6 +12,7 @@ use App\Form\UserFormType;
|
||||
use App\Libs\Breadcrumb;
|
||||
use App\Libs\NavList;
|
||||
use App\Repository\UserRepository;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@ -20,6 +21,7 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\CurrentUser;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use Symfony\Component\String\Slugger\SluggerInterface;
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
class AdminController extends AbstractController
|
||||
@ -96,8 +98,11 @@ class AdminController extends AbstractController
|
||||
}
|
||||
|
||||
#[Route('/add-user', name: 'app_add_user')]
|
||||
public function addUser(Request $request, #[CurrentUser()] User $admin): Response
|
||||
{
|
||||
public function addUser(
|
||||
Request $request,
|
||||
#[CurrentUser()] User $admin,
|
||||
SluggerInterface $slugger
|
||||
): Response {
|
||||
$this->denyAccessUnlessGranted('ROLE_ADMIN');
|
||||
$this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($admin);
|
||||
$this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($admin);
|
||||
@ -141,8 +146,22 @@ class AdminController extends AbstractController
|
||||
->setRate($form->get('rate')->getData())
|
||||
->setLevel($form->get('level')->getData())
|
||||
->setCompany($admin->getCompany())
|
||||
->setPasswordChanged(new DateTime())
|
||||
;
|
||||
|
||||
if ($form->get('imageName')->getData()) {
|
||||
/** @var \Symfony\Component\HttpFoundation\File\UploadedFile $file */
|
||||
$file = $form['imageName']->getData();
|
||||
$destination = $this->getParameter('kernel.project_dir').'/public/uploads/user_images/';
|
||||
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
|
||||
$newFilename = $slugger->slug($originalFilename).'-'.uniqid().'.'.$file->guessExtension();
|
||||
$file->move(
|
||||
$destination,
|
||||
$newFilename
|
||||
);
|
||||
|
||||
$user->setImageName($newFilename);
|
||||
}
|
||||
|
||||
$msg = MessageFactory::createUser($admin, $user, 'Welcome', "Welcome to CM Tracker");
|
||||
|
||||
|
@ -71,17 +71,21 @@ class CommunityResourceController extends AbstractController
|
||||
$rcs = $this->entityManager->getRepository(CommunityResource::class)->findAll();
|
||||
|
||||
$map = new Map('default');
|
||||
$map->center(new Point(39.768502, -86.157918))
|
||||
->zoom(9)
|
||||
$map->center(new Point($_ENV['MAP_CENTER_LAT'], $_ENV['MAP_CENTER_LON']))
|
||||
->zoom($_ENV['MAP_ZOOM_LEVEL'])
|
||||
;
|
||||
|
||||
foreach ($rcs as $rsc) {
|
||||
/** @var CommunityResource $rsc */
|
||||
$map->addMarker(new Marker(
|
||||
position: new Point($rsc->getLat(), $rsc->getLon()),
|
||||
title: $rsc->getName(),
|
||||
infoWindow: new InfoWindow(
|
||||
content: "{$rsc->getName()}<br>{$rsc->getAddress()}, {$rsc->getCity()}, {$rsc->getState()->value} {$rsc->getZip()}<br>Services: " . $rsc->getServicesAvailable()
|
||||
)
|
||||
),
|
||||
extra: [
|
||||
'type' => ''
|
||||
]
|
||||
));
|
||||
}
|
||||
|
||||
@ -92,6 +96,7 @@ class CommunityResourceController extends AbstractController
|
||||
[
|
||||
'map' => $map,
|
||||
'breadcrumbs' => [
|
||||
new Breadcrumb($this->generateUrl('app_community_resource'), 'List Resources'),
|
||||
new Breadcrumb('#', 'Community Resources')
|
||||
],
|
||||
'notifications' => $this->msgs,
|
||||
|
@ -6,13 +6,23 @@ use App\Entity\Messages;
|
||||
use App\Entity\User;
|
||||
use App\Libs\Breadcrumb;
|
||||
use App\Libs\NavList;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FileType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\CurrentUser;
|
||||
use Symfony\Component\String\Slugger\SluggerInterface;
|
||||
use Vich\UploaderBundle\Entity\File;
|
||||
|
||||
class DefaultController extends AbstractController
|
||||
{
|
||||
@ -56,20 +66,106 @@ class DefaultController extends AbstractController
|
||||
],
|
||||
'notifications' => $this->msgs,
|
||||
'notificationCount' => $this->notificationCount,
|
||||
'milesTravelledYTD' => 0,
|
||||
'milesTravelled30Days' => 0,
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[Route('/profile', name: 'app_profile')]
|
||||
public function profile(#[CurrentUser()] User $user): Response
|
||||
{
|
||||
public function profile(
|
||||
Request $request,
|
||||
#[CurrentUser()] User $user,
|
||||
SluggerInterface $slugger
|
||||
): Response {
|
||||
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
|
||||
$this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user);
|
||||
$this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user);
|
||||
|
||||
$this->navLinks['profile'] = NavList::PRESENT_LINK;
|
||||
|
||||
$form = $this->createFormBuilder($user)
|
||||
->add('name', TextType::class, [
|
||||
'label' => 'Name',
|
||||
'label_attr' => ['class' => 'form-label'],
|
||||
'attr' => ['class' => 'form-control'],
|
||||
])
|
||||
->add('email', EmailType::class, [
|
||||
'label' => 'Email',
|
||||
'label_attr' => ['class' => 'form-label'],
|
||||
'attr' => ['class' => 'form-control'],
|
||||
])
|
||||
->add('password', RepeatedType::class, [
|
||||
'type' => PasswordType::class,
|
||||
'invalid_message' => 'The password fields must match.',
|
||||
'required' => false,
|
||||
'mapped' => false,
|
||||
'first_options' => ['label' => 'Password', 'label_attr' => ['class' => 'form-label']],
|
||||
'second_options' => ['label' => 'Repeat Password', 'label_attr' => ['class' => 'form-label']],
|
||||
])
|
||||
->add('imageName', FileType::class, [
|
||||
'label' => 'Profile Picture',
|
||||
'required' => false,
|
||||
'mapped' => false
|
||||
])
|
||||
->add('submit', SubmitType::class, [
|
||||
'label' => 'Save Profile',
|
||||
'attr' => ['class' => 'btn btn-lg bg-gradient-dark btn-lg w-100 mt-4 mb-0']
|
||||
])
|
||||
->getForm()
|
||||
;
|
||||
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$firstPassword = $form->get('password')['first']->getData();
|
||||
$secondPassword = $form->get('password')['second']->getData();
|
||||
|
||||
if ($firstPassword !== $secondPassword) {
|
||||
$this->addFlash('danger', 'The password fields must match.');
|
||||
return $this->redirectToRoute('app_profile');
|
||||
}
|
||||
|
||||
$plainPassword = $form->get('password')['first']->getData();
|
||||
|
||||
if ($plainPassword) {
|
||||
$user->setPassword(
|
||||
$this->userPasswordHasher->hashPassword(
|
||||
$user,
|
||||
$plainPassword
|
||||
)
|
||||
);
|
||||
$user->setPasswordChanged(new DateTime())
|
||||
}
|
||||
|
||||
if ($form['imageName']->getData()) {
|
||||
/** @var \Symfony\Component\HttpFoundation\File\UploadedFile $file */
|
||||
$file = $form['imageName']->getData();
|
||||
$destination = $this->getParameter('kernel.project_dir').'/public/uploads/user_images/';
|
||||
|
||||
if (!file_exists($destination)) {
|
||||
mkdir($destination, 0775);
|
||||
}
|
||||
|
||||
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
|
||||
$newFilename = $slugger->slug($originalFilename).'-'.uniqid().'.'.$file->guessExtension();
|
||||
$file->move(
|
||||
$destination,
|
||||
$newFilename
|
||||
);
|
||||
|
||||
$user->setImageName($newFilename);
|
||||
}
|
||||
|
||||
$this->entityManager->persist($user);
|
||||
$this->entityManager->flush();
|
||||
|
||||
return $this->redirectToRoute('app_dashboard');
|
||||
} elseif ($form->isSubmitted() && !$form->isValid()) {
|
||||
$this->addFlash('danger', 'The form contains errors.');
|
||||
}
|
||||
|
||||
return $this->render(
|
||||
'internal/profile.html.twig',
|
||||
array_merge(
|
||||
@ -80,8 +176,16 @@ class DefaultController extends AbstractController
|
||||
],
|
||||
'notifications' => $this->msgs,
|
||||
'notificationCount' => $this->notificationCount,
|
||||
'currentUser' => $user,
|
||||
'form' => $form->createView(),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[Route('/uploads/user_images/{imageName}', name: 'app_user_image')]
|
||||
public function displayUserImage(string $imageName): Response
|
||||
{
|
||||
return new BinaryFileResponse($this->getParameter('kernel.project_dir')."/public/uploads/user_images/{$imageName}");
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ class ItineraryController extends AbstractController
|
||||
#[Route('/itinerary/report', name: 'app_report_itinerary')]
|
||||
public function reportItinerary(Request $request, #[CurrentUser()] ?User $user): Response
|
||||
{
|
||||
$this->navLinks['case_itinerary'] = NavList::PRESENT_LINK;
|
||||
|
||||
$this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user);
|
||||
$this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user);
|
||||
|
||||
@ -76,6 +78,8 @@ class ItineraryController extends AbstractController
|
||||
#[Route('/itinerary/map', name: 'app_map_itinerary')]
|
||||
public function mapItinerary(Request $request, #[CurrentUser()] ?User $user): Response
|
||||
{
|
||||
$this->navLinks['case_itinerary'] = NavList::PRESENT_LINK;
|
||||
|
||||
$case = null;
|
||||
if ($request->getPayload()->get('caseId')) {
|
||||
$case = $this->entityManager->getRepository(MemberCase::class)->find($request->getPayload()->get('caseId'));
|
||||
@ -93,8 +97,8 @@ class ItineraryController extends AbstractController
|
||||
]);
|
||||
|
||||
$map = new Map('default');
|
||||
$map->center(new Point(39.768502, -86.157918))
|
||||
->zoom(9)
|
||||
$map->center(new Point($_ENV['MAP_CENTER_LAT'], $_ENV['MAP_CENTER_LON']))
|
||||
->zoom($_ENV['MAP_ZOOM_LEVEL'])
|
||||
;
|
||||
|
||||
$total_distance = 0;
|
||||
@ -148,7 +152,7 @@ class ItineraryController extends AbstractController
|
||||
[
|
||||
'breadcrumbs' => [
|
||||
new Breadcrumb($this->generateUrl('app_my_cases'), 'My Cases'),
|
||||
new Breadcrumb($this->generateUrl('app_itinerary_report'), 'Itinerary Report'),
|
||||
new Breadcrumb($this->generateUrl('app_report_itinerary'), 'Itinerary Report'),
|
||||
],
|
||||
'notifications' => $this->msgs,
|
||||
'notificationCount' => $this->notificationCount,
|
||||
|
@ -14,10 +14,13 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
use Vich\UploaderBundle\Entity\File;
|
||||
use Vich\UploaderBundle\Mapping\Annotation as Vich;
|
||||
|
||||
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_USERNAME', fields: ['username'])]
|
||||
#[UniqueEntity(fields: ['username'], message: 'There is already an account with this username')]
|
||||
#[Vich\Uploadable]
|
||||
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
{
|
||||
#[ORM\Id]
|
||||
@ -80,6 +83,15 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
#[ORM\OneToMany(targetEntity: UserCase::class, mappedBy: 'user')]
|
||||
private Collection $userCases;
|
||||
|
||||
#[Vich\UploadableField(mapping: 'profile_image', fileNameProperty: 'imageName', size: 'size', mimeType: 'mimeType', originalName: 'originalName', dimensions: 'dimensions')]
|
||||
private ?File $imageFile = null;
|
||||
|
||||
#[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
|
||||
private ?string $imageName = null;
|
||||
|
||||
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
|
||||
private ?\DateTimeInterface $passwordChanged = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->userCases = new ArrayCollection();
|
||||
@ -351,4 +363,40 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
|
||||
return $jobs;
|
||||
}
|
||||
|
||||
public function getImageFile(): ?File
|
||||
{
|
||||
return $this->imageFile;
|
||||
}
|
||||
|
||||
public function setImageFile(?File $imageFile): static
|
||||
{
|
||||
$this->imageFile = $imageFile;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getImageName(): ?string
|
||||
{
|
||||
return $this->imageName;
|
||||
}
|
||||
|
||||
public function setImageName(?string $imageName): static
|
||||
{
|
||||
$this->imageName = $imageName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPasswordChanged(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->passwordChanged;
|
||||
}
|
||||
|
||||
public function setPasswordChanged(\DateTimeInterface $passwordChanged): static
|
||||
{
|
||||
$this->passwordChanged = $passwordChanged;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -27,8 +27,10 @@
|
||||
<link
|
||||
rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0"/>
|
||||
<!-- CSS Files -->
|
||||
<link id="pagestyle" href="{{ asset('css/material-dashboard.css') }}?v=3.2.0" rel="stylesheet"/> {% block stylesheets %}{% endblock %}
|
||||
<link id="pagestyle" href="{{ asset('css/material-dashboard.css') }}?v=3.2.0" rel="stylesheet"/>
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
|
||||
{% block stylesheets %}{% endblock %}
|
||||
{% block page_css %}{% endblock %}
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-200"> {% block body %}{% endblock %}
|
||||
|
@ -83,6 +83,10 @@
|
||||
<label for='user_form_rate' class='form-label'>Rate</label>
|
||||
<input type='number' name='{{ field_name(form.rate) }}' id='user_form_rate' class='form-control' min='0' step='0.01'/>
|
||||
</div>
|
||||
<div class='input-group input-group-outline mb-3'>
|
||||
<label for='user_form_file' class='form-label'>Profile Image</label>
|
||||
<input type='file' name='{{ field_name(form.imageName) }}' id='user_form_file' class='form-control'/>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<button type="submit" class="btn btn-lg bg-gradient-dark btn-lg w-100 mt-4 mb-0">Add User</button>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<div class="container-fluid py-2">
|
||||
<div>
|
||||
Totals:
|
||||
{{ total_distance }}
|
||||
{{ total_distance }}mi
|
||||
/
|
||||
{{ total_duration }}
|
||||
</div>
|
||||
|
@ -114,10 +114,5 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sidenav-footer position-absolute w-100 bottom-0 ">
|
||||
<div class="mx-3">
|
||||
<a class="btn btn-outline-dark mt-4 w-100" href="https://www.creative-tim.com/learning-lab/bootstrap/overview/material-dashboard?ref=sidebarfree" type="button">Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
{% endblock %}
|
||||
|
@ -6,7 +6,7 @@
|
||||
<div class='ms-md-auto pe-md-3 d-flex align-items-left' id='messages'>
|
||||
{% for label, messages in app.flashes %}
|
||||
{% for message in messages %}
|
||||
<div class="flash-{{ label }} bg-gradient-info text-white">
|
||||
<div class="flash-{{ label }} bg-gradient-{{ label }} text-white">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
@ -8,5 +8,56 @@
|
||||
|
||||
<main class="main-content position-relative max-height-vh-100 h-100 border-radius-lg ">
|
||||
{{ block('topnav', 'internal/libs/top-nav.html.twig') }}
|
||||
{{ form_start(form) }}
|
||||
|
||||
{{ form_errors(form) }}
|
||||
<div class='container'>
|
||||
<div class='row'>
|
||||
<div class='col' id='profile-image'>
|
||||
<input type='hidden' name='id' value='{{ currentUser.id }}'/>
|
||||
<img class='profile-image' src='{% if currentUser.imageName %}/uploads/user_images/{{ currentUser.imageName }}{% endif %}'/>
|
||||
|
||||
{{ form_row(form.imageName) }}
|
||||
</div>
|
||||
<div class='col'>
|
||||
<div class='input-group input-group-outline mb-3 is-filled'>
|
||||
<label for='profile_form_name' class='form-label'>Name</label>
|
||||
<input type='text' name='{{ field_name(form.name) }}' id='profile_form_name' class='form-control' value='{{ currentUser.name }}'/>
|
||||
</div>
|
||||
|
||||
<div class='input-group input-group-outline mb-3 is-filled'>
|
||||
<label for='profile_form_email' class='form-label'>Email</label>
|
||||
<input type='email' name='{{ field_name(form.email) }}' id='profile_form_email' class='form-control' value='{{ currentUser.email }}'/>
|
||||
</div>
|
||||
|
||||
<div class='input-group input-group-outline mb-3'>
|
||||
<label for='profile_form_password' class='form-label'>Password</label>
|
||||
<input type='password' name='{{ field_name(form.password.first) }}' id='profile_form_password' class='form-control' autocomplete='new-password'/>
|
||||
</div>
|
||||
<div class='input-group input-group-outline mb-3'>
|
||||
<label for='profile_form_confirmPassword' class='form-label'>Confirm Password</label>
|
||||
<input type='password' name='{{ field_name(form.password.second) }}' id='profile_form_confirmPassword' class='form-control' autocomplete='new-password'/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='row'>
|
||||
<div class='col text-center'>
|
||||
<div class='input-group input-group-outline mb-3'>
|
||||
{{ form_row(form.submit) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ form_end(form) }}
|
||||
</main>
|
||||
{% endblock %}
|
||||
|
||||
{% block page_css %}
|
||||
<style rel='stylesheet'>
|
||||
.profile-image {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
Reference in New Issue
Block a user