1- from datetime import datetime
1+ import calendar
2+ from datetime import datetime , timedelta
23import math
34from flask import Flask , render_template , request , redirect , url_for
45from flask_sqlalchemy import SQLAlchemy
@@ -42,13 +43,24 @@ class Task(db.Model):
4243 id = db .Column (db .Integer , primary_key = True ,
4344 unique = True , nullable = False ) # task id
4445 name = db .Column (db .String (80 ), nullable = False ) # task name
46+ original_due_date = db .Column (
47+ db .Date , default = datetime .now ().date (), nullable = False
48+ ) # task due date
4549 due_date = db .Column (
4650 db .Date , default = datetime .now ().date (), nullable = False
4751 ) # task due date
4852 priority = db .Column (db .Integer , default = 1 ,
4953 nullable = False ) # task priority
5054 difficulty = db .Column (db .Integer , default = 1 ,
5155 nullable = False ) # task difficulty
56+ repeat_interval = db .Column (
57+ db .Integer , default = 1 , nullable = False
58+ ) # task repeat interval
59+ repeat_often = db .Column (db .Integer , default = 5 ,
60+ nullable = False ) # task repeat often
61+ times_completed = db .Column (
62+ db .Integer , default = 0 , nullable = False
63+ ) # number if times task has completed
5264 completed = db .Column (
5365 db .Boolean , default = False , nullable = False
5466 ) # is task completed
@@ -123,15 +135,23 @@ def add_task(): # add task to task list
123135 due_date = request .form .get ("due_date" ) # get due date
124136 priority = int (request .form .get ("priority" )) # get priority
125137 difficulty = int (request .form .get ("difficulty" )) # get difficulty
138+ repeat_interval = int (
139+ request .form .get ("repeat_interval" )
140+ ) # get task repeat interval
141+ repeat_often = int (request .form .get ("repeat_often" )
142+ ) # get task repeat often
126143 user = User .query .first () # get first user
127144 if user :
128145 new_task = Task (
129146 name = name ,
130147 user_id = user .id ,
131148 priority = priority ,
132149 difficulty = difficulty ,
150+ repeat_interval = repeat_interval ,
151+ repeat_often = repeat_often ,
152+ original_due_date = datetime .strptime (due_date , "%Y-%m-%d" ),
133153 due_date = datetime .strptime (due_date , "%Y-%m-%d" ),
134- )
154+ ) # create new task with input parameters
135155 db .session .add (new_task ) # add new task to task list
136156 db .session .commit () # commit database changes
137157 return redirect (url_for ("index" )) # redirect to index page template
@@ -141,7 +161,15 @@ def add_task(): # add task to task list
141161def complete_task (task_id ): # complete task from task id
142162 task = Task .query .get (task_id ) # get task by task id
143163 if task :
144- task .completed = True # complete the task
164+ if task .repeat_often == 5 : # if task is one-time task
165+ task .completed = True # complete the task
166+ task .times_completed += 1 # increase times task completed by 1
167+ task .due_date = calculate_next_recurring_event (
168+ task .original_due_date ,
169+ task .times_completed ,
170+ task .repeat_interval ,
171+ task .repeat_often ,
172+ ) # calculate next task due date
145173 user = User .query .first () # get first user
146174 if user :
147175 user .add_xp (round (task .priority * task .difficulty )) # add XP
@@ -158,21 +186,82 @@ def delete_task(task_id): # delete task from task id
158186 return redirect (url_for ("index" )) # redirect to index page template
159187
160188
189+ def calculate_next_recurring_event (
190+ original_date , times_completed , repeat_interval , repeat_often
191+ ): # calculate next recurring event date
192+ if repeat_often == 1 : # if task repeat often is daily
193+ return original_date + timedelta (
194+ days = repeat_interval * times_completed
195+ ) # add days to original date
196+ elif repeat_often == 2 : # if task repeat often is weekly
197+ return original_date + timedelta (
198+ weeks = repeat_interval * times_completed
199+ ) # add weeks to original date
200+ elif repeat_often == 3 : # if task repeat often is monthly
201+ new_month = (
202+ original_date .month + repeat_interval * times_completed
203+ ) # get new month
204+ new_year = original_date .year + (new_month - 1 ) // 12 # get new year
205+ new_month = (
206+ new_month - 1
207+ ) % 12 # clamp month from 1 (January) to 12 (December)
208+ max_days_in_month = calendar .monthrange (new_year , new_month )[
209+ 1
210+ ] # get number of days in month
211+ return datetime (
212+ new_year , new_month , min (original_date .day , max_days_in_month )
213+ ) # add months to original date
214+ elif repeat_often == 4 : # if task repeat often is yearly
215+ new_year = original_date .year + repeat_interval * times_completed
216+ max_days_in_month = calendar .monthrange (new_year , original_date .month )[
217+ 1
218+ ] # get number of days in month
219+ return datetime (
220+ new_year , original_date .month , min (
221+ original_date .day , max_days_in_month )
222+ ) # add years in original date
223+ else :
224+ return None
225+
226+
161227def init_db (): # initialize database
162228 with app .app_context ():
163229 db .create_all () # create tables if they don't exist
230+ today = datetime .now ().strftime (
231+ "%Y-%m-%d"
232+ ) # get today's date in YYYY-MM-DD format
164233 if User .query .count () == 0 : # if there is no users
165234 new_user = User (username = "Player" ) # create new user
166235 db .session .add (new_user ) # add new user to database
167236 db .session .commit () # commit database changes
237+ if "original_due_date" not in [
238+ column ["name" ] for column in db .inspect (db .engine ).get_columns ("task" )
239+ ]: # check if original due date column is not in task table
240+ db .session .execute (
241+ text ("ALTER TABLE task ADD COLUMN original_due_date DATE" )
242+ ) # create original due date column
243+ db .session .execute (
244+ text ("UPDATE task SET original_due_date = ?" ), (today )
245+ ) # update existing rows
246+ db .session .commit () # commit database changes
247+ db .session .execute (
248+ text ("ALTER TABLE task ALTER COLUMN original_due_date SET NOT NULL" )
249+ ) # set column to not null
250+ db .session .commit () # commit database changes
168251 if "due_date" not in [
169252 column ["name" ] for column in db .inspect (db .engine ).get_columns ("task" )
170253 ]: # check if due date column is not in task table
171254 db .session .execute (
172- text (
173- "ALTER TABLE task ADD COLUMN due_date DATE NOT NULL DEFAULT CURRENT_TIMESTAMP"
174- )
255+ text ("ALTER TABLE task ADD COLUMN due_date DATE" )
175256 ) # create due date column
257+ db .session .execute (
258+ text ("UPDATE task SET due_date = ?" ), (today )
259+ ) # update existing rows
260+ db .session .commit () # commit database changes
261+ db .session .execute (
262+ text ("ALTER TABLE task ALTER COLUMN due_date SET NOT NULL" )
263+ ) # set column to not null
264+ db .session .commit () # commit database changes
176265 if "priority" not in [
177266 column ["name" ] for column in db .inspect (db .engine ).get_columns ("task" )
178267 ]: # check if priority column is not in task table
@@ -185,8 +274,36 @@ def init_db(): # initialize database
185274 db .session .execute (
186275 text ("ALTER TABLE task ADD COLUMN difficulty INT NOT NULL DEFAULT 1" )
187276 ) # create difficulty column
277+ if "repeat_interval" not in [
278+ column ["name" ] for column in db .inspect (db .engine ).get_columns ("task" )
279+ ]: # check if repeat interval column is not in task table
280+ db .session .execute (
281+ text (
282+ "ALTER TABLE task ADD COLUMN repeat_interval INT NOT NULL DEFAULT 1"
283+ )
284+ ) # create repeat interval column
285+ if "repeat_often" not in [
286+ column ["name" ] for column in db .inspect (db .engine ).get_columns ("task" )
287+ ]: # check if repeat often column is not in task table
288+ db .session .execute (
289+ text ("ALTER TABLE task ADD COLUMN repeat_often INT NOT NULL DEFAULT 5" )
290+ ) # create repeat often column
291+ if "times_completed" not in [
292+ column ["name" ] for column in db .inspect (db .engine ).get_columns ("task" )
293+ ]: # check if times completed column is not in task table
294+ db .session .execute (
295+ text (
296+ "ALTER TABLE task ADD COLUMN times_completed INT NOT NULL DEFAULT 0"
297+ )
298+ ) # create times completed column
188299 tasks = Task .query .all () # get list of tasks
189300 for task in tasks : # repeat for each task
301+ if (
302+ task .original_due_date is None
303+ ): # check if task original due date is none
304+ task .original_due_date = (
305+ datetime .now ().date ()
306+ ) # set task original due date to today's date
190307 if task .due_date is None : # check if task due date is none
191308 task .due_date = (
192309 datetime .now ().date ()
@@ -195,6 +312,10 @@ def init_db(): # initialize database
195312 task .priority = 1 # set task priority to low
196313 if task .difficulty is None : # check if task difficulty is none
197314 task .difficulty = 1 # set task difficulty to low
315+ if task .repeat_interval is None : # check if repeat interval is none
316+ task .repeat_interval = 1 # set repeat interval to 1
317+ if task .repeat_often is None : # check if repeat often is none
318+ task .repeat_often = 1 # set repeat often to once
198319 db .session .commit () # commit database changes
199320
200321
0 commit comments