2021-01-21 02:15:19 +00:00
#!/usr/bin/env python
2017-09-17 14:34:51 +00:00
# -*- coding: utf-8 -*-
""" How do I even adult? """
2017-10-23 00:58:19 +00:00
import math
2017-09-17 14:34:51 +00:00
import collections
2017-10-23 00:58:19 +00:00
import datetime
import calendar
2017-09-26 02:24:27 +00:00
import click
2017-10-30 23:41:33 +00:00
import flask
2017-09-17 14:34:51 +00:00
import poobrains
app = poobrains . app
def tomorrow ( ) :
return datetime . datetime . now ( ) + datetime . timedelta ( days = 1 )
2017-10-24 02:56:33 +00:00
def firstweekday ( weekday , first_day_of_month ) :
""" return day of month which is first occurence of weekday in a month beginning on weekday first_day_of_month. """
weekday = weekday - 1
first_day_of_month = first_day_of_month - 1
if first_day_of_month < = weekday :
return weekday - first_day_of_month + 1
elif first_day_of_month > weekday :
return weekday - first_day_of_month + 7 + 1
2021-01-21 02:15:19 +00:00
class TaskForm ( poobrains . form . AutoForm ) :
2017-10-11 16:17:17 +00:00
2017-10-23 00:58:19 +00:00
def __init__ ( self , model_or_instance , * * kwargs ) :
2017-10-11 16:17:17 +00:00
2017-10-23 00:58:19 +00:00
super ( TaskForm , self ) . __init__ ( model_or_instance , * * kwargs )
2017-10-30 23:41:33 +00:00
choices = [ ]
for task in Task . list ( ' read ' , flask . g . user ) :
choices . append ( ( task , task . title ) )
2018-03-13 17:39:05 +00:00
dep_value = [ x . dependency for x in self . instance . task_dependencies ]
2017-11-02 02:37:00 +00:00
self . dependencies = poobrains . form . fields . Select ( type = poobrains . form . types . StorableInstanceParamType ( Task ) , multi = True , choices = choices , value = dep_value )
2017-10-11 16:17:17 +00:00
2017-11-02 02:37:00 +00:00
def process ( self , submit ) :
2018-03-13 17:39:05 +00:00
r = super ( TaskForm , self ) . process ( submit )
2017-11-02 02:37:00 +00:00
if submit == ' submit ' :
dependencies = self . fields [ ' dependencies ' ] . value
TaskDependency . delete ( ) . where ( TaskDependency . task == self . instance ) . execute ( )
try :
for dependency in dependencies :
newdep = TaskDependency ( )
newdep . task = self . instance
newdep . dependency = dependency
newdep . save ( force_insert = True )
except poobrains . storage . IntegrityError :
poobrains . flash ( " At least have the decency to build an indirect loop! " )
2018-03-13 17:39:05 +00:00
return r
2017-11-02 02:37:00 +00:00
@app.expose ( ' /task ' , force_secure = True )
2017-09-17 14:34:51 +00:00
class Task ( poobrains . commenting . Commentable ) :
2017-09-26 02:24:27 +00:00
class Meta :
2021-07-07 12:46:27 +00:00
order_by = ( ' -priority ' , ' checkdate ' , ' -date ' )
2017-09-26 02:24:27 +00:00
2017-10-11 16:17:17 +00:00
form_add = TaskForm
2017-11-02 02:37:00 +00:00
form_edit = TaskForm
2017-10-11 16:17:17 +00:00
2017-09-17 14:34:51 +00:00
title = poobrains . storage . fields . CharField ( )
2017-09-26 01:08:51 +00:00
checkdate = poobrains . storage . fields . DateTimeField ( default = tomorrow , null = True )
2018-04-24 01:06:10 +00:00
priority = poobrains . storage . fields . IntegerField ( default = 0 , form_widget = poobrains . form . fields . Select , choices = [
2017-09-20 21:40:46 +00:00
( - 2 , ' Very low ' ) ,
( - 1 , ' Low ' ) ,
( 0 , ' Normal ' ) ,
( 1 , ' High ' ) ,
( 2 , ' VERY HIGH ' )
] )
2017-10-23 00:58:19 +00:00
status = poobrains . storage . fields . CharField ( default = ' new ' , form_widget = poobrains . form . fields . Select , choices = [
2017-10-10 01:46:00 +00:00
( ' new ' , ' new ' ) ,
( ' ongoing ' , ' ongoing ' ) ,
( ' finished ' , ' finished ' ) ,
( ' aborted ' , ' aborted ' )
] )
progress = poobrains . storage . fields . IntegerField ( default = 0 , constraints = [
poobrains . storage . fields . Check ( ' progress >= 0 ' ) ,
poobrains . storage . fields . Check ( ' progress <= 100 ' )
] )
2017-09-17 14:34:51 +00:00
description = poobrains . md . MarkdownField ( )
2017-11-19 04:46:10 +00:00
reward_served = poobrains . storage . fields . BooleanField ( default = False )
2018-04-19 20:56:53 +00:00
@property
def css_class ( self ) :
classes = [ ]
2018-04-20 16:56:34 +00:00
classes . append ( self . checkdate_css )
2018-04-19 20:56:53 +00:00
classes . append ( self . priority_css )
2018-04-20 16:56:34 +00:00
return ' ' . join ( classes )
@property
def checkdate_css ( self ) :
2018-04-19 20:56:53 +00:00
if isinstance ( self . checkdate , datetime . datetime ) :
now = datetime . datetime . now ( )
if self . checkdate < now :
2018-04-20 16:56:34 +00:00
return ' checkdate-passed '
2018-04-19 20:56:53 +00:00
elif self . checkdate - datetime . timedelta ( days = 1 ) < now : # checkdate within the next 24h
2018-04-20 16:56:34 +00:00
return ' checkdate-24h '
2018-04-19 20:56:53 +00:00
2018-04-20 16:56:34 +00:00
return ' '
2018-04-19 20:56:53 +00:00
2018-03-13 17:39:05 +00:00
@property
def priority_label ( self ) :
""" gives the choice of the currently set priority """
return dict ( self . __class__ . priority . choices ) [ self . priority ]
@property
def priority_css ( self ) :
2018-04-19 20:56:53 +00:00
return ' priority- %s ' % self . priority_label . lower ( ) . replace ( ' ' , ' - ' )
@property
def progress_svg ( self ) :
2018-04-22 22:37:01 +00:00
return Progress ( handle = self . progress ) . render ( ' raw ' )
2018-03-13 17:39:05 +00:00
2017-11-19 04:46:10 +00:00
def validate ( self ) :
pass # FIXME/TODO: dependency resolution
def save ( self , * * kwargs ) :
2018-03-13 17:39:05 +00:00
if self . _pk and not self . reward_served and self . status == ' finished ' : # FIXME: _pk is an ugly hack to determin if we're editing or adding but peewee didn't offer anything better last i checked
2017-11-19 04:46:10 +00:00
reward_token = RewardToken ( )
reward_token . task = self
reward_token . owner = self . owner
reward_token . group = self . group
reward_token . save ( force_insert = True )
self . reward_served = True
return super ( Task , self ) . save ( * * kwargs )
2017-09-17 14:34:51 +00:00
2018-03-13 17:39:05 +00:00
@classmethod
def class_tree ( cls , root = None , current_depth = 0 ) :
if current_depth == 0 :
2018-04-22 22:37:01 +00:00
tree = poobrains . rendering . Tree ( root = poobrains . rendering . RenderString ( ' dependencies ' ) , mode = ' inline ' )
2018-03-13 17:39:05 +00:00
else :
tree = poobrains . rendering . Tree ( root = root , mode = ' inline ' )
if current_depth > 100 :
if root :
2018-04-19 20:56:53 +00:00
message = " Possible loop in dependencies of Task: ' %s ' . " % root . name
2018-03-13 17:39:05 +00:00
else :
2018-04-19 20:56:53 +00:00
message = " Possible loop in dependencies of a Task but don ' t have a root for this tree. Are you fucking with current_depth manually? "
2018-03-13 17:39:05 +00:00
app . logger . error ( message )
return tree
deps = TaskDependency . select ( ) . where ( TaskDependency . task == root )
for dep in deps :
tree . children . append ( dep . dependency . tree ( current_depth = current_depth + 1 ) )
return tree
def tree ( self , current_depth = 0 ) :
return self . __class__ . class_tree ( root = self , current_depth = current_depth )
2017-09-17 14:34:51 +00:00
class RecurringTask ( poobrains . commenting . Commentable ) :
title = poobrains . storage . fields . CharField ( )
2017-09-26 01:08:51 +00:00
checkdate = poobrains . storage . fields . IntegerField ( null = True , help_text = ' Time frame in seconds ' )
2018-05-03 14:56:59 +00:00
priority = poobrains . storage . fields . IntegerField ( form_widget = poobrains . form . fields . Select , choices = [
2017-09-17 14:34:51 +00:00
( - 2 , ' Very low ' ) ,
( - 1 , ' Low ' ) ,
( 0 , ' Normal ' ) ,
( 1 , ' High ' ) ,
( 2 , ' VERY HIGH ' )
] )
year = poobrains . storage . fields . IntegerField ( null = True )
2017-10-23 00:58:19 +00:00
month = poobrains . storage . fields . IntegerField ( null = True , form_widget = poobrains . form . fields . Select , choices = [
2017-09-17 14:34:51 +00:00
( None , ' Any ' ) ,
( 1 , ' January ' ) ,
( 2 , ' February ' ) ,
( 3 , ' March ' ) ,
( 4 , ' April ' ) ,
( 5 , ' May ' ) ,
( 6 , ' June ' ) ,
( 7 , ' July ' ) ,
( 8 , ' August ' ) ,
( 9 , ' September ' ) ,
( 10 , ' October ' ) ,
( 11 , ' November ' ) ,
( 12 , ' December ' )
] )
2017-10-26 21:59:18 +00:00
weeks = poobrains . storage . fields . IntegerField ( null = True , help_text = " Every n weeks after creation. " )
2017-10-23 00:58:19 +00:00
weekday_month = poobrains . storage . fields . IntegerField ( null = True , form_widget = poobrains . form . fields . Select , choices = [ ( None , ' Any ' ) ] + [ ( x , x ) for x in range ( 1 , 7 ) ] )
weekday = poobrains . storage . fields . IntegerField ( null = True , form_widget = poobrains . form . fields . Select , choices = [
2017-09-17 14:34:51 +00:00
( None , ' Any ' ) ,
( 1 , ' Monday ' ) ,
( 2 , ' Tuesday ' ) ,
( 3 , ' Wednesday ' ) ,
( 4 , ' Thursday ' ) ,
( 5 , ' Friday ' ) ,
( 6 , ' Saturday ' ) ,
( 7 , ' Sunday ' )
] )
2017-10-23 00:58:19 +00:00
day = poobrains . storage . fields . IntegerField ( null = True , form_widget = poobrains . form . fields . Select , choices = [ ( None , ' Any ' ) ] + [ ( x , x ) for x in range ( 1 , 32 ) ] )
hour = poobrains . storage . fields . IntegerField ( null = True , choices = [ ( None , ' Any ' ) ] + [ ( x , x ) for x in range ( 0 , 24 ) ] , help_text = ' 0-23 ' )
minute = poobrains . storage . fields . IntegerField ( null = True , choices = [ ( None , ' Any ' ) ] + [ ( x , x ) for x in range ( 0 , 60 ) ] , help_text = ' 0-59 ' )
2017-09-17 14:34:51 +00:00
description = poobrains . md . MarkdownField ( )
latest_task = poobrains . storage . fields . ForeignKeyField ( Task , null = True )
2017-10-11 16:17:17 +00:00
class TaskDependency ( poobrains . storage . Model ) :
2017-11-02 02:37:00 +00:00
class Meta :
order_by = [ ' task ' ]
primary_key = poobrains . storage . CompositeKey ( ' task ' , ' dependency ' )
2018-03-13 17:39:05 +00:00
task = poobrains . storage . fields . ForeignKeyField ( Task , related_name = ' task_dependencies ' )
2017-10-11 16:17:17 +00:00
dependency = poobrains . storage . fields . ForeignKeyField ( Task , related_name = ' provides ' , constraints = [ poobrains . storage . fields . Check ( ' dependency_id <> task_id ' ) ] )
2018-03-13 17:39:05 +00:00
@app.expose ( ' /rewards/ ' , mode = ' full ' )
2017-09-20 21:40:46 +00:00
class Reward ( poobrains . commenting . Commentable ) :
2017-09-17 14:34:51 +00:00
2017-09-20 21:40:46 +00:00
title = poobrains . storage . fields . CharField ( )
description = poobrains . md . MarkdownField ( null = True )
2017-09-17 14:34:51 +00:00
2017-11-02 02:37:00 +00:00
2018-03-13 17:39:05 +00:00
class RedeemForm ( poobrains . auth . BoundForm ) :
title = " Redeem a token "
def __init__ ( self , * args , * * kwargs ) :
super ( RedeemForm , self ) . __init__ ( * args , * * kwargs )
choices = [ ]
for choice in self . instance . reward_choices :
choices . append ( ( choice . reward , choice . reward . render ( ' inline ' ) ) )
self . reward = poobrains . form . fields . Radio ( choices = choices , type = poobrains . form . types . StorableInstanceParamType ( Reward ) )
self . submit = poobrains . form . Button ( type = ' submit ' , label = u ' 🍰 ' )
def process ( self , * args , * * kwargs ) :
reward = self . fields [ ' reward ' ] . value
if reward :
self . instance . reward = reward
self . instance . redeemed = True
self . instance . save ( )
poobrains . flash ( " Token redeemed, enjoy your reward now! :) " )
return poobrains . redirect ( reward . url ( ' full ' ) )
flash ( u " The cake might be a lie. 🤔 " , ' error ' )
return self
@app.expose ( ' /tokens/ ' , mode = ' redeem ' )
2017-11-19 04:46:10 +00:00
class RewardToken ( poobrains . auth . Administerable ) :
task = poobrains . storage . fields . ForeignKeyField ( Task )
reward = poobrains . storage . fields . ForeignKeyField ( Reward , null = True )
2018-03-13 17:39:05 +00:00
redeemed = poobrains . storage . fields . BooleanField ( default = False )
form_redeem = RedeemForm # tells self.form to use RedeemForm for mode 'redeem' updates
class Meta :
modes = collections . OrderedDict ( [
( ' add ' , ' create ' ) ,
( ' teaser ' , ' read ' ) ,
( ' inline ' , ' read ' ) ,
( ' full ' , ' read ' ) ,
( ' edit ' , ' update ' ) ,
( ' delete ' , ' delete ' ) ,
( ' redeem ' , ' update ' )
] )
2017-11-19 04:46:10 +00:00
def save ( self , * * kwargs ) :
rv = super ( RewardToken , self ) . save ( * * kwargs )
if not len ( self . reward_choices ) :
for reward in Reward . select ( ) . order_by ( poobrains . storage . fn . Random ( ) ) . limit ( 5 ) :
choice = RewardTokenChoice ( )
choice . token = self
choice . reward = reward
choice . save ( force_insert = True )
return rv
def redeem ( self , reward ) :
self . reward = reward
self . save ( )
class RewardTokenChoice ( poobrains . storage . Model ) :
class Meta :
primary_key = poobrains . storage . CompositeKey ( ' token ' , ' reward ' )
order_by = [ ' token ' , ' reward ' ]
token = poobrains . storage . fields . ForeignKeyField ( RewardToken , related_name = ' reward_choices ' )
reward = poobrains . storage . fields . ForeignKeyField ( Reward )
2018-03-13 17:39:05 +00:00
class TaskControl ( poobrains . auth . Protected ) :
user = None
2018-04-16 04:46:12 +00:00
new = None
ongoing = None
finished = None
aborted = None
2018-03-13 17:39:05 +00:00
def __init__ ( self , handle = None , * * kwargs ) :
super ( TaskControl , self ) . __init__ ( * * kwargs )
self . user = poobrains . auth . User . load ( handle )
2018-04-24 17:07:53 +00:00
self . menu_actions = poobrains . rendering . Menu ( ' task-add ' )
self . menu_actions . append ( Task . url ( ' add ' ) , ' Add new ' )
2018-03-13 17:39:05 +00:00
2018-04-16 04:46:12 +00:00
base_query = Task . list ( ' read ' , poobrains . g . user ) . where ( Task . owner == self . user )
self . new = base_query . where ( Task . status == ' new ' )
self . ongoing = base_query . where ( Task . status == ' ongoing ' )
2018-04-19 20:56:53 +00:00
self . finished = base_query . where ( Task . status == ' finished ' , Task . checkdate > datetime . datetime . now ( ) )
2018-04-16 04:46:12 +00:00
self . aborted = base_query . where ( Task . status == ' aborted ' )
2018-04-22 23:41:47 +00:00
@property
def title ( self ) :
2018-04-22 23:46:59 +00:00
return " %s s goals " % self . user . name
2018-04-22 23:41:47 +00:00
2018-04-24 01:06:10 +00:00
# @property
# def menu_actions(self):
# m = poobrains.rendering.Menu('actions')
# m.append('#', poobrains.Markup('<span class="priority priority-very-low">vewy low</span>'))
#
# return m
2018-04-16 04:46:12 +00:00
# def view(self, handle=None, offset=0, **kwargs):
#
# super(TaskControl, self).view(handle=handle, **kwargs) # checks permissions
# u = poobrains.auth.User.load(handle)
#
# q = Task.list('read', poobrains.g.user).where(Task.owner == u, Task.status != 'aborted', Task.status != 'finished').order_by(Task.priority.desc(), Task.checkdate.desc(), Task.created, Task.title)
#
# listing = poobrains.storage.Listing(Task, title="Your goals", query=q, offset=offset, pagination_options={'handle': handle})
#
# return listing.view(**kwargs)
2018-03-13 17:39:05 +00:00
app . site . add_view ( TaskControl , ' /~<handle>/tasks/ ' , mode = ' full ' , endpoint = ' taskcontrol_handle ' )
app . site . add_view ( TaskControl , ' /~<handle>/tasks/+<int:offset> ' , mode = ' full ' , endpoint = ' taskcontrol_handle_offset ' )
2018-04-19 20:56:53 +00:00
@app.expose ( ' /svg/progress ' )
class Progress ( poobrains . svg . SVG ) :
width = ' 100 % '
height = ' 20px '
@property
def percent ( self ) :
return int ( self . handle )
def view ( self , mode = None , handle = None , * * kwargs ) :
try :
self . percent # makes sure handle makes sense
return super ( Progress , self ) . view ( mode = mode , handle = handle , * * kwargs )
except TypeError :
abort ( 400 , ' Progress value must be 0-100. ' )
2018-03-13 17:39:05 +00:00
@app.route ( ' / ' )
def front ( ) :
return poobrains . redirect ( TaskControl . url ( handle = poobrains . g . user . name , mode = ' full ' ) )
2017-09-17 14:34:51 +00:00
@app.cron
def create_recurring ( ) :
now = datetime . datetime . now ( )
dated_tasks = collections . OrderedDict ( )
for template in RecurringTask . select ( ) :
2017-09-26 02:24:27 +00:00
try :
2017-10-23 00:58:19 +00:00
if template . latest_task :
2018-04-19 20:56:53 +00:00
base_date = template . latest_task . date
2017-10-23 00:58:19 +00:00
else : # for some reason this can be None without triggering Task.DoesNotExist
2018-04-19 20:56:53 +00:00
base_date = template . date
2017-10-23 00:58:19 +00:00
2017-09-26 02:24:27 +00:00
except Task . DoesNotExist :
2018-04-19 20:56:53 +00:00
base_date = template . date
2017-09-17 14:34:51 +00:00
2017-09-19 16:42:58 +00:00
2017-09-20 21:40:46 +00:00
dates = collections . OrderedDict ( )
2017-09-21 21:02:03 +00:00
# add years
2017-09-19 16:42:58 +00:00
for year in range ( base_date . year , now . year + 1 ) :
if not template . year or template . year == year :
2017-09-20 21:40:46 +00:00
dates [ year ] = collections . OrderedDict ( )
2021-01-21 02:15:19 +00:00
years = list ( dates . keys ( ) )
2017-09-19 16:42:58 +00:00
2017-09-21 21:02:03 +00:00
# add months
2021-01-21 02:15:19 +00:00
for year , _ in dates . items ( ) :
2017-09-19 16:42:58 +00:00
# Determine whether this is the first, last (or neither) year of the range
2021-01-21 02:15:19 +00:00
first_year = year == years [ 0 ]
last_year = year == years [ - 1 ]
2017-09-17 14:34:51 +00:00
2017-10-23 00:58:19 +00:00
if not template . month is None :
2017-09-20 21:40:46 +00:00
2017-09-26 01:08:51 +00:00
if first_year and last_year :
valid = template . month > = base_date . month and template . month < = now . month
elif first_year :
valid = template . month > = base_date . month
elif last_year :
valid = template . month < = now . month
else :
valid = True
if valid :
dates [ year ] [ template . month ] = collections . OrderedDict ( )
2017-09-21 17:43:52 +00:00
2017-09-20 21:40:46 +00:00
2017-09-21 17:43:52 +00:00
else :
2017-09-21 21:02:03 +00:00
2017-09-21 17:43:52 +00:00
if first_year and last_year :
2017-09-26 01:08:51 +00:00
months = range ( base_date . month , now . month + 1 )
2017-09-21 17:43:52 +00:00
elif first_year :
months = range ( base_date . month , 13 )
elif last_year :
months = range ( 1 , now . month + 1 )
else :
months = range ( 1 , 13 )
for month in months :
dates [ year ] [ month ] = collections . OrderedDict ( )
2017-09-20 21:40:46 +00:00
2017-09-21 21:02:03 +00:00
# add days
2021-01-21 02:15:19 +00:00
for year , months in dates . items ( ) :
2017-09-21 21:02:03 +00:00
2021-01-21 02:15:19 +00:00
first_year = year == years [ 0 ]
last_year = year == years [ - 1 ]
2017-09-21 21:02:03 +00:00
2021-01-21 02:15:19 +00:00
for month , _ in months . items ( ) :
2017-09-21 21:02:03 +00:00
2017-09-26 01:08:51 +00:00
first_month = first_year and month == base_date . month
2017-09-21 21:02:03 +00:00
last_month = last_year and month == now . month
2017-10-24 02:56:33 +00:00
first_day_of_month = datetime . datetime ( year = year , month = month , day = 1 )
2017-10-23 00:58:19 +00:00
if not template . day is None :
2017-09-26 01:08:51 +00:00
#first_year_valid = first_year and month <= base_date.month
#middle_year_valid = not first_year and not last_year
#last_year_valid = last_year and month >= now.month
#weekday_valid = not template.weekday or datetime.datetime(year, month, template.day).isoweekday == template.weekday - 1
2017-09-21 21:02:03 +00:00
2017-09-26 01:08:51 +00:00
if first_month and last_month :
valid = template . day > = base_date . day and template . day < = now . day
elif first_month :
valid = template . day > = base_date . day
elif last_month :
valid = template . day < = now . day
else :
valid = True
valid = valid and ( not template . weekday or datetime . datetime ( year , month , template . day ) . isoweekday ( ) == template . weekday ) # check if the date has the correct weekday
2017-10-24 02:56:33 +00:00
valid = valid and ( not template . weekday_month or day == firstweekday ( template . weekday , first_day_of_month . isoweekday ( ) ) + ( 7 * ( template . weekday_month - 1 ) ) ) # check if date has correct'th number of weekday occurence in this month (2nd friday or whatev)
2017-10-30 22:10:02 +00:00
week_valid = False
if template . weeks :
base_monday = datetime . datetime ( year = base_date . year , month = base_date . month , day = base_date . day - base_date . weekday ( ) )
current_monday = dt - datetime . timedelta ( days = dt . weekday ( ) )
delta = current_monday - base_monday
if delta . days % ( 7 * template . weeks ) == 0 :
week_valid = True
else :
week_valid = True
2017-09-21 21:02:03 +00:00
2017-09-26 01:08:51 +00:00
#if (first_year_valid or middle_year_valid or last_year_valid) and weekday_valid:
2017-10-30 22:10:02 +00:00
if valid and week_valid :
2017-09-26 01:08:51 +00:00
dates [ year ] [ month ] [ template . day ] = collections . OrderedDict ( )
2017-09-21 21:02:03 +00:00
else :
if first_month and last_month :
days = range ( base_date . day , now . day + 1 )
elif first_month :
days = range ( base_date . day , calendar . monthrange ( year , month ) [ 1 ] + 1 )
elif last_month :
days = range ( 1 , now . day + 1 )
2017-10-23 00:58:19 +00:00
else :
days = range ( 1 , 32 ) # days that don't exist are weeded out by trying to create a datetime from it
2017-10-10 00:20:46 +00:00
2017-10-23 00:58:19 +00:00
for day in days :
try :
dt = datetime . datetime ( year = year , month = month , day = day )
except ValueError :
continue # means we have an invalid date on our hands, skip to next iteration of the loop
2017-09-20 21:40:46 +00:00
2017-10-24 02:56:33 +00:00
#weekday_distance = template.weekday - first_day_of_month.isoweekday()
2017-10-30 22:10:02 +00:00
week_valid = False
if template . weeks :
base_monday = datetime . datetime ( year = base_date . year , month = base_date . month , day = base_date . day - base_date . weekday ( ) )
current_monday = dt - datetime . timedelta ( days = dt . weekday ( ) )
delta = current_monday - base_monday
if delta . days % ( 7 * template . weeks ) == 0 :
week_valid = True
else :
week_valid = True
2017-10-26 21:59:18 +00:00
2017-10-23 00:58:19 +00:00
weekday_valid = not template . weekday or dt . isoweekday ( ) == template . weekday
2017-10-10 00:39:05 +00:00
2017-10-30 22:10:02 +00:00
if week_valid and weekday_valid :
2017-10-24 02:56:33 +00:00
#weekday_month_valid = not template.weekday_month or (day + weekday_distance) / 7.0 == template.weekday_month - 1
weekday_month_valid = not template . weekday_month or day == firstweekday ( template . weekday , first_day_of_month . isoweekday ( ) ) + ( 7 * ( template . weekday_month - 1 ) )
if weekday_month_valid :
dates [ year ] [ month ] [ day ] = collections . OrderedDict ( )
2017-09-20 21:40:46 +00:00
2017-09-17 14:34:51 +00:00
2017-09-26 01:08:51 +00:00
# add hours
2021-01-21 02:15:19 +00:00
for year , months in dates . items ( ) :
2017-09-26 01:08:51 +00:00
2021-01-21 02:15:19 +00:00
first_year = year == years [ 0 ]
last_year = year == years [ - 1 ]
2017-09-26 01:08:51 +00:00
2021-01-21 02:15:19 +00:00
for month , days in months . items ( ) :
2017-09-26 01:08:51 +00:00
first_month = first_year and month == base_date . month
last_month = last_year and month == now . month
2021-01-21 02:15:19 +00:00
for day , _ in days . items ( ) :
2017-09-26 01:08:51 +00:00
first_day = first_month and day == base_date . day
last_day = last_month and day == now . day
2017-10-23 00:58:19 +00:00
if not template . hour is None :
2017-09-26 01:08:51 +00:00
if first_day and last_day :
valid = template . hour > = base_date . hour and template . hour < = now . hour
elif first_day :
valid = template . hour > = base_date . hour
elif last_day :
valid = template . hour < = now . hour
else :
valid = True
if valid :
2017-09-26 02:24:27 +00:00
dates [ year ] [ month ] [ day ] [ template . hour ] = collections . OrderedDict ( )
2017-09-26 01:08:51 +00:00
else :
if first_day and last_day :
hours = range ( base_date . hour , now . hour + 1 )
elif first_day :
hours = range ( base_date . hour , 24 )
elif last_day :
hours = range ( 0 , now . hour + 1 )
else :
hours = range ( 0 , 24 )
for hour in hours :
dates [ year ] [ month ] [ day ] [ hour ] = collections . OrderedDict ( )
task_dates = [ ]
# add minutes
2021-01-21 02:15:19 +00:00
for year , months in dates . items ( ) :
2017-09-26 01:08:51 +00:00
2021-01-21 02:15:19 +00:00
first_year = year == years [ 0 ]
last_year = year == years [ - 1 ]
2017-09-26 01:08:51 +00:00
2021-01-21 02:15:19 +00:00
for month , days in months . items ( ) :
2017-09-26 01:08:51 +00:00
first_month = first_year and month == base_date . month
last_month = last_year and month == now . month
2021-01-21 02:15:19 +00:00
for day , hours in days . items ( ) :
2017-09-26 01:08:51 +00:00
first_day = first_month and day == base_date . day
last_day = last_month and day == now . day
2021-01-21 02:15:19 +00:00
for hour , _ in hours . items ( ) :
2017-09-26 01:08:51 +00:00
first_hour = first_day and hour == base_date . hour
last_hour = last_day and hour == now . hour
2017-10-23 00:58:19 +00:00
if not template . minute is None :
2017-09-26 01:08:51 +00:00
if first_hour and last_hour :
2017-10-23 00:58:19 +00:00
valid = template . minute > base_date . minute and template . minute < = now . minute
2017-09-26 01:08:51 +00:00
elif first_hour :
2017-10-23 00:58:19 +00:00
valid = template . minute > base_date . minute
2017-09-26 01:08:51 +00:00
elif last_hour :
valid = template . minute < = now . minute
else :
valid = True
if valid :
task_dates . append ( datetime . datetime ( year = year , month = month , day = day , hour = hour , minute = template . minute ) )
else :
if first_hour and last_hour :
for minute in range ( base_date . minute + 1 , now . minute + 1 ) :
task_dates . append ( datetime . datetime ( year = year , month = month , day = day , hour = hour , minute = minute ) )
2017-09-26 02:24:27 +00:00
elif first_hour :
for minute in range ( base_date . minute + 1 , 60 ) :
task_dates . append ( datetime . datetime ( year = year , month = month , day = day , hour = hour , minute = minute ) )
elif last_hour :
for minute in range ( 0 , now . minute + 1 ) :
task_dates . append ( datetime . datetime ( year = year , month = month , day = day , hour = hour , minute = minute ) )
else :
for minute in range ( 0 , 60 ) :
task_dates . append ( datetime . datetime ( year = year , month = month , day = day , hour = hour , minute = minute ) )
2017-09-26 01:08:51 +00:00
click . echo ( " Creating %d tasks for ' %s ' . " % ( len ( task_dates ) , template . title ) )
with click . progressbar ( task_dates ) as proxy :
for date in proxy :
task = Task ( )
2017-09-26 02:24:27 +00:00
task . name = " %s - %d - %d - %d - %d - %d " % ( template . name , date . year , date . month , date . day , date . hour , date . minute )
task . owner = template . owner
task . group = template . group
2017-10-23 00:58:19 +00:00
task . status = ' new '
2017-09-26 01:08:51 +00:00
task . title = template . title
2018-04-19 20:56:53 +00:00
task . date = date
2017-09-26 02:24:27 +00:00
if template . checkdate :
task . checkdate = date + datetime . timedelta ( seconds = template . checkdate )
2017-09-26 01:08:51 +00:00
task . priority = template . priority
task . description = template . description
task . save ( force_insert = True )
2017-09-17 14:34:51 +00:00
2021-07-07 12:46:27 +00:00
for tag in template . tags :
binding = poobrains . tagging . TagBinding ( )
binding . priority = 42
binding . tag = tag
binding . model = Task . __name__
binding . handle = task . handle_string
binding . save ( )
2017-09-26 02:24:27 +00:00
if len ( task_dates ) :
template . latest_task = task
template . save ( )
2017-09-17 14:34:51 +00:00
if __name__ == ' __main__ ' :
app . cli ( )