Skip to content
Snippets Groups Projects
Commit 67824f1a authored by Eirik Morland's avatar Eirik Morland
Browse files

Issue #3429528: Add a page for listing members (and admins)

parent 5c457edf
No related branches found
No related tags found
1 merge request!42Add the theme hook and templates
Pipeline #126015 passed with warnings
<?php
namespace Drupal\violinist_teams\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Url;
use Drupal\violinist_teams\TeamNode;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Controller for the team members page.
*/
final class MembersController extends ControllerBase {
public function __construct(
private EntityTypeManagerInterface $entity_type_manager,
private ModuleHandlerInterface $module_handler) {}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager'),
$container->get('module_handler'),
);
}
/**
* Build the team members page.
*/
public function build(TeamNode $team) {
$build = [];
$build['invite'] = [
'#type' => 'link',
'#title' => $this->t('Invite users via link'),
'#url' => Url::fromRoute('violinist_teams.team_members_invite', [
'team' => $team->id(),
]),
'#attributes' => [
'class' => [
'btn',
'btn-success',
'use-ajax',
],
'data-dialog-type' => 'modal',
],
];
// Then let's also show a table of all the users, and the status they have.
$admins = $team->getAdministrators();
$members = $team->getMembers();
$rows = [];
$ids_added = [];
foreach ($admins as $admin) {
$ids_added[] = $admin->id();
$rows[] = [
'#theme' => 'violinist_teams_team_member_row',
'#user' => $admin,
'#role' => $this->t('Administrator'),
];
}
foreach ($members as $member) {
if (in_array($member->id(), $ids_added)) {
continue;
}
$rows[] = [
'#theme' => 'violinist_teams_team_member_row',
'#user' => $member,
'#role' => $this->t('Member'),
];
}
$build['members'] = [
'#theme' => 'violinist_teams_team_members_table',
'#rows' => $rows,
];
return $build;
}
}
<?php
declare(strict_types=1);
namespace Drupal\violinist_teams\Form;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\CurrentRouteMatch;
use Drupal\Core\Url;
use Drupal\violinist_teams\TeamManager;
use Drupal\violinist_teams\TeamNode;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a Violinist teams form.
*/
final class InviteMembersForm extends FormBase {
/**
* Team node.
*
* @var \Drupal\violinist_teams\TeamNode
*/
protected $team;
/**
* The constructor.
*/
public function __construct(CurrentRouteMatch $routeMatch,
private TeamManager $teamManager
) {
$this->routeMatch = $routeMatch;
$team = $this->routeMatch->getParameter('team');
if ($team instanceof TeamNode) {
$this->team = $team;
}
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('current_route_match'),
$container->get('violinist_teams.team_manager')
);
}
/**
* {@inheritdoc}
*/
public function getFormId(): string {
return 'violinist_teams_team_settings';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, TeamNode $team = NULL): array {
if (!$team instanceof TeamNode) {
return $form;
}
$form['team'] = [
'#type' => 'value',
'#value' => $team,
];
$form['description'] = [
'#prefix' => '<p class="my-2">',
'#suffix' => '</p>',
'#markup' => $this->t('Invite users by sharing the one-time use link you can create below. When visiting the link, they will be able to log in with any provider.'),
];
$form['role'] = [
'#type' => 'select',
'#title' => $this->t('Role'),
'#options' => [
'member' => $this->t('Member'),
'admin' => $this->t('Administrator'),
],
'#default_value' => 'member',
];
$form['invite_link'] = [
'#prefix' => '<div id="invite_link" class="hidden">',
'#suffix' => '</div>',
'#theme' => 'violinist_teams_invite_link_textfield',
];
$form['cancel'] = [
'#type' => 'link',
'#title' => $this->t('Cancel'),
'#url' => Url::fromRoute('violinist_teams.team_members', [
'team' => $team->id(),
], [
'attributes' => [
'class' => [
'btn',
'btn-danger',
'inline-block',
],
],
]),
];
$form['invite'] = [
'#type' => 'submit',
'#value' => $this->t('Generate and copy link'),
'#ajax' => [
'callback' => '::ajaxSubmit',
],
];
return $form;
}
/**
* Ajax callback for the invite.
*/
public function ajaxSubmit(array &$form, FormStateInterface $form_state) {
$timestamp = time();
$team = $form_state->getValue('team');
$member_type = $form_state->getValue('role');
$form['invite_link']['#link'] = Url::fromRoute('violinist_teams.invite_accept', [
'team_id' => $team->id(),
'timestamp' => time(),
'membership_type' => $member_type,
'hash' => $this->teamManager->getInviteHash($team, $member_type, $timestamp),
])->setAbsolute()->toString();
$response = new AjaxResponse();
$response->addCommand(new ReplaceCommand('#invite_link', $form['invite_link']));
$response->addCommand(new InvokeCommand('#invite_link', 'show'));
return $response;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
}
}
<input type="text" readonly disabled value="{{ link }}">
<tr class="bg-white hover:bg-gray-50 dark:hover:bg-gray-600">
<th scope="row" class="flex items-center px-6 py-4 text-gray-900 whitespace-nowrap dark:text-white">
<div class="ps-3">
<div class="text-base font-semibold">{{ name }}</div>
<div class="font-normal text-gray-500">{{ mail }}</div>
</div>
</th>
<td class="px-6 py-4">
{{ role }}
</td>
{# <td class="px-6 py-4">#}
{# #}{# todo: Fix the edit link #}
{# </td>#}
</tr>
<div class="relative overflow-x-auto mt-5">
<div class="flex items-center justify-between flex-column flex-wrap md:flex-row space-y-4 md:space-y-0 pb-4 bg-white dark:bg-gray-900">
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" class="px-6 py-3">
Name
</th>
<th scope="col" class="px-6 py-3">
Role
</th>
</tr>
</thead>
<tbody>
{% for row in rows %}
{{ row }}
{% endfor %}
</tbody>
</table>
</div>
......@@ -9,6 +9,45 @@ use Drupal\Core\Entity\EntityInterface;
use Drupal\user\UserInterface;
use Drupal\violinist_teams\TeamNode;
/**
* Implements hook_theme().
*/
function violinist_teams_theme($existing, $type, $theme, $path) {
return [
'violinist_teams_invite_link_textfield' => [
'variables' => [
'link' => '',
],
],
'violinist_teams_team_members_table' => [
'variables' => [
'rows' => [],
],
],
'violinist_teams_team_member_row' => [
'variables' => [
'user' => NULL,
'role' => 'member',
],
],
];
}
/**
* Implements hook_preprocess_HOOK().
*/
function violinist_teams_preprocess_violinist_teams_team_member_row(&$variables) {
if (empty($variables['user'])) {
return;
}
$user = $variables['user'];
if (!$user instanceof UserInterface) {
return;
}
$variables['name'] = $user->getDisplayName();
$variables['mail'] = $user->getEmail();
}
/**
* Implements hook_entity_bundle_info_alter().
*/
......
......@@ -34,6 +34,30 @@ violinist_teams.team_settings:
requirements:
_custom_access: '\Drupal\violinist_teams\Controller\TeamSettingsController::accessTeamSettings'
violinist_teams.team_members:
path: '/teams/{team}/members'
defaults:
_title: 'Team Members'
_controller: '\Drupal\violinist_teams\Controller\MembersController::build'
options:
parameters:
team:
type: entity:node
requirements:
_violinist_teams_access: 'admin_or_member'
violinist_teams.team_members_invite:
path: '/teams/{team}/members/invite'
defaults:
_title: 'Invite Team Members'
_form: 'Drupal\violinist_teams\Form\InviteMembersForm'
options:
parameters:
team:
type: entity:node
requirements:
_violinist_teams_access: 'admin'
violinist_teams.invite_accept:
path: '/violinist-teams/invite/{team_id}/{membership_type}/{timestamp}/{hash}'
defaults:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment