###################################################################### # Copyright (c) 2007, Petteri Aimonen # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright # notice and this list of conditions. # * Redistributions in binary form must reproduce the above copyright # notice and this list of conditions in the documentation and/or other # materials provided with the distribution. '''Upkeep tasks, removing inactive animals etc.''' import datetime import settings from pymisc import _ from dataaccess import date_todb, getlastdate, remove_animal from dataaccess import groupfeed_getlast, save_importlog, cleanup_importlogs from database import db_conn class Upkeeper: '''Container for upkeep tasks''' def __init__(self, logger): self.cursor = db_conn.cursor() self.animals = self.animallist() self.logger = logger def animallist(self): '''Get list of all animals in the database''' self.cursor.execute("SELECT animalid FROM animals") data = self.cursor.fetchall() return [row[0] for row in data] def check_animals_inactive(self): '''Check for inactive animals. Animals with no feed data during last 2 days are marked to database and logged. ''' date = getlastdate() date -= datetime.timedelta(2) self.cursor.execute("SELECT animalid FROM animals WHERE active=1 AND " \ "animalid NOT IN (SELECT animalid FROM feeds WHERE " \ "date>=? GROUP BY animalid)", (date_todb(date),)) data = self.cursor.fetchall() for animalid, in data: self.logger.log_markedinactive(animalid) self.cursor.executemany("UPDATE animals SET active=0 WHERE " \ "animalid=?", data) def check_animals_active(self): '''Check for active animals marked inactive. Inactive animals with feed data during last day are logged. ''' date = getlastdate() self.cursor.execute("SELECT animalid FROM animals WHERE active=0 AND " \ "animalid IN (SELECT animalid FROM feeds WHERE date=?)", (date_todb(date),)) for animalid, in self.cursor.fetchall(): self.logger.log_inactivehasfeeds(animalid) def check_old_animals(self): '''Remove animals with no feed data at all''' for animalid in self.animals: self.cursor.execute("SELECT COUNT(*) FROM feeds WHERE animalid=?", (animalid, )) count = self.cursor.fetchone()[0] if count == 0: self.logger.log_removedanimal(animalid) remove_animal(animalid) def check_old_feeds(self): '''Remove old feed data''' date = getlastdate() keepdays = settings.parser.getint("DEFAULT", "keepfeeddata") date -= datetime.timedelta(keepdays) self.cursor.execute("DELETE FROM feeds WHERE date<=?", (date_todb(date), )) self.cursor.execute("DELETE FROM groupfeed WHERE date<=?", (date_todb(date), )) def check_groupfeed_missing(self): '''Check for missing groupfeed days''' gfeeddate = groupfeed_getlast() afeeddate = getlastdate() if gfeeddate and afeeddate and gfeeddate < afeeddate: self.logger.log_missing_gfeed() def check_smallfeeds(self): '''Check for too small feeds''' threshold = settings.parser.getint("NOTICES", "smallfeed") date = getlastdate() self.cursor.execute("SELECT animalid, grams FROM feeds " + "WHERE date=? AND grams<=?", (date_todb(date), threshold)) for animalid, grams in self.cursor.fetchall(): self.logger.log_smallfeed(animalid, grams) def check_feeddeltas(self): '''Check for variations in feed amounts''' threshold = settings.parser.getfloat("NOTICES", "feeddelta") period = settings.parser.getint("NOTICES", "feeddeltaperiod") todate = getlastdate() fromdate = todate - datetime.timedelta(period) self.cursor.execute("SELECT animalid, MAX(MAX(grams) - AVG(grams), " \ "AVG(grams) - MIN(grams)) / AVG(grams) AS delta FROM feeds " \ "WHERE date>=? AND date<=? GROUP BY animalid", (date_todb(fromdate), date_todb(todate))) for aid, delta in self.cursor.fetchall(): if delta is None: continue delta = delta * 100. if delta > threshold: self.logger.log_feeddelta(aid, delta) def savelog(self): '''Save import log to database and clean up old logs''' save_importlog(self.logger.format()) keepdays = settings.parser.getint("DEFAULT", "keepimportlogs") keepdate = datetime.datetime.today() keepdate -= datetime.timedelta(keepdays) cleanup_importlogs(keepdate) def getupkeeptasks(logger): '''Get list of upkeep tasks as [(description, function, args, kwargs)]. Call function(*args, **kwargs) Logger is ImportLogger instance and is used for logging upkeep messages. ''' upkeeper = Upkeeper(logger) tasks = [(_('Checking active animals'), upkeeper.check_animals_active, (), {}), (_('Checking inactive animals'), upkeeper.check_animals_inactive, (), {}), (_('Removing old animals'), upkeeper.check_old_animals, (), {}), (_('Removing old feed data'), upkeeper.check_old_feeds, (), {}), (_('Checking for missing groupfeed data'), upkeeper.check_groupfeed_missing, (), {}), (_('Checking for small feeds'), upkeeper.check_smallfeeds, (), {}), (_('Checking for feed deviations'), upkeeper.check_feeddeltas, (), {}), (_('Saving import log'), upkeeper.savelog, (), {}), (_('Saving database'), db_conn.commit, (), {}) ] return tasks