=====================
Intervention Security
=====================

These are the functional tests for intervention security.

First we need to set up the school.

    >>> from schooltool.app.browser.ftests import setup
    >>> setup.setUpBasicSchool()

We'll create a princpal, a guidance counselor, two teachers and three students.
The principal will not teach or advise any student, but by virtue of being
in the administrators group, will be able to do everything for all student
data.  The counselor doesn't teach at all but advises two of the three students.
This will give him the ability to create and edit data for those two students.
The two teachers will have a combination between teaching some of the students
and advising some.  The corner cases will come from the various combinations.

    >>> from schooltool.intervention.browser.ftests import ftests
    >>> ftests.addPerson('Principal', 'Principal', 'principal', 'pwd',
    ...                  groups=['administrators'])
    >>> ftests.addPerson('Counselor', 'Counselor', 'counselor', 'pwd')
    >>> ftests.addPerson('Teacher1', 'Teacher1', 'teacher1', 'pwd')
    >>> ftests.addPerson('Teacher2', 'Teacher2', 'teacher2', 'pwd')
    >>> ftests.addPerson('Student1', 'Student1', 'student1', 'pwd')
    >>> ftests.addPerson('Student2', 'Student2', 'student2', 'pwd')
    >>> ftests.addPerson('Student3', 'Student3', 'student3', 'pwd')

We'll create sessions for each user.

    >>> principal = setup.logIn('principal', 'pwd')
    >>> counselor = setup.logIn('counselor', 'pwd')
    >>> teacher1 = setup.logIn('teacher1', 'pwd')
    >>> teacher2 = setup.logIn('teacher2', 'pwd')
    >>> student1 = setup.logIn('student1', 'pwd')
    >>> student2 = setup.logIn('student2', 'pwd')
    >>> student3 = setup.logIn('student3', 'pwd')

All tests will use the test_access() method to test which users are allowed
to visit which urls.

    >>> user_list = [principal, counselor, teacher1, teacher2, student1,
    ...              student2, student3]
    >>> from zope.publisher.interfaces import NotFound
    >>> from zope.security.interfaces import Unauthorized
    >>> def test_access(url, allowed_list):
    ...     for user in user_list:
    ...         if user in allowed_list:
    ...             try:
    ...                 user.open(url)
    ...             except Unauthorized:
    ...                 raise Exception('%s could not access %s' % (
    ...                     user.username, url))
    ...             except NotFound:
    ...                 raise Exception('%s could not access %s' % (
    ...                     user.username, url))
    ...         else:
    ...             try:
    ...                 user.open(url)
    ...                 raise Exception('%s should not be able to access %s' % (
    ...                     user.username, url))
    ...             except Unauthorized:
    ...                 pass
    ...             except NotFound:
    ...                 pass

We need to add the advisors to each student.

    >>> ftests.addAdvisors('Student1', ['counselor', 'teacher1', 'teacher2'])
    >>> ftests.addAdvisors('Student2', ['counselor'])
    >>> ftests.addAdvisors('Student3', ['teacher1', 'teacher2'])

Next we'll create some sections, setting up various combinations between
teachers and students.

    >>> ftests.addCourseSectionMembers('course1', 'section1', ['Teacher1'],
    ...     ['Student1', 'Student2'])
    >>> ftests.addCourseSectionMembers('course2', 'section2', ['Teacher2'],
    ...     ['Student3'])

We need to visit the student intervention centers using the traversal adapter
to auto-vivify the InterventionStudent objects.

    >>> for student in ['Student1', 'Student2', 'Student3']:
    ...     principal.getLink('Manage').click()
    ...     principal.getLink('Persons').click()
    ...     principal.getLink(student).click()
    ...     principal.getLink('Intervention Center').click()

Now we can create variables with urls for the student intervention center as
well as add message and goals.

    >>> schoolyear_url = 'http://localhost/schooltool.interventions/2005-2006'
    >>> student1_url = schoolyear_url + '/student1'
    >>> student2_url = schoolyear_url + '/student2'
    >>> student3_url = schoolyear_url + '/student3'
    >>> add_msg_student1 = student1_url + '/messages/+/addMessage.html'
    >>> add_msg_student2 = student2_url + '/messages/+/addMessage.html'
    >>> add_msg_student3 = student3_url + '/messages/+/addMessage.html'
    >>> add_goal_student1 = student1_url + '/goals/+/addGoal.html'
    >>> add_goal_student2 = student2_url + '/goals/+/addGoal.html'
    >>> add_goal_student3 = student3_url + '/goals/+/addGoal.html'

    >>> trv_student1 = 'http://localhost/persons/student1/schoolyears/2005-2006'
    >>> trv_student2 = 'http://localhost/persons/student2/schoolyears/2005-2006'
    >>> trv_student3 =  'http://localhost/persons/student3/schoolyears/2005-2006'
    >>> student1_messages = trv_student1 + '/messages'
    >>> student2_messages = trv_student2 + '/messages'
    >>> student3_messages = trv_student3 + '/messages'
    >>> student1_goals = trv_student1 + '/goals'
    >>> student2_goals = trv_student2 + '/goals'
    >>> student3_goals = trv_student3 + '/goals'

We'll test viewing student1's data as well as adding messages and goals.
Since all staff either teach or advise student1, or they are an administrator,
they all can access the student data.  The students may not.

    >>> all_staff = [principal, counselor, teacher1, teacher2]
    >>> test_access(student1_url, all_staff)
    >>> test_access(add_msg_student1, all_staff)
    >>> test_access(add_goal_student1, all_staff)

We'll test viewing student2's data as well as adding messages and goals.
Since teacher2 does not either teach or advise student2, he won't have access.

    >>> test_access(student2_url, [principal, counselor, teacher1])
    >>> test_access(add_msg_student2, [principal, counselor, teacher1])
    >>> test_access(add_goal_student2, [principal, counselor, teacher1])

We'll test viewing student3's data as well as adding messages and goals.
Since the counselor does not teach or advise student3, he won't have access.

    >>> test_access(student3_url, [principal, teacher1, teacher2])
    >>> test_access(add_msg_student3, [principal, teacher1, teacher2])
    >>> test_access(add_goal_student3, [principal, teacher1, teacher2])

The first message and goal we'll add for student1 will be for the student only.
The same people who are allowed to add messages or goals will be able to view
and edit them.  Additionally, the student, by virtue of being on the persons
responsible list, will be able to view the message and goal, but not edit
the goal.

    >>> ftests.addMessage(principal, add_msg_student1, ['student1'])
    From: ...
    >>> ftests.addEditGoal(principal, add_goal_student1, ['student1'])
    From: ...

    >>> message_url = student1_messages + '/1'
    >>> goal_url = student1_goals + '/1'
    >>> goal_edit = goal_url + '/editGoal.html'

    >>> test_access(message_url, all_staff + [student1])
    >>> test_access(goal_url, all_staff + [student1])
    >>> test_access(goal_edit, all_staff)

We'll have the principal edit the goal to remove student1 from the persons
responsible list.  Then we'll test that student1 can no longer access the goal.

    >>> ftests.addEditGoal(principal, goal_edit, ['teacher1'])
    >>> test_access(goal_url, all_staff)
    >>> test_access(goal_edit, all_staff)

The second message and goal we'll add for student1 will be for the counselor.
The same people who are allowed to add messages or goals will be able to view
and edit them.  This time, the student, not being on the persons responsible
list, will not be able to view the message and goal, nor edit the goal.

    >>> ftests.addMessage(principal, add_msg_student1, ['counselor'])
    From: ...
    >>> ftests.addEditGoal(principal, add_goal_student1, ['counselor'])
    From: ...

    >>> message_url = student1_messages + '/2'
    >>> goal_url = student1_goals + '/2'
    >>> goal_edit = goal_url + '/editGoal.html'

    >>> test_access(message_url, all_staff)
    >>> test_access(goal_url, all_staff)
    >>> test_access(goal_edit, all_staff)

The first message and goal we'll add for student2 will be for the counselor.
The same people who are allowed to add messages or goals will be able to view
and edit them.  That means teacher2 will not have access becuase he is not
teacher or advisor and is not on the persons responsible list.

    >>> ftests.addMessage(principal, add_msg_student2, ['counselor'])
    From: ...
    >>> ftests.addEditGoal(principal, add_goal_student2, ['counselor'])
    From: ...

    >>> message_url = student2_messages + '/1'
    >>> goal_url = student2_goals + '/1'
    >>> goal_edit = goal_url + '/editGoal.html'

    >>> test_access(message_url, [principal, counselor, teacher1])
    >>> test_access(goal_url, [principal, counselor, teacher1])
    >>> test_access(goal_edit, [principal, counselor, teacher1])

Now we'll add teacher2 as an advisor of student2, create a message and goal
for teacher2, and then remove teacher2 as the advisor of student2.  This will
allow us to test the access granted to teacher2 that comes from being on the 
list of persons responsible even if he is not a teacher, advisor or
administrator.

    >>> ftests.addAdvisors('Student2', ['teacher2'])
    >>> ftests.addMessage(principal, add_msg_student2, ['teacher2'])
    From: ...
    >>> ftests.addEditGoal(principal, add_goal_student2, ['teacher2'])
    From: ...
    >>> ftests.removeAdvisors('Student2', ['teacher2'])

    >>> message_url = student2_messages + '/2'
    >>> goal_url = student2_goals + '/2'
    >>> goal_edit = goal_url + '/editGoal.html'

    >>> test_access(message_url, all_staff)
    >>> test_access(goal_url, all_staff)
    >>> test_access(goal_edit, all_staff)

We'll have the principal edit the goal to remove teacher2 from the persons
responsible list.  Then we'll test that teacher2 can no longer view or edit
the goal.

    >>> ftests.addEditGoal(principal, goal_edit, ['teacher1'])
    >>> test_access(goal_url, [principal, counselor, teacher1])
    >>> test_access(goal_edit, [principal, counselor, teacher1])

The first message and goal we'll add for student3 will be for teacher1.
The same people who are allowed to add messages or goals will be able to view
and edit them.  That means the counselor will not have access becuase he is not
a teacher or advisor of student3 and is not on the persons responsible list.

    >>> ftests.addMessage(principal, add_msg_student3, ['teacher1'])
    From: ...
    >>> ftests.addEditGoal(principal, add_goal_student3, ['teacher1'])
    From: ...

    >>> message_url = student3_messages + '/1'
    >>> goal_url = student3_goals + '/1'
    >>> goal_edit = goal_url + '/editGoal.html'

    >>> test_access(message_url, [principal, teacher1, teacher2])
    >>> test_access(goal_url, [principal, teacher1, teacher2])
    >>> test_access(goal_edit, [principal, teacher1, teacher2])

Now we'll add counselor as an advisor of student3, create a message and goal
for counselor, and then remove counselor as the advisor of student3.  This will
allow us to test the access granted to counselor that comes from being on the 
list of persons responsible even if he is not a teacher, advisor or
administrator.

    >>> ftests.addAdvisors('Student3', ['counselor'])
    >>> ftests.addMessage(principal, add_msg_student3, ['counselor'])
    From: ...
    >>> ftests.addEditGoal(principal, add_goal_student3, ['counselor'])
    From: ...
    >>> ftests.removeAdvisors('Student3', ['counselor'])

    >>> message_url = student3_messages + '/2'
    >>> goal_url = student3_goals + '/2'
    >>> goal_edit = goal_url + '/editGoal.html'

Now we'll test that counselor has the same acesss as that of the other staff,
all of whom are either the teacher, advisor or administrator of the student.

    >>> test_access(message_url, all_staff)
    >>> test_access(goal_url, all_staff)
    >>> test_access(goal_edit, all_staff)

We'll have the principal edit the goal to remove counselor from the persons
responsible list.  Then we'll test that counselor can no longer view or edit
the goal.

    >>> ftests.addEditGoal(principal, goal_edit, ['teacher1'])
    >>> test_access(goal_url, [principal, teacher1, teacher2])
    >>> test_access(goal_edit, [principal, teacher1, teacher2])


Intervention dashboard security
-------------------------------

It's one thing to protect the student intervention data from the wrong user's
eyes, but there's also an intervention dashboard view that exposes information
about student interventions.  We will make sure that users are only allowed to
see their own dashboard.

    >>> users_url = 'http://localhost/persons'
    >>> principal_inbox = users_url + '/principal/intervention_tab'
    >>> principal_search = principal_inbox + '/search_students.html'
    >>> counselor_inbox = users_url + '/counselor/intervention_tab'
    >>> counselor_search = counselor_inbox + '/search_students.html'
    >>> teacher1_inbox = users_url + '/teacher1/intervention_tab'
    >>> teacher1_search = teacher1_inbox + '/search_students.html'
    >>> teacher2_inbox = users_url + '/teacher2/intervention_tab'
    >>> teacher2_search = teacher2_inbox + '/search_students.html'
    >>> student1_inbox = users_url + '/student1/intervention_tab'
    >>> student1_search = student1_inbox + '/search_students.html'
    >>> student2_inbox = users_url + '/student2/intervention_tab'
    >>> student2_search = student2_inbox + '/search_students.html'
    >>> student3_inbox = users_url + '/student3/intervention_tab'
    >>> student3_search = student3_inbox + '/search_students.html'

    >>> test_access(principal_inbox, [principal])
    >>> test_access(principal_search, [principal])
    >>> test_access(counselor_inbox, [counselor])
    >>> test_access(counselor_search, [counselor])
    >>> test_access(teacher1_inbox, [teacher1])
    >>> test_access(teacher1_search, [teacher1])
    >>> test_access(teacher2_inbox, [teacher2])
    >>> test_access(teacher2_search, [teacher2])
    >>> test_access(student1_inbox, [student1])
    >>> test_access(student1_search, [student1])
    >>> test_access(student2_inbox, [student2])
    >>> test_access(student2_search, [student2])
    >>> test_access(student3_inbox, [student3])
    >>> test_access(student3_search, [student3])

