示例#1
0
    def render(self):

        req_id = self.request.params.get('request_id')
        req = Request.by_id(self.session, req_id)
        if not req:
            return ''

        # check if request have already been consumed
        if not self.user.is_admin:
            today = datetime.now()
            if req.date_from <= today:
                log.error('User %s tried to CANCEL consumed request %d.' %
                          (self.user.login, req.id))
                return req.status

        # delete from calendar
        if req.status == 'APPROVED_ADMIN' and req.ics_url:
            settings = self.request.registry.settings
            with open(settings['pyvac.celery.yaml']) as fdesc:
                Conf = yaml.load(fdesc, YAMLLoader)
            caldav_url = Conf.get('caldav').get('url')
            delFromCal(caldav_url, req.ics_url)

        RequestHistory.new(self.session, req, req.status, 'CANCELED',
                           self.user)
        req.update_status('CANCELED')
        # save who performed this action
        req.last_action_user_id = self.user.id

        self.session.flush()
        return req.status
示例#2
0
    def render(self):

        req_id = self.request.params.get('request_id')
        req = Request.by_id(self.session, req_id)
        if not req:
            return ''
        reason = self.request.params.get('reason')

        req.reason = reason
        RequestHistory.new(self.session,
                           req,
                           req.status,
                           'DENIED',
                           self.user,
                           reason=reason)
        req.update_status('DENIED')
        # save who performed this action
        req.last_action_user_id = self.user.id

        self.session.flush()

        # call celery task directly, do not wait for polling
        from celery.registry import tasks
        from celery.task import subtask
        req_task = tasks['worker_denied']
        data = {'req_id': req.id}
        subtask(req_task).apply_async(kwargs={'data': data}, countdown=5)

        log.info('scheduling task worker_denied for %s' % data)

        return req.status
示例#3
0
文件: worker.py 项目: lansolo99/pyvac
    def process(self, data):
        """ accepted by manager
        auto flag as accepted by HR
        """
        req = Request.by_id(self.session, data['req_id'])
        # after new field was added, it may not be set yet
        if not req.date_updated:
            return

        delta = datetime.now() - req.date_updated
        # after Request.date_updated + 3 days, auto accept it by HR
        if delta.days >= 3:
            # auto accept it as HR
            self.log.info('3 days passed, auto accept it by HR')

            # create history entry
            msg = 'Automatically accepted by HR after 3 days passed'
            # use error_message field, as it should not be used here
            # if it fails in ERROR it should be overwritten anyway
            # as the status will be changed from APPROVED_ADMIN to ERROR
            RequestHistory.new(self.session, req,
                               req.status, 'APPROVED_ADMIN',
                               user=None, error_message=msg)
            # update request status after sending email
            req.update_status('APPROVED_ADMIN')
            self.session.flush()
            transaction.commit()

            data['autoaccept'] = True
            async_result = subtask(WorkerApproved).delay(data=data)
            self.log.info('task scheduled %r' % async_result)
示例#4
0
    def render(self):

        req_id = self.request.params.get('request_id')
        req = Request.by_id(self.session, req_id)
        if not req:
            return ''

        data = {'req_id': req.id}

        only_manager = False
        # we should handle the case where the admin is also a user manager
        if (self.user.ldap_user and (req.user.manager_dn == self.user.dn)
                and (req.status == 'PENDING')):
            only_manager = True

        if self.user.is_admin and not only_manager:
            # create history entry
            RequestHistory.new(self.session, req,
                               req.status, 'APPROVED_ADMIN',
                               self.user)
            req.update_status('APPROVED_ADMIN')
            # save who performed this action
            req.last_action_user_id = self.user.id

            task_name = 'worker_approved'
            settings = self.request.registry.settings
            with open(settings['pyvac.celery.yaml']) as fdesc:
                Conf = yaml.load(fdesc, YAMLLoader)
            data['caldav.url'] = Conf.get('caldav').get('url')
        else:
            # create history entry
            RequestHistory.new(self.session, req,
                               req.status, 'ACCEPTED_MANAGER',
                               self.user)
            req.update_status('ACCEPTED_MANAGER')
            # save who performed this action
            req.last_action_user_id = self.user.id

            task_name = 'worker_accepted'

        self.session.flush()

        # call celery task directly, do not wait for polling
        from celery.registry import tasks
        from celery.task import subtask
        req_task = tasks[task_name]

        subtask(req_task).apply_async(kwargs={'data': data}, countdown=5)

        log.info('scheduling task %s for req_id: %d' % (task_name,
                                                        data['req_id']))
        return req.status
示例#5
0
    def delete(self, account):
        # cancel all associated requests for this user
        requests = account.requests
        for req in requests:
            req.update_status('CANCELED')
            # delete all request history entries for this user
            # otherwise it will raise a integrity error
            for entry in req.history:
                self.session.delete(entry)
        self.session.flush()

        # cancel all request history entries in case there are entries in
        # this table but without an existing request
        histo_reqs = RequestHistory.by_user(self.session, account.id)
        for entry in histo_reqs:
            self.session.delete(entry)
        self.session.flush()

        # cancel associated password recovery attempts for this user
        for item in account.recovery:
            self.session.delete(item)

        super(Delete, self).delete(account)
        if account.ldap_user:
            # delete in ldap
            ldap = LdapCache()
            try:
                ldap.delete_user(account.dn)
            except IndexError:
                log.info('User %s seems already deleted in ldap' % account.dn)
示例#6
0
    def render(self):
        try:
            form_date_from = self.request.params.get('date_from')
            if ' - ' not in form_date_from:
                msg = 'Invalid format for period.'
                self.request.session.flash('error;%s' % msg)
                return HTTPFound(location=route_url('home', self.request))

            dates = self.request.params.get('date_from').split(' - ')
            date_from = datetime.strptime(dates[0], '%d/%m/%Y')
            date_to = datetime.strptime(dates[1], '%d/%m/%Y')
            breakdown = self.request.params.get('breakdown')

            # retrieve holidays for user so we can remove them from selection
            holidays = get_holiday(self.user,
                                   year=date_from.year,
                                   use_datetime=True)

            submitted = [
                d for d in daterange(date_from, date_to)
                if d.isoweekday() not in [6, 7] and d not in holidays
            ]
            days = float(len(submitted))
            pool = None

            days_diff = (date_to - date_from).days
            if days_diff < 0:
                msg = 'Invalid format for period.'
                self.request.session.flash('error;%s' % msg)
                return HTTPFound(location=route_url('home', self.request))

            if (date_to == date_from) and days > 1:
                # same day, asking only for one or less day duration
                msg = 'Invalid value for days.'
                self.request.session.flash('error;%s' % msg)
                return HTTPFound(location=route_url('home', self.request))

            if days <= 0:
                msg = 'Invalid value for days.'
                self.request.session.flash('error;%s' % msg)
                return HTTPFound(location=route_url('home', self.request))

            # check if user is sudoed
            check_user = self.get_target_user(self.user)
            # retrieve future requests for user so we can check overlap
            futures = [
                d for req in Request.by_user_future(self.session, check_user)
                for d in daterange(req.date_from, req.date_to)
            ]
            intersect = set(futures) & set(submitted)
            if intersect:
                err_intersect = True
                # must check for false warning in case of half day requests
                if len(intersect) == 1:
                    # only one date in conflict, check if it's for an half-day
                    dt = intersect.pop()
                    # retrieve the request for this date
                    req = [
                        req for req in Request.by_user_future(
                            self.session, check_user)
                        for d in daterange(req.date_from, req.date_to)
                        if d == dt
                    ]
                    if len(req) < 2:
                        req = req.pop()
                        if req.label != breakdown:
                            # intersect is false, it's not the same halfday
                            err_intersect = False
                            log.debug(
                                'False positive on intersect '
                                'for %s (%s): request: %d (%s)' %
                                (date_from, breakdown, req.id, req.label))

                if err_intersect:
                    msg = 'Invalid period: days already requested.'
                    self.request.session.flash('error;%s' % msg)
                    return HTTPFound(location=route_url('home', self.request))

            vac_type = VacationType.by_id(self.session,
                                          int(self.request.params.get('type')))

            if not self.user.is_admin:
                # check if vacation requires user role
                if (vac_type.visibility
                        and self.user.role not in vac_type.visibility):
                    msg = 'You are not allowed to use type: %s' % vac_type.name
                    self.request.session.flash('error;%s' % msg)
                    return HTTPFound(location=route_url('home', self.request))

            # check RTT usage access
            if vac_type.name == u'RTT':
                if self.user.has_feature('disable_rtt'):
                    msg = 'You are not allowed to use type: %s' % vac_type.name
                    self.request.session.flash('error;%s' % msg)
                    return HTTPFound(location=route_url('home', self.request))

            # label field is used when requesting half day
            label = u''
            if breakdown != 'FULL':
                # handle half day
                if (days > 1):
                    msg = ('AM/PM option must be used only when requesting a '
                           'single day.')
                    self.request.session.flash('error;%s' % msg)
                    return HTTPFound(location=route_url('home', self.request))
                else:
                    days = 0.5
                    label = unicode(breakdown)

            # check RTT usage
            if vac_type.name == u'RTT':
                pool = rtt_data = check_user.get_rtt_usage(self.session)
                if rtt_data is not None and rtt_data['left'] <= 0:
                    msg = 'No RTT left to take.'
                    self.request.session.flash('error;%s' % msg)
                    return HTTPFound(location=route_url('home', self.request))
                # check that we have enough RTT to take
                if rtt_data is not None and days > rtt_data['left']:
                    msg = 'You only have %s RTT to use.' % rtt_data['left']
                    self.request.session.flash('error;%s' % msg)
                    return HTTPFound(location=route_url('home', self.request))
                # check that we request vacations in the allowed year
                if rtt_data is not None and (date_from.year != rtt_data['year']
                                             or
                                             date_to.year != rtt_data['year']):
                    msg = ('RTT can only be used for year %d.' %
                           rtt_data['year'])
                    self.request.session.flash('error;%s' % msg)
                    return HTTPFound(location=route_url('home', self.request))

            message = None
            # check Exceptionnel mandatory field
            if vac_type.name == u'Exceptionnel':
                message = self.request.params.get('exception_text')
                message = message.strip() if message else message
                if not message:
                    msg = ('You must provide a reason for %s requests' %
                           vac_type.name)
                    self.request.session.flash('error;%s' % msg)
                    return HTTPFound(location=route_url('home', self.request))
                # check size
                if len(message) > 140:
                    msg = ('%s reason must not exceed 140 characters' %
                           vac_type.name)
                    self.request.session.flash('error;%s' % msg)
                    return HTTPFound(location=route_url('home', self.request))

            # check for Compensatoire type (LU holiday recovery)
            if vac_type.name == u'Compensatoire':
                to_recover = self.request.params.get('recovered_holiday')
                if to_recover == '-1':
                    msg = 'You must select a date for %s' % vac_type.name
                    self.request.session.flash('error;%s' % msg)
                    return HTTPFound(location=route_url('home', self.request))

                recover_date = datetime.strptime(to_recover, '%d/%m/%Y')
                vac_class = vac_type.get_class(check_user.country)
                if vac_class:
                    error = vac_class.validate_request(check_user, None, days,
                                                       recover_date, date_to)
                    if error is not None:
                        self.request.session.flash('error;%s' % error)
                        return HTTPFound(
                            location=route_url('home', self.request))
                    message = to_recover

            # check Récupération reason field
            if vac_type.name == u'Récupération':
                message = self.request.params.get('exception_text')
                message = message.strip() if message else message
                # check size
                if message and len(message) > 140:
                    msg = ('%s reason must not exceed 140 characters' %
                           vac_type.name)
                    self.request.session.flash('error;%s' % msg)
                    return HTTPFound(location=route_url('home', self.request))

            # check CP usage
            if vac_type.name == u'CP':
                cp_class = check_user.get_cp_class(self.session)
                pool = check_user.get_cp_usage(self.session)

                if cp_class:
                    # only FR and LU have a dedicated CP class to use

                    # convert days to hours for LU if needed
                    days = cp_class.convert_days(days)

                    error = cp_class.validate_request(check_user, pool, days,
                                                      date_from, date_to)
                    if error is not None:
                        self.request.session.flash('error;%s' % error)
                        return HTTPFound(
                            location=route_url('home', self.request))

                if pool:
                    # remove expire datetimes as it's not json serializable
                    if 'n_1' in pool:
                        pool['n_1'].pop('expire', None)
                    if 'extra' in pool:
                        pool['extra'].pop('expire', None)
                    pool['acquis'].pop('expire', None)
                    pool['restant'].pop('expire', None)

            # create the request
            # default values
            target_status = u'PENDING'
            target_user = self.user
            target_notified = False

            sudo_use = False
            if self.user.is_admin:
                sudo_user_id = int(self.request.params.get('sudo_user'))
                if sudo_user_id != -1:
                    user = User.by_id(self.session, sudo_user_id)
                    if user:
                        sudo_use = True
                        target_user = user
                        target_status = u'APPROVED_ADMIN'
                        target_notified = True

            # save pool status when making the request
            if pool:
                pool_status = json.dumps(pool)
            else:
                pool_status = json.dumps({})

            request = Request(
                date_from=date_from,
                date_to=date_to,
                days=days,
                vacation_type=vac_type,
                status=target_status,
                user=target_user,
                notified=target_notified,
                label=label,
                message=message,
                pool_status=pool_status,
            )
            self.session.add(request)
            self.session.flush()
            # create history entry
            sudo_user = None
            if sudo_use:
                sudo_user = self.user
            RequestHistory.new(self.session,
                               request,
                               '',
                               target_status,
                               target_user,
                               pool_status,
                               message=message,
                               sudo_user=sudo_user)

            if request and not sudo_use:
                msg = 'Request sent to your manager.'
                self.request.session.flash('info;%s' % msg)
                # call celery task directly, do not wait for polling
                from celery.registry import tasks
                from celery.task import subtask
                req_task = tasks['worker_pending']
                data = {'req_id': request.id}
                subtask(req_task).apply_async(kwargs={'data': data},
                                              countdown=5)
                log.info('scheduling task worker_pending for %s' % data)

            if request and sudo_use:
                settings = self.request.registry.settings
                if 'pyvac.celery.yaml' in settings:
                    with open(settings['pyvac.celery.yaml']) as fdesc:
                        Conf = yaml.load(fdesc, YAMLLoader)
                    caldav_url = Conf.get('caldav').get('url')
                    request.add_to_cal(caldav_url, self.session)
                    msg = 'Request added to calendar and DB.'
                    self.request.session.flash('info;%s' % msg)

        except Exception as exc:
            log.error(exc)
            msg = ('An error has occured while processing this request: %r' %
                   exc)
            self.request.session.flash('error;%s' % msg)

        return HTTPFound(location=route_url('home', self.request))