diff options
author | Changjin Lee <changjin9792@gmail.com> | 2023-03-23 23:41:05 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-23 23:41:05 +0800 |
commit | 115f80652be90f1cce69bc3fb592e64ee26a85d6 (patch) | |
tree | 49aaefddd943f01ba1d596cf20768c968998acea | |
parent | 2e3d7e0c3ea5f790eec14d111538e244e779cf91 (diff) | |
parent | 2de7dd9c1eee94dcb58fa4bbf91e2b7576bf9f31 (diff) |
Merge pull request #5 from noisrucer/developmain
Girok v0.1.2 release
49 files changed, 4775 insertions, 1 deletions
diff --git a/.github/.gitmessage.txt b/.github/.gitmessage.txt new file mode 100755 index 0000000..9b99323 --- /dev/null +++ b/.github/.gitmessage.txt @@ -0,0 +1,23 @@ +################ +# Format: [Type] <Title> +# Within 50 characters / Clearly indicate the changes / No period at the end +# ex) [Feat] Add R-CNN Model +# Write below + +# Do not delete the line below + +################ +# Write detailed description below +# Use "-" for multiple lines (72 characters per line) + +################ +# Write footer below (issue number related to the current commit) +# ex) issue #7 + +################ +# Feat : New Feature +# Fix : Bug Fix +# Docs : Modify docs +# Refact : Refactoring +# Style : Changes that do not affect code logic +################ diff --git a/.github/.pre-commit-config.yaml b/.github/.pre-commit-config.yaml new file mode 100755 index 0000000..dcdb3d5 --- /dev/null +++ b/.github/.pre-commit-config.yaml @@ -0,0 +1,18 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: check-yaml + - id: check-json +- repo: https://github.com/psf/black + rev: stable + hooks: + - id: black + language_version: python3.8 +- repo: https://gitlab.com/pycqa/flake8 + rev: 4.0.1 + hooks: + - id: flake8
\ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/README.md b/.github/ISSUE_TEMPLATE/README.md new file mode 100755 index 0000000..5cb1e9d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/README.md @@ -0,0 +1,18 @@ +## Template Description + + 1. Bug Report (BUG) + * To fix bugs during development + + 2. Feature Request (Feat) + * Request new features + + 3. Extra (EXT) + * Extra + +## Rules + + 1. Common + * Title + * ex) [Feat] Develop user registration APIs + * Label + * Choose label according to the template diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100755 index 0000000..5cde92e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,15 @@ +--- +name: Bug Report +about: Bug Report Template +title: "" +labels: "" +assignees: "" +--- + +## Bug Description + +## Bug Simulation + +## Error Message + +## Screenshots diff --git a/.github/ISSUE_TEMPLATE/docs.md b/.github/ISSUE_TEMPLATE/docs.md new file mode 100644 index 0000000..8801215 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/docs.md @@ -0,0 +1,9 @@ +--- +name: Docs +about: Documentation +title: "" +labels: "" +assignees: "" +--- + +## Description diff --git a/.github/ISSUE_TEMPLATE/extra.md b/.github/ISSUE_TEMPLATE/extra.md new file mode 100755 index 0000000..3ee87a4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/extra.md @@ -0,0 +1,11 @@ +--- +name: Extra +about: Extra +title: "" +labels: "" +assignees: "" +--- + +## Description + +## Comments diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100755 index 0000000..8dbadab --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,13 @@ +--- +name: Feature Request +about: Template for requesting new features +title: "" +labels: "" +assignees: "" +--- + +## Description + +## Purpose + +## Comments diff --git a/.github/ISSUE_TEMPLATE/refactor.md b/.github/ISSUE_TEMPLATE/refactor.md new file mode 100644 index 0000000..4805248 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/refactor.md @@ -0,0 +1,9 @@ +--- +name: Refactor +about: Refactor +title: "" +labels: "" +assignees: "" +--- + +## Description diff --git a/.github/commit_template_manual.md b/.github/commit_template_manual.md new file mode 100755 index 0000000..15f89fe --- /dev/null +++ b/.github/commit_template_manual.md @@ -0,0 +1,27 @@ +# Apply Commit Template Message + +Do `git clone` and you will see .gitmessage.txt + +๊ทธ ํ,<br> +Do `git config --local commit.template .github/.gitmessage.txt`<br> +to set the commit template. + +Now,<br> +Do `git commit` when you commit instead of `git commit -m "message"`<br> + +After completing your commit, just close the commit file or<br> + +**โ For Linux bash or VSCode,** + +Type `Ctrl + x`<br> +then you'll see save message, and type `y` to save it. + +If you type Enter, then commit is complete! + +**โ For git bash** + +Just do `:wq` + +<br> + +Then `git push` diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100755 index 0000000..ce3733e --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,29 @@ +## PR Description + +- + +<br> + +## Image (Optional) + +- + +<br> + +## Key Changes + +- + +<br> + +## Related Issue + +- + +<br> + +## To Reviewers + +- + +<br> diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f1190bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. +.env +**/__pycache__ +**/__pycache__/** +# dependencies +/node_modules/ +**/node_modules/ +/.pnp +.pnp.js + +**/__pycache__ +**/.env +/venv/ +**/venv/ +.idea/ +venv/ +.backend_venv/ +.cli_venv/ +.venv/ +**/.venv/ +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* @@ -1 +0,0 @@ -# girok-cli
\ No newline at end of file diff --git a/dist/girok-0.1.0-py3-none-any.whl b/dist/girok-0.1.0-py3-none-any.whl Binary files differnew file mode 100644 index 0000000..fb2c24f --- /dev/null +++ b/dist/girok-0.1.0-py3-none-any.whl diff --git a/dist/girok-0.1.0.tar.gz b/dist/girok-0.1.0.tar.gz Binary files differnew file mode 100644 index 0000000..0851a9d --- /dev/null +++ b/dist/girok-0.1.0.tar.gz diff --git a/dist/girok-0.1.1-py3-none-any.whl b/dist/girok-0.1.1-py3-none-any.whl Binary files differnew file mode 100644 index 0000000..52d4501 --- /dev/null +++ b/dist/girok-0.1.1-py3-none-any.whl diff --git a/dist/girok-0.1.1.tar.gz b/dist/girok-0.1.1.tar.gz Binary files differnew file mode 100644 index 0000000..2ea2e29 --- /dev/null +++ b/dist/girok-0.1.1.tar.gz diff --git a/dist/girok-0.1.2-py3-none-any.whl b/dist/girok-0.1.2-py3-none-any.whl Binary files differnew file mode 100644 index 0000000..43623d5 --- /dev/null +++ b/dist/girok-0.1.2-py3-none-any.whl diff --git a/dist/girok-0.1.2.tar.gz b/dist/girok-0.1.2.tar.gz Binary files differnew file mode 100644 index 0000000..fdebf13 --- /dev/null +++ b/dist/girok-0.1.2.tar.gz diff --git a/girok/__init__.py b/girok/__init__.py new file mode 100644 index 0000000..48fef32 --- /dev/null +++ b/girok/__init__.py @@ -0,0 +1 @@ +__version__ = "0.1.2"
\ No newline at end of file diff --git a/girok/__main__.py b/girok/__main__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/girok/__main__.py diff --git a/girok/api/auth.py b/girok/api/auth.py new file mode 100644 index 0000000..6d71a38 --- /dev/null +++ b/girok/api/auth.py @@ -0,0 +1,34 @@ +import requests +from girok.config import get_config +cfg = get_config() + +base_url = cfg.base_url + +def register(email, password): + resp = requests.post(base_url + "/register", json={ + "email": email, + "password": password + }) + return resp + + +def login(email, password): + files = { + "username": (None, email), + "password": (None, password) + } + + resp = requests.post(base_url + "/login", files=files) + return resp + + +def validate_access_token(access_token): + options = { + "headers": { + "Authorization": "Bearer " + access_token, + } + } + + + resp = requests.get(base_url + "/validate-access-token", headers=options['headers']) + return resp
\ No newline at end of file diff --git a/girok/api/category.py b/girok/api/category.py new file mode 100644 index 0000000..f01d274 --- /dev/null +++ b/girok/api/category.py @@ -0,0 +1,131 @@ +import requests +from rich.console import Console + +from girok.config import get_config +import girok.utils.auth as auth_utils +import girok.utils.general as general_utils +import girok.utils.display as display_utils +import girok.constants as constants + +console = Console() +cfg = get_config() + +def get_categories(): + resp = requests.get( + cfg.base_url + "/categories", + headers=auth_utils.build_jwt_header(cfg.config_path) + ) + if resp.status_code == 200: + return general_utils.bytes2dict(resp.content) + + + +def add_category(cat_str: str, color=None): + cats = cat_str.split('/') + resp = requests.post( + cfg.base_url + "/categories", + json={ + "names": cats, + "color": color + }, + headers=auth_utils.build_jwt_header(cfg.config_path) + ) + return resp + + +def remove_category(cat_str: str): + cats = cat_str.split('/') + resp = requests.delete( + cfg.base_url + "/categories", + json={ + "cats": cats + }, + headers=auth_utils.build_jwt_header(cfg.config_path) + ) + + return resp + + +def rename_category(cat_str: str, new_name: str): + cats = cat_str.split('/') + resp = requests.patch( + cfg.base_url + "/categories/name", + json={ + "cats": cats, + "new_name": new_name + }, + headers=auth_utils.build_jwt_header(cfg.config_path) + ) + + return resp + + +def move_category(cat_str: str, new_parent_cat_str: str): + if cat_str.endswith('/'): + cat_str = cat_str[:-1] + if new_parent_cat_str.endswith('/'): + new_parent_cat_str = new_parent_cat_str[:-1] + + cats = cat_str.split('/') if cat_str else [] + new_parent_cats = new_parent_cat_str.split('/') if new_parent_cat_str else [] + resp = requests.patch( + cfg.base_url + "/categories/parent", + json={ + "cats": cats, + "new_parent_cats": new_parent_cats + }, + headers=auth_utils.build_jwt_header(cfg.config_path) + ) + return resp + + +def get_last_cat_id(cats: list): + resp = requests.get( + cfg.base_url + "/categories/last-cat-id", + json={ + "cats": cats + }, + headers=auth_utils.build_jwt_header(cfg.config_path) + ) + if resp.status_code == 200: + return general_utils.bytes2dict(resp.content)['cat_id'] + elif resp.status_code == 400: + err_msg = general_utils.bytes2dict(resp.content)['detail'] + display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR) + exit(0) + else: + display_utils.center_print(resp.content, constants.DISPLAY_TERMINAL_COLOR_ERROR) + exit(0) + + +def get_category_color(cat_id: int): + resp = requests.get( + cfg.base_url + f"/categories/{cat_id}/color", + headers=auth_utils.build_jwt_header(cfg.config_path) + ) + + if resp.status_code == 200: + return general_utils.bytes2dict(resp.content)['color'] + elif resp.status_code == 400: + err_msg = general_utils.bytes2dict(resp.content)['detail'] + display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR) + exit(0) + else: + display_utils.center_print(resp.content, constants.DISPLAY_TERMINAL_COLOR_ERROR) + exit(0) + + +def get_color_dict(): + resp = requests.get( + cfg.base_url + "/categories/color", + headers=auth_utils.build_jwt_header(cfg.config_path) + ) + if resp.status_code == 200: + color_dict = general_utils.bytes2dict(resp.content) + return color_dict + elif resp.status_code == 400: + err_msg = general_utils.bytes2dict(resp.content)['detail'] + display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR) + else: + display_utils.center_print("Error occurred.", constants.DISPLAY_TERMINAL_COLOR_ERROR) +
\ No newline at end of file diff --git a/girok/api/task.py b/girok/api/task.py new file mode 100644 index 0000000..04e972b --- /dev/null +++ b/girok/api/task.py @@ -0,0 +1,146 @@ +from typing import Union +from textual import log +from datetime import datetime +import requests + +from girok.config import get_config +import girok.utils.auth as auth_utils +import girok.utils.display as display_utils +import girok.utils.general as general_utils +import girok.utils.task as task_utils +import girok.constants as constants + +cfg = get_config() + +def create_task(task_data: dict): + print(task_data) + resp = requests.post( + cfg.base_url + "/tasks", + json=task_data, + headers=auth_utils.build_jwt_header(cfg.config_path) + ) + if resp.status_code == 201: + task = general_utils.bytes2dict(resp.content) + task_id = task['task_id'] + return task_id + elif resp.status_code == 400: + err_msg = general_utils.bytes2dict(resp.content)['detail'] + display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR) + else: + display_utils.center_print("Error occurred.", constants.DISPLAY_TERMINAL_COLOR_ERROR) + + +def get_single_task(task_id: int): + resp = requests.get( + cfg.base_url + f"/tasks/{task_id}", + headers=auth_utils.build_jwt_header(cfg.config_path), + ) + if resp.status_code == 200: + task = general_utils.bytes2dict(resp.content) + return task + elif resp.status_code == 400: + err_msg = general_utils.bytes2dict(resp.content)['detail'] + display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR) + else: + display_utils.center_print(resp.content, constants.DISPLAY_TERMINAL_COLOR_ERROR) + + + +def get_tasks( + cats: Union[list, None] = None, + start_date: Union[str, None] = None, + end_date: Union[str, None] = None, + tag: Union[str, None] = None, + priority: Union[int, None] = None, + no_priority: bool = False, + view: str = "category" +): + query_str_obj = { + "category": cats, + "start_date": start_date, + "end_date": end_date, + "tag": tag, + "priority": priority, + "no_priority": no_priority, + "view": view + } + resp = requests.get( + cfg.base_url + "/tasks", + headers=auth_utils.build_jwt_header(cfg.config_path), + params=query_str_obj + ) + return resp + + +def remove_task(task_id: int): + resp = requests.delete( + cfg.base_url + f"/tasks/{task_id}", + headers=auth_utils.build_jwt_header(cfg.config_path), + ) + return resp + + +def get_tags(): + resp = requests.get( + cfg.base_url + "/tasks/tags", + headers=auth_utils.build_jwt_header(cfg.config_path) + ) + + return resp + + +def change_task_tag(task_id: int, new_tag_name: str): + resp = requests.patch( + cfg.base_url + f"/tasks/{task_id}/tag", + headers=auth_utils.build_jwt_header(cfg.config_path), + json={ + "new_tag_name": new_tag_name + } + ) + + if resp.status_code == 204: + display_utils.center_print(f"Successfully renamed [ID: {task_id}] tag to {new_tag_name}.", "black on green") + elif resp.status_code == 400: + err_msg = general_utils.bytes2dict(resp.content)['detail'] + display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR) + else: + display_utils.center_print(resp.content, constants.DISPLAY_TERMINAL_COLOR_ERROR) + + +def change_task_priority(task_id: int, new_priority: int): + resp = requests.patch( + cfg.base_url + f"/tasks/{task_id}/priority", + headers=auth_utils.build_jwt_header(cfg.config_path), + json={ + "new_priority": new_priority + } + ) + + if resp.status_code == 204: + display_utils.center_print(f"Successfully change [ID: {task_id}] priority to {new_priority}.", "black on green") + elif resp.status_code == 400: + err_msg = general_utils.bytes2dict(resp.content)['detail'] + display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR) + else: + display_utils.center_print(resp.content, constants.DISPLAY_TERMINAL_COLOR_ERROR) + + +def change_task_date(task_id: int, new_date: str): + resp = requests.patch( + cfg.base_url + f"/tasks/{task_id}/date", + headers=auth_utils.build_jwt_header(cfg.config_path), + json={ + "new_date": new_date + } + ) + + if resp.status_code == 204: + display_utils.center_print(f"Successfully change [ID: {task_id}] date to {new_date}.", "black on green") + elif resp.status_code == 400: + err_msg = general_utils.bytes2dict(resp.content)['detail'] + display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR) + else: + display_utils.center_print(resp.content, constants.DISPLAY_TERMINAL_COLOR_ERROR) + + + diff --git a/girok/calendar_cli/calendar_app.py b/girok/calendar_cli/calendar_app.py new file mode 100644 index 0000000..443aba6 --- /dev/null +++ b/girok/calendar_cli/calendar_app.py @@ -0,0 +1,37 @@ +from textual.app import App, ComposeResult +from textual.containers import Container, Horizontal, Vertical +from textual.widgets import Button, Footer, Header, Static, Label, Placeholder, Tree +from textual.messages import Message +from textual.widget import Widget + +import girok.api.category as category_api +import girok.utils.calendar as calendar_utils +from rich.table import Table +from rich.style import Style +from textual import log + +from girok.calendar_cli.sidebar import SidebarContainer, CategoryTree +from girok.calendar_cli.calendar_container import CalendarContainer +import girok.constants as constants + +class CalendarApp(Horizontal): + CSS_PATH = "./demo_dock.css" + + def compose(self): + yield SidebarContainer(id="sidebar-container") + yield CalendarContainer(id="calendar-container") + + def on_category_tree_category_changed(self, event): + self.query_one(CalendarContainer).update_cat_path(event.cat_path) + cat_tree = self.query_one(CategoryTree) + + def on_tag_tree_tag_changed(self, event): + tag = event.tag + if tag.endswith(" " + constants.LEFT_ARROW_EMOJI): + tag = tag[:-2] + if tag == "All Tags": + tag = "" + self.query_one(CalendarContainer).update_tag(tag) + + def on_category_tree_custom_test_message(self, event): + self.refresh()
\ No newline at end of file diff --git a/girok/calendar_cli/calendar_container.py b/girok/calendar_cli/calendar_container.py new file mode 100644 index 0000000..38d54c9 --- /dev/null +++ b/girok/calendar_cli/calendar_container.py @@ -0,0 +1,324 @@ +import asyncio +from datetime import datetime, timedelta +import calendar + +from textual.app import App, ComposeResult +from textual.containers import Container, Horizontal, Vertical +from textual.widgets import Button, Footer, Header, Static, Label, Placeholder, Tree, DataTable +from textual.messages import Message +from textual.widget import Widget +from textual.reactive import var +from rich.text import Text +from rich.style import Style +from rich.segment import Segment +from rich.panel import Panel +from rich.markdown import Markdown +from textual import log + +import girok.api.task as task_api +import girok.api.category as category_api +import girok.utils.calendar as calendar_utils +import girok.utils.general as general_utils +import girok.utils.task as task_utils +import girok.constants as constants +from girok.calendar_cli.sidebar import CategoryTree, TagTree + + +class WeekdayBarContainer(Horizontal): + pass + +class CalendarHeader(Vertical): + year = datetime.now().year + month = datetime.now().month + cat_path = "" + tag = "" + + def on_mount(self): + self.display_date() + + def compose(self): + month_name = task_utils.get_month_name_by_number(self.month) + + with Horizontal(): + with Container(id="calendar-header-category-container"): + yield Static(self.cat_path, id="calendar-header-category") + with Container(id="calendar-header-date-container"): + yield Static(Text(f"{month_name} {self.year}", style=Style(color=constants.CALENDAR_HEADER_DATE_COLOR, bold=True)), id="calendar-header-date") + with Container(id="calendar-header-tag-container"): + yield Static(f"{self.tag}", id="calendar-header-tag") + yield Horizontal() + with WeekdayBarContainer(id="weekday-bar"): + yield Static(Text("Monday", style=Style(color=constants.CALENDAR_WEEKDAY_NAME_COLOR, bold=True)), classes="calendar-weekday-name") + yield Static(Text("Tuesday", style=Style(color=constants.CALENDAR_WEEKDAY_NAME_COLOR, bold=True)), classes="calendar-weekday-name") + yield Static(Text("Wednesday", style=Style(color=constants.CALENDAR_WEEKDAY_NAME_COLOR, bold=True)), classes="calendar-weekday-name") + yield Static(Text("Thursday", style=Style(color=constants.CALENDAR_WEEKDAY_NAME_COLOR, bold=True)), classes="calendar-weekday-name") + yield Static(Text("Friday", style=Style(color=constants.CALENDAR_WEEKDAY_NAME_COLOR, bold=True)), classes="calendar-weekday-name") + yield Static(Text("Saturday", style=Style(color="#87C5FA", bold=True)), classes="calendar-weekday-name") + yield Static(Text("Sunday", style=Style(color="#DB4455", bold=True)), classes="calendar-weekday-name") + + def update_year_and_month(self, year, month): + self.year, self.month = year, month + self.display_date() + + def update_cat_path(self, new_cat_path): + self.cat_path = new_cat_path + self.display_date() + + def update_tag(self, new_tag): + self.tag = new_tag + self.display_date() + + def display_date(self): + month_name = task_utils.get_month_name_by_number(self.month, abbr=False) + calendar_header_category = self.query_one("#calendar-header-category") + calendar_header_date = self.query_one("#calendar-header-date") + calendar_header_tag = self.query_one("#calendar-header-tag") + calendar_weekday_bar = self.query_one("#weekday-bar") + + calendar_header_category.update(Text(f"Category: /{self.cat_path}", style=Style(color=constants.CALENDAR_HEADER_DATE_COLOR))) + calendar_header_date.update(Text(f"{month_name} {self.year}", style=Style(color=constants.CALENDAR_HEADER_DATE_COLOR, bold=True))) + calendar_header_tag.update(Text(f"Tag: {self.tag}", style=Style(color=constants.CALENDAR_HEADER_DATE_COLOR))) + + +class CalendarCell(Vertical): + pass + + +class Calendar(Container): + year = datetime.now().year + month = datetime.now().month + cat_path = "" # If "", show all categories + tag = "" + tasks = [] + can_focus = True + cur_month_first_day_cell_num = None + cur_focused_cell_cord = (None, None) + cur_focused_cell = None + m = 5 + n = 7 + grid = [[False for _ in range(7)] for _ in range(5)] + is_pop_up = False + + class TaskCellSelected(Message): + def __init__(self, cell_tasks, year, month, day): + super().__init__() + self.cell_tasks = cell_tasks + self.year = year + self.month = month + self.day = day + + def on_mount(self |