Skip to content
Snippets Groups Projects
UseCase.rst 13.74 KiB

Use Case

To install the following use cases, please:

  • Create the page and tt-content records.
  • Copy the JSON form code to a new empty form (open Form in JSON mode).

Self Registration

Concept:

  • The T3 FE User record will be created on the fly in the last step, when the user set's the password.
  • Form Registration
    • Input: last name, first name, email.
    • Create record in table Person, if no name or email sibling is found. Else give a hint to do a password reset.
    • Set a new Person.auth token.
    • Set Person.authExpired = NOW() + INTERVAL 1 DAY.
    • Send an email to the given email address with a password reset link (incl. the token) which is time limited.
    • Further steps: See Set password.
  • Form Request password reset link
    • This is optional, but useful to offer the opportunity to reset the own password.
    • Input: email address.
    • Send an email to the given email address with a password reset link (incl. a token) which is time limited.
      • Only send email if the email address is known!
      • If email is not found, the user should not be noticed. This prohibits misusing the form to validate email adresses.
      • Set a new Person.auth token.
      • Set Person.authExpired = NOW() + INTERVAL 1 DAY.
  • Form Set password
    • The user types in the new password.
    • On save:
      • If the FE account does not exist, it will be created.
      • Set the FE user password.
      • Clear Person.authExpired.

Table: Person

CREATE TABLE `Person` (
  `id` int(11) UNSIGNED NOT NULL,
  `lastName` varchar(64) NOT NULL DEFAULT '',
  `firstName` varchar(64) NOT NULL DEFAULT '',
  `email` varchar(128) NOT NULL,
  `account` varchar(128) NOT NULL,
  `auth`  varchar(32) NOT NULL,
  `authExpire` datetime NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8 PACK_KEYS=1;

Registration

Page: Registration

  • Page Alias: registration

QFQ content record:

#
# {{action:SE}}: thanksRegistration
#


form={{SELECT IF('{{action:SE}}' = '','registration','') }}

20.sql = SELECT "<p>Thank you for your registration.</p><p>An email with further instructions has been sent to you.</p>"
                , "<p>You should receive the mail during the next 5 minutes. If not, please check your SPAM folder.</p>"

            FROM (SELECT '') AS fake
            WHERE '{{action:SE}}' = 'thanksRegistration'
              AND '{{form:SE}}'=''

Form: registration

{
    "title": "Registration",
    "tableName": "Person",
    "permitNew": "always",
    "permitEdit": "never",
    "showButton": "close,save",
    "forwardMode": "url-sip-skip-history",
    "forwardPage": "?id=registration&action=thanksRegistration",
    "parameter": "submitButtonText=Register",
    "FormElement_ff": [
        {
            "enabled": "yes",
            "name": "firstName",
            "label": "First name",
            "mode": "required",
            "type": "text"
        },
        {
            "enabled": "yes",
            "name": "lastName",
            "label": "Last name",
            "mode": "required",
            "type": "text"
        },
        {
            "enabled": "yes",
            "name": "email",
            "label": "Email",
            "mode": "required",
            "class": "native",
            "type": "text",
            "checkType": "email",
            "parameter": "retype\r\nretypeLabel=Retype email"
        },
        {
            "enabled": "yes",
            "label": "Check for double registration",
            "mode": "show",
            "modeSql": "",
            "class": "action",
            "type": "beforeSave",
            "parameter": "sqlValidate={{!SELECT p.id FROM Person AS p WHERE p.email='{{email:F:alnumx}}'  OR ('{{firstName:F:allbut}}'=p.firstName AND  '{{lastName:F:allbut}}'=p.lastName ) LIMIT 1 }}\r\n expectRecords=0\r\nmessageFail=Sorry, person already registered by name or email. Please just reset the password under <a href='?id=reset'>reset</a>"
        },
        {
            "enabled": "yes",
            "label": "auth, deadline",
            "class": "action",
            "type": "afterSave",
            "parameter": "# Set token & expiration\r\nsqlBefore={{UPDATE Person SET auth='{{random:V}}', authExpire=DATE_ADD(NOW(), INTERVAL 1 DAY) WHERE id={{id:R}} }}"
        },
        {
            "enabled": "yes",
            "label": "a) sendEmail, b) fe user",
            "mode": "show",
            "class": "action",
            "type": "sendMail",
            "value": "Dear new user\r\nPlease set a new password under {{baseUrl:Y}}?id=set&auth={{auth:R}}\r\nRegards.",
            "parameter": "sendMailTo={{email:R}}\r\nsendMailSubject=Registration confirmation\r\nsendMailFrom={{ADMINISTRATIVE_EMAIL:Y}}\r\n\r\n# Create User in T3\r\nsqlAfter={{INSERT INTO {{dbNameT3:Y}}.fe_users (pid, usergroup, username, password, first_name, last_name, name, email) VALUES (6, '1', '{{email:F:alnumx}}','$p$initial invalid hash',  '{{firstName:R}}', '{{lastName:R}}', '{{firstName:R}} {{lastName:R}}', '{{email:F:alnumx}}') }}"
        }
    ]
}

Request password reset link

Page: reset

  • Page Alias: reset

QFQ content record:

#
# {{action:SE}}: passwordReset
#
# Empty: {{action:SE}}='' > shows the form angezeigt 'passwordReset'.
# Given: {{action:SE}}='confirmation' > show confirmation.
#
form={{SELECT IF('{{action:SE}}' = '','passwordReset','') }}
r=1

10 {
  sql = SELECT '' FROM (SELECT '') AS fake WHERE '{{action:SE}}'='confirmation'
  head = <div class="alert alert-success">
           <p>Thank you.</p>
           <p>If the email address is known in our database, we sent a password reset link to it.</p>
           <p>The mail should be received during the next minutes. If not, please check you junk folder.</p>
           <p>To set a new password, please click on the link provided in the email.</p>
         </div>
}

Form: passwordReset

Note

Take care that there is one dummy person record with person.id=1

Form 'passwordReset':

{
    "title": "Password reset",
    "tableName": "Person",
    "permitNew": "never",
    "permitEdit": "always",
    "escapeTypeDefault": "c",
    "render": "bootstrap",
    "dirtyMode": "exclusive",
    "showButton": "save",
    "multiMode": "none",
    "forwardMode": "url-sip-skip-history",
    "forwardPage": "?id={{pageAlias:T}}&action=confirmation",
    "labelAlign": "default",
    "parameter": "submitButtonText = Send password reset email",
    "deleted": "no",
    "FormElement_ff": [
        {
            "enabled": "yes",
            "name": "emailValue",
            "label": "Email",
            "mode": "show",
            "class": "native",
            "type": "text",
            "encode": "specialchar",
            "checkType": "email",
            "ord": 10
        },
        {
            "enabled": "yes",
            "label": "Check for *example.com email",
            "mode": "show",
            "class": "action",
            "type": "beforeSave",
            "ord": 20,
            "parameter": "sqlValidate={{!SELECT 'fake' FROM (SELECT '')  AS fake WHERE '{{emailValue:F:alnumx}}' LIKE '%example.com'  }}\r\n expectRecords=0\r\nmessageFail=Sorry, Password reset is not possible for *example.com."
        },
        {
            "enabled": "yes",
            "label": "a) set auth, expire, b) send email",
            "mode": "show",
            "class": "action",
            "type": "sendMail",
            "encode": "specialchar",
            "checkType": "auto",
            "ord": 50,
            "value": "Dear new user\r\nPlease set a new password under {{baseUrl:Y}}?id=set&auth={{auth:V}}\r\nRegards.",
            "parameter": "fillStoreVar={{!SELECT CONCAT(p.firstName , ' ', p.lastName) AS name, p.id AS _pId, @expire:=DATE_ADD(NOW(), INTERVAL 4 DAY) AS expireTs, QDATE_FORMAT(@expire) AS expire, p.email, '{{random:V}}' AS auth FROM Person AS p WHERE p.email='{{emailValue:F:alnumx}}' AND p.email!='' LIMIT 1}}\r\n\r\nsendMailTo={{email:VE}}\r\nsendMailSubject=Password Reset\r\nsendMailFrom=webmaster@example.com\r\nsendMailGrId=123\r\nsendMailXId=456\r\n\r\n# Set token & expiration\r\nsqlAfter = {{UPDATE Person SET auth='{{auth:V}}', authExpire='{{expireTs:V}}' WHERE email='{{emailValue:F:alnumx}}' AND email!='' LIMIT 1}}"
        }
    ]
}

Set new password

Page: set

  • Page
    • Alias: set
    • Hide in menu: yes

QFQ content record:

#
# {{auth:CE}} - empty >> Form 'setPassword'
# {{auth:CE}} - unknown | expired >> Error message
# {{auth:SE}} - valid >> Set Password
#
# {{action:CE}} - 'thanks'

form={{SELECT IF( ISNULL(p.id), '', 'passwordSet' )
          FROM (SELECT '') AS fake
          LEFT JOIN Person AS p
            ON p.auth='{{auth:C:alnumx}}'
              AND p.auth!=''
              AND NOW()<p.authExpire }}

r={{SELECT IFNULL(p.id, 0) FROM (SELECT '') AS fake LEFT JOIN Person AS p ON p.auth='{{auth:C:alnumx}}' AND p.auth!='' AND NOW()<p.authExpire}}


10 {
  sql = SELECT IF( ISNULL(p.id)
                   , 'Token invalid'
                   , IF( NOW()<p.authExpire
                        ,''
                        , IF( p.authExpire=0, 'Password already set', 'Token expired') )
                 )
          FROM (SELECT '') AS fake
          LEFT JOIN Person AS p
            ON p.auth='{{auth:C:alnumx}}'
              AND p.auth!=''
          WHERE '{{action:SE}}'=''
              AND (ISNULL(p.id) OR NOW()>=p.authExpire)
  head = <div class="alert alert-warning" role="alert">
  tail = </div>
}

20.sql = SELECT 'Thanks for setting the password. Please <a href="?id=login">log in</a> now.'
           FROM (SELECT '') AS fake
           WHERE '{{action:SE}}'='thanks'

Form: passwordSet

Note

Please adjust the numbers for usergroup and pid in FormElement Update fe_user.password > parameter > sqlInsert to your needs. Remember that every FE-User needs at least one FE-Group to log in successfully.

Form 'passwordSet':

{
    "title": "Set password",
    "tableName": "Person",
    "permitNew": "never",
    "permitEdit": "always",
    "escapeTypeDefault": "c",
    "render": "bootstrap",
    "dirtyMode": "exclusive",
    "showButton": "save",
    "multiMode": "none",
    "forwardMode": "url-sip-skip-history",
    "forwardPage": "?{{pageAlias:T}}&action=thanks",
    "parameter": "submitButtonText='Set password'",
    "FormElement_ff": [
        {
            "enabled": "yes",
            "name": "myValue",
            "label": "Password",
            "mode": "show",
            "class": "native",
            "type": "password",
            "checkType": "pattern",
            "checkPattern": "[a-zA-Z0-9-_+ *\\\/.,:;]{10,}",
            "ord": 10,
            "parameter": "retype\r\nretypeLabel=Retype password\r\ndata-pattern-error=At least 10 characters are required. Valid characters: a-z A-Z 0-9 -_+*\/.,:;\r\nextraButtonPassword"
        },
        {
            "enabled": "yes",
            "label": "Update fe_user.password",
            "mode": "show",
            "class": "action",
            "type": "afterSave",
            "encode": "specialchar",
            "ord": 20,
            "parameter": "slaveId={{SELECT fe.uid FROM {{dbNameT3:Y}}.fe_users AS fe WHERE fe.username='{{email:RE}}' AND fe.username!='' AND fe.deleted=0 LIMIT 1}}\r\n\r\n# Create FE User. Please update values of `pid`, `usergroup` to your setup.\r\nsqlInsert = {{INSERT INTO {{dbNameT3:Y}}.fe_users ( `pid`, `usergroup`, `username`, `email`, `name`, `password`,`crdate`) VALUES ( 5 , 1 , '{{email:RE}}', '{{email:RE}}', '{{lastName:RE}}, {{firstName:RE}}', '{{myValue:FE:all:p}}',  UNIX_TIMESTAMP() ) }}\r\n\r\nsqlUpdate = {{UPDATE {{dbNameT3:Y}}.fe_users SET password='{{myValue:FE:all:p}}' WHERE uid={{slaveId:V0}}  }}\r\n\r\nsqlAfter={{UPDATE Person SET authExpire=0 WHERE id={{id:R}} }}"
        }
    ]
}