def test_non_existing_individual_task_retrieval( calendar_data: CalendarData) -> None: with pytest.raises(ValueError): calendar_data.task_from_calendar(calendar_id="sample_data_file", year=2017, month=11, day=6, task_id=0)
def test_tasks_can_be_filtered_after_retrieval( calendar_data: CalendarData, past_normal_tasks_data: Dict) -> None: year = 2001 tasks = calendar_data.tasks_from_calendar(year, 1, past_normal_tasks_data) assert len(tasks["1"]) > 0 # if we switch to next month, month 1 should become empty calendar_data.hide_past_tasks(year, 2, tasks) assert len(tasks["1"]) == 0
def edit_task_action(calendar_id: str, year: int, month: int, day: int, task_id: int) -> Response: month_names = GregorianCalendar.MONTH_NAMES calendar_data = CalendarData(current_app.config["DATA_FOLDER"], current_app.config["WEEK_STARTING_DAY"]) repeats = request.args.get("repeats") == "1" try: if repeats: task = calendar_data.repetitive_task_from_calendar( calendar_id=calendar_id, year=year, month=month, task_id=int(task_id)) else: task = calendar_data.task_from_calendar( calendar_id=calendar_id, year=year, month=month, day=day, task_id=int(task_id), ) except (FileNotFoundError, IndexError): abort(404) if task["details"] == " ": task["details"] = "" emojis_enabled = current_app.config.get("EMOJIS_ENABLED", False) return cast( Response, render_template( "task.html", calendar_id=calendar_id, year=year, month=month, day=day, min_year=current_app.config["MIN_YEAR"], max_year=current_app.config["MAX_YEAR"], month_names=month_names, task=task, base_url=current_app.config["BASE_URL"], editing=True, emojis_enabled=emojis_enabled, button_default_color_value=current_app. config["BUTTON_CUSTOM_COLOR_VALUE"], buttons_colors=current_app.config["BUTTONS_COLORS_LIST"], buttons_emojis=current_app.config["BUTTONS_EMOJIS_LIST"] if emojis_enabled else tuple(), ), )
def delete_task_action(calendar_id: str, year: str, month: str, day: str, task_id: str) -> Response: calendar_data = CalendarData(current_app.config["DATA_FOLDER"], current_app.config["WEEK_STARTING_DAY"]) calendar_data.delete_task( calendar_id=calendar_id, year_str=year, month_str=month, day_str=day, task_id=int(task_id), ) return cast(Response, jsonify({}))
def hide_repetition_task_instance_action(calendar_id: str, year: str, month: str, day: str, task_id: str) -> Response: calendar_data = CalendarData(current_app.config["DATA_FOLDER"], current_app.config["WEEK_STARTING_DAY"]) calendar_data.hide_repetition_task_instance( calendar_id=calendar_id, year_str=year, month_str=month, day_str=day, task_id_str=task_id, ) return cast(Response, jsonify({}))
def save_task_action(calendar_id: str) -> Response: title = request.form["title"].strip() date = request.form.get("date", "") if len(date) > 0: date_fragments = re.split("-", date) year = int(date_fragments[0]) # type: Optional[int] month = int(date_fragments[1]) # type: Optional[int] day = int(date_fragments[2]) # type: Optional[int] else: year = month = day = None is_all_day = request.form.get("is_all_day", "0") == "1" start_time = request.form["start_time"] end_time = request.form.get("end_time", None) details = request.form["details"].replace("\r", "").replace("\n", "<br>") color = request.form["color"] has_repetition = request.form.get("repeats", "0") == "1" repetition_type = request.form.get("repetition_type") repetition_subtype = request.form.get("repetition_subtype") repetition_value = int(request.form["repetition_value"]) calendar_data = CalendarData(current_app.config["DATA_FOLDER"], current_app.config["WEEK_STARTING_DAY"]) calendar_data.create_task( calendar_id=calendar_id, year=year, month=month, day=day, title=title, is_all_day=is_all_day, start_time=start_time, end_time=end_time, details=details, color=color, has_repetition=has_repetition, repetition_type=repetition_type, repetition_subtype=repetition_subtype, repetition_value=repetition_value, ) if year is None: return redirect("{}/{}/".format(current_app.config["BASE_URL"], calendar_id), code=302) else: return redirect( "{}/{}/?y={}&m={}".format(current_app.config["BASE_URL"], calendar_id, year, month), code=302, )
def update_task_day_action(calendar_id: str, year: str, month: str, day: str, task_id: str) -> Response: new_day = request.data.decode("utf-8") calendar_data = CalendarData(current_app.config["DATA_FOLDER"], current_app.config["WEEK_STARTING_DAY"]) calendar_data.update_task_day( calendar_id=calendar_id, year_str=year, month_str=month, day_str=day, task_id=int(task_id), new_day_str=new_day, ) return cast(Response, jsonify({}))
def test_hidden_montly_weekday_repetitions_dont_appear( calendar_data: CalendarData, ) -> None: year = 2017 month = 12 data = calendar_data.load_calendar( "repetitive_monthly_weekday_hidden_task_data_file") tasks = calendar_data.tasks_from_calendar(year=year, month=month, data=data) tasks = calendar_data.add_repetitive_tasks_from_calendar(year=year, month=month, data=data, tasks=tasks) assert str(month) not in tasks
def test_existing_repetitive_task_retrieval( calendar_data: CalendarData) -> None: task_id = 2 task = calendar_data.repetitive_task_from_calendar( calendar_id="sample_data_file", year=2017, month=11, task_id=task_id) assert task is not None assert task["id"] == task_id assert task["is_all_day"] is True
def main_calendar_action(calendar_id: str) -> Response: GregorianCalendar.setfirstweekday(current_app.config["WEEK_STARTING_DAY"]) current_day, current_month, current_year = GregorianCalendar.current_date() year = int(request.args.get("y", current_year)) year = max(min(year, current_app.config["MAX_YEAR"]), current_app.config["MIN_YEAR"]) month = int(request.args.get("m", current_month)) month = max(min(month, 12), 1) month_name = GregorianCalendar.MONTH_NAMES[month - 1] if current_app.config["HIDE_PAST_TASKS"]: view_past_tasks = False else: view_past_tasks = request.cookies.get("ViewPastTasks", "1") == "1" calendar_data = CalendarData(current_app.config["DATA_FOLDER"], current_app.config["WEEK_STARTING_DAY"]) try: data = calendar_data.load_calendar(calendar_id) except FileNotFoundError: abort(404) tasks = calendar_data.tasks_from_calendar(year, month, data) tasks = calendar_data.add_repetitive_tasks_from_calendar( year, month, data, tasks) if not view_past_tasks: calendar_data.hide_past_tasks(year, month, tasks) if current_app.config[ "WEEK_STARTING_DAY"] == constants.WEEK_START_DAY_MONDAY: weekdays_headers = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"] else: weekdays_headers = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"] return cast( Response, render_template( "calendar.html", calendar_id=calendar_id, year=year, month=month, month_name=month_name, current_year=current_year, current_month=current_month, current_day=current_day, month_days=GregorianCalendar.month_days(year, month), previous_month_link=previous_month_link(year, month), next_month_link=next_month_link(year, month), base_url=current_app.config["BASE_URL"], tasks=tasks, display_view_past_button=current_app. config["SHOW_VIEW_PAST_BUTTON"], weekdays_headers=weekdays_headers, ), )
def wrapper(*args: Any, **kwargs: Any) -> Any: username = get_session_username(str(request.cookies.get(SESSION_ID))) authorization = Authorization(calendar_data=CalendarData( data_folder=current_app.config["DATA_FOLDER"])) if "calendar_id" not in kwargs: raise ValueError("calendar_id") calendar_id = str(kwargs["calendar_id"]) if not authorization.can_access(username=username, calendar_id=calendar_id): abort(403) return decorated_function(*args, **kwargs)
def test_existing_individual_task_retrieval( calendar_data: CalendarData) -> None: task_id = 4 task = calendar_data.task_from_calendar(calendar_id="sample_data_file", year=2017, month=11, day=6, task_id=task_id) assert task is not None assert task["id"] == task_id assert task["is_all_day"] is True
def test_creates_task_with_start_and_end_dates( save_calendar_mock: MagicMock, calendar_data: CalendarData) -> None: year = 2017 month = 12 day = 10 title = "an irrelevant title" is_all_day = False start_time = "12:00" end_time = "13:00" details = "" color = "an_irrelevant_color" has_repetition = False repetition_type = "" repetition_subtype = "" repetition_value = 0 calendar_id = "sample_empty_data_file" result = calendar_data.create_task( calendar_id=calendar_id, year=year, month=month, day=day, title=title, is_all_day=is_all_day, start_time=start_time, end_time=end_time, details=details, color=color, has_repetition=has_repetition, repetition_type=repetition_type, repetition_subtype=repetition_subtype, repetition_value=repetition_value, ) assert result is True save_calendar_mock.assert_called_once_with(ANY, filename=calendar_id) call_args, _ = save_calendar_mock.call_args data = call_args[0] assert "tasks" in data assert "normal" in data["tasks"] assert str(year) in data["tasks"]["normal"] assert str(month) in data["tasks"]["normal"][str(year)] assert str(day) in data["tasks"]["normal"][str(year)][str(month)] assert len(data["tasks"]["normal"][str(year)][str(month)][str(day)]) == 1 task_data = data["tasks"]["normal"][str(year)][str(month)][str(day)][0] assert "title" in task_data assert task_data["title"] == title assert task_data["is_all_day"] is False assert task_data["start_time"] == start_time assert task_data["end_time"] == end_time
def test_loads_normal_tasks_from_calendar_given_data( calendar_data: CalendarData, sample_data_file_data: Dict) -> None: year = 2017 month = 12 month_str = str(month) tasks = calendar_data.tasks_from_calendar(year, month, sample_data_file_data) assert len(tasks[month_str]) == 1 assert len(tasks[month_str]["25"]) == 2 assert tasks[month_str]["25"][0]["id"] in [0, 1] assert tasks[month_str]["25"][1]["id"] in [0, 1] assert tasks[month_str]["25"][0]["id"] != tasks[month_str]["25"][1]["id"]
def test_joins_repetitive_tasks_with_normal_ones( calendar_data: CalendarData, sample_data_file_data: Dict) -> None: year = 2017 month = 11 month_str = str(month) tasks = calendar_data.tasks_from_calendar(year, month, sample_data_file_data) assert len(tasks[month_str]) == 1 tasks = calendar_data.add_repetitive_tasks_from_calendar( year, month, sample_data_file_data, tasks) assert len(tasks[month_str]) > 0 # month has 4 mondays repetitive_weekly_weekday_task_ocurrences = 4 # month has 5 thursdays repetitive_weekly_weekday_3_task_ocurrences = 5 repetitive_monthly_weekday_task_ocurrences = 1 repetitive_monthly_monthday_task_ocurrences = 1 # We're counting the number of days with tasks, not the exact number of tasks (day 6 has 2 tasks) assert len( tasks[month_str]) == (repetitive_weekly_weekday_task_ocurrences + repetitive_monthly_weekday_task_ocurrences + repetitive_monthly_monthday_task_ocurrences + repetitive_weekly_weekday_3_task_ocurrences) assert len(tasks[month_str]["6"]) == 2 # Normal task should be first (as repetitive ones are appended afterwards) assert tasks[month_str]["6"][0]["id"] == 4 assert "repetition_value" not in tasks[month_str]["6"][0] assert "repetition_value" in tasks[month_str]["6"][1] assert tasks[month_str]["6"][1]["repetition_value"] == 0 assert tasks[month_str]["6"][1][ "repetition_subtype"] == CalendarData.REPETITION_SUBTYPE_WEEK_DAY assert tasks[month_str]["6"][1][ "repetition_type"] == CalendarData.REPETITION_TYPE_WEEKLY
def new_task_action(calendar_id: str, year: int, month: int) -> Response: GregorianCalendar.setfirstweekday(current_app.config["WEEK_STARTING_DAY"]) current_day, current_month, current_year = GregorianCalendar.current_date() year = max(min(int(year), current_app.config["MAX_YEAR"]), current_app.config["MIN_YEAR"]) month = max(min(int(month), 12), 1) month_names = GregorianCalendar.MONTH_NAMES if current_month == month and current_year == year: day = current_day else: day = 1 day = int(request.args.get("day", day)) task = { "date": CalendarData.date_for_frontend(year, month, day), "is_all_day": True, "repeats": False, "details": "", } emojis_enabled = current_app.config.get("EMOJIS_ENABLED", False) return cast( Response, render_template( "task.html", calendar_id=calendar_id, year=year, month=month, min_year=current_app.config["MIN_YEAR"], max_year=current_app.config["MAX_YEAR"], month_names=month_names, task=task, base_url=current_app.config["BASE_URL"], editing=False, emojis_enabled=emojis_enabled, button_default_color_value=current_app. config["BUTTON_CUSTOM_COLOR_VALUE"], buttons_colors=current_app.config["BUTTONS_COLORS_LIST"], buttons_emojis=current_app.config["BUTTONS_EMOJIS_LIST"] if emojis_enabled else tuple(), ), )
def calendar_data() -> CalendarData: return CalendarData("test/fixtures")
def test_non_existing_repetitive_task_retrieval( calendar_data: CalendarData) -> None: with pytest.raises(IndexError): calendar_data.repetitive_task_from_calendar( calendar_id="sample_data_file", year=2017, month=11, task_id=111)
def test_error_retrieving_tasks_from_calendar( year: int, month: int, data: Dict, calendar_data: CalendarData) -> None: with pytest.raises(ValueError): calendar_data.tasks_from_calendar(year, month, data)
def past_normal_tasks_data(calendar_data: CalendarData) -> Dict: return calendar_data.load_calendar(filename="past_normal_tasks")
def update_task_action(calendar_id: str, year: str, month: str, day: str, task_id: str) -> Response: # Logic is same as save + delete, could refactor but can wait until need to change any save/delete logic calendar_data = CalendarData(current_app.config["DATA_FOLDER"], current_app.config["WEEK_STARTING_DAY"]) # For creation of "updated" task use only form data title = request.form["title"].strip() date = request.form.get("date", "") if len(date) > 0: fragments = re.split("-", date) updated_year = int(fragments[0]) # type: Optional[int] updated_month = int(fragments[1]) # type: Optional[int] updated_day = int(fragments[2]) # type: Optional[int] else: updated_year = updated_month = updated_day = None is_all_day = request.form.get("is_all_day", "0") == "1" start_time = request.form["start_time"] end_time = request.form.get("end_time", None) details = request.form["details"].replace("\r", "").replace("\n", "<br>") color = request.form["color"] has_repetition = request.form.get("repeats", "0") == "1" repetition_type = request.form.get("repetition_type", "") repetition_subtype = request.form.get("repetition_subtype", "") repetition_value = int(request.form["repetition_value"]) # type: int calendar_data.create_task( calendar_id=calendar_id, year=updated_year, month=updated_month, day=updated_day, title=title, is_all_day=is_all_day, start_time=start_time, end_time=end_time, details=details, color=color, has_repetition=has_repetition, repetition_type=repetition_type, repetition_subtype=repetition_subtype, repetition_value=repetition_value, ) # For deletion of old task data use only url data calendar_data.delete_task( calendar_id=calendar_id, year_str=year, month_str=month, day_str=day, task_id=int(task_id), ) if updated_year is None: return redirect("{}/{}/".format(current_app.config["BASE_URL"], calendar_id), code=302) else: return redirect( "{}/{}/?y={}&m={}".format(current_app.config["BASE_URL"], calendar_id, updated_year, updated_month), code=302, )
def authorization() -> Authorization: return Authorization(calendar_data=CalendarData("test/fixtures"))
def sample_data_file_data(calendar_data: CalendarData) -> Dict: return calendar_data.load_calendar(filename="sample_data_file")