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/...
    ...

Now let the Toad try on the 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
    ... """)
    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
    ... Host: localhost:7080
    ... 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
    ... """)
    HTTP/1.1 303 See Other
    ...
    Location: http://localhost/frogpond/persons/frog/calendar/2005-02-03...
    ...

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 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/2005-02-03...
    ...


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 403 Forbidden
    ...

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 403 Forbidden
    ...

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 403 Forbidden
    ...

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 403 Forbidden
    ...

