Add checkbox to HumHub signup screen

Hi, I’m very new to Yii, so please be patient. :slight_smile:

I need to modify the Sign up screen of the popular, Yii-powered, HumHub social system.

The signup screen is basically one email address textfield and a button.

I need to add a checkbox under the email textfield and, if the user doesn’t check it, he simply can’t register (he must accept privacy policy terms).

I found the login screen under protected/humhub/modules/user/views/auth:

<div class="panel-body">

                <p><?= Yii::t('UserModule.auth', "Don't have an account? Join the network by entering your e-mail address."); ?></p>

                <?php $form = ActiveForm::begin(['id' => 'invite-form']); ?>
                <?= $form->field($invite, 'email')->input('email', ['id' => 'register-email', 'placeholder' => $invite->getAttributeLabel('email'), 'aria-label' => $invite->getAttributeLabel('email')])->label(false); ?>
                <?php if ($invite->showCaptureInRegisterForm()) : ?>
                    <div id="registration-form-captcha" style="display: none;">
                        <div><?= Yii::t('UserModule.auth', 'Please enter the letters from the image.'); ?></div>

                        <?= $form->field($invite, 'captcha')->widget(Captcha::class, [
                            'captchaAction' => 'auth/captcha',
                        ])->label(false); ?>
                    </div>
                <?php endif; ?>
                <hr>
                <?= Html::submitButton(Yii::t('UserModule.auth', 'Register'), ['class' => 'btn btn-primary', 'data-ui-loader' => '']); ?>

                <?php ActiveForm::end(); ?>
            </div>
        </div>

Here I should add my checkbox but I don’t know how to do it and I can’t imagine any further implications. For example: it’s not that important, but is the checkbox automatically related to a db field? Is there anywhere in other files (configuration, controllers, etc.) some other thing I must edit to make the checkbox work?

Any tip is appreciated.

It is related to $invite, not sure if it’s the model or a form. You can add a public property to that class and add <?= $form->field($invite, 'agree')->checkbox() ?>. Then you’ll need a validation rule in the class corresponding to $invite.

@samdark: hi Alexander, first of all thank you for your kind reply. Do model and forms generally live in standard paths? Should I search for an Invite.php file that contains an Invite class in a particular path? HumHub is based on Yii version 2.0.

Do model and forms generally live in standard paths?

Depends on the project.

Should I search for an Invite.php file that contains an Invite class in a particular path?

Search it in the whole project.

Thanks to Saint Grep :slight_smile: I found an Invite.php class under humhub/modules/user/models.

I suppose (not sure because there are things named “invite” anywhere in the project) this is the class I was looking for.

So, you suggest to declare a public property in this class, just the way they have done with $captcha. Should the property have a conventional name or can I choose any name?

Then, you say I need a validation rule: here I see an array of arrays but I must find some documentation to be able to create and add the rule myself.

In the meantime, I coded a working (and unsecure) client side behavior: when the checkbox is unchecked, the button is disabled and viceversa. I’m not happy with that, honestly.

<?php

/**
 * @link https://www.humhub.org/
 * @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
 * @license https://www.humhub.com/licences
 */

namespace humhub\modules\user\models;

use humhub\components\ActiveRecord;
use humhub\modules\user\models\User;
use humhub\modules\space\models\Space;
use Yii;
use yii\helpers\Url;

/**
 * This is the model class for table "user_invite".
 *
 * @property integer $id
 * @property integer $user_originator_id
 * @property integer $space_invite_id
 * @property string $email
 * @property string $source
 * @property string $token
 * @property string $created_at
 * @property integer $created_by
 * @property string $updated_at
 * @property integer $updated_by
 * @property string $language
 * @property string $firstname
 * @property string $lastname
 * @property string $captcha
 */
class Invite extends ActiveRecord
{

    const SOURCE_SELF = 'self';
    const SOURCE_INVITE = 'invite';
    const TOKEN_LENGTH = 12;

    public $captcha;

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'user_invite';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['user_originator_id', 'space_invite_id'], 'integer'],
            [['token'], 'unique'],
            [['firstname', 'lastname'], 'string', 'max' => 255],
            [['source', 'token'], 'string', 'max' => 254],
            [['email'], 'string', 'max' => 150],
            [['language'], 'string', 'max' => 10],
            [['email'], 'required'],
            [['email'], 'unique'],
            [['email'], 'email'],
            [['email'], 'unique', 'targetClass' => User::class, 'message' => Yii::t('UserModule.base', 'E-Mail is already in use! - Try forgot password.')],
            [['captcha'], 'captcha', 'captchaAction' => 'user/auth/captcha', 'on' => static::SOURCE_INVITE],
        ];
    }

    /**
     * @inheritdoc
     */
    public function scenarios()
    {
        $scenarios = parent::scenarios();
        $scenarios['invite'] = ['email'];

        if ($this->showCaptureInRegisterForm()) {
            $scenarios['invite'][] = 'captcha';
        }

        return $scenarios;
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'email' => Yii::t('UserModule.invite', 'Email'),
            'created_at' => Yii::t('UserModule.base', 'Created at'),
            'source' => Yii::t('UserModule.base', 'Source'),
            'language' => Yii::t('base', 'Language'),
        ];
    }

    /**
     * @inheritdoc
     */
    public function beforeSave($insert)
    {
        if ($insert && $this->token == '') {
            $this->token = Yii::$app->security->generateRandomString(self::TOKEN_LENGTH);
        }

        return parent::beforeSave($insert);
    }

    public function selfInvite()
    {
        $this->source = self::SOURCE_SELF;
        $this->language = Yii::$app->language;

        // Delete existing invite for e-mail - but reuse token
        $existingInvite = Invite::findOne(['email' => $this->email]);
        if ($existingInvite !== null) {
            $this->token = $existingInvite->token;
            $existingInvite->delete();
        }

        if ($this->allowSelfInvite() && $this->save()) {
            $this->sendInviteMail();
            return true;
        }

        return false;
    }

    /**
     * Sends the invite e-mail
     */
    public function sendInviteMail()
    {
        $module = Yii::$app->moduleManager->getModule('user');
        $registrationUrl = Url::to(['/user/registration', 'token' => $this->token], true);

        // User requested registration link by its self
        if ($this->source == self::SOURCE_SELF) {
            $mail = Yii::$app->mailer->compose([
                'html' => '@humhub/modules/user/views/mails/UserInviteSelf',
                'text' => '@humhub/modules/user/views/mails/plaintext/UserInviteSelf'
            ], [
                'token' => $this->token,
                'registrationUrl' => $registrationUrl
            ]);
            $mail->setTo($this->email);
            $mail->setSubject(Yii::t('UserModule.base', 'Welcome to %appName%', ['%appName%' => Yii::$app->name]));
            $mail->send();
        } elseif ($this->source == self::SOURCE_INVITE && $this->space !== null) {

            if ($module->sendInviteMailsInGlobalLanguage) {
                Yii::$app->language = Yii::$app->settings->get('defaultLanguage');
            }

            $mail = Yii::$app->mailer->compose([
                'html' => '@humhub/modules/user/views/mails/UserInviteSpace',
                'text' => '@humhub/modules/user/views/mails/plaintext/UserInviteSpace'
            ], [
                'token' => $this->token,
                'originator' => $this->originator,
                'originatorName' => $this->originator->displayName,
                'space' => $this->space,
                'registrationUrl' => $registrationUrl
            ]);
            $mail->setTo($this->email);
            $mail->setSubject(Yii::t('UserModule.base', 'You\'ve been invited to join {space} on {appName}', ['space' => $this->space->name, 'appName' => Yii::$app->name]));
            $mail->send();

            // Switch back to users language
            if (Yii::$app->user->language !== '') {
                Yii::$app->language = Yii::$app->user->language;
            }
        } elseif ($this->source == self::SOURCE_INVITE) {

            // Switch to systems default language
            if($module->sendInviteMailsInGlobalLanguage) {
                Yii::$app->language = Yii::$app->settings->get('defaultLanguage');
            }

            $mail = Yii::$app->mailer->compose([
                'html' => '@humhub/modules/user/views/mails/UserInvite',
                'text' => '@humhub/modules/user/views/mails/plaintext/UserInvite'
            ], [
                'originator' => $this->originator,
                'originatorName' => $this->originator->displayName,
                'token' => $this->token,
                'registrationUrl' => $registrationUrl
            ]);
            $mail->setTo($this->email);
            $mail->setSubject(Yii::t('UserModule.invite', 'You\'ve been invited to join %appName%', ['%appName%' => Yii::$app->name]));
            $mail->send();

            // Switch back to users language
            if (Yii::$app->user->language !== '') {
                Yii::$app->language = Yii::$app->user->language;
            }
        }
    }

    /**
     * Return user which triggered this invite
     *
     * @return \yii\db\ActiveQuery
     */
    public function getOriginator()
    {
        return $this->hasOne(User::class, ['id' => 'user_originator_id']);
    }

    /**
     * Return space which is involved in this invite
     *
     * @return \yii\db\ActiveQuery
     */
    public function getSpace()
    {
        return $this->hasOne(Space::class, ['id' => 'space_invite_id']);
    }

    /**
     * Allow users to invite themself
     *
     * @return boolean allow self invite
     */
    public function allowSelfInvite()
    {
        return (Yii::$app->getModule('user')->settings->get('auth.anonymousRegistration'));
    }

    public function showCaptureInRegisterForm()
    {
        return (Yii::$app->getModule('user')->settings->get('auth.showCaptureInRegisterForm'));
    }
}

Any name would do. Just use the same name in the view template.

I’ve done anything as described, but it doesn’t work.

It doesn’t cause any kind of error, but there’s no validation (the empty checkbox is completely ignored and I can pass the registration, even if the checbox is unchecked).

I’ve tried:

[['customCheck'], 'required']

[['customCheck', 'boolean'], 'required']

[['customCheck', 'boolean'], 'required', 'requiredValue'=>1]

[['customCheck'], 'required', 'requiredValue'=>1, 'on' => ['register'], 'skipOnEmpty' => false, 'skipOnError' => false, 'message'=>'my message']

I’ve found and red the docs, but I couldn’t find a solution.

Either that’s wrong model file or something else HumHub specific. Likely it’s a good idea to ask in HumHub community.

I did it, but unfortunately I received no technical reply, so I decided to ask here. I will try other solutions. Thanks.