# This file is part of Indico.
# Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
#
# Indico 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 3 of the
# License, or (at your option) any later version.
#
# Indico 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 Indico; if not, see <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

from sqlalchemy.dialects.postgresql import JSON

from indico.core.db import db
from indico.core.db.sqlalchemy import UTCDateTime, PyIntEnum
from indico.core.db.sqlalchemy.util.queries import limit_groups
from indico.modules.events.requests import get_request_definitions
from indico.util.date_time import now_utc
from indico.util.i18n import _
from indico.util.string import return_ascii
from indico.util.struct.enum import TitledIntEnum


class RequestState(TitledIntEnum):
    __titles__ = [_('Pending'), _('Accepted'), _('Rejected'), _('Withdrawn')]
    pending = 0
    accepted = 1
    rejected = 2
    withdrawn = 3


class Request(db.Model):
    """Event-related requests, e.g. for a webcast"""
    __tablename__ = 'requests'
    __table_args__ = {'schema': 'events'}

    #: request ID
    id = db.Column(
        db.Integer,
        primary_key=True
    )
    #: ID of the event
    event_id = db.Column(
        db.Integer,
        index=True,
        nullable=False
    )
    #: the request type name
    type = db.Column(
        db.String,
        nullable=False
    )
    #: the requests's date, a :class:`RequestState` value
    state = db.Column(
        PyIntEnum(RequestState),
        nullable=False,
        default=RequestState.pending
    )
    #: plugin-specific data of the payment
    data = db.Column(
        JSON,
        nullable=False
    )
    #: ID of the user creating the request
    created_by_id = db.Column(
        db.Integer,
        nullable=False
    )
    #: the date/time the request was created
    created_dt = db.Column(
        UTCDateTime,
        default=now_utc,
        index=True,
        nullable=False
    )
    #: ID of the user processing the request
    processed_by_id = db.Column(
        db.Integer,
        nullable=True
    )
    #: the date/time the request was accepted/rejected
    processed_dt = db.Column(
        UTCDateTime,
        nullable=True
    )
    #: an optional comment for an accepted/rejected request
    comment = db.Column(
        db.Text,
        nullable=True
    )

    @property
    def event(self):
        from MaKaC.conference import ConferenceHolder
        return ConferenceHolder().getById(str(self.event_id))

    @event.setter
    def event(self, event):
        self.event_id = int(event.getId())

    @property
    def created_by_user(self):
        from MaKaC.user import AvatarHolder
        return AvatarHolder().getById(str(self.event_id))

    @created_by_user.setter
    def created_by_user(self, user):
        self.created_by_id = int(user.getId())

    @property
    def processed_by_user(self):
        from MaKaC.user import AvatarHolder
        return AvatarHolder().getById(str(self.event_id))

    @processed_by_user.setter
    def processed_by_user(self, user):
        self.processed_by_id = int(user.getId())

    @property
    def definition(self):
        return get_request_definitions().get(self.type)

    @definition.setter
    def definition(self, definition):
        assert self.type is None
        self.type = definition.name

    @property
    def can_be_modified(self):
        """Determines if the request can be modified or if a new one must be sent"""
        return self.state in {RequestState.pending, RequestState.accepted}

    def send(self):
        """Sends a new/modified request"""
        self.state = RequestState.pending
        if self.id is None:
            db.session.add(self)
        # TODO: notify

    def withdraw(self):
        """Withdraws the request"""
        self.state = RequestState.withdrawn
        # TODO: notify

    @return_ascii
    def __repr__(self):
        state = self.state.name if self.state is not None else None
        return '<Request({}, {}, {})>'.format(self.id, self.event_id, state)

    @classmethod
    def find_latest_for_event(cls, event, type_=None):
        """Returns the latest requests for a given event.

        :param event: the event to find the requests for
        :param type_: the request type to retrieve, or `None` to get all
        :return: a dict mapping request types to a :class:`Request`
                 or if `type_` was specified, a single :class:`Request` or `None`
        """
        query = cls.find(event_id=int(event.getId()))
        if type_ is not None:
            return (query.filter_by(type=type_)
                    .order_by(cls.created_dt.desc())
                    .first())
        else:
            query = limit_groups(query, cls, cls.type, cls.created_dt.desc(), 1)
            return {req.type: req for req in query}

@@ -3184,37 +3184,42 @@
 etById(str(self.
-event
+created_by
 _id))%0A%0A    @crea
@@ -3452,37 +3452,44 @@
 etById(str(self.
-event
+processed_by
 _id))%0A%0A    @proc

Fix wrong attribute