Functional doctest for calendaring
==================================

This test verifies the security checking for calendars.

Set up
------

We will obviously need a SchoolBell instance.

    >>> print http("""
    ... POST /@@contents.html HTTP/1.1
    ... Authorization: Basic mgr:mgrpw
    ... Content-Length: 81
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... type_name=BrowserAdd__schoolbell.app.app.SchoolBellApplication&\
    ... new_value=frogpond""")
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/@@contents.html
    ...

Let's create a person so that we can fool around with his calendar:

    >>> print http("""
    ... POST /frogpond/persons/add.html HTTP/1.1
    ... Authorization: Basic mgr:mgrpw
    ... Content-Length: 112
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... field.title=Frog&field.username=frog&field.password=pwd&\
    ... field.verify_password=pwd&field.photo=&UPDATE_SUBMIT=Add
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons
    ...

Let's create more persons so that we can test access control.

    >>> print http("""
    ... POST /frogpond/persons/add.html HTTP/1.1
    ... Authorization: Basic mgr:mgrpw
    ... Content-Length: 114
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... field.title=Toad&field.username=toad&field.password=doat&\
    ... field.verify_password=doat&field.photo=&UPDATE_SUBMIT=Add
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons
    ...

Adding new events
-----------------

Let the Frog add an ordinary event that takes place on 3rd February, 2005:

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/add.html HTTP/1.1
    ... Authorization: Basic frog:pwd
    ... Content-Length: 159
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... field.title=Sleeping&field.start_date=2005-02-03&\
    ... field.start_time=01:00&field.duration=500&field.recurrence.used=&\
    ... field.recurrence_type=daily&UPDATE_SUBMIT=Add
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar
    ...

Let's grant the Toad the viewCalendar permission on Frog's calendar:

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/acl.html HTTP/1.1
    ... Authorization: Basic mgr:mgrpw
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... marker-sb.person.toad=1&\
    ... sb.person.toad=schoolbell.viewCalendar&\
    ... UPDATE_SUBMIT=Set
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar
    ...

Toad should still not even see the new event links (but span tags instead):

    >>> print http(r"""
    ... GET /frogpond/persons/frog/calendar HTTP/1.1
    ... Authorization: Basic toad:doat
    ... """, handle_errors=False)
    HTTP/1.1 200 Ok
    ...
          <span class="event-new"
    ...

Now let the Toad try to add an event on the Frog's calendar (even though there
is no link for it):

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/add.html HTTP/1.1
    ... Authorization: Basic toad:doat
    ... Content-Length: 159
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... field.title=Dreaming&field.start_date=2005-02-03&\
    ... field.start_time=01:00&field.duration=500&field.recurrence.used=&\
    ... field.recurrence_type=daily&UPDATE_SUBMIT=Add
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/@@login.html...
    ...

Let's grant the Toad the addEvent permission on Frog's calendar:

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/acl.html HTTP/1.1
    ... Authorization: Basic mgr:mgrpw
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... marker-sb.person.toad=1&\
    ... sb.person.toad=schoolbell.addEvent&\
    ... UPDATE_SUBMIT=Set
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar
    ...

Now the Toad can add events to Frog's calendar:

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/add.html HTTP/1.1
    ... Authorization: Basic toad:doat
    ... Content-Length: 159
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... field.title=Dreaming&field.start_date=2005-02-03&\
    ... field.start_time=01:00&field.duration=500&field.recurrence.used=&\
    ... field.recurrence_type=daily&UPDATE_SUBMIT=Add
    ... """, handle_errors=False)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar
    ...


Editing events
--------------

Let's add a calendar through iCalendar PUT view (so we would know the event id):

    >>> print http(r"""
    ... PUT /frogpond/persons/frog/calendar/calendar.ics HTTP/1.1
    ... Authorization: Basic frog:pwd
    ... Content-Length: 244
    ... Content-Type: text/calendar
    ...
    ... BEGIN:VCALENDAR
    ... VERSION:2.0
    ... PRODID:-//SchoolTool.org/NONSGML SchoolBell//EN
    ... BEGIN:VEVENT
    ... UID:dummy-uid
    ... SUMMARY:Empty calendar
    ... DTSTART:20050204T100000
    ... DURATION:PT1H
    ... DTSTAMP:20050203T150000
    ... END:VEVENT
    ... END:VCALENDAR
    ... """, handle_errors=False)
    HTTP/1.1 200 Ok
    Content-Length: 0
    Set-Cookie: ...
    <BLANKLINE>

Let the Frog modify this event:

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/dummy-uid/edit.html?date=2005-02-04 HTTP/1.1
    ... Authorization: Basic frog:pwd
    ... Content-Length: 159
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... field.title=Sleeping&field.start_date=2005-02-03&\
    ... field.start_time=01:00&field.duration=500&field.recurrence.used=&\
    ... field.recurrence_type=daily&UPDATE_SUBMIT=Add
    ... """, handle_errors=False)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar
    ...

Now let the Toad try and modify the event too:

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/dummy-uid/edit.html?date=2005-02-04 HTTP/1.1
    ... Authorization: Basic toad:doat
    ... Content-Length: 159
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... field.title=Sleeping&field.start_date=2005-02-03&\
    ... field.start_time=01:00&field.duration=500&field.recurrence.used=&\
    ... field.recurrence_type=daily&UPDATE_SUBMIT=Add
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/@@login.html?forbidden=yes&nexturl=http://localhost/frogpond/persons/frog/calendar/dummy-uid
    ...

Let's grant the Toad the viewCalendar permission on Frog's calendar:

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/acl.html HTTP/1.1
    ... Authorization: Basic mgr:mgrpw
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... marker-sb.person.toad=1&\
    ... sb.person.toad=schoolbell.viewCalendar&\
    ... UPDATE_SUBMIT=Set
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar
    ...

Toad should not see the event delete link

    >>> print http(r"""
    ... GET /frogpond/persons/frog/calendar/2005-02-03 HTTP/1.1
    ... Authorization: Basic toad:doat
    ... """, handle_errors=False)
    HTTP/1.1 200 Ok
    ...
               <h6 style="background: #7590ae">
                 <a href="http://localhost/frogpond/persons/frog/calendar/dummy-uid"
                    title="Sleeping">
                   Sleeping
                   <span class="start-end">
                     (<span>01:00</span>
                        -
                      <span>09:20</span>)
                   </span>
                 </a>
               </h6>
    ...

Let's grant the Toad the modifyEvent permission on Frog's calendar:

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/acl.html HTTP/1.1
    ... Authorization: Basic mgr:mgrpw
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... marker-sb.person.toad=1&\
    ... sb.person.toad=schoolbell.modifyEvent&\
    ... sb.person.toad=schoolbell.viewCalendar&\
    ... UPDATE_SUBMIT=Set
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar
    ...

Now let the Toad try and modify the event too:

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/dummy-uid/edit.html?date=2005-02-04 HTTP/1.1
    ... Authorization: Basic toad:doat
    ... Content-Length: 159
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... field.title=Sleeping&field.start_date=2005-02-03&\
    ... field.start_time=01:00&field.duration=500&field.recurrence.used=&\
    ... field.recurrence_type=daily&UPDATE_SUBMIT=Add
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar
    ...


Uploading iCalendar files
-------------------------

Random anonymous persons cannot see or overwrite someone's calendar

    >>> print http(r"""
    ... GET /frogpond/persons/frog/calendar.ics HTTP/1.1
    ... """, handle_errors=True)
    HTTP/1.1 401 Unauthorized
    ...

    >>> print http(r"""
    ... PUT /frogpond/persons/frog/calendar.ics HTTP/1.1
    ... Host: localhost:7080
    ... Content-Length: 244
    ... Content-Type: text/calendar
    ...
    ... BEGIN:VCALENDAR
    ... VERSION:2.0
    ... PRODID:-//SchoolTool.org/NONSGML SchoolBell//EN
    ... BEGIN:VEVENT
    ... UID:empty-calendar-placeholder@schooltool.org
    ... SUMMARY:Empty calendar
    ... DTSTART:20050204T100000
    ... DURATION:PT1H
    ... DTSTAMP:20050203T150000
    ... END:VEVENT
    ... END:VCALENDAR
    ... """, handle_errors=True)
    HTTP/1.1 401 Unauthorized
    ...

The manager can let Toad see Frog's calendar:

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/@@acl.html HTTP/1.1
    ... Authorization: Basic mgr:mgrpw
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... marker-sb.person.toad=1&\
    ... sb.person.toad=schoolbell.viewCalendar&\
    ... UPDATE_SUBMIT=Set
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar
    ...

    >>> print http(r"""
    ... GET /frogpond/persons/frog/calendar/ HTTP/1.1
    ... Authorization: Basic toad:doat
    ... """, handle_errors=False)
    HTTP/1.1 200 Ok
    ...

    >>> print http(r"""
    ... GET /frogpond/persons/frog/calendar.ics HTTP/1.1
    ... Authorization: Basic toad:doat
    ... """, handle_errors=False)
    HTTP/1.1 200 Ok
    ...

However Toad cannot modify the calendar.

    >>> print http(r"""
    ... PUT /frogpond/persons/frog/calendar/calendar.ics HTTP/1.1
    ... Authorization: Basic toad:doat
    ... Content-Length: 244
    ... Content-Type: text/calendar
    ...
    ... BEGIN:VCALENDAR
    ... VERSION:2.0
    ... PRODID:-//SchoolTool.org/NONSGML SchoolBell//EN
    ... BEGIN:VEVENT
    ... UID:some-uid@example.com
    ... SUMMARY:Sample event
    ... DTSTART:20050204T100000
    ... DURATION:PT1H
    ... DTSTAMP:20050203T150000
    ... END:VEVENT
    ... END:VCALENDAR
    ... """, handle_errors=True)
    HTTP/1.1 401 Unauthorized
    ...

Unless the manager grants him modification permissions too.

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/@@acl.html HTTP/1.1
    ... Authorization: Basic mgr:mgrpw
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... marker-sb.person.toad=1&\
    ... sb.person.toad=schoolbell.viewCalendar&\
    ... sb.person.toad=schoolbell.addEvent&\
    ... sb.person.toad=schoolbell.modifyEvent&\
    ... UPDATE_SUBMIT=Set
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar
    ...

    >>> print http(r"""
    ... PUT /frogpond/persons/frog/calendar/calendar.ics HTTP/1.1
    ... Authorization: Basic toad:doat
    ... Content-Length: 244
    ... Content-Type: text/calendar
    ...
    ... BEGIN:VCALENDAR
    ... VERSION:2.0
    ... PRODID:-//SchoolTool.org/NONSGML SchoolBell//EN
    ... BEGIN:VEVENT
    ... UID:some-uid@example.com
    ... SUMMARY:Sample event
    ... DTSTART:20050204T100000
    ... DURATION:PT1H
    ... DTSTAMP:20050203T150000
    ... END:VEVENT
    ... END:VCALENDAR
    ... """, handle_errors=False)
    HTTP/1.1 200 Ok
    ...

The permissions are more finely-grained: if Toad has the addEvent permission,
but not modifyEvent, he can only add new events, but not modify or delete
existing ones.

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/@@acl.html HTTP/1.1
    ... Authorization: Basic mgr:mgrpw
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... marker-sb.person.toad=1&\
    ... sb.person.toad=schoolbell.viewCalendar&\
    ... sb.person.toad=schoolbell.addEvent&\
    ... UPDATE_SUBMIT=Set
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar
    ...

Modification: forbidden

    >>> print http(r"""
    ... PUT /frogpond/persons/frog/calendar/calendar.ics HTTP/1.1
    ... Authorization: Basic toad:doat
    ... Content-Length: 244
    ... Content-Type: text/calendar
    ...
    ... BEGIN:VCALENDAR
    ... VERSION:2.0
    ... PRODID:-//SchoolTool.org/NONSGML SchoolBell//EN
    ... BEGIN:VEVENT
    ... UID:some-uid@example.com
    ... SUMMARY:Sample event (modified)
    ... DTSTART:20050204T100000
    ... DURATION:PT1H
    ... DTSTAMP:20050203T150000
    ... END:VEVENT
    ... END:VCALENDAR
    ... """)
    HTTP/1.1 401 Unauthorized
    ...

Removal: forbidden

    >>> print http(r"""
    ... PUT /frogpond/persons/frog/calendar/calendar.ics HTTP/1.1
    ... Authorization: Basic toad:doat
    ... Content-Length: 244
    ... Content-Type: text/calendar
    ...
    ... BEGIN:VCALENDAR
    ... VERSION:2.0
    ... PRODID:-//SchoolTool.org/NONSGML SchoolBell//EN
    ... BEGIN:VEVENT
    ... UID:empty-calendar-placeholder@schooltool.org
    ... SUMMARY:Empty calendar
    ... DTSTART:20050204T100000
    ... DURATION:PT1H
    ... DTSTAMP:20050203T150000
    ... END:VEVENT
    ... END:VCALENDAR
    ... """)
    HTTP/1.1 401 Unauthorized
    ...

Addition: allowed

    >>> print http(r"""
    ... PUT /frogpond/persons/frog/calendar/calendar.ics HTTP/1.1
    ... Authorization: Basic toad:doat
    ... Content-Length: 244
    ... Content-Type: text/calendar
    ...
    ... BEGIN:VCALENDAR
    ... VERSION:2.0
    ... PRODID:-//SchoolTool.org/NONSGML SchoolBell//EN
    ... BEGIN:VEVENT
    ... UID:some-uid2@example.com
    ... SUMMARY:New event
    ... DTSTART:20050204T120000
    ... DURATION:PT1H
    ... DTSTAMP:20050203T150000
    ... END:VEVENT
    ... BEGIN:VEVENT
    ... UID:some-uid@example.com
    ... SUMMARY:Sample event
    ... DTSTART:20050204T100000
    ... DURATION:PT1H
    ... DTSTAMP:20050203T150000
    ... END:VEVENT
    ... END:VCALENDAR
    ... """)
    HTTP/1.1 200 Ok
    ...

Now let's allow modification, but not addition

    >>> print http("""
    ... POST /frogpond/persons/frog/calendar/@@acl.html HTTP/1.1
    ... Authorization: Basic mgr:mgrpw
    ... Content-Type: application/x-www-form-urlencoded
    ...
    ... marker-sb.person.toad=1&\
    ... sb.person.toad=schoolbell.viewCalendar&\
    ... sb.person.toad=schoolbell.modifyEvent&\
    ... UPDATE_SUBMIT=Set
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar
    ...

Removal: allowed

    >>> print http(r"""
    ... PUT /frogpond/persons/frog/calendar/calendar.ics HTTP/1.1
    ... Authorization: Basic toad:doat
    ... Content-Length: 244
    ... Content-Type: text/calendar
    ...
    ... BEGIN:VCALENDAR
    ... VERSION:2.0
    ... PRODID:-//SchoolTool.org/NONSGML SchoolBell//EN
    ... BEGIN:VEVENT
    ... UID:some-uid@example.com
    ... SUMMARY:Sample event
    ... DTSTART:20050204T100000
    ... DURATION:PT1H
    ... DTSTAMP:20050203T150000
    ... END:VEVENT
    ... END:VCALENDAR
    ... """)
    HTTP/1.1 200 Ok
    ...

Modification: allowed

    >>> print http(r"""
    ... PUT /frogpond/persons/frog/calendar/calendar.ics HTTP/1.1
    ... Authorization: Basic toad:doat
    ... Content-Length: 244
    ... Content-Type: text/calendar
    ...
    ... BEGIN:VCALENDAR
    ... VERSION:2.0
    ... PRODID:-//SchoolTool.org/NONSGML SchoolBell//EN
    ... BEGIN:VEVENT
    ... UID:some-uid@example.com
    ... SUMMARY:Sample event (modified)
    ... DTSTART:20050204T100000
    ... DURATION:PT2H
    ... DTSTAMP:20050203T150000
    ... END:VEVENT
    ... END:VCALENDAR
    ... """)
    HTTP/1.1 200 Ok
    ...

Addition: not allowed

    >>> print http(r"""
    ... PUT /frogpond/persons/frog/calendar/calendar.ics HTTP/1.1
    ... Authorization: Basic toad:doat
    ... Content-Length: 244
    ... Content-Type: text/calendar
    ...
    ... BEGIN:VCALENDAR
    ... VERSION:2.0
    ... PRODID:-//SchoolTool.org/NONSGML SchoolBell//EN
    ... BEGIN:VEVENT
    ... UID:some-uid@example.com
    ... SUMMARY:Sample event (modified)
    ... DTSTART:20050204T100000
    ... DURATION:PT2H
    ... DTSTAMP:20050203T150000
    ... END:VEVENT
    ... BEGIN:VEVENT
    ... UID:some-uid2@example.com
    ... SUMMARY:New event
    ... DTSTART:20050204T120000
    ... DURATION:PT1H
    ... DTSTAMP:20050203T150000
    ... END:VEVENT
    ... END:VCALENDAR
    ... """)
    HTTP/1.1 401 Unauthorized
    ...

