Index: main/waeup.sirp/trunk/src/waeup/sirp/browser/pages.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/browser/pages.py	(revision 7333)
+++ main/waeup.sirp/trunk/src/waeup/sirp/browser/pages.py	(revision 7334)
@@ -1407,10 +1407,11 @@
             yield(dict(url=url, name=key, container=val))
 
-class ShowStudentsPage(SIRPPage):
+class ShowStudentsInDepartmentPage(SIRPPage):
     """Page that lists all students in the department.
     """
     grok.context(IDepartment)
     grok.require('waeup.showStudents')
-    grok.name('showstudents')
+    grok.name('showdepstudents')
+    grok.template('showstudentspage')
     pnav = 1
     label = 'Students'
@@ -1429,4 +1430,19 @@
         datatable.need()
         return
+
+class ShowStudentsInCertificatePage(ShowStudentsInDepartmentPage):
+    """Page that lists all students studying a certificate.
+    """
+    grok.context(ICertificate)
+    grok.require('waeup.showStudents')
+    grok.name('showcertstudents')
+    pnav = 1
+    label = 'Students'
+
+    @property
+    def getStudents(self):
+        hitlist = searchstudents(query=self.context.code,
+            searchtype='certcode', view=self)
+        return hitlist
 
 class DepartmentManageFormPage(SIRPEditFormPage):
Index: main/waeup.sirp/trunk/src/waeup/sirp/browser/viewlets.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/browser/viewlets.py	(revision 7333)
+++ main/waeup.sirp/trunk/src/waeup/sirp/browser/viewlets.py	(revision 7334)
@@ -434,5 +434,5 @@
     icon = 'actionicon_student.png'
     text = 'Show students'
-    target = 'showstudents'
+    target = 'showdepstudents'
 
 class ManageCourseActionButton(ManageActionButton):
@@ -449,4 +449,14 @@
     grok.view(CertificatePage)
     text = 'Manage certificate'
+
+class ShowCertificateStudentsActionButton(ManageActionButton):
+    """ 'Show students' button for certificates.
+    """
+    grok.context(ICertificate)
+    grok.view(CertificatePage)
+    grok.require('waeup.showStudents')
+    icon = 'actionicon_student.png'
+    text = 'Show students'
+    target = 'showcertstudents'
 
 class ManageCertificateCourseActionButton(ManageActionButton):
Index: main/waeup.sirp/trunk/src/waeup/sirp/permissions.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/permissions.py	(revision 7333)
+++ main/waeup.sirp/trunk/src/waeup/sirp/permissions.py	(revision 7334)
@@ -82,11 +82,51 @@
     grok.permissions('waeup.showStudents', 'waeup.viewAcademics')
 
-class CourseAdviser(grok.Role):
-    """The course adviser role is meant for the
-    assignment of dynamic roles only.
-    """
-    grok.name('waeup.local.CourseAdviser')
-    grok.title(u'Course Adviser')
-    grok.permissions('waeup.showStudents')
+class CourseAdviser100(grok.Role):
+    """The course adviser role is meant for the
+    assignment of dynamic roles only.
+    """
+    grok.name('waeup.local.CourseAdviser100')
+    grok.title(u'Course Adviser 100L')
+    grok.permissions('waeup.showStudents', 'waeup.viewAcademics')
+
+class CourseAdviser200(grok.Role):
+    """The course adviser role is meant for the
+    assignment of dynamic roles only.
+    """
+    grok.name('waeup.local.CourseAdviser200')
+    grok.title(u'Course Adviser 200L')
+    grok.permissions('waeup.showStudents', 'waeup.viewAcademics')
+
+class CourseAdviser300(grok.Role):
+    """The course adviser role is meant for the
+    assignment of dynamic roles only.
+    """
+    grok.name('waeup.local.CourseAdviser300')
+    grok.title(u'Course Adviser 300L')
+    grok.permissions('waeup.showStudents', 'waeup.viewAcademics')
+
+class CourseAdviser400(grok.Role):
+    """The course adviser role is meant for the
+    assignment of dynamic roles only.
+    """
+    grok.name('waeup.local.CourseAdviser400')
+    grok.title(u'Course Adviser 400L')
+    grok.permissions('waeup.showStudents', 'waeup.viewAcademics')
+
+class CourseAdviser500(grok.Role):
+    """The course adviser role is meant for the
+    assignment of dynamic roles only.
+    """
+    grok.name('waeup.local.CourseAdviser500')
+    grok.title(u'Course Adviser 500L')
+    grok.permissions('waeup.showStudents', 'waeup.viewAcademics')
+
+class CourseAdviser600(grok.Role):
+    """The course adviser role is meant for the
+    assignment of dynamic roles only.
+    """
+    grok.name('waeup.local.CourseAdviser600')
+    grok.title(u'Course Adviser 600L')
+    grok.permissions('waeup.showStudents', 'waeup.viewAcademics')
 
 class Owner(grok.Role):
@@ -194,10 +234,10 @@
         to assign each role to).
         """
-        return [
-            dict(
+        list_of_dict = [dict(
                 name=name,
                 title=role.title,
                 description=role.description)
-            for name, role in self._roles]
+                for name, role in self._roles]
+        return sorted(list_of_dict, key=lambda x: x['name'])
 
 def get_users_with_local_roles(context):
Index: main/waeup.sirp/trunk/src/waeup/sirp/permissions.txt
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/permissions.txt	(revision 7333)
+++ main/waeup.sirp/trunk/src/waeup/sirp/permissions.txt	(revision 7334)
@@ -39,8 +39,8 @@
     >>> from waeup.sirp.permissions import get_waeup_roles
     >>> len(list(get_waeup_roles()))
-    10
+    11
 
     >>> len(list(get_waeup_roles(also_local=True)))
-    16
+    22
 
 
@@ -53,9 +53,14 @@
     >>> from waeup.sirp.permissions import get_waeup_role_names
     >>> list(get_waeup_role_names())
-    [u'waeup.ACManager', u'waeup.AcademicsOfficer',
-     u'waeup.AccommodationOfficer', u'waeup.Applicant',
+    [u'waeup.ACManager',
+     u'waeup.AcademicsOfficer',
+     u'waeup.AccommodationOfficer',
+     u'waeup.Applicant',
      u'waeup.ApplicationsOfficer',
-     u'waeup.PortalManager', u'waeup.Student',
-     u'waeup.StudentsClearanceOfficer', u'waeup.StudentsManager',
+     u'waeup.PortalManager',
+     u'waeup.Student',
+     u'waeup.StudentsClearanceOfficer',
+     u'waeup.StudentsCourseAdviser',
+     u'waeup.StudentsManager',
      u'waeup.StudentsOfficer']
 
Index: main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py	(revision 7333)
+++ main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py	(revision 7334)
@@ -594,5 +594,4 @@
 
     def render(self):
-        self.redirect(self.url(self.context, 'view_clearance'))
         return
 
@@ -615,4 +614,5 @@
         else:
             self.flash('Student is in the wrong state.')
+            self.redirect(self.url(self.context,'view_clearance'))
             return
         args = {'subject':message}
@@ -857,4 +857,36 @@
     target = 'manage'
 
+class StudentValidateCoursesActionButton(ManageActionButton):
+    grok.order(3)
+    grok.context(IStudentStudyLevel)
+    grok.view(StudyLevelDisplayFormPage)
+    grok.require('waeup.validateStudent')
+    text = 'Validate courses'
+    target = 'validate_courses'
+    icon = 'actionicon_accept.png'
+
+    @property
+    def target_url(self):
+        if self.context.getStudent().state != REGISTERED or \
+            str(self.context.__parent__.current_level) != self.context.__name__:
+            return ''
+        return self.view.url(self.view.context, self.target)
+
+class StudentRejectCoursesActionButton(ManageActionButton):
+    grok.order(4)
+    grok.context(IStudentStudyLevel)
+    grok.view(StudyLevelDisplayFormPage)
+    grok.require('waeup.validateStudent')
+    text = 'Reject courses'
+    target = 'reject_courses'
+    icon = 'actionicon_reject.png'
+
+    @property
+    def target_url(self):
+        if self.context.getStudent().state not in (VALIDATED, REGISTERED) or \
+            str(self.context.__parent__.current_level) != self.context.__name__:
+            return ''
+        return self.view.url(self.view.context, self.target)
+
 class StudyLevelManageFormPage(SIRPEditFormPage):
     """ Page to edit the student study level data
@@ -915,4 +947,57 @@
             self.flash('Successfully removed: %s' % ', '.join(deleted))
         self.redirect(self.url(self.context, u'@@manage')+'#tab-2')
+        return
+
+class ValidateCoursesPage(grok.View):
+    """ Validate course list by course adviser
+    """
+    grok.context(IStudentStudyLevel)
+    grok.name('validate_courses')
+    grok.require('waeup.validateStudent')
+
+    def update(self):
+        if str(self.context.__parent__.current_level) != self.context.__name__:
+            self.flash('This level does not correspond current level.')
+        elif self.context.getStudent().state == REGISTERED:
+            IWorkflowInfo(self.context.getStudent()).fireTransition('validate_courses')
+            self.flash('Course list has been registered.')
+        else:
+            self.flash('Student is in the wrong state.')
+        self.redirect(self.url(self.context))
+        return
+
+    def render(self):
+        return
+
+class RejectCoursesPage(grok.View):
+    """ Reject course list by course adviser
+    """
+    grok.context(IStudentStudyLevel)
+    grok.name('reject_courses')
+    grok.require('waeup.validateStudent')
+
+    def update(self):
+        if str(self.context.__parent__.current_level) != self.context.__name__:
+            self.flash('This level does not correspond current level.')
+            self.redirect(self.url(self.context))
+            return
+        elif self.context.getStudent().state == VALIDATED:
+            IWorkflowInfo(self.context.getStudent()).fireTransition('reset8')
+            message = 'Course list request has been annulled'
+            self.flash(message)
+        elif self.context.getStudent().state == REGISTERED:
+            IWorkflowInfo(self.context.getStudent()).fireTransition('reset7')
+            message = 'Course list request has been rejected'
+            self.flash(message)
+        else:
+            self.flash('Student is in the wrong state.')
+            self.redirect(self.url(self.context))
+            return
+        args = {'subject':message}
+        self.redirect(self.url(self.context.getStudent()) +
+            '/contactstudent?%s' % urlencode(args))
+        return
+
+    def render(self):
         return
 
Index: main/waeup.sirp/trunk/src/waeup/sirp/students/dynamicroles.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/students/dynamicroles.py	(revision 7333)
+++ main/waeup.sirp/trunk/src/waeup/sirp/students/dynamicroles.py	(revision 7334)
@@ -46,10 +46,10 @@
     rolename_mapping = {
         'waeup.local.ClearanceOfficer':'waeup.StudentsClearanceOfficer',
-        'waeup.local.CourseAdviser100':'waeup.StudentsCourseAdviser100',
-        'waeup.local.CourseAdviser200':'waeup.StudentsCourseAdviser200',
-        'waeup.local.CourseAdviser300':'waeup.StudentsCourseAdviser300',
-        'waeup.local.CourseAdviser400':'waeup.StudentsCourseAdviser400',
-        'waeup.local.CourseAdviser500':'waeup.StudentsCourseAdviser500',
-        'waeup.local.CourseAdviser600':'waeup.StudentsCourseAdviser600'
+        'waeup.local.CourseAdviser100':'waeup.StudentsCourseAdviser',
+        'waeup.local.CourseAdviser200':'waeup.StudentsCourseAdviser',
+        'waeup.local.CourseAdviser300':'waeup.StudentsCourseAdviser',
+        'waeup.local.CourseAdviser400':'waeup.StudentsCourseAdviser',
+        'waeup.local.CourseAdviser500':'waeup.StudentsCourseAdviser',
+        'waeup.local.CourseAdviser600':'waeup.StudentsCourseAdviser'
         }
 
@@ -100,6 +100,9 @@
             obj = getattr(
                 self._context[self.subcontainer], self.extra_attrib, None)
+            current_level = getattr(
+                self._context[self.subcontainer], 'current_level', None)
         else:
             obj = getattr(self._context, self.extra_attrib, None)
+            current_level = None
         # lookup local roles for connected course and all parent
         # objects. This way we fake 'role inheritance'.
@@ -113,6 +116,12 @@
                     # permissions (allow, deny or unset) for the
                     # passed in principal id.
-                    result.append(
-                        (self.rolename_mapping[role_id], setting))
+                    # Make an exception for Course Advisers:
+                    # Grant additional role only if external role corresponds
+                    # with current_level of student.
+                    if not current_level or \
+                        'CourseAdviser' not in  role_id or \
+                        str(current_level) in role_id:
+                        result.append(
+                            (self.rolename_mapping[role_id], setting))
                     return result
             obj = getattr(obj, '__parent__', None)
Index: main/waeup.sirp/trunk/src/waeup/sirp/students/permissions.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/students/permissions.py	(revision 7333)
+++ main/waeup.sirp/trunk/src/waeup/sirp/students/permissions.py	(revision 7334)
@@ -53,4 +53,7 @@
     grok.name('waeup.clearStudent')
 
+class ValidateStudent(grok.Permission):
+    grok.name('waeup.validateStudent')
+
 # Local role
 class StudentRecordOwner(grok.Role):
@@ -83,2 +86,7 @@
     grok.title(u'Clearance Officer (all students)')
     grok.permissions('waeup.clearStudent','waeup.viewStudent')
+
+class StudentsCourseAdviser(grok.Role):
+    grok.name('waeup.StudentsCourseAdviser')
+    grok.title(u'Course Adviser (all students)')
+    grok.permissions('waeup.validateStudent','waeup.viewStudent')
Index: main/waeup.sirp/trunk/src/waeup/sirp/university/certificate.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/university/certificate.py	(revision 7333)
+++ main/waeup.sirp/trunk/src/waeup/sirp/university/certificate.py	(revision 7334)
@@ -32,4 +32,14 @@
     """
     grok.implements(ICertificate, ICertificateAdd)
+
+    @property       # Make this method read_only and looking like an attr.
+    def local_roles(cls):
+        return ['waeup.local.CourseAdviser100',
+                'waeup.local.CourseAdviser200',
+                'waeup.local.CourseAdviser300',
+                'waeup.local.CourseAdviser400',
+                'waeup.local.CourseAdviser500',
+                'waeup.local.CourseAdviser600',
+                ]
 
     def __init__(self, code=u'NA', title=u'Unnamed Certificate',
Index: main/waeup.sirp/trunk/src/waeup/sirp/university/department.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/university/department.py	(revision 7333)
+++ main/waeup.sirp/trunk/src/waeup/sirp/university/department.py	(revision 7334)
@@ -33,5 +33,12 @@
     def local_roles(cls):
         return ['waeup.local.DepartmentManager',
-                'waeup.local.ClearanceOfficer',]
+                'waeup.local.ClearanceOfficer',
+                'waeup.local.CourseAdviser100',
+                'waeup.local.CourseAdviser200',
+                'waeup.local.CourseAdviser300',
+                'waeup.local.CourseAdviser400',
+                'waeup.local.CourseAdviser500',
+                'waeup.local.CourseAdviser600',
+                ]
 
     # A simple counter for ids.
Index: main/waeup.sirp/trunk/src/waeup/sirp/university/faculty.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/university/faculty.py	(revision 7333)
+++ main/waeup.sirp/trunk/src/waeup/sirp/university/faculty.py	(revision 7334)
@@ -34,5 +34,12 @@
     def local_roles(cls):
         return ['waeup.local.DepartmentManager',
-                'waeup.local.ClearanceOfficer',]
+                'waeup.local.ClearanceOfficer',
+                'waeup.local.CourseAdviser100',
+                'waeup.local.CourseAdviser200',
+                'waeup.local.CourseAdviser300',
+                'waeup.local.CourseAdviser400',
+                'waeup.local.CourseAdviser500',
+                'waeup.local.CourseAdviser600',
+                ]
 
     def __init__(self,
