Exemplo n.º 1
0
class ApiDevPanel_ResourceHistory(UUIDView):
    """ List history of resource
    """

    access = 'is_admin'
    known_methods = ['GET', 'DELETE']
    response_schema = {
        'sha': Char_Field(title=MSG(u'SHA of the commit')),
        'author_date': Datetime_Field(title=MSG("Datetime of commit")),
        'author_name': Char_Field(title=MSG(u"Commit's author name")),
        'message_short': Char_Field(title=MSG(u"Commit's title"))
    }
    def GET(self, root, context):
        resource = self.get_resource_from_uuid(context)
        revisions = resource.get_revisions(content=False)
        return self.return_json(revisions, context)
Exemplo n.º 2
0
class ApiDevPanel_ClassidViewDetails(Api_View):
    """ Give details about a class_id
    """

    access = 'is_admin'

    path_query_schema = {
        'class_id': Char_Field(title=MSG(u'A class_id registered in DB'))
    }
    response_schema = {
        'class_title':
        Char_Field(title=MSG(u'The class_title of the resource cls')),
        'class_id':
        Char_Field(title=MSG(u'The class_id of the resource cls'))
    }

    def GET(self, root, context):
        class_id = context.path_query['class_id']
        cls = context.database.get_resource_class(class_id)
        kw = {'class_title': cls.class_title, 'class_id': class_id}
        return self.return_json(kw, context)
Exemplo n.º 3
0
class Calendar(DBResource):

    class_id = 'calendar'
    class_title = MSG(u'Calendar')
    class_views = ['edit']

    # Fields
    title = DBResource.title(required=True)
    hidden_for_users = Char_Field(multiple=True)
    color = Color_Field(title=MSG(u'Color'), default='#0467BA', required=True)
    owner = Owner_Field

    # Views
    _fields = ['title', 'color']
    new_instance = Calendar_NewInstance(fields=_fields)
    edit = Calendar_Edit(fields=_fields)
Exemplo n.º 4
0
class Applications_View(AutoTable):

    title = MSG(u'Applications')
    base_classes = ('application', )
    table_fields = ['checkbox', 'title', 'subscription', 'nb_answers', 'ctime']
    table_actions = [Remove_BrowseButton]

    # Fields
    nb_answers = Char_Field(title=MSG(u'Nb answers'))

    def get_item_value(self, resource, context, item, column):
        if column == 'nb_answers':
            return item.get_n_forms()
        elif column == 'ctime':
            return context.format_datetime(item.get_value('ctime'))
        # Proxy
        proxy = super(Applications_View, self)
        return proxy.get_item_value(resource, context, item, column)
Exemplo n.º 5
0
class ApiDevPanel_ServerView(Api_View):
    """ Return informations about server timestamp / pid / port
    """

    access = 'is_admin'
    known_methods = ['GET']
    response_schema = {
        'timestamp': Char_Field(title=MSG(u"Server's start timestamp")),
        'pid': Integer_Field(title=MSG(u"Server's PID")),
        'port': Integer_Field(title=MSG(u"Server's port"))
    }

    def GET(self, root, context):
        server = context.server
        kw = {'timestamp': server.timestamp,
              'pid': getpid(),
              'port': server.port}
        return self.return_json(kw, context)
Exemplo n.º 6
0
class UUIDView(Api_View):
    """ Base view for all uuid related views
    """

    class_id = None
    base_class_id = None
    access = True
    known_methods = ['DELETE']

    path_query_schema = {'uuid': Char_Field(title=MSG(u'The uuid of a resource in DB'))}

    def is_access_allowed(self, context):
        # TODO: can be move in itools main view
        query = get_resource_by_uuid_query(
            uuid=context.path_query_base['uuid'],
            base_class_id=self.base_class_id,
            class_id=self.class_id)
        search = context.database.search(query)
        if not search:
            if context.database.search(query):
                # Exist but ...
                # Unauthorized (401)
                if context.user is None:
                    raise Unauthorized
                # Forbidden (403)
                raise Forbidden
            raise NotFound
        resource = search.get_resources().next()
        return context.is_access_allowed(resource, self)


    def get_resource_from_uuid(self, context):
        uuid = context.path_query['uuid']
        return context.root.get_resource_by_uuid(
            uuid=uuid, context=context,
            base_class_id=self.base_class_id,
            class_id=self.class_id)


    access_DELETE = 'is_allowed_to_remove'
    def DELETE(self, resource, context):
        resource = self.get_resource_from_uuid(context)
        resource.parent.del_resource(resource.name)
        return None
Exemplo n.º 7
0
class TestValidators(AutoEdit):

    access = True
    title = MSG(u"Test validators")

    fields = [
        'field_1', 'field_2', 'field_3', 'field_4', 'field_5', 'field_6',
        'field_7', 'field_8', 'field_9', 'field_10', 'field_11', 'field_12',
        'field_13', 'field_14', 'field_15'
    ]

    field_1 = Integer_Field(
        title=MSG(u'5+5 equals to ?'),
        validators=[validator('equals-to', base_value=10)],
        error_messages={'not_equals': MSG(u'Give me a 10 ;)')})
    field_2 = Char_Field(title=MSG(u'Hexadecimal color'),
                         validators=[validator('hexadecimal')])
    field_3 = Integer_Field(title=MSG(u'Give a positive number'),
                            validators=[validator('integer-positive')])
    field_4 = Integer_Field(
        title=MSG(u'Give a strict positive number'),
        validators=[validator('integer-positive-not-null')])
    field_5 = Integer_Field(title=MSG(u'Give a number (max value 10)'),
                            validators=[validator('max-value', max_value=10)])
    field_6 = Integer_Field(title=MSG(u'Give a number (min value 10)'),
                            validators=[validator('min-value', min_value=10)])
    field_7 = Integer_Field(
        title=MSG(u'Give a number (>=10 and <=20)'),
        validators=[validator('min-max-value', min_value=10, max_value=20)])
    field_8 = Char_Field(title=MSG(u'Give text (min length: 3 characters)'),
                         validators=[validator('min-length', min_length=3)])
    field_9 = Char_Field(title=MSG(u'Give text (max length: 5 characters)'),
                         validators=[validator('max-length', max_length=5)])
    field_10 = Email_Field(
        title=MSG(u'Give an email (unique in DB)'),
        validators=[validator('unique', field_name='email')],
        error_messages={
            'invalid': MSG(u'Give be an email address !!!'),
            'unique': MSG(u'This address is already used')
        })
    field_11 = File_Field(
        title=MSG(u'File extension (png)'),
        validators=[validator('file-extension', allowed_extensions=['png'])])
    field_12 = File_Field(title=MSG(u'File mimetypes (image/png)'),
                          validators=[
                              validator('file-mimetypes',
                                        allowed_mimetypes=['image/png'])
                          ])
    field_13 = File_Field(
        title=MSG(u'Image max pixels'),
        validators=[validator('image-pixels', max_pixels=10 * 10)])
    field_14 = Char_Field(title=MSG(u'Strong password'),
                          validators=[validator('strong-password')])
    field_15 = Integer_Field(title=MSG(u'Number >=5 and equals to 10'),
                             validators=[
                                 validator('min-value', min_value=5),
                                 validator('equals-to', base_value=10),
                             ])

    def _get_datatype(self, resource, context, name):
        field = self.get_field(resource, name)
        return field(resource=resource)

    def action(self, resource, context, form):
        print form
Exemplo n.º 8
0
class Event(Content):

    class_id = 'event'
    class_title = MSG(u'Event')
    class_description = MSG(u'Calendar event')
    class_icon16 = 'icons/16x16/event.png'
    class_icon48 = 'icons/48x48/event.png'
    class_views = ['edit', 'links', 'backlinks', 'edit_state', 'subscribe']

    # Render
    render = Event_Render

    # Fields
    owner = Owner_Field
    calendar = Select_Field(datatype=Calendars_Enumerate, required=True,
                            title=MSG(u'Calendar'), indexed=True)
    dtstart = Start_Field
    dtend = End_Field
    place = Char_Field(title=MSG(u'Where'))
    status = Select_Field(datatype=Status, title=MSG(u'State'))
    rrule = RRule_Field(title=MSG(u'Recurrence'))
    exdate = Date_Field(multiple=True)
    reminder = Reminder_Field(title=MSG(u'Reminder'))
    uid = Char_Field(readonly=True)


    def init_resource(self, **kw):
        super(Event, self).init_resource(**kw)

        # uid
        context = get_context()
        if 'uid' not in kw:
            uid = '%s@%s' % (self.abspath, context.uri.authority)
            self.set_value('uid', uid)


    def get_dates(self):
        start = self.get_value('dtstart')
        if type(start) is datetime:
            start = start.date()

        end = self.get_value('dtend')
        if type(end) is datetime:
            end = end.date()

        # Recurrence
        rrule = self.metadata.get_property('rrule')
        dates = get_dates(start, end, rrule)
        # Exclude dates
        exdate = self.get_value('exdate')
        dates.difference_update(exdate)
        # Ok
        return sorted(dates)


    def get_value(self, name, language=None):
        if name in ('rrule_interval', 'rrule_byday', 'rrule_until'):
            f_name, kk, param = name.partition('_')
            property = self.metadata.get_property(f_name, language=language)
            if property:
                value = property.get_parameter(param)
                if param == 'byday' and value is not None:
                    bydays = []
                    for v in value:
                        bydays.append(DaysOfWeek.get_name_by_shortname(v))
                    return bydays
                return value
        proxy = super(Event, self)
        return proxy.get_value(name, language)


    def get_catalog_values(self):
        values = super(Event, self).get_catalog_values()
        values['dates'] = self.get_dates()
        return values


    def next_time_event(self):
        reminder = self.get_value('reminder')
        if not reminder:
            return None, None

        # Get start time (if no time, start_time is midnight)
        start = self.get_value('dtstart')
        start_time = start.time() if type(start) is datetime else time(0)

        # Dates
        context = get_context()
        now = context.timestamp
        delta = timedelta(seconds=reminder)
        for date in self.get_dates():
            date = datetime.combine(date, start_time)
            reminder = context.fix_tzinfo(date - delta)
            if reminder > now:
                return reminder, date

        return None, None


    def time_event(self, payload):
        context = get_context()
        to_addr = self.get_resource(self.get_owner()).get_value('email')
        send_email('event-reminder', context, to_addr, event=self, date=payload)


    def get_ns_event(self, current_day, grid=False):
        abspath = str(self.abspath)
        ns = {
            'id': abspath,
            'link': abspath,
            'title': self.get_title(),
            'cal': 0,
            'color': self.get_color(),
            'current_day': current_day,
            'description': self.get_value('description'),
            'status': self.get_value('status') or 'cal_busy',
            'url': None}

        ###############################################################
        # URL
        context = get_context()
        view = self.get_view('edit')
        if context.is_access_allowed(self, view, context.user):
            ns['url'] = '%s/;edit?date=%s' % (abspath, current_day)

        ###############################################################
        # Set dtstart and dtend values using '...' for events which
        # appear into more than one cell
        dtstart = self.get_value('dtstart')
        dtend = self.get_value('dtend')

        dtstart_type = type(dtstart)
        if dtstart_type is datetime:
            ns['start'] = Time.encode(dtstart.time())[:5]
        else:
            ns['start'] = '00:00'

        if type(dtend) is datetime:
            ns['end'] = Time.encode(dtend.time())[:5]
        else:
            ns['end'] = '23:59'

        ###############################################################
        # Time
        e_dtstart = dtstart
        e_dtend = dtend
        if type(dtstart) is datetime:
            e_dtstart = dtstart.date()
        if type(dtend) is datetime:
            e_dtend = dtend.date()

        # Does current event occurs on current date ?
        starts_on = e_dtstart == current_day
        ends_on = e_dtend == current_day
        out_on = (e_dtstart < current_day and e_dtend > current_day)
        ns['TIME'] = None
        if grid:
            # Neither a full day event nor a multiple days event
            if dtstart_type is datetime and dtstart.date() == dtend.date():
                if ns['start'] == ns['end']:
                    ns['TIME'] = ns['start']
                else:
                    ns['TIME'] = '%s - %s' % (ns['start'], ns['end'])
            else:
                ns['start'] = ns['end'] = None
        elif not out_on:
            if dtstart_type is datetime:
                value = ''
                if starts_on and ns['start'] != ns['end']:
                    value = ns['start']
                    if ends_on:
                        value = value + '-'
                    else:
                        value = value + '...'
                if ends_on and ns['start'] != ns['end']:
                    value = value + ns['end']
                    if not starts_on:
                        value = '...' + value
                if value:
                    ns['TIME'] = value
        return ns


    def get_message(self, context, language=None):
        # Subject
        title=self.get_title()
        subject = MSG(u'The event "{title}" has been modified')
        subject = subject.gettext(title=title, language=language)
        # Body
        message = MSG(u'DO NOT REPLY TO THIS EMAIL.\n\n'
                      u'The user "{last_author}" has made some modifications '
                      u'to the event "{title}".\n'
                      u'To view these modifications please visit:\n'
                      u'{resource_uri}\n')
        uri = context.get_link(self)
        uri = str(context.uri.resolve(uri))
        uri += '/;edit'
        last_author = self.get_value('last_author')
        last_author = context.root.get_user_title(last_author)
        body = message.gettext(last_author=last_author, resource_uri=uri,
                               title=title, language=language)

        # And return
        return subject, body


    def get_color(self):
        calendar = self.get_resource(self.get_value('calendar'))
        return calendar.get_value('color')


    # Views
    new_instance = Event_NewInstance
    edit = Event_Edit
Exemplo n.º 9
0
class ConfigAgenda(Folder):

    class_id = 'agenda'
    class_version = '20110606'
    class_title = MSG(u'Agenda')
    class_description = MSG(u'Schedule your time with calendar files.')
    class_icon16 = 'icons/16x16/calendar.png'
    class_icon48 = 'icons/48x48/calendar.png'
    class_views = [
        'monthly_view', 'weekly_view', 'daily_view',
        'edit_timetables', 'new_calendar', 'import_', 'export_form']

    # Configuration
    config_name = '/agenda'
    config_group = 'content'

    # Fields
    timetables = Char_Field(datatype=Timetables, multiple=True,
        title=MSG(u'Timetables'))
    timetables_default = [
        (time( 7,0), time( 8,0)),
        (time( 8,0), time( 9,0)),
        (time( 9,0), time(10,0)),
        (time(10,0), time(11,0)),
        (time(11,0), time(12,0)),
        (time(12,0), time(13,0)),
        (time(13,0), time(14,0)),
        (time(14,0), time(15,0)),
        (time(15,0), time(16,0)),
        (time(16,0), time(17,0)),
        (time(17,0), time(18,0)),
        (time(18,0), time(19,0)),
        (time(19,0), time(20,0)),
        (time(20,0), time(21,0))]


    def init_resource(self, **kw):
        super(ConfigAgenda, self).init_resource(**kw)
        # Create default calendar
        kw = {'title': {'en': u'My events'}, 'color': '#AC81A1'}
        self.make_resource(None, Calendar, **kw)


    def get_timetables(self):
        """Build a list of timetables represented as tuples(start, end).
        Data are taken from metadata or from class value.

        Example of metadata:
          <timetables>(8,0),(10,0);(10,30),(12,0);(13,30),(17,30)</timetables>
        """
        timetables = self.get_value('timetables')
        if timetables:
            return timetables

        # From class value
        return self.timetables_default


    def get_document_types(self):
        return [Calendar, Event]


    #######################################################################
    # User Interface
    #######################################################################
    def to_ical(self, context):
        """Serialize as an ical file, generally named .ics
        """

        lines = ['BEGIN:VCALENDAR\n',
                'VERSION:2.0\n',
                'PRODID:-//itaapy.com/NONSGML ikaaro icalendar V1.0//EN\n']

        # Calendar components
        for event in self.search_resources(cls=Event):
            lines.append('BEGIN:VEVENT\n')
            for ikaaro_name, ics_name in ikaaro_to_ics:
                property = event.get_property(ikaaro_name)
                lang = property.get_parameter('lang')
                if lang:
                    property = Property(property.value, LANGUAGE=lang)
                    p_schema = {'LANGUAGE': String(multiple=False)}
                else:
                    p_schema = None
                datatype = event.get_field(ikaaro_name).datatype
                line = property_to_str(ics_name, property, datatype, p_schema)
                lines.append(line)

            lines.append('END:VEVENT\n')
        lines.append('END:VCALENDAR\n')

        return ''.join(lines)


    def parse_ical(self, data):
        """Parse iCal data to produce a sequence of tuples:

        name, value {param_name: param_value}

        Where all the elements ('name', 'value', 'param_name' and 'param_value')
        are byte strings.

        Only elements that are handled by Ikaaro are keeped
        """
        unfolded = unfold_lines(data)
        iterator = iter(unfolded)
        for line in iterator:
            parameters = {}
            name, line = read_name(line)
            # Read the parameters and the property value
            value, parameters = get_tokens(line)
            if name == 'BEGIN' and value not in ('VCALENDAR', 'VEVENT'):
                while get_tokens(read_name(iterator.next())[1])[0] != value:
                    pass
                continue
            else:
                yield name, value, parameters


    def load_state_from_ical_file(self, file):
        # Clear Calendar
        for event in self._get_names():
            self.del_resource(event)

        ical = iCalendar()
        ical.reset()
        ical._load_state_from_file(file)
        timezones = ical.get_components('VTIMEZONE')
        events = ical.get_components('VEVENT')

        i = 0
        for event in events:
            filename = str(i)
            properties = {}
            for name, value in event.get_property().items():
                if name in ics_to_ikaaro:
                    name = ics_to_ikaaro[name]
                    properties[name] = value.value
            properties['uid'] = event.uid
            self.make_resource(filename, Event, **properties)
            i += 1

    # Views
    monthly_view = MonthlyView
    weekly_view = WeeklyView
    daily_view = DailyView
    new_event = Calendar_NewEvent
    edit_timetables = TimetablesForm
    export = Calendar_Export
    import_ = Calendar_Import
    export_form = Calendar_ExportForm
    calendars = Calendars_View
    new_calendar = NewResource_Local(title=MSG(u'Add calendar'))
Exemplo n.º 10
0
class Application(Folder):

    class_id = 'application'
    class_title = MSG(u"Collection Application")
    class_description = MSG(u"Create from an OpenDocument Spreadsheet file")
    class_views = ['view_admin', 'edit', 'edit_ods', 'register', 'view']

    # FIXME Configuration obsolete ?
    allowed_users = 10

    # Fields
    subscription = Subscription_Field(required=True)
    data = File_Field(title=MSG(u'ODS file'),
                      multilingual=False,
                      required=True)
    filename = Char_Field()
    mimetype = Char_Field()

    def init_resource(self, *args, **kw):
        proxy = super(Application, self)
        proxy.init_resource(*args, **kw)
        # Initial forms answers containers
        self.make_resource('forms', Forms)

    def load_ods_file(self, data, context):
        if self.get_resource('model', soft=True):
            self.del_resource('model')
            context.database.save_changes()
        # Create model container
        self.make_resource('model', FormModel)
        model = self.get_resource('model')
        # Save informations
        filename, mimetype, body = data
        self.set_value('data', body)
        self.set_value('filename', filename)
        self.set_value('mimetype', mimetype)
        # Analyse it
        return model.load_ods_file(context)

    def get_form(self):
        # OBSOLETE METHOD FIXME
        raise NotImplementedError

    def search_forms(self):
        query = AndQuery(PhraseQuery('base_classes', 'form'),
                         get_base_path_query(self.abspath))
        return get_context().search(query)

    def get_forms(self):
        return self.search_forms().get_resources()

    def get_n_forms(self):
        return len(self.search_forms())

    def get_stats(self):
        stats = {}
        stats['registered_users'] = 0
        stats['unconfirmed_users'] = 0
        stats['empty_forms'] = 0
        stats['pending_forms'] = 0
        stats['finished_forms'] = 0
        users = self.get_resource('/users')
        for form in self.get_forms():
            stats['registered_users'] += 1
            user = users.get_resource(form.name, soft=True)
            if user is not None:
                if user.get_value('password') is None:
                    stats['unconfirmed_users'] += 1
                else:
                    state = form.get_value('form_state')
                    if state == EMPTY:
                        stats['empty_forms'] += 1
                    elif state == PENDING:
                        stats['pending_forms'] += 1
                    elif state == FINISHED:
                        stats['finished_forms'] += 1
        return stats

    def get_param_folder(self):
        return self

    def get_admin_url(self, context):
        base_url = context.uri.resolve(self.abspath)
        return base_url.resolve2(';view')

    def get_spread_url(self, context, email=None):
        base_url = context.uri.resolve(self.abspath)
        spread_url = base_url.resolve2(';login')
        if email is not None:
            spread_url.query['username'] = email
        return spread_url

    def subscribe_user(self, user):
        root = self.get_resource('/')
        username = user.name
        # Give the role "guests" to see public resources (logo, etc.)
        if (root.get_user_role(username) is None
                # Except to top-level admins
                and not root.is_admin(user, self)):
            root.set_user_role(username, 'guests')
        # Add the form
        if self.get_resource(username, soft=True) is None:
            self.make_resource(username,
                               Form,
                               title={'en': user.get_title()},
                               form_state=NOT_REGISTERED)

    # Views
    new_instance = Application_NewInstance()
    edit = Application_Edit()
    edit_ods = Application_EditODS()
    view_admin = IconsView()
    register = Application_Register()