% -*- mode: latex; -*- mustache tags:  
\ifx\wholebook\relax\else

	\documentclass[10pt,twoside,english]{root/support/latex/sbabook/sbabook}
  \usepackage{import}
  \subimport{root/support/latex/}{common.tex}

  \hypersetup{pdfinfo = {
    Title = {TinyBlog: Building an Admin Seaside Web Interface with Magritte},
    Author = {},
    Keywords = {pharo, smalltalk}}}
  \begin{document}
\fi

\chapter{Previous Week Solution}
You can load the solution of the previous week using the following snippet:

\begin{displaycode}{smalltalk}
Gofer new 
   smalltalkhubUser: 'PharoMooc' project: 'TinyBlog';
   package: 'ConfigurationOfTinyBlog';
   load. 
#ConfigurationOfTinyBlog asClass loadWeek4Correction
\end{displaycode}

To test the code, you should start the Seaside HTTP server using the Seaside Control Panel tool (cf. previous week) or directly execute the following code:

\begin{displaycode}{smalltalk}
ZnZincServerAdaptor startOn: 8080.
\end{displaycode}

You might also need to create some posts:

\begin{displaycode}{smalltalk}
TBBlog reset ; 
	createDemoPosts
\end{displaycode}

Before continuing, stop the Teapot server:

\begin{displaycode}{smalltalk}
	TBTeapotWebApp stop
\end{displaycode}
\chapter{Describe your Model Data with Magritte}
Magritte is a library to describe data. 
Using Magritte descriptions, you can then generate various representations for your data or operations such as requests.
Combined with Seaside, Magritte enable HTML forms and reports generation.
The Quuve software (cf. \url{http://www.pharo.org/success}) of Debris Publishing company is a brilliant example of Magritte powerfulness: all HTML tables have been automatically generated.
Data validation is also defined in Magritte descriptions and not spread in the UI code. This tutorial will not describe this but you can refer to the Seaside book (\url{http://book.seaside.st}) and the Magritte tutorial (\url{https://github.com/SquareBracketAssociates/Magritte}).

This week, we will start by describing with Magritte the five instance vairables of \textcode{TBPost}, then we will use these descriptions to automatically generate Seaside components. 
\section{Magritte Descriptions}
The five following methods classified in the 'descriptions' protocol of \textcode{TBPost}. Note that the name of these methods does not matter although we use naming convention.  In fact, the \textcode{\textless{}magritteDescription\textgreater{}}  pragma allows Magritte to retrieve descriptions. 

A post title is a string and must be filled (required).

\begin{displaycode}{smalltalk}
TBPost >> descriptionTitle
   <magritteDescription>
   ^ MAStringDescription new
      accessor: #title;
      beRequired;
      yourself
\end{displaycode}

The text of a post is a multi-line string that is also mandatory.

\begin{displaycode}{smalltalk}
TBPost >> descriptionText
   <magritteDescription>
   ^ MAMemoDescription new
      accessor: #text;
      beRequired;
      yourself
\end{displaycode}

The category of a post is an optional string. If it is not specified, the post will belong to the 'Unclassified' category.

\begin{displaycode}{smalltalk}
TBPost >> descriptionCategory
   <magritteDescription>
   ^ MAStringDescription new
      accessor: #category;
      yourself
\end{displaycode}

The creation date of a post is important to sort posts before displaying them. 

\begin{displaycode}{smalltalk}
TBPost >> descriptionDate
   <magritteDescription>
   ^ MADateDescription new
      accessor: #date;
      beRequired;
      yourself
\end{displaycode}

The  \textcode{visible} instance variable must be a boolean value.

\begin{displaycode}{smalltalk}
TBPost >> descriptionVisible
   <magritteDescription>
   ^ MABooleanDescription new
      accessor: #visible;
      beRequired;
      yourself
\end{displaycode}

   
\section{Possible Enhancements}
We could improve these descriptions and make them more complete. For example, ensure that the date of a new post cannot be before the current date. We could also define the category of post must be one the already existing categories. With richer descriptions, you can produce more complete generated UI elements.
\chapter{Administration UI of TinyBlog}
We will now develop the Administration UI of TinyBlog. Through this exercise, we will show how to use session information and Magritte descriptions to define reports.
Our objective is: the user should be able to log in using a login and a password to access the administration part of TinyBlog. The link to log in will be placed below the list of categories.
\section{Authentification Component}
Let's start by developing an authentification Component that will open a modal dialog asking for a login and a password. Note that such a functionnality should be part of a component library of Seaside.

This component illustrates how values can be elegantly retrieved from the user directly the instance variable of the component.

\begin{displaycode}{smalltalk}
WAComponent subclass: #TBAuthentificationComponent
   instanceVariableNames: 'password account component'
   classVariableNames: ''
   category: 'TinyBlog-Components'

TBAuthentificationComponent >> account
   ^ account

TBAuthentificationComponent >> account: anObject
   ^ account := anObject

TBAuthentificationComponent >> password
   ^ password

TBAuthentificationComponent >> password: anObject
   ^ password := anObject

TBAuthentificationComponent >> component
   ^ component

TBAuthentificationComponent >> component: anObject
   component := anObject
\end{displaycode}

The  \textcode{component} instance variable is initialized by the following class-side method:

\begin{displaycode}{smalltalk}
TBauthenticationComponent class >> from: aComponent
   ^ self new component: aComponent
\end{displaycode}

The \textcode{renderContentOn:} method define the content of the modal dialog.

\begin{displaycode}{smalltalk}
TBAuthentificationComponent >> renderContentOn: html

   html tbsModal id: 'myAuthDialog'; with: [
    html tbsModalDialog: [
      html tbsModalContent: [
        html tbsModalHeader: [
          html tbsModalCloseIcon.
          html tbsModalTitle level: 4; with: 'Authentification'
        ].
        html tbsModalBody: [
          html form: [
            html text: 'Account:'.
            html break.
    html textInput
              callback: [ :value | account := value ];
              value: account.
    html break.
    html text: 'Password:'.
    html break.
    html passwordInput
      callback: [ :value | password := value ];
      value: password.
    html break.
    html break.
    html tbsModalFooter: [
      html tbsSubmitButton value: 'Cancel'.
        html tbsSubmitButton
          bePrimary;
            callback: [ self validate ];
          value: 'SignIn'.
      ] ] ] ] ] ]
\end{displaycode}
\subsubsection{Criticism}
What do you think about the above method? Propose a refactoring using multiple methods to better modularize the differents elements of the form.
\subsubsection{Our Solution}
\begin{displaycode}{smalltalk}
TBAuthentificationComponent >> renderContentOn: html
   html tbsModal
      id: 'myAuthDialog';
      with: [ html tbsModalDialog: [ 
                     html tbsModalContent: [ 
                           self renderHeaderOn: html.
                           html
                              tbsModalBody: [ 
                                 html
                                    form: [ 
                                       self renderInputAccountOn: html. 
                                       html break.
                                       self renderInputPasswordOn: html. 
                                       html break.
                                       html break.
                                       html tbsModalFooter: [ self renderOkCancelOn: html ] ] ] ] ] ]
\end{displaycode}

\begin{displaycode}{smalltalk}
TBAuthentificationComponent >> renderHeaderOn: html
   html
      tbsModalHeader: [ 
         html tbsModalCloseIcon.
         html tbsModalTitle
            level: 4;
            with: 'Authentification' ]
\end{displaycode}

\begin{displaycode}{smalltalk}
TBAuthentificationComponent >> renderInputAccountOn: html
   html text: 'Account:'.
   html break.
   html textInput
         callback: [ :value | account := value ];
         value: account
\end{displaycode}

\begin{displaycode}{smalltalk}
TBAuthentificationComponent >> renderInputPasswordOn: html
   html text: 'Password:'.
   html break.
   html passwordInput
      callback: [ :value | password := value ];
      value: password
\end{displaycode}

\begin{displaycode}{smalltalk}
TBAuthentificationComponent >> renderOkCancelOn: html
   renderOkCancelOn: html
      html tbsButton 
		   attributeAt: 'type' put: 'button';
		   value: 'Cancel'.
      html tbsSubmitButton
         bePrimary;
         callback: [ self validate ];
         value: 'SignIn'
\end{displaycode}

When the user click on the 'SignIn' button, the \textcode{validate} message is sent and it verifies the login/password entered by the user to access the 'admin' part.

\begin{displaycode}{smalltalk}
TBAuthentificationComponent >> validate
   (self account = 'admin' and: [ self password = 'password' ]) 
      ifTrue: [ self alert: 'Success!' ]
\end{displaycode}
\subsubsection{Criticism}
Authentication should not be the responsability of the modal dialog. It would be better that it delegates this task to another model object that interact the backend to authenticate users. You can look for another method to achieve user authentication (using a database backend, LDAP or simply text files). 

Moreover, the  \textcode{TBAuthentificationComponent} component could display the name of the currently connected user.
\subsection{Integrate Authentication}
We now integrate a link in the application that will trigger the display of the authentication modal dialog. At the beginning of the \textcode{renderContentOn:} method of \textcode{TBPostsListComponent}, we add the render of \textcode{TBAuthentificationComponent}. We also pass to this component a reference to the component that display the posts.

\begin{displaycode}{smalltalk}
TBPostsListComponent >> renderContentOn: html
   super renderContentOn: html.
   html render: (TBAuthentificationComponent from: self).
   html
      tbsContainer: [ 
         html tbsRow
            showGrid;
            with: [ self renderCategoryColumnOn: html.
                  self renderPostColumnOn: html ] ] 
\end{displaycode}

We define a method that displays a key logo and the 'SignIn' link.

\begin{displaycode}{smalltalk}
TBPostsListComponent >> renderSignInOn: html
   html tbsGlyphIcon perform: #iconLock.
   html html: '<a data-toggle="modal" href="#myAuthDialog" class="link">SignIn</a>'.
\end{displaycode}

We introduce this link below the list of categories.

\begin{displaycode}{smalltalk}
TBPostsListComponent >> renderCategoryColumnOn: html
   html tbsColumn
      extraSmallSize: 12;
      smallSize: 2;
      mediumSize: 4;
      with: [ 
		   self basicRenderCategoriesOn: html.
         self renderSignInOn: html ]
\end{displaycode}

Figure \ref{authentification} shows what is displayed when the user click on the 'SignIn' link.


\begin{figure}

\begin{center}
\includegraphics[width=0.75\textwidth]{figures/Authentification.png}\caption{Authentication Modal Dialog.\label{authentification}}\end{center}
\end{figure}

\section{Administration of Posts}
We will create two components. The first one will be a report that contains all posts and the second one will contain this report. The report will be automatically generated with Magritte as a Seaside component and we could have only one component. However, we believe that sperating the administration component from the report is a good pratice regarding for evolution.  Let's start by the administration component.
\subsection{Creating the Administration Component }
\textcode{TBAdminComponent}  inherit from \textcode{TBScreenComponent} to benefit from the header and access to the blog model. It will contain the report that will create in the following.

\begin{displaycode}{smalltalk}
TBScreenComponent subclass: #TBAdminComponent
   instanceVariableNames: ''
   classVariableNames: ''
   category: 'TinyBlog-Components'
\end{displaycode}

We define a first testing version of the \textcode{renderContentOn:} method:

\begin{displaycode}{smalltalk}
TBAdminComponent >> renderContentOn: html
   super renderContentOn: html.
   html tbsContainer: [
      html heading: 'Blog Admin'.
      html horizontalRule ]
\end{displaycode}

We modify the \textcode{validate} method to invoke the \textcode{gotoAdministration} method defined in \textcode{TBPostsListComponent}. This latter method calls the administration component. 

\begin{displaycode}{smalltalk}
TBPostsListComponent >> gotoAdministration
   self call: TBAdminComponent new
\end{displaycode}

\begin{displaycode}{smalltalk}
TBAuthentificationComponent >> validate
   (self account = 'admin' and: [ self password = 'password' ])
      ifTrue: [ self component gotoAdministration ]
\end{displaycode}

Figure \ref{adminSimple} illustrates what you obtain after logging in into your application.


\begin{figure}

\begin{center}
\includegraphics[width=0.75\textwidth]{figures/BlogAdminSimple.png}\caption{An Empty Administration Component.\label{adminSimple}}\end{center}
\end{figure}

\subsection{The Report Component}
The list of posts is displayed by a dynamically generated report with Magritte. We use Magritte here to create the fonctionnalities of the administration part of TinyBlog (list, create, edit and remove posts). For modularity purpose, we create a Seaside component for the report.

\begin{displaycode}{smalltalk}
TBSMagritteReport subclass: #TBPostsReport
   instanceVariableNames: ''
   classVariableNames: ''
   category: 'TinyBlog-Components'
\end{displaycode}

We add a class-side method named \textcode{from:} and pass it the blog object to use to create the report. Since all posts have the same magritte descriptions, we use one post object to retrieve them.

\begin{displaycode}{smalltalk}
TBPostsReport class >> from: aBlog
   | allBlogs |
   allBlogs := aBlog allBlogPosts.
   ^ self rows: allBlogs description: allBlogs anyOne magritteDescription
\end{displaycode}

We can now, add a report to the \textcode{TBAdminComponent}.

\begin{displaycode}{smalltalk}
TBScreenComponent subclass: #TBAdminComponent
   instanceVariableNames: 'report'
   classVariableNames: ''
   category: 'TinyBlog-Components'
\end{displaycode}

\begin{displaycode}{smalltalk}
TBAdminComponent >> report
   ^ report

TBAdminComponent >> report: aReport
   report := aReport
\end{displaycode}

Since the report is a child component of \textcode{TBAdminComponent}, we must redefine the \textcode{children}  method as follows.

\begin{displaycode}{smalltalk}
TBAdminComponent >> children
   ^ super children copyWith: self report 
\end{displaycode}

In the \textcode{initialize} method of \textcode{TBAdminComponent} we instanciate a \textcode{TBPostsReport} and pass it the current blog object to access posts.

\begin{displaycode}{smalltalk}
TBAdminComponent >> initialize
   super initialize.
   self report: (TBPostsReport from: self blog)
\end{displaycode}

We can now display the report in the \textcode{renderContentOn:} method. 

\begin{displaycode}{smalltalk}
TBAdminComponent >> renderContentOn: html
   super renderContentOn: html.
   html tbsContainer: [
      html heading: 'Blog Admin'.
      html horizontalRule.
      html render: self report ]
\end{displaycode}

By default, the report display all data available in posts even if some columns are not useful. We can filter columns and only display the title, the category and the creation date.

We add a class-side method on \textcode{TBPostsReport} to select columns and we modify the \textcode{from:}  methode to use it.

\begin{displaycode}{smalltalk}
TBPostsReport class >> filteredDescriptionsFrom: aBlogPost
   ^ aBlogPost magritteDescription select: [ :each | #(title category date) includes: each accessor selector ]
   
TBPostsReport class >> from: aBlog
   | allBlogs |
   allBlogs := aBlog allBlogPosts.
   ^ self rows: allBlogs description: (self filteredDescriptionsFrom: allBlogs anyOne)
\end{displaycode}
\subsection{Improve the Report}
Currently, the generated report is raw. There are no titles on columns, columns order is not fixed (it can change from instance to another).  We will modify Magritte descriptions of posts to improve this.

\begin{displaycode}{smalltalk}
TBPost >> descriptionTitle
   <magritteDescription>
   ^ MAStringDescription new
      label: 'Title';
      priority: 100;
      accessor: #title;
      beRequired;
      yourself
\end{displaycode}

\begin{displaycode}{smalltalk}
TBPost >> descriptionText
   <magritteDescription>
   ^ MAMemoDescription new
      label: 'Text';
      priority: 200;
      accessor: #text;
      beRequired;
      yourself
\end{displaycode}

\begin{displaycode}{smalltalk}
TBPost >> descriptionCategory
   <magritteDescription>
   ^ MAStringDescription new
      label: 'Category';
      priority: 300;
      accessor: #category;
      yourself
\end{displaycode}

\begin{displaycode}{smalltalk}
TBPost >> descriptionDate
   <magritteDescription>
   ^ MADateDescription new
      label: 'Date';
      priority: 400;
      accessor: #date;
      beRequired;
      yourself
\end{displaycode}

\begin{displaycode}{smalltalk}
TBPost >> descriptionVisible
   <magritteDescription>
   ^ MABooleanDescription new
      label: 'Visible';
      priority: 500;
      accessor: #visible;
      beRequired;
      yourself
\end{displaycode}

Figure \ref{adminReportDraft} shows what the report looks like after logging in.


\begin{figure}

\begin{center}
\includegraphics[width=0.85\textwidth]{figures/ReportDraft.png}\caption{Administration of Posts with a Report.\label{adminReportDraft}}\end{center}
\end{figure}

\subsection{Manage Posts}
We now set up CRUD (Create Read Update Delete) actions to let administrators manage  posts. We will add a enew colum (instance of \textcode{MACommandColumn}) in the report that will group all operations on posts using   \textcode{addCommandOn:}. This is done during the report creation and we modify the report to have access to the blog. 

\begin{displaycode}{smalltalk}
TBSMagritteReport subclass: #TBPostsReport
	instanceVariableNames: 'report blog'
	classVariableNames: ''
	category: 'TinyBlog-Components'

TBSMagritteReport >> blog
   ^ blog

TBSMagritteReport >> blog: aTBBlog
   blog := aTBBlog
\end{displaycode}

\begin{displaycode}{smalltalk}
TBPostsReport class >> from: aBlog
	| report blogPosts |
	blogPosts := aBlog allBlogPosts.
	report := self rows: blogPosts description: (self filteredDescriptionsFrom: blogPosts anyOne).
	report blog: aBlog.
	report addColumn: (MACommandColumn new
		addCommandOn: report  selector: #viewPost: text: 'View'; yourself;
		addCommandOn: report selector: #editPost: text: 'Edit'; yourself;
		addCommandOn: report selector: #deletePost: text: 'Delete'; yourself).
	 ^ report
\end{displaycode}

A link is displayed above the report to add a post (add). Since this link is part of the \textcode{TBPostsReport} component, we redefine its \textcode{renderContentOn:} to introduce this \textcode{add} link.

\begin{displaycode}{smalltalk}
TBPostsReport >> renderContentOn: html
   html tbsGlyphIcon perform: #iconPencil.
   html anchor
      callback: [ self addPost ];
      with: 'Add post'.
   super renderContentOn: html
\end{displaycode}

Figure \ref{RapportNewLookActions} shows the new version of the posts report.


\begin{figure}

\begin{center}
\includegraphics[width=0.75\textwidth]{figures/RapportNewLookActions.png}\caption{Link to Add a Post.\label{RapportNewLookActions}}\end{center}
\end{figure}

\subsection{Implementing CRUD Actions on Posts}
Each action (Create/Read/Update/Delete) is associated to one method of the \textcode{TBPostsReport} objet. We will detail the implementation of each of them that consists in creating a customized form for each action. Indeed, if the user wants to read a post, it does not need a 'save' button that is only needed when editing the post.
\subsubsection{Adding a Post}
\begin{displaycode}{smalltalk}
TBPostsReport >> renderAddPostForm: aPost
	^ aPost asComponent
		addDecoration: (TBSMagritteFormDecoration buttons: { #save -> 'Add post' .  #cancel -> 'Cancel'});
		yourself
\end{displaycode}

The \textcode{renderAddPostForm} method demonstrates the power of Magritte to generate forms. In this example, the \textcode{asComponent} message sent to a model object (instance of \textcode{TBPost}) directly creates a Seaside component. By adding a decoration to this Seaside component, we can introduce the ok/cancel buttons.

\begin{displaycode}{smalltalk}
TBPostsReport >> addPost
	| post |
	post := self call: (self renderAddPostForm: TBPost new).
	post ifNotNil: [ blog writeBlogPost: post ]
\end{displaycode}

The \textcode{addPost} method first displays generated form component returned by \textcode{renderAddPostForm:} and then add the newly created post to the blog.

Figure \ref{addAPost} shows the form to add a post. 


\begin{figure}

\begin{center}
\includegraphics[width=0.75\textwidth]{figures/AddAPost.png}\caption{Form to Add a Post.\label{addAPost}}\end{center}
\end{figure}

\subsubsection{Edit a Post}
\begin{displaycode}{smalltalk}
TBPostsReport >> renderEditPostForm: aPost
	^ aPost asComponent
		addDecoration: (TBSMagritteFormDecoration buttons: { #save -> 'Save post' . #cancel -> 'Cancel'});
		yourself

TBPostsReport >> editPost: aPost
	| post |
	post := self call: (self renderEditPostForm: aPost).
	post ifNotNil: [ blog save ]
\end{displaycode}
\subsubsection{Read a Post}
\begin{displaycode}{smalltalk}
TBPostsReport >> viewPost: aPost
	self call: (self renderViewPostForm: aPost)

TBPostsReport >> renderViewPostForm: aPost
	^ aPost asComponent
		addDecoration: (TBSMagritteFormDecoration buttons: { #cancel -> 'Back' });
		yourself
\end{displaycode}
\subsubsection{Remove a Post}
To prevent mistakes, we introduce a modal dialog to make the user confirm a post removal. Once removed, the list of posts displayed by the \textcode{TBPostsReport} component should be refreshed as we will see in the following.

\begin{displaycode}{smalltalk}
TBPostsReport >> deletePost: aPost
	(self confirm: 'Do you want remove this post ?') 
		ifTrue: [ blog removeBlogPost: aPost ]
\end{displaycode}

\begin{displaycode}{smalltalk}
TBBlog >> removeBlogPost: aPost
	posts remove: aPost ifAbsent: [ ].
	self save.
\end{displaycode}

The last method above has been added in the \textcode{TBBlog} class that belongs to the model of our application. We must write a new unit test to cover this functionnality.

\begin{displaycode}{smalltalk}
TBBlogTest >> testRemoveBlogPost
	self assert: blog size equals: 1.
	blog removeBlogPost: blog allBlogPosts anyOne.
	self assert: blog size equals: 0
\end{displaycode}
\subsection{Dealing with Data Update}
Methods \textcode{TBPostsReport \textgreater{}\textgreater{} addPost:} and \textcode{TBPostsReport \textgreater{}\textgreater{} deletePost:} correctly modify data in the model (and the database) but the displayed data on screen are not correctly updated. There is a mismatch between data in the model and data displayed by the view. The view (the report) should be refreshed.

\begin{displaycode}{smalltalk}
TBPostsReport >> refreshReport
	self rows: blog allBlogPosts.
	self refresh.
\end{displaycode}

\begin{displaycode}{smalltalk}
TBPostsReport >> addPost
	| post |
	post := self call: (self renderAddPostForm: TBPost new).
	post ifNotNil: [
		blog writeBlogPost: post.
 		self refreshReport
	]

TBPostsReport >> deletePost: aPost
	(self confirm: 'Do you want remove this post ?') 
		ifTrue: [ blog removeBlogPost: aPost.
				 self refreshReport ]
\end{displaycode}

Now, the form works well and it also take into account contraints expressed in Magritte descriptions such mandatory fields. 
\subsection{Improve the Form Skin}
We will now modify Magritte descriptions to make form generators use Bootstrap. First, we specify that the form should be rendered inside a Bootstrap conainer.

\begin{displaycode}{smalltalk}
TBPost >> descriptionContainer
	<magritteContainer>
	^ super descriptionContainer
		componentRenderer: TBSMagritteFormRenderer;
		yourself
\end{displaycode}

We can now, improve the style of the input fields with Bootstrap specific annotations.

\begin{displaycode}{smalltalk}
TBPost >> descriptionTitle
	<magritteDescription>
	^ MAStringDescription new
		label: 'Title';
		priority: 100;
		accessor: #title;
		requiredErrorMessage: 'A blog post must have a title.';
		comment: 'Please enter a title';
		componentClass: TBSMagritteTextInputComponent;
		beRequired;
		yourself
\end{displaycode}

\begin{displaycode}{smalltalk}
TBPost >> descriptionText
	<magritteDescription>
	^ MAMemoDescription new
		label: 'Text';
		priority: 200;
		accessor: #text;
		beRequired;
		requiredErrorMessage: 'A blog post must contain a text.';
		comment: 'Please enter a text';
		componentClass: TBSMagritteTextAreaComponent;
		yourself
\end{displaycode}

\begin{displaycode}{smalltalk}
TBPost >> descriptionCategory
	<magritteDescription>
	^ MAStringDescription new
		label: 'Category';
		priority: 300;
		accessor: #category;
		comment: 'Unclassified if empty';
		componentClass: TBSMagritteTextInputComponent;
		yourself
\end{displaycode}

\begin{displaycode}{smalltalk}
TBPost >> descriptionVisible
	<magritteDescription>
	^ MABooleanDescription new
		checkboxLabel: 'Visible';
		priority: 500;
		accessor: #visible;
		componentClass: TBSMagritteCheckboxComponent;
		beRequired;
		yourself
\end{displaycode}

Figure \ref{addAPostBootstrap} shows what looks like a form to add a post.


\begin{figure}

\begin{center}
\includegraphics[width=0.85\textwidth]{figures/AddAPostBootstrap.png}\caption{Bootstrap-based Generated Form to Add a Post.\label{addAPostBootstrap}}\end{center}
\end{figure}

\section{Session Management}
A session object is associated to each instance of Seaside application. A session is dedicated to store informations shared and accessible by all components of the application such as the currently authenticated user. We will describe now how to use a session to manage log in. 

The blog admin may want to switch between the private (admin) and public (readers) part of TinyBlog.

We introduce a new subclass of \textcode{WASession} named \textcode{TBSession}. 
To know wether a user is connected or not, we define a session object with an instance  variable named \textcode{logged} that contains a boolean value. 

\begin{displaycode}{smalltalk}
WASession subclass: #TBSession
	instanceVariableNames: 'logged'
	classVariableNames: ''
	category: 'TinyBlog-Components'

TBSession >> logged
	^ logged

TBSession >> logged: anObject
	logged := anObject

TBSession >> isLogged
	^ self logged
\end{displaycode}

We initialize this instance variable to \textcode{false} when the session is created.

\begin{displaycode}{smalltalk}
TBSession >> initialize
	super initialize.
	self logged: false.
\end{displaycode}

In the admin part of TinyBlog, we add a link to switch to the public part. We use here the  \textcode{answer}  message because the administration composant has been called using the \textcode{call:} message.

\begin{displaycode}{smalltalk}
TBAdminComponent >> renderContentOn: html
	super renderContentOn: html.
	html tbsContainer: [
		html heading: 'Blog Admin'.
		html tbsGlyphIcon perform: #iconEyeOpen.
		html anchor
			callback: [ self answer ];
			with: 'Public Area'.
		html horizontalRule.
		html render: self report.
	]
\end{displaycode}

In the public part, we modify the behavior of the application when the user click on the link to access the admin part. This link only opens the authentication modal dialog if the user is not already connected.

\begin{displaycode}{smalltalk}
TBPostsListComponent >> renderSignInOn: html
	self session isLogged
		ifFalse: [
			html tbsGlyphIcon perform: #iconLock.
			html html: '<a data-toggle="modal" href="#myAuthDialog" class="link">SignIn</a>' ]
		ifTrue: [
			html tbsGlyphIcon perform: #iconUser.
			html anchor callback: [ self gotoAdministration ]; with: 'Private area' ]
\end{displaycode}

The \textcode{TBAuthentificationComponent} component shoudl now update the \textcode{logged} instance variable of the session if the user successfully log in as an administrator.

\begin{displaycode}{smalltalk}
TBauthentificationComponent >> validate
	(self account = 'admin' and: [ self password = 'password' ]) 
		ifTrue: [ self session logged: true.
		component gotoAdministration ]
\end{displaycode}

Finally, we have to configure Seaside to use session object instance of \textcode{TBSession} for the TinyBlog application. 
This is done in the \textcode{initialize} class-side method of \textcode{TBApplicationRootComponent}.

\begin{displaycode}{smalltalk}
TBApplicationRootComponent class >> initialize
      "self initialize"
      | app |
      app := WAAdmin register: self asApplicationAt: 'TinyBlog'.
      app 
         preferenceAt: #sessionClass put: TBSession.
      app
         addLibrary: JQDeploymentLibrary;
         addLibrary: JQUiDeploymentLibrary;
         addLibrary: TBSDeploymentLibrary
\end{displaycode}

Before testing, remember that this method must be executed manually \textcode{TBApplicationRootComponent initialize}, because the class already exists.
\section{Possible Enhancements}
\begin{itemize}
\item Add a \symbol{34}Disconnect\symbol{34} button
\item Manage multiple administrator accounts which implies to improve session management and store the current user login 
\item Manage multiple blogs 
\end{itemize}


\ifx\wholebook\relax\else
\end{document}
\fi