Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

Customising the CMS /

Customization of the login page


Reply


6 Posts   1018 Views

Avatar
vodoomoth

Community Member, 22 Posts

26 December 2012 at 11:37am

Hello,

I have a website that has two locales, fr_FR and en_US and on every page of my website, the header contains a "Login" (en_US) or "Connexion" (fr_FR) link. The link allows users to login and turns into a link for editing the user's profile.

Question 1:
I have realized that the login form is displayed in French no matter the language of the page where the link is clicked. I would like to have the login form localized according to the language of the page where the login form link was clicked. How can I do that? Is there some information that I can use to determine the previous page? What programmatic is usually used to know the current session locale?

Question 2:
The access to some of my pages (from the blog module) is restricted to some groups. However, those pages appear in the list of articles without being filtered with respect to the user's access rights to individual articles (the lack of filtering isn't a problem for me on the website that I'm currently working on). When a user who isn't connected (or who doesn't have the access rights) clicks to view one of those pages, he is presented with the login page. I would like to make the login page "group-aware" so as to display the names of the groups that can access the "target" page.
1- Is it possible to find information about the target page (which may be related to question 1) and if yes, how?
2- Is there a way to list the groups that have access to a page? I'm asking this question because I am not familiar with the architecture of the code, specifically when it comes to the class of objects that have access restrictions attached to them (is it Page? or SiteTree? or some other class?).

Thank you.

Avatar
vodoomoth

Community Member, 22 Posts

27 December 2012 at 10:48am

Edited: 28/12/2012 4:29am

Question 2, item 2 – way to list the groups that have access to a page, done. Use $this->ViewerGroups() when in a subclass of Page, or $this->owner->ViewerGroups when in a DataObjectDecorator. I used a decorator on BlogEntry and I've been able to insert the list of groups that can view an article right above the article summary, without touching the content of the article.

Question 1 - determining the previous page, done. Use the BackURL argument: $_REQUEST['BackURL']. It happens that this argument is automatically added when a non-connected user tries to view an access-protected page. This answers Question 2, item 1.

Question 1 - determining the locale, done. I haven't found a "session locale" per se but I have found that each blog article (and probably any translatable page) has its locale information reachable via… "Locale"! In a decorator, "$locale = $this->owner->Locale;" yields the page's locale in the variable.

Question 1 - localizing the login form depending on the previous page, WIP. I think I just have to retrieve the object that matches the URL fragment in BackURL. Working on it.

[EDIT: removed an unwelcome line break]

Avatar
martimiz

Forum Moderator, 1132 Posts

28 December 2012 at 1:16am

At question 1 localization of the login form:

Maybe this post can be of some help: http://www.silverstripe.org/general-questions/show/19556

Avatar
vodoomoth

Community Member, 22 Posts

28 December 2012 at 4:46am

@martimiz: thanks for the link; it helped but it didn't solve the problem. I've added the code indicated in Page_Controller.init but thanks to the debugger in Eclipse, I've seen this:
* non-connected en_US user clicks a link to an access-restricted article
* Page_Controller.init is called with an ID > 0, requested URL pointing to an en_US page (/pages/articles-en/roadmap), no BackURL, and the locale is then en_US
* a permission control takes place at some unknown point then there's a redirect to the login page
* Page_Controller.init is called with an ID < 0, for Security/login, with BackURL = /pages/articles-en/roadmap and the locale is fr_FR.

At that point, I can no longer know that the real intended target's locale is en_US. Unless I'm able to map the URLSegment in BackURL to a Page object and retrieve that object's locale, which will allow me to change the locale of the login page.

So to solve this once and for all: how can I map a URLSegment to a Page/SiteTree/whatever is pertinent object? Thank you all.

Avatar
vodoomoth

Community Member, 22 Posts

28 December 2012 at 5:40am

Edited: 28/12/2012 5:44am

OK. I've succeeded in the initial intention which was to have the Login page displayed in the language of an "access-restricted" (don't even know if that's valid English) page.

It is indeed in Page_Controller.init (in mysite/Page.php) that all the cooking takes place. The whole function is below.

Please, note that this code is very far from being clean. Too much defensive programming, redundancy, etc. The code will probably not work if the last segment happens to be used for different locales. Put more clearly: if you have mywebsite.com/pages/faq and mywebsite/pages-en/faq, it won't work.

You've been warned.

   public function init() {
      // Note: you should use SS template require tags inside your templates
      // instead of putting Requirements calls here. However these are
      // included so that our older themes still work
      Requirements::themedCSS('layout');

      //RSSFeed::linkToFeed($this->Link() . "rss", "Flux RSS");

      if($this->dataRecord->hasExtension('Translatable')) {
         i18n::set_locale($this->dataRecord->Locale);
      }
      if ($this->ID < 0) { // we're dealing with a Security virtual page
         $URLSegment = $_REQUEST['BackURL'];
         if (!empty($URLSegment)) {
            $lastSegment = '';
            $lastPos = strrpos($URLSegment, "/");
            $len = strlen($URLSegment);
            if ($lastPos == $len - 1) {
               $shortenedURL = substr($URLSegment, 0, $len - 1);
               $lastSegment = substr($shortenedURL, strrpos($shortenedURL, "/") + 1);
            } else {
               $lastSegment = substr($URLSegment, strrpos($URLSegment, "/") + 1);
            }
            // find the Page that matches the urlfrag
            Translatable::disable_locale_filter();
            $sitetree = DataObject::get_one(
                  'SiteTree',
                  sprintf(
                        '"URLSegment" = \'%s\'',
                        Convert::raw2sql($lastSegment)
                  )
            );
            Translatable::enable_locale_filter();
            // get its locale
            if ($sitetree) {
               $forcedLocale = $sitetree->Locale;
               // set the current locale to the page's locale
               $this->dataRecord->Locale = $forcedLocale;
               i18n::set_locale($forcedLocale);
            }
         }
      }
      parent::init();
   }

The finding of the page that matches $lastSegment was taken from ModelAsController.php. To be sure that you've selected the appropriate page, a recursive function is needed so as to ensure that the path matches the selected object. I'm too lazy now to do it. Left as an exercise to you :-)

Avatar
vodoomoth

Community Member, 22 Posts

28 December 2012 at 7:41am

Edited: 28/12/2012 7:43am

Just to share my success (and, unabashedly, to flaunt… just a little).
The results of the customized login page can be seen in the attached screen captures.

Last instruction on the how: I've added a decorator to Security. This decorator class has functions that give me the title of the target page and a pretty print listing of its groups (if you've read the previous posts, you'll notice that the pretty print function has been –almost– duplicated in two decorators). To sum up, here are the lines that I've added in mysite/_config.php :

// for listing the article's ViewerGroups in BlogSummary.ss
Object::add_extension('BlogEntry','CustomBlogEntry');

// for forcing the locale of the login page to the locale of the target page
Object::add_extension('Page_Controller','CustomLoginUtils');
// for the title and ViewerGroups of the target page (the URL of which is in BackURL)
Object::add_extension('Security','CustomLoginUtils');

Last thing, it's quite obvious but stating it won't hurt: there were also some changes done in themes/MyTheme/templates/Security_login.ss

Hope all that helps someone. Cheers!