-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enh: Check User Birthday field #67
Conversation
What I've currently not found a way around for is if the birthday field isn't set to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, these AI-generated summaries take more time to read than the PR itself. I would prefer a short compact sentence describing the purpose of the PR than AI blah blah blah :-)
In general, I don't know whether it makes sense to simply lock out users with an early/incorrect date of birth.
I'm currently not sure how we can best implement this check.
models/RegistrationChecks.php
Outdated
// Check if the user's age meets the minimum age requirement | ||
if ($userAge < $minimumAge) { | ||
// Perform logout if the age check fails | ||
Yii::$app->user->logout(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am unsure whether we should simply log out here, e.g. a user could have entered an incorrect date of birth. We would then log them out without further notice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could attempt a redirect or display a error message requesting to contact an Administrator for more information? The problem is the birthday field can always be manipulated when it comes to adding a date because the user must click the checkbox field which they see the age beforehand no?
models/RegistrationChecks.php
Outdated
// Check if the user and their profile property are not null before accessing them | ||
if ($module->showAgeCheck() && $this->user !== null && $this->user->profile !== null) { | ||
// Calculate the user's age | ||
$birthday = $this->user->profile->birthday; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could move this code into a seperate private method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can attempt do to this if required, would you want the call to also be made within this function through a static method or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think a static method will be necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking closer, we'll also have to do something within this class as well else it doesn't really do anything for EVENT_BEFORE_VALIDATE
as the current #67 (comment) throws an error calling for Profile::models
which doesn't exist. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, could maybe the legal
module inject an AgeValidator
for the Birthday field in the profile and make sure that no too young users are created?
Wouldn't that also work if the birthday field is activated in ShowOnRegistration?
I could look into this, although I'm not much of a fan of injections, because if another module were to also be created that injects into the field then there would be a conflict between both injections, so if we were to do this then we'd have to tread carefully doing so. 🤔 |
Thinking about it, it would be much easier to implement if there were a core |
Here's an example for the requested <?php
namespace humhub\modules\legal\validators;
use DateTime;
use Yii;
use yii\base\Model;
use yii\validators\Validator;
/**
* AgeValidator validates that the given value represents an age greater than or equal to a specified minimum age.
*/
class AgeValidator extends Validator
{
/**
* Initializes the validator.
*/
public function init()
{
parent::init();
if ($this->message === null) {
$this->message = Yii::t('LegalModule.base', 'You must be at least {age} years old.', ['age' => Yii::$app->getModule('legal')->getMinimumAge()]);
}
}
/**
* Validates the age of the user based on the given attribute value.
*
* @param \yii\base\Model $model the data model being validated
* @param string $attribute the name of the attribute to be validated
*/
public function validateAttribute($model, $attribute)
{
// Ensure we are validating the birthday attribute during user registration
if ($model instanceof \humhub\modules\user\models\forms\Registration) {
$birthday = $this->user->profile->birthday;
if ($birthday !== null && $birthday != '' && $birthday->format('Y') != '0000') {
$minimumAge = Yii::$app->getModule('legal')->getMinimumAge();
$minimumAgeDate = new DateTime("-{$minimumAge} years");
$today = new DateTime();
$age = $today->diff($birthday)->y;
if ($age < $minimumAge) {
$this->addError($model, $attribute, $this->message, ['age' => $minimumAge]);
}
}
}
}
/**
* Attaches the validator to the Birthday field of the model.
*
* @param \yii\base\Model $model the model to attach the validator to
*/
public static function attachToBirthday($model)
{
$validator = new self();
$validator->validateAttribute($model, 'birthday');
}
} Please make any necessary modifications if needed. |
Couldn't we use the BEFORE_VALIDATE event of the Profile model and do this additional validation? |
Could you provide some documentation for this? |
Here is an example: https://docs.humhub.org/docs/develop/modules-event-handler/#model-validation |
So knowing this, maybe something along the lines of this? Events.php Examples/**
* Performs age validation before the registration form is validated.
*
* @param \yii\base\Event $event the event parameter
* @throws \Exception if an error occurs while performing age validation
*/
public static function onBeforeValidate($event)
{
$registrationForm = $event->sender;
$profile = $registrationForm->models['Profile'];
// Check if $profile is loaded and the birthday attribute is set
if ($profile !== null && isset($profile->birthday)) {
// Option 1: Access birthday directly from profile
$birthday = $profile->birthday;
} else {
// Option 2: Access birthday through user->profile
$birthday = Yii::$app->user->profile->birthday;
}
// Perform age validation using $birthday
$minimumAge = Yii::$app->getModule('legal')->getMinimumAge();
// Check if birthday is set and has a year
if ($birthday !== null && $birthday != '' && $birthday->format('Y') != '0000') {
$minimumAgeDate = new DateTime("-{$minimumAge} years");
$today = new DateTime();
$age = $today->diff($birthday)->y;
if ($age < $minimumAge) {
// Add an error if age is less than the minimum age requirement
$registrationForm->addError('profile', Yii::t('LegalModule.base', 'You must be at least {age} years old.', ['age' => $minimumAge]));
}
}
} config.php Example<?php /** @noinspection MissedFieldInspection */
use humhub\components\Controller;
use humhub\modules\content\widgets\richtext\ProsemirrorRichText;
use humhub\modules\user\models\forms\Registration;
use humhub\widgets\FooterMenu;
use humhub\widgets\LayoutAddons;
use humhub\modules\user\models\Profile;
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
return [
'id' => 'legal',
'class' => 'humhub\modules\legal\Module',
'namespace' => 'humhub\modules\legal',
'events' => [
['class' => FooterMenu::class, 'event' => FooterMenu::EVENT_INIT, 'callback' => ['humhub\modules\legal\Events', 'onFooterMenuInit']],
['class' => LayoutAddons::class, 'event' => LayoutAddons::EVENT_INIT, 'callback' => ['humhub\modules\legal\Events', 'onLayoutAddonInit']],
['class' => Registration::class, 'event' => Registration::EVENT_BEFORE_RENDER, 'callback' => ['humhub\modules\legal\Events', 'onRegistrationFormRender']],
['class' => Registration::class, 'event' => Registration::EVENT_AFTER_INIT, 'callback' => ['humhub\modules\legal\Events', 'onRegistrationFormInit']],
['class' => Registration::class, 'event' => Registration::EVENT_AFTER_REGISTRATION, 'callback' => ['humhub\modules\legal\Events', 'onRegistrationAfterRegistration']],
['class' => Controller::class, 'event' => Controller::EVENT_BEFORE_ACTION, 'callback' => ['humhub\modules\legal\Events', 'onBeforeControllerAction']],
['class' => ProsemirrorRichText::class, 'event' => ProsemirrorRichText::EVENT_AFTER_RUN, 'callback' => ['humhub\modules\legal\Events', 'onAfterRunRichText']],
['class' => Profile::class, 'event' => Profile::EVENT_BEFORE_VALIDATE, 'callback' => ['humhub\modules\legal\Events', 'onBeforeValidate']],
]
]; |
Haven't had time for a review yet. But it looks good. It might be better to put the validation in a separate validator class + an option to activate this validator. |
Just to confirm, you want the It should use the validator class for the main parts of the code and be called in Would you also want an option to enable/disable the validator, similar to the age requirement option from the configuration settings? |
I'm not sure if I'm a fan of this method, but it should be better than just logging out the user;
|
I like this approach. Question would be, do we need an option to enable this behavior? And maybe unit tests for the AgeValidator would be good. |
Well, to answer the question about an option for enabling the validator, I don't think we'd need to due to the minimum age already having this. As for the unit tests, I don't have much experience with this so I believe this would have to be someone other than me doing it. 🤔 |
@Semir1212 What do you think regarding the field hint? |
@luke- "Show checkbox" is not clear enough. Hint is fine. |
Why are you closing the PR. Shouldn't we enforce a minimum age in the profile field? |
For some reason when renaming a branch it closes and deletes the original branch. |
@luke- can a branch be made for this P/R? |
I've created a new P/R for a proof-of-concept for this functionality, please use #89 for new reference. |
Here's what this P/R provides;
Null Check: Before performing any operations, we ensure that the
$user
object and its profile property are notnull
. This prevents errors when trying to access properties of null objects, which could occur if the user is not logged in or if their profile information is missing.Age Calculation: If the user object and its profile are not
null
, we proceed with calculating the user's age. We retrieve the user's birthdate from their profile and calculate their age based on the current year and their birth year.Minimum Age Comparison: We compare the user's age with the minimum age requirement specified by the
$module->getMinimumAge()
method. If the user's age is less than the minimum age requirement, this indicates that they are underage.Logout: If the user's age is less than the minimum age requirement, we log the user out. This action ensures that underage users are not allowed to continue using the system. Logging the user out prevents them from accessing restricted content or performing actions that require them to be of legal age.
Age Confirmation Check: If the user's age meets the minimum age requirement, we proceed with the regular age confirmation check. This involves checking whether the user has accepted the age confirmation, which is typically done through the checkbox mechanism during registration or account setup.
Return Value: The method returns
true
if the user's age meets the minimum age requirement and they have not yet confirmed their age. This indicates that the age confirmation step should be displayed to the user. If the user's age is below the minimum age requirement, the method logs them out and returnsfalse
, preventing further access to the system.In summary, this updated
showAgeCheck()
method ensures that underage users are logged out automatically and prevents them from accessing restricted content or performing actions that require them to be of legal age.