This file is indexed.

/usr/share/pyshared/schooltool/calendar/app.py is in python-schooltool 1:2.1.0-0ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
#
# SchoolTool - common information systems platform for school administration
# Copyright (c) 2005 Shuttleworth Foundation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
"""
SchoolTool calendaring objects.
"""
import base64

from persistent.dict import PersistentDict
from persistent import Persistent
from zope.interface import implements, implementer
from zope.schema import getFieldNames
from zope.component import adapts, adapter
from zope.annotation.interfaces import IAttributeAnnotatable, IAnnotations
from zope.container.contained import Contained
from zope.location.interfaces import ILocation

from schooltool.calendar.icalendar import read_icalendar
from schooltool.calendar.interfaces import ICalendar
from schooltool.calendar.interfaces import ICalendarEvent
from schooltool.calendar.interfaces import IExpandedCalendarEvent
from schooltool.calendar.mixins import CalendarMixin
from schooltool.calendar.simple import SimpleCalendarEvent
from schooltool.app.interfaces import ISchoolToolCalendarEvent
from schooltool.app.interfaces import ISchoolToolCalendar
from schooltool.app.interfaces import IWriteCalendar
from schooltool.app.interfaces import IHaveCalendar


CALENDAR_KEY = 'schooltool.app.calendar.Calendar'


class CalendarEvent(SimpleCalendarEvent, Persistent, Contained):
    """A persistent calendar event contained in a persistent calendar."""

    implements(ISchoolToolCalendarEvent, IAttributeAnnotatable)

    __parent__ = None

    resources = property(lambda self: self._resources)

    def __init__(self, *args, **kwargs):
        resources = kwargs.pop('resources', ())
        SimpleCalendarEvent.__init__(self, *args, **kwargs)
        self.__name__ = base64.encodestring(self.unique_id.encode('utf-8')).replace('\n', '')
        self._resources = ()
        for resource in resources:
            self.bookResource(resource)

    def __conform__(self, interface):
        if interface is ICalendar:
            return self.__parent__

    def bookResource(self, resource):
        calendar = ISchoolToolCalendar(resource)
        if resource in self.resources:
            raise ValueError('resource already booked')
        if calendar is self.__parent__:
            raise ValueError('cannot book itself')
        self._resources += (resource, )
        if self.__parent__ is not None:
            calendar.addEvent(self)

    def unbookResource(self, resource):
        if resource not in self.resources:
            raise ValueError('resource not booked')
        self._resources = tuple([r for r in self.resources
                                 if r is not resource])
        ISchoolToolCalendar(resource).removeEvent(self)

    @property
    def owner(self):
        if self.__parent__:
            return self.__parent__.__parent__
        else:
            return None


class Calendar(Persistent, CalendarMixin):
    """A persistent calendar."""

    # CalendarMixin is only used for the expand() method

    implements(ISchoolToolCalendar, IAttributeAnnotatable)

    __name__ = 'calendar'

    title = property(lambda self: self.__parent__.title)

    def __init__(self, owner):
        self.events = PersistentDict()
        self.__parent__ = owner

    def __iter__(self):
        return self.events.itervalues()

    def __len__(self):
        return len(self.events)

    def addEvent(self, event):
        assert ISchoolToolCalendarEvent.providedBy(event)
        if event.unique_id in self.events:
            raise ValueError('an event with this unique_id already exists')
        if event.__parent__ is None:
            for resource in event.resources:
                if ISchoolToolCalendar(resource) is self:
                    raise ValueError('cannot book itself')
            event.__parent__ = self
            for resource in event.resources:
                ISchoolToolCalendar(resource).addEvent(event)
        elif self.__parent__ not in event.resources:
            raise ValueError("Event already belongs to a calendar")
        self.events[event.unique_id] = event

    def removeEvent(self, event):
        if self.__parent__ in event.resources:
            event.unbookResource(self.__parent__)
        else:
            del self.events[event.unique_id]
            parent_calendar = event.__parent__
            if self is parent_calendar:
                for resource in event.resources:
                    event.unbookResource(resource)
                event.__parent__ = None

    def clear(self):
        # clear is not actually used anywhere in schooltool.app (except tests),
        # so it doesn't have to be efficient.
        for e in list(self):
            self.removeEvent(e)

    def find(self, unique_id):
        return self.events[unique_id]


def getCalendar(owner):
    """Adapt an ``IAnnotatable`` object to ``ISchoolToolCalendar``."""
    annotations = IAnnotations(owner)
    try:
        return annotations[CALENDAR_KEY]
    except KeyError:
        calendar = Calendar(owner)
        annotations[CALENDAR_KEY] = calendar
        return calendar
getCalendar.factory = Calendar # Convention to make adapter introspectable


class WriteCalendar(object):
    r"""An adapter that allows writing iCalendar data to a calendar.

        >>> calendar = Calendar(None)
        >>> adapter = WriteCalendar(calendar)
        >>> adapter.write('''\
        ... BEGIN:VCALENDAR
        ... VERSION:2.0
        ... PRODID:-//SchoolTool.org/NONSGML SchoolTool//EN
        ... BEGIN:VEVENT
        ... UID:some-random-uid@example.com
        ... SUMMARY:LAN party
        ... DTSTART:20050226T160000
        ... DURATION:PT6H
        ... DTSTAMP:20050203T150000
        ... END:VEVENT
        ... END:VCALENDAR
        ... ''')
        >>> for e in calendar:
        ...     print e.dtstart.strftime('%Y-%m-%d %H:%M'), e.title
        2005-02-26 16:00 LAN party

    Supporting other charsets would be nice too:

        >>> calendar = Calendar(None)
        >>> adapter = WriteCalendar(calendar)
        >>> adapter.write('''\
        ... BEGIN:VCALENDAR
        ... VERSION:2.0
        ... PRODID:-//SchoolTool.org/NONSGML SchoolTool//EN
        ... BEGIN:VEVENT
        ... UID:some-random-uid@example.com
        ... SUMMARY:LAN party %s
        ... DTSTART:20050226T160000
        ... DURATION:PT6H
        ... DTSTAMP:20050203T150000
        ... END:VEVENT
        ... END:VCALENDAR
        ... ''' %  chr(163), charset='latin-1')
        >>> titles = [e.title for e in calendar]
        >>> titles[0]
        u'LAN party \xa3'

    """

    adapts(ISchoolToolCalendar)
    implements(IWriteCalendar)

    # Hook for unit tests.
    read_icalendar = staticmethod(read_icalendar)

    _event_attrs = getFieldNames(ICalendarEvent)

    def __init__(self, context, request=None):
        self.calendar = context

    def write(self, data, charset='UTF-8'):
        changes = {} # unique_id -> (old_event, new_event)
        for e in self.calendar:
            changes[e.unique_id] = (e, None)

        for event in self.read_icalendar(data, charset):
            old_event = changes.get(event.unique_id, (None, ))[0]
            changes[event.unique_id] = (old_event, event)

        for old_event, new_event in changes.itervalues():
            if old_event is None:
                # new_event is a SimpleCalendarEvent, we need a CalendarEvent
                kwargs = dict([(attr, getattr(new_event, attr))
                               for attr in self._event_attrs])
                self.calendar.addEvent(CalendarEvent(**kwargs))
            elif new_event is None:
                self.calendar.removeEvent(old_event)
            elif old_event != new_event:
                # modify in place
                for attr in self._event_attrs:
                    setattr(old_event, attr, getattr(new_event, attr))


def clearCalendarOnDeletion(event):
    """When you delete an object, it's calendar should be cleared

        >>> from schooltool.relationship.tests import setUp, tearDown
        >>> from schooltool.testing.setup import setUpCalendaring

        >>> setUp()
        >>> setUpCalendaring()

        >>> import zope.event
        >>> old_subscribers = zope.event.subscribers[:]
        >>> from schooltool.app.cal import clearCalendarOnDeletion
        >>> zope.event.subscribers.append(clearCalendarOnDeletion)

    We will need some object that implements IHaveCalendar for that:

        >>> from zope.container.btree import BTreeContainer
        >>> container = BTreeContainer()
        >>> from schooltool.person.person import Person
        >>> container = BTreeContainer()
        >>> container['petras'] = petras =  Person(username="Petras")
        >>> def clearCalendar():
        ...     print "Clearing calendar"
        >>> ISchoolToolCalendar(petras).clear = clearCalendar

    If we delete Petras his calendar should be cleared:

        >>> del container['petras']
        Clearing calendar

    Restore old subscribers:

        >>> zope.event.subscribers[:] = old_subscribers
        >>> tearDown()

    """
    if IHaveCalendar.providedBy(event.object):
        ISchoolToolCalendar(event.object).clear()


@adapter(IExpandedCalendarEvent)
@implementer(ILocation)
def expandedEventLocation(event):
    original = event.__dict__['original']
    return ILocation(original)