Iliad Framework, the registration form (part 2)

In the previous post we build a registration form and in this one we will attach it to our application.

We start adding an instance variable to our application to contain the registration widget and another instance variable to contain the current user:

ILApplication subclass: #LcBlogProjectNotes
    instanceVariableNames: 'loginWidget registrationWidget currentuser' 
    classVariableNames: ''
    poolDictionaries: ''
    category: 'LeonardoBlog'

As we have done for the loginWidget, we create an accessor method that will construct the widget if it hasn’t been instanciated:

!LcBlogProjectNotes methodsFor: 'accessing'!
registrationWidget
    ^ registrationWidget ifNil: [ registrationWidget := PnCreateUser new ]

We also create accessors for the current user instance variable:

!LcBlogProjectNotes methodsFor: 'accessing'!
currentuser: anObject
    currentuser := anObject

!LcBlogProjectNotes methodsFor: 'accessing'!
currentuser
    ^ currentuser

Now we create a controller for the registration page:

!LcBlogProjectNotes methodsFor: 'controllers'!
register
    ^ [ :e | e div class:'container'; build: self registrationWidget ]

Now we have our new controller and we can test it from the login page. The controller name, register, match with the href in the login page.

Iliad Framework, the registration form (part 2)

Iliad Framework, the registration form

In the previous post we talked about checking emails addresses, just to show how we can use regexps in Pharo.

In this post we are returning to the Iliad Framework and we will be a registration form.

We start, as we have done for the login form, creating a component for the registration form. This component will then be integrated into the application and another controller will be build.

ILWidget subclass: #PnCreateUser
    instanceVariableNames: 'email password password2 name surname errors'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'LeonardoBlog'!

As you can see the instance variable of this component, like what was happening in the registration form, are derived from the variable state of the component. We created an instance variable for every data that the user will enter and a errors fields that will be empty whenxb there are no errors.

The initialize method clear all the instance variables:

!PnCreateUser methodsFor: 'initialization'!
initialize
    super initialize.
    name := ''.
    surname := ''.
    password := ''.
    password2 := ''.
    email := ''.
    errors := ''.! !

As you saw in the login form when you are programming in Smalltalk you usually create short methods, more short than the method you will be used to. This is an example:

!PnCreateUser methodsFor: 'building'!
contents
    ^ [ :e | 
    e h1 text: 'Register your account'.
    e p
        text:
            'You will use your email to login'.
    e form
        build: [ :form | 
            self buildEmailRow: form.
            
            self buildNameRow: form.
            self buildSurnameRow: form.
            
            self buildPasswordRow: form.
            self buildRepeatPasswordRow: form.
            
            self buildErrorMessageRow: form.
            
            form button
                class: 'btn btn-default';
                text: 'Register to project notes';
                action: [ self registerAction ] ] ]! !

!PnCreateUser methodsFor: 'building'!
buildErrorMessageRow: aForm
    errors
        ifNotEmpty: [ (aForm div class: 'alert alert-warning') ul
        build: [ :box | (errors findTokens: String cr) do: [ :msg | box li text: msg ] ] ]! !

!PnCreateUser methodsFor: 'building'!
buildPasswordRow: aForm
    aForm div class: (errors ifNotNil: [ 'form-group has-error' ] ifNil:  [ 'form-group' ]);
            build: [ : row | 
                row label text:'Password: '.
                row input class:'form-control';  type: 'password'; action: [ :text | password := text ]; value:'' ]! !

!PnCreateUser methodsFor: 'building'!
buildEmailRow: aForm
    aForm div class: (errors ifNotNil: [ 'form-group has-error' ] ifNil:  [ 'form-group' ]);
            build: [ : row | 
                row label text:'Email'.
                row input class:'form-control'; action: [ :text | email:= text ]; value:email]! !

!PnCreateUser methodsFor: 'building'!
buildSurnameRow: aForm
    aForm div class: (errors ifNotNil: [ 'form-group has-error' ] ifNil:  [ 'form-group' ]);
            build: [ : row | 
                row label text:'Surname'.
                row input class:'form-control'; action: [ :text | surname:= text ]; value:email]! !

!PnCreateUser methodsFor: 'building'!
buildRepeatPasswordRow: aForm
    aForm div class: (errors ifNotNil: [ 'form-group has-error' ] ifNil:  [ 'form-group' ]);
            build: [ : row | 
                row label text:'Repeat Password: '.
                row input class:'form-control'; type: 'password'; action: [ :text | password2 := text ]; value:'']! !

!PnCreateUser methodsFor: 'building'!
buildNameRow: aForm
    aForm div class: (errors ifNotNil: [ 'form-group has-error' ] ifNil:  [ 'form-group' ]);
            build: [ : row | 
                row label text:'Name'.
                row input class:'form-control'; action: [ :text | name:= text ]; value:email]! !

In the previous example there is nothing interesting: just creating a form like the login form but with more fields. This is the error checking method that we will be calling before the registration action:

!PnCreateUser methodsFor: 'actions'!
checkErrors
    errors := ''.
    email ifEmpty: [ errors := errors, 'The email must not be empty because you need to login in the system', String cr ].
    (PnUtils checkEmail: email) ifFalse: [ errors := errors, 'This doesn''t look like a real email to me', String cr ].
    name ifEmpty: [ errors := errors, 'The name is a required field', String cr ].
    surname ifEmpty: [ errors := errors, 'The surname is a required field', String cr ].
    (password, password2) ifEmpty: [ errors := errors, 'You must enter a password', String cr ].
    (password = password2) ifFalse: [ errors := errors, 'The password are not matching', String cr ].
    ! !

As you see I only fill the errors instance variable with the error message and the row building methods will do the rest.

Now the registration action, that is more interesting:

!PnCreateUser methodsFor: 'actions'!
registerAction
    | u |
    self markDirty; checkErrors.
    errors ifNotEmpty: [ ^ self. ].
    
    u := PnUser new realname:name; surname: surname; email: email; password: password.
    PnUserDAO current register:u.
    self show:(ILInformationWidget new informationString: 'We created an user for you. Click ok to go to the app.') 
        onAnswer: [ : e | self redirectToLocal: 'notes' ].! !

The interesting bits are in the DAO usage, that “persist” the PnUser object, and the show:onAnswer: method.

The show:onAnswer: method of the ILWidget class can handle the control flow for you. In the next page rendering process the invoking widget will be substituted with the passed widget, in this case ILInformationWidget. When the shown widget (ILInformationWidget) will call the answer method the control flow will return to the block passed to show:onAnswer:.

This block redirect the browser to the notes controller, which will handle the notes creation and visualization proces.

Iliad Framework, the registration form

Pharo, Checking emails with regexp

In the previous post we build a login form and we saw that we should provide an user registration form.

We are going to build a registration form so we need to check emails. I will create a new class PnUtils to contain all the string-checking utilities that we need for our App:

Object subclass: #PnUtils
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'LeonardoBlog'

Now, in a class method, I will implement my email-checking:

!PnUtils class methodsFor: 'as yet unclassified'!
checkEmail: anEmail
    ^ anEmail asUppercase matchesRegex:  '[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z][A-Z][A-Z]?[A-Z]?'.

As you see I check the email addresses using the RegExp feature of Smalltalk. The regexp is taken from this site.

I know that at this times my should send an activation email to let the user activate yourself but I won’t do it as I don’t want to mess up with SMTP configuration.

In this discussion I want to show you how simple is to use regexp from Pharo Smalltalk, without loading any external libraries.

Ok. We must test it to see if it’s working or not:

TestCase subclass: #PnUtilsTest
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'LeonardoBlog-Tests'

!PnUtilsTest methodsFor: 'tests'!
testEmailOk
    self assert: (PnUtils checkEmail: 'leonardoce@interfree.it' ).
    self assert: (PnUtils checkEmail: 'leonardoce@interfree.com' ).   

!PnUtilsTest methodsFor: 'tests'!
testEmailNotOk
    self assert: (PnUtils checkEmail: 'leonardoce@interfree.sirtr' ) not.

The tests should all be working.

Pharo, Checking emails with regexp

Iliad Framework, the users-dao intermezzo

In the previous post we build a login form. In that form we included a “Register” link and so we must provide a way to make our users entries persistent.

Using Smalltalk the image is already persistent, saved every time you need reloaded from the image file. To cut a long story short if you don’t need ACID transactions and a strong mechanism to backup and restore data you can use the image as your database.

This may look strange (and do look strange) to non-smalltalkers but this wonderful post explains very well why using your image as a persistence layer isn’t a crazy idea.

For our didactic purpose we can safely use the image.

We need to store users so we start by creating an PnUser class:

Object subclass: #PnUser
    instanceVariableNames: 'realname surname email md5pwd'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'LeonardoBlog'!

As you see this is a really simple class. You can automatically generate the accessors method using the Pharo browser. You will obtain something like this:

!PnUser methodsFor: 'accessing'!
email
    ^ email

password:pwd
    md5pwd :=  (MD5 hashMessage:pwd) hex.

realname: anObject
    realname := anObject

email: anObject
    email := anObject

realname
    ^ realname

surname: anObject
    surname := anObject

surname
    ^ surname

email
    ^ email

email: anObject
    email := anObject

realname
    ^ realname

surname: anObject
    surname := anObject

surname
    ^ surname

realname: anObject
    realname := anObject

Instead of storing the password we store the MD5 hash code and so we have these methods:

!PnUser methodsFor: 'accessing'!
password:pwd
    md5pwd :=  (MD5 hashMessage:pwd) hex.

!PnUser methodsFor: 'accessing'!
hasPassword:aString
    ^ (MD5 hashMessage:aString) hex = md5pwd .

The MD5 class has all the code needed to compute the MD5 hash code of a string. Pharo has a lot of utilities to ease the life of developers.

Ok. Now we need a class to store users informations. We call it PnUserDAO and we will use a Dictionary to store users informations: the key will be the email and the value the PnUser object.

Let’s start with the class definition:

Object subclass: #PnUserDAO
    instanceVariableNames: 'usersDictionary'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'LeonardoBlog'!

When we initialize a DAO we create a new Dictionary where we will store the users:

!PnUserDAO methodsFor: 'initialization'!
initialize
    super initialize.
    usersDictionary := Dictionary new.

The first thing we need is a method to store a new user:

!PnUserDAO methodsFor: 'accessing'!
register:anUser
    usersDictionary at: anUser email put: anUser

Then we need a method to retrieve an user from the email:

!PnUserDAO methodsFor: 'accessing'!
userForEmail: anEmail
    ^ usersDictionary at: anEmail ifAbsent: nil.

We created a DAO and now we need to create a test case, just to see if everything is working. Before every test we create a new DAO with a test user and after the test we delete the DAO just created:

TestCase subclass: #PnUserDAOTest
    instanceVariableNames: 'dao'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'LeonardoBlog-Tests'!

!PnUserDAOTest methodsFor: 'running'!
setUp
    | testUser |
    super setUp.
    dao := PnUserDAO new.
    testUser := PnUser new
        surname: 'Test user';
        realname: 'Test name';
        password: 'test';
        email: 'test@test.eu'.
    dao register: testUser.

!PnUserDAOTest methodsFor: 'running'!
tearDown
    super tearDown.
    dao := nil.

Now we can test the register: method:

!PnUserDAOTest methodsFor: 'tests'!
testUserCreation
    |u|
    u := PnUser new email: 'leonardo@leo.it'; realname:'Leonardo'; surname:'Test'.
    dao register:u.
    self assert:(dao userForEmail: 'leonardo@leo.it') isNotNil.

The login method needs a way to check for an user and a password:

!PnUserDAO methodsFor: 'authentication'!
userForEmail: anEmail password:pwd
    |user|
    user := self userForEmail: anEmail.
    user ifNil: [ ^ nil ].
    (user hasPassword: pwd) ifTrue: [ ^ user ] ifFalse: [ ^ nil].

Let’s test it:

!PnUserDAOTest methodsFor: 'tests'!
testAuthentication
    self assert:(dao userForEmail:'test@test.eu' password:'test' ) isNotNil.
    self assert:(dao userForEmail:'test@test.eu' password:'testnot' ) isNil.

As we will offer an user deregistration procedure we need a unregister: method:

!PnUserDAO methodsFor: 'accessing'!
unregister: anEmail
    usersDictionary removeKey: anEmail ifAbsent: [ ].
    ^ self

We test it:

!PnUserDAOTest methodsFor: 'tests'!
testRemovingUnknownUser
    dao unregister: 'nonexitent'

!PnUserDAOTest methodsFor: 'tests'!
testRemovingKnownUser
    |u|
    u := PnUser new email: 'leonardo@leo.it'; realname:'Leonardo'; surname:'Test'.
    dao register:u.
    self assert:(dao userForEmail: 'leonardo@leo.it') isNotNil.
    dao unregister:'leonardo@leo.it'.
    self assert:(dao userForEmail: 'leonardo@leo.it') isNil.

Now we create a method to remove all known users:

!PnUserDAO methodsFor: 'util'!
deleteAllUsers
    usersDictionary removeAll

This is the test:

!PnUserDAOTest methodsFor: 'tests'!
testDeleteAllUsers
    self assert:(dao userForEmail:'test@test.eu' password:'test' ) isNotNil .
    dao deleteAllUsers .
    self assert:(dao userForEmail:'test@test.eu' password:'test' ) isNil .

Well… if everything is ok you have all units test working correctly and you can be happy!

PnUserDAO test cases

Iliad Framework, the users-dao intermezzo

Iliad Framework, the login form

In the previous post we talked about customizing the generated page to include references to the Bootstrap project.

This is the first lession where we start working on a complete example, a projecs-notes app usable from desktop and mobile web browsers using the twitter bootstrap framework.

Now we will start working on a login page.

To build a new page with a form I will start making a component that will be built from the application controller named login. The controller will be named PnProjectLogin.

Let’s start building this new component creating a class whose superclass is ILWidget:

ILWidget subclass: #PnProjectLogin
    instanceVariableNames: 'username password loginError'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'LeonardoBlog'

remember that widgets are stateful: the instance variables will be populated by the application and by the user.

  • username will be the text entered by the user in the login form;
  • password as previous;
  • loginError will be the string of the error message of the login or nil if there is no error message.

I won’t show the accessor methods because they can be automatically generated by the Pharo browser but I will show the initializer method:

!PnProjectLogin methodsFor: 'initialization'!
initialize
    super initialize.
    loginError := nil.
    username := ''.
    password := ''.! !

Let’s start by creating a method to build the username field and the relative label:

!PnProjectLogin methodsFor: 'building'!
buildLoginRow: aForm
    aForm div class: (loginError ifNotNil: [ 'form-group has-error' ] ifNil:  [ 'form-group' ]);
            build: [ : row | 
                row label text:'Login:'.
                row input class:'form-control'; action: [ :text | username := text ]; value:username ]! !

See how interesting it the build: method: it takes a block and evaluate it passing, as argument, the receiver. Before executing the passed block the method opens the element and closes it when the block finished. In the previous example the aForm div execution results in a DIV element that get automatically closed when the block has terminated its execution.

Another interesting thing is the class: method invocation on the aForm div element: to comply with the bootstrap rules we need to insert the has-error class when this element of the form is wrong. To do this we check the loginError contents.

In the input element, the action block takes the element text content.

This method is somewhat similiar:

!PnProjectLogin methodsFor: 'building'!
buildPasswordRow: aForm
    aForm div class:(loginError ifNotNil: [ 'form-group has-error' ] ifNil:  [ 'form-group' ]);
            build: [ : row |
                row label text:'Password'.
                row input class:'form-control'; type:'password'; action: [ :text | password := text ] ]! !

As you see, while the login field get constructed with a value (or the previous one), the password is always empty.

Ok. Now we will construct the error message row of the form:

!PnProjectLogin methodsFor: 'building'!
buildErrorMessageRow: aForm
    loginError ifNotNil: [
    (aForm div class: 'alert alert-warning') text: loginError ]! !

Obviously we have to build the errors row only if there are errors! Well. Now we are missing the “register” link.

!PnProjectLogin methodsFor: 'building'!
buildRegisterRow: aForm
    (aForm div class: 'form-group') a
        href: 'register';
        text: 'Want to register?'! !

Let’s bind all together in the contents method:

!PnProjectLogin methodsFor: 'building' stamp: 'LeonardoCecchi 2/28/2014 23:03'!
contents
    ^ [ :e | 
    e h1 text: 'Project Notes - Login'.
    e p
        text:
            'Project Notes is a note taking app that you
            can use for your project. It will store memos for
            you and for your team.'.
    e p text: 'Believe me, you really need this app!!'.
    e form
        build: [ :form | 
            self buildLoginRow: form.
            self buildPasswordRow: form.
            self buildErrorMessageRow: form.
            self buildRegisterRow: form.
            form button
                class: 'btn btn-default';
                text: 'Login!!';
                action: [ self loginAction ] ] ]! !

In the loginAction method, which is called when the user press on the “Login” button we execute the loginAction method of this class, which is defined like this:

!PnProjectLogin methodsFor: 'actions'!
loginAction
    self markDirty .
    username ifEmpty: [ ^ loginError := 'Please enter the user name' ].
    password ifEmpty: [ ^ loginError := 'Please enter the password' ].
    loginError := nil.
    "self redirectToLocal: 'browseProject'."

In this method, which for now is only a stub, we check for empty data and then we will call the main page.

Now we need to integrate this widget in our application, LcBlogProjectNotes. We must add an instance variable named loginWidget.

ILApplication subclass: #LcBlogProjectNotes
    instanceVariableNames: 'loginWidget
    classVariableNames: ''
    poolDictionaries: ''
    category: 'LeonardoBlog'

As we discussed in the relative article we need an accessor method that lazily creates the widget:

!LcBlogProjectNotes methodsFor: 'accessing'!
loginWidget
    ^ loginWidget ifNil: [ loginWidget := PnProjectLogin new ]! !

Now we can create the controller method:

!LcBlogProjectNotes methodsFor: 'controllers'!
login
    ^ [ :e | e div class:'container'; build: self loginWidget ]! !

If you go to http://localhost:7070/ProjectNotes/login you should see the following result:

Project notes login form

Yeah! We succesfuly build our first form, even with error checking. When the loginError is not empty the form looks like this:

Project notes login form error

Iliad Framework, the login form

Iliad Framework, how to customize the page generation

In the previous post we talked about how to include static resources in the Pharo image to be server with our application.

Let’s start with a new web application and, as we have seen in the relative post, we must create a class deriving from ILApplication, write the path method and an empty index controller:

ILApplication subclass: #LcBlogProjectNotes
    instanceVariableNames: ''
    classVariableNames: ''
    category: 'LeonardoBlog'
"LcApplication class>>path protocol accessing"
path
    ^ 'ProjectNotes'
"LcApplication>>index protocol controllers"
index
    ^ [ :e | e h1 text:'Hi!' ]

Remember to put the index method in the protocol controllers!

Now we must integrate all the bootstrap code from the static resources generated in the previous post in the page.

Do to that we must override the updatePage: method from ILApplication like this:

"LcApplication>>updatePage protocol updating"
updatePage: aPage
    "Includes bootstrap JS"
    
    aPage head link
      rel: 'stylesheet';
      href: '/bootstrap/css/bootstrap.min.css'.
    aPage head link
      rel: 'stylesheet';
      href: '/bootstrap/css/bootstrap-theme.min.css'.
    aPage head javascript src: '/bootstrap/js/bootstrap.min.js'.
    aPage head meta
      httpEquiv: 'X-UA-Compatible';
      content: 'IE=edge'.
    aPage head meta
      name: 'viewport';
      content: 'width=device-width, initial-scale=1'.
    
    "We want a title for our app"
    aPage head title: 'A project note-taking app'

The updatePage: method get called when the page has been constructed and before its contents are sent to the browser. In this method you can customize the generated page as you want.

Voila’! We have integrated Bootstrap JS.

Iliad Framework, how to customize the page generation

Iliad Framework, serving static resources

In the previous lesson we talked about how to use an Iliad webapp with a browser without Javascript enabled.

In this lesson we will talk about static resources to be included in your web-app.

When you will deploy your web application in the “real world” you want your static resources served by a specific web server as Apache but, while you are developing your application, you can make use of the web server embedded inside the Pharo Smalltalk environment: Komanche.

Iliad makes really easy to serve static resources. Now we will learn how to embed in your Pharo image Bootstrap JS. Let’s assume you already downloaded the compiled distribution to a file named bootstrap-3.1.1-dist.zip and that you extracted it in a folder named ~/tmp/bootstrap-3.1.1-dist.

To include it in your Pharo image you need to derive a class from ILMemoryDirectory for every Bootstrap JS subdirectory like this:

ILMemoryDirectory subclass: #LcBootstrapCss
    instanceVariableNames: ''
    classVariableNames: ''
    category: 'LeonardoBlog'
ILMemoryDirectory subclass: #LcBootstrapFonts
    instanceVariableNames: ''
    classVariableNames: ''
    category: 'LeonardoBlog'
ILMemoryDirectory subclass: #LcBootstrapJs
    instanceVariableNames: ''
    classVariableNames: ''
    category: 'LeonardoBlog'

Now we tell the classes to load all the resources contained in the corresponding directories. Open a workspace and execute the following commands:

LcBootstrapCss addAllFilesIn:'/home/leonardo/tmp/bootstrap-3.1.1-dist/css'.
LcBootstrapJs addAllFilesIn:'/home/leonardo/tmp/bootstrap-3.1.1-dist/js'.
LcBootstrapFonts addAllFilesIn:'/home/leonardo/tmp/bootstrap-3.1.1-dist/fonts'.

You will see that a series of method are getting created under the files protocol. This is were the content of Bootstrap JS will be loaded.

Now we need to configure the subdirectory under the resources will be published. We just need to create a path method under the accessing protocol like this:

"LcBootstrapJs>>path protocol accessing"
path
    ^ 'bootstrap/js'
"LcBootstrapFonts>>path protocol accessing"
path
    ^ 'bootstrap/fonts'
"LcBootstrapCss>>path protocol accessing"
path
    ^ 'bootstrap/css'

Now we need to register these new classes to be loaded by the Iliad framework and the code to register the app must also be executed when you load your class in a fresh image. This is the place where the initialize method of the class side comes in:

"LcBootstrapJs class>>initialize protocol initialization"
initialize
    ILFileHandler addDirectory: self new
"LcBootstrapFonts class>>initialize protocol initialization"
initialize
    ILFileHandler addDirectory: self new
"LcBootstrapCss class>>initialize protocol initialization"
initialize
    ILFileHandler addDirectory: self new

Now the initialization must be done by hand in a workspace:

LcBootstrapJs initialize.
LcBootstrapCss initialize.
LcBootstrapFonts initialize.

Try using a web browser pointing to http://localhost:7070/bootstrap/js/bootstrap.js and you will see the Bootstrap Js code. The same thing happens with the other directories.

Check that also the following URLS get served:

Now you are sure that everything is working.

Iliad Framework, serving static resources