Skip to content

Commit 59040eb

Browse files
authored
Merge pull request #18 from CuBoulder/issue/1723
TOS fields and form
2 parents 59c2f6d + 20db9f1 commit 59040eb

8 files changed

+354
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
langcode: en
2+
status: true
3+
dependencies:
4+
config:
5+
- field.storage.user.field_accepted_date
6+
module:
7+
- user
8+
- datetime
9+
id: user.user.field_accepted_date
10+
field_name: field_accepted_date
11+
entity_type: user
12+
bundle: user
13+
label: 'TOS Accepted Date'
14+
description: 'The date and time when the user accepted the Terms of Service.'
15+
required: false
16+
translatable: true
17+
default_value: { }
18+
default_value_callback: ''
19+
settings:
20+
timezone_override: ''
21+
field_type: datetime
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
langcode: en
2+
status: true
3+
dependencies:
4+
config:
5+
- field.storage.user.field_tos_acceptance
6+
module:
7+
- user
8+
id: user.user.field_tos_acceptance
9+
field_name: field_tos_acceptance
10+
entity_type: user
11+
bundle: user
12+
label: 'Terms of Service Accepted'
13+
description: 'Indicates whether the user has accepted the Terms of Service.'
14+
required: false
15+
translatable: true
16+
default_value:
17+
-
18+
value: 0
19+
default_value_callback: ''
20+
settings: { }
21+
field_type: boolean
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
langcode: en
2+
status: true
3+
dependencies:
4+
module:
5+
- user
6+
- datetime
7+
id: user.field_accepted_date
8+
field_name: field_accepted_date
9+
entity_type: user
10+
type: datetime
11+
settings:
12+
datetime_type: datetime
13+
module: core
14+
locked: false
15+
cardinality: 1
16+
translatable: true
17+
indexes: { }
18+
persist_with_no_fields: false
19+
custom_storage: false
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
langcode: en
2+
status: true
3+
dependencies:
4+
module:
5+
- user
6+
id: user.field_tos_acceptance
7+
field_name: field_tos_acceptance
8+
entity_type: user
9+
type: boolean
10+
settings:
11+
on_label: 'Accepted'
12+
off_label: 'Not Accepted'
13+
module: core
14+
locked: false
15+
cardinality: 1
16+
translatable: true
17+
indexes: { }
18+
persist_with_no_fields: false
19+
custom_storage: false
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
namespace Drupal\ucb_user_invite\Controller;
4+
5+
use Drupal\Core\Controller\ControllerBase;
6+
use Drupal\Core\Datetime\DrupalDateTime;
7+
use Drupal\Core\Session\AccountProxyInterface;
8+
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
9+
use Drupal\user\UserStorageInterface;
10+
use Symfony\Component\DependencyInjection\ContainerInterface;
11+
use Symfony\Component\HttpFoundation\JsonResponse;
12+
use Symfony\Component\HttpFoundation\Request;
13+
14+
/**
15+
* Controller for handling TOS acceptance.
16+
*/
17+
class TosAcceptanceController extends ControllerBase {
18+
19+
/**
20+
* The current user.
21+
*
22+
* @var \Drupal\Core\Session\AccountProxyInterface
23+
*/
24+
protected $currentUser;
25+
26+
/**
27+
* The user storage.
28+
*
29+
* @var \Drupal\user\UserStorageInterface
30+
*/
31+
protected $userStorage;
32+
33+
/**
34+
* Constructs a TosAcceptanceController object.
35+
*
36+
* @param \Drupal\Core\Session\AccountProxyInterface $current_user
37+
* The current user.
38+
* @param \Drupal\user\UserStorageInterface $user_storage
39+
* The user storage.
40+
*/
41+
public function __construct(AccountProxyInterface $current_user, UserStorageInterface $user_storage) {
42+
$this->currentUser = $current_user;
43+
$this->userStorage = $user_storage;
44+
}
45+
46+
/**
47+
* {@inheritdoc}
48+
*/
49+
public static function create(ContainerInterface $container) {
50+
return new static(
51+
$container->get('current_user'),
52+
$container->get('entity_type.manager')->getStorage('user')
53+
);
54+
}
55+
56+
/**
57+
* Handles TOS acceptance.
58+
*
59+
* @param \Symfony\Component\HttpFoundation\Request $request
60+
* The request object.
61+
*
62+
* @return \Symfony\Component\HttpFoundation\JsonResponse
63+
* A JSON response.
64+
*/
65+
public function accept(Request $request) {
66+
$user = $this->userStorage->load($this->currentUser->id());
67+
68+
if (!$user) {
69+
return new JsonResponse([
70+
'success' => FALSE,
71+
'message' => 'User not found.',
72+
], 404);
73+
}
74+
75+
if (!$user->hasField('field_tos_acceptance')) {
76+
return new JsonResponse([
77+
'success' => FALSE,
78+
'message' => 'TOS acceptance field not found.',
79+
], 500);
80+
}
81+
82+
// Set TOS accepted to TRUE.
83+
$user->set('field_tos_acceptance', 1);
84+
85+
// Update the accepted_date field if it exists.
86+
if ($user->hasField('field_accepted_date')) {
87+
// Create a DrupalDateTime object in UTC timezone.
88+
$date = new DrupalDateTime('now', DateTimeItemInterface::STORAGE_TIMEZONE);
89+
// Format according to datetime storage format.
90+
$formatted_date = $date->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT);
91+
$user->set('field_accepted_date', $formatted_date);
92+
}
93+
94+
$user->save();
95+
96+
return new JsonResponse([
97+
'success' => TRUE,
98+
'message' => 'Terms of Service accepted successfully.',
99+
]);
100+
}
101+
102+
}

ucb_user_invite.install

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,115 @@ function ucb_user_invite_update_9502() {
8888
$field_config->save();
8989
}
9090
}
91+
92+
/**
93+
* Adds the 'field_tos_acceptance' and 'field_accepted_date' fields to the User entity.
94+
*
95+
* Introduced to support Terms of Service acceptance tracking.
96+
*/
97+
function ucb_user_invite_update_9503() {
98+
$entity_type = 'user';
99+
$bundle = 'user';
100+
101+
// Create field_tos_acceptance (boolean).
102+
$tos_field_name = 'field_tos_acceptance';
103+
$tos_field_storage = \Drupal::entityTypeManager()
104+
->getStorage('field_storage_config')
105+
->load($entity_type . '.' . $tos_field_name);
106+
107+
if (!$tos_field_storage) {
108+
$tos_field_storage = \Drupal::entityTypeManager()
109+
->getStorage('field_storage_config')
110+
->create([
111+
'field_name' => $tos_field_name,
112+
'entity_type' => $entity_type,
113+
'type' => 'boolean',
114+
'settings' => [
115+
'on_label' => 'Accepted',
116+
'off_label' => 'Not Accepted',
117+
],
118+
]);
119+
$tos_field_storage->save();
120+
}
121+
122+
$tos_field_config = \Drupal::entityTypeManager()
123+
->getStorage('field_config')
124+
->load($entity_type . '.' . $bundle . '.' . $tos_field_name);
125+
126+
if (!$tos_field_config) {
127+
$tos_field_config = \Drupal::entityTypeManager()
128+
->getStorage('field_config')
129+
->create([
130+
'field_name' => $tos_field_name,
131+
'entity_type' => $entity_type,
132+
'bundle' => $bundle,
133+
'label' => t('Terms of Service Accepted'),
134+
'description' => t('Indicates whether the user has accepted the Terms of Service.'),
135+
'required' => FALSE,
136+
'default_value' => [
137+
[
138+
'value' => 0,
139+
],
140+
],
141+
]);
142+
$tos_field_config->save();
143+
}
144+
145+
// Create field_accepted_date (datetime).
146+
$date_field_name = 'field_accepted_date';
147+
$date_field_storage = \Drupal::entityTypeManager()
148+
->getStorage('field_storage_config')
149+
->load($entity_type . '.' . $date_field_name);
150+
151+
if (!$date_field_storage) {
152+
$date_field_storage = \Drupal::entityTypeManager()
153+
->getStorage('field_storage_config')
154+
->create([
155+
'field_name' => $date_field_name,
156+
'entity_type' => $entity_type,
157+
'type' => 'datetime',
158+
'settings' => [
159+
'datetime_type' => 'datetime',
160+
],
161+
]);
162+
$date_field_storage->save();
163+
}
164+
165+
$date_field_config = \Drupal::entityTypeManager()
166+
->getStorage('field_config')
167+
->load($entity_type . '.' . $bundle . '.' . $date_field_name);
168+
169+
if (!$date_field_config) {
170+
$date_field_config = \Drupal::entityTypeManager()
171+
->getStorage('field_config')
172+
->create([
173+
'field_name' => $date_field_name,
174+
'entity_type' => $entity_type,
175+
'bundle' => $bundle,
176+
'label' => t('TOS Accepted Date'),
177+
'description' => t('The date and time when the user accepted the Terms of Service.'),
178+
'required' => FALSE,
179+
]);
180+
$date_field_config->save();
181+
}
182+
183+
// Set default value for all existing users to FALSE (0) for tos_acceptance.
184+
$user_storage = \Drupal::entityTypeManager()->getStorage('user');
185+
$query = $user_storage->getQuery()
186+
->accessCheck(FALSE)
187+
->condition('uid', 0, '>');
188+
$uids = $query->execute();
189+
190+
if (!empty($uids)) {
191+
$users = $user_storage->loadMultiple($uids);
192+
foreach ($users as $user) {
193+
if ($user->hasField('field_tos_acceptance')) {
194+
$current_value = $user->get('field_tos_acceptance')->value;
195+
if ($current_value === NULL) {
196+
$user->set('field_tos_acceptance', 0);
197+
$user->save();
198+
}
199+
}
200+
}
201+
}
202+
}

ucb_user_invite.module

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,53 @@ function ucb_user_invite_mail($key, &$message, $params) {
3131
$message['body'] = ['#markup' => $tokenService->replace(strtr($template, $variables), $tokens, $options)];
3232
}
3333
}
34+
35+
/**
36+
* Implements hook_preprocess_page().
37+
*/
38+
function ucb_user_invite_preprocess_page(&$variables) {
39+
// Check if TOS acceptance is enabled in site configuration.
40+
$site_config = \Drupal::config('ucb_site_configuration.settings');
41+
$tos_enabled = $site_config->get('tos_acceptance_enabled');
42+
43+
// If TOS acceptance is not enabled (default is FALSE), don't show the modal.
44+
if (empty($tos_enabled)) {
45+
return;
46+
}
47+
48+
// Only check for logged-in users on user pages.
49+
$route_match = \Drupal::routeMatch();
50+
$route_name = $route_match->getRouteName();
51+
52+
// Check if this is a user page route.
53+
if (in_array($route_name, ['entity.user.canonical', 'user.page'])) {
54+
$current_user = \Drupal::currentUser();
55+
56+
// Only show modal to authenticated users.
57+
if ($current_user->isAuthenticated()) {
58+
$user = \Drupal::entityTypeManager()
59+
->getStorage('user')
60+
->load($current_user->id());
61+
62+
// Check if user has accepted TOS.
63+
if ($user && $user->hasField('field_tos_acceptance')) {
64+
$tos_accepted = $user->get('field_tos_acceptance')->value;
65+
66+
// If TOS not accepted, attach the library to show modal.
67+
if (empty($tos_accepted)) {
68+
$variables['#attached']['library'][] = 'boulder_base/ucb-tos-acceptance';
69+
70+
// TOS URL from Web Central Website.
71+
$tos_url = 'https://www.colorado.edu/webcentral';
72+
73+
// Pass settings to JavaScript.
74+
$variables['#attached']['drupalSettings']['ucb_tos_acceptance'] = [
75+
'show_modal' => TRUE,
76+
'tos_url' => $tos_url,
77+
'accept_url' => Url::fromRoute('ucb_user_invite.tos_acceptance')->toString(),
78+
];
79+
}
80+
}
81+
}
82+
}
83+
}

ucb_user_invite.routing.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,13 @@ ucb_user_invite.settings_form:
1919
_permission: administer user invite
2020
options:
2121
_admin_route: true
22+
23+
ucb_user_invite.tos_acceptance:
24+
path: '/ucb-user-invite/tos-acceptance/accept'
25+
defaults:
26+
_controller: '\Drupal\ucb_user_invite\Controller\TosAcceptanceController::accept'
27+
requirements:
28+
_user_is_logged_in: 'TRUE'
29+
_format: 'json'
30+
_csrf_request_header_token: 'TRUE'
31+
methods: [POST]

0 commit comments

Comments
 (0)