Skip to content

Commit 4fda8cc

Browse files
committed
Add task repetition with repeat interval and repeat frequency
1 parent 9c1f24f commit 4fda8cc

File tree

2 files changed

+145
-6
lines changed

2 files changed

+145
-6
lines changed

app.py

Lines changed: 127 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from datetime import datetime
1+
import calendar
2+
from datetime import datetime, timedelta
23
import math
34
from flask import Flask, render_template, request, redirect, url_for
45
from 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
141161
def 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+
161227
def 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

templates/index.html

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,22 @@ <h1>Endless Task List App using Flask</h1>
5454
<option value="2">Medium</option>
5555
<option value="3">Hard</option></select
5656
><br />
57+
Repeat every:
58+
<input
59+
type="number"
60+
id="repeat_interval"
61+
name="repeat_interval"
62+
min="1"
63+
step="1"
64+
/><br />
65+
Repeat interval:
66+
<select id="repeat_often" name="repeat_often">
67+
<option value="1">Daily</option>
68+
<option value="2">Weekly</option>
69+
<option value="3">Monthly</option>
70+
<option value="4">Yearly</option>
71+
<option value="5" selected>Once</option>
72+
</select>
5773
<input type="submit" value="Add Task" />
5874
</form>
5975
<ul>
@@ -66,6 +82,8 @@ <h1>Endless Task List App using Flask</h1>
6682
Medium {% elif task.priority == 3 %} High {% endif %}<br />
6783
Difficulty: {% if task.difficulty == 1 %} Easy {% elif task.difficulty
6884
== 2 %} Medium {% elif task.difficulty == 3 %} Hard {% endif %}<br />
85+
Repeat: {% if task.difficulty == 3 %} Month {% elif task.difficulty == 4
86+
%} Year {% elif task.difficulty == 5 %} Once {% endif %}<br />
6987
{% if not task.completed %}<!--show complete button if task is not completed-->
7088
<a href="/complete_task/{{ task.id }}">Complete</a>
7189
{% endif %}

0 commit comments

Comments
 (0)