Skip to content

Commit

Permalink
feat: code quality and update to v1.0.0
Browse files Browse the repository at this point in the history
big refactor, needs testing, probably a lot of stuff broke
  • Loading branch information
dni committed Oct 22, 2024
1 parent dc499bb commit 0763cf2
Show file tree
Hide file tree
Showing 30 changed files with 4,373 additions and 1,462 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: lint
on:
push:
branches:
- main
pull_request:

jobs:
lint:
uses: lnbits/lnbits/.github/workflows/lint.yml@dev
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
12 changes: 12 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"semi": false,
"arrowParens": "avoid",
"insertPragma": false,
"printWidth": 80,
"proseWrap": "preserve",
"singleQuote": true,
"trailingComma": "none",
"useTabs": false,
"bracketSameLine": false,
"bracketSpacing": false
}
47 changes: 47 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
all: format check

format: prettier black ruff

check: mypy pyright checkblack checkruff checkprettier

prettier:
poetry run ./node_modules/.bin/prettier --write .
pyright:
poetry run ./node_modules/.bin/pyright

mypy:
poetry run mypy .

black:
poetry run black .

ruff:
poetry run ruff check . --fix

checkruff:
poetry run ruff check .

checkprettier:
poetry run ./node_modules/.bin/prettier --check .

checkblack:
poetry run black --check .

checkeditorconfig:
editorconfig-checker

test:
PYTHONUNBUFFERED=1 \
DEBUG=true \
poetry run pytest
install-pre-commit-hook:
@echo "Installing pre-commit hook to git"
@echo "Uninstall the hook with poetry run pre-commit uninstall"
poetry run pre-commit install

pre-commit:
poetry run pre-commit run --all-files


checkbundle:
@echo "skipping checkbundle"
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

lnbits scheduler extension [previously: crontabs]

IMPORTANT:
IMPORTANT:

- **The user that runs LNBits server MUST have crontab -e permissions in order to read/write to crontab file.**
- This extension should be limited to admin account(s).
- min version 0.12.10
Expand All @@ -11,23 +12,24 @@ IMPORTANT:

https://github.com/bitkarrot/scheduler/assets/73979971/888d9e77-4edf-4573-85ee-8fc43c710120

### Overview:
Add, Edit, Delete and Monitor your scheduled Jobs from the Main Panel.
### Overview:

Add, Edit, Delete and Monitor your scheduled Jobs from the Main Panel.

<img width="992" alt="Screenshot 2024-01-19 at 2 39 23 PM" src="https://github.com/bitkarrot/scheduler/assets/73979971/01656f95-bdde-4015-99c5-415ce9483ddb">

### Create a job Dialog Box.
### Create a job Dialog Box.

Schedule a specific http call with a specific timed interval.

1. Create a new job by clicking "New Scheduled Job"
2. Fill the options for your new SCHEDULED JOB
- Enter a Name for your Job
- Select an action (GET/PUT/POST/DEL)
- Enter the URL
- Add any headers if required
- Add body data if required, leave blank if there is no body (e.g. for DELETE)
- enter the scheduled time/day you want to run your job. You can use [crontab.guru](https://crontab.guru) to help validate your cron schedules.
- Enter a Name for your Job
- Select an action (GET/PUT/POST/DEL)
- Enter the URL
- Add any headers if required
- Add body data if required, leave blank if there is no body (e.g. for DELETE)
- enter the scheduled time/day you want to run your job. You can use [crontab.guru](https://crontab.guru) to help validate your cron schedules.
3. Save your scheduled job and return to the main page to test the job (Orange) or start the job (Green arrow)
4. All methods for controlling your job are on the main panel [Start/Stop, Edit, Test, View Logs and Delete]

Expand All @@ -36,6 +38,7 @@ NOTE: Jobs may not run automatically on creation depending on the release versio
<img width="605" alt="imgtwo" src="https://github.com/bitkarrot/scheduler/assets/73979971/77f55660-52b6-459c-9ce2-d81e6fa7d1b5">

### There are three sets of logs:

- Individual Job Logs - these are viewable by clicking on the blue info icons on the main panel.
- Test job Logs - this is for testing the job and the result is not recorded to the database only to the test log file.
- Complete Extension Logs - This will show all errors and all events, these are viewable by clicking on the "View all logs" button, located the top of the main panel.
- Test job Logs - this is for testing the job and the result is not recorded to the database only to the test log file.
- Complete Extension Logs - This will show all errors and all events, these are viewable by clicking on the "View all logs" button, located the top of the main panel.
18 changes: 6 additions & 12 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from fastapi import APIRouter

from lnbits.db import Database
from lnbits.helpers import template_renderer

db = Database("ext_scheduler")
from .crud import db
from .views import scheduler_generic_router
from .views_api import scheduler_api_router

scheduler_ext: APIRouter = APIRouter(prefix="/scheduler", tags=["scheduler"])
scheduler_ext.include_router(scheduler_generic_router)
scheduler_ext.include_router(scheduler_api_router)

scheduler_static_files = [
{
Expand All @@ -14,11 +15,4 @@
}
]


def scheduler_renderer():
return template_renderer(["scheduler/templates"])


from .views import * # noqa
from .views_api import * # noqa
from .cron_handler import * # noqa
__all__ = ["db", "scheduler_ext", "scheduler_static_files"]
10 changes: 5 additions & 5 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Scheduler",
"short_description": "Generate Scheduled tasks via crontabs for lnbits",
"tile": "/scheduler/static/image/scheduler.png",
"contributors": ["bitkarrot"],
"min_lnbits_version": "0.12.10"
"name": "Scheduler",
"short_description": "Generate Scheduled tasks via crontabs for lnbits",
"tile": "/scheduler/static/image/scheduler.png",
"contributors": ["bitkarrot"],
"min_lnbits_version": "1.0.0"
}
74 changes: 39 additions & 35 deletions cron_handler.py
Original file line number Diff line number Diff line change
@@ -1,58 +1,60 @@
from crontab import CronTab, CronSlices
import json
from typing import Union

'''
CronHanlder class contains methods for handling cron jobs, create, edit, delete
from crontab import CronSlices, CronTab

"""
CronHandler class contains methods for handling cron jobs, create, edit, delete
see originaldocs for python-crontab package
https://pypi.org/project/python-crontab/
'''
"""


class CronHandler():
def __init__(self, user:str):
class CronHandler:
def __init__(self, user: Union[str, bool] = True):
self._user = user
self._cron = CronTab(user=self._user)

def get_cron(self):
return self._cron

def set_cron(self, cron):
self._cron = cron

def get_user(self):
return self._user

def set_user(self, user):
self._user = user
self._user = user

async def list_jobs(self) -> str:
async def list_jobs(self) -> list:
jobs = []
for job in self._cron:
jobs.append(str(job))
return jobs

async def pretty_print_jobs(self) -> None:
print(f'==== Cron Jobs List: ====')
print("==== Cron Jobs List: ====")
jobs = await self.list_jobs()
for i in jobs:
print(i)

async def new_job(self, command:str, frequency:str, comment:str, env:json):
async def new_job(self, command: str, frequency: str, comment: str, env: dict):
job = self._cron.new(command=command, comment=comment)
if len(env) > 0:
for key in env:
job.env[key] = env[key]
job.setall(frequency)
if job.is_valid():
if job.is_valid():
self._cron.write_to_user(user=self._user)
return f"job created: {command}, {self._user}, {frequency}"
else:
else:
return f"Error creating job: {command}, {self._user}, {frequency}"

# TODO: add means to edit env variables in the job
async def edit_job(self, command:str, frequency:str, comment:str):
iter = self._cron.find_comment(comment)
for job in iter:
async def edit_job(self, command: str, frequency: str, comment: str):
jobs = self._cron.find_comment(comment)
for job in jobs:
## assume job comment ID is unique
job.command = command
job.setall(frequency)
Expand All @@ -62,21 +64,21 @@ async def edit_job(self, command:str, frequency:str, comment:str):
else:
return f"Error editing job: {command}, {self._user}, {frequency}"

async def enable_job_by_comment(self, comment:str, bool:bool):
# print(f'enable_job_by_comment: {comment}, bool: {bool}')
iter = self._cron.find_comment(comment)
async def enable_job_by_comment(self, comment: str, active: bool):
jobs = self._cron.find_comment(comment)
## assume iter is only 1 long as using unique comment ID
for job in iter:
job.enable(bool)
for job in jobs:
job.enable(active)
self._cron.write_to_user(user=self._user)
return job.is_enabled()

async def get_job_status(self, job_id: str) -> bool:
iter = self._cron.find_comment(job_id)
for job in iter:
jobs = self._cron.find_comment(job_id)
for job in jobs:
return job.is_enabled()
return False

async def remove_job(self, command=str):
async def remove_job(self, command: str):
self._cron.remove_all(command=command)
self._cron.write_to_user(user=self._user)

Expand All @@ -92,22 +94,24 @@ async def remove_by_time(self, time):
self._cron.remove_all(time=time)
self._cron.write_to_user(user=self._user)


async def set_global_env_vars(self, env:dict):
for (name, value) in env.items():
self._cron.env[name] = value
async def set_global_env_vars(self, env: dict):
if self._cron.env:
for name, value in env.items():
self._cron.env[name] = value
self._cron.write_to_user(user=self._user)

async def get_global_env_vars(self):
output = ''
for (name, value) in self._cron.env.items():
output += f'name: {name}, value: {value}\n'
output = ""
if self._cron.env:
for name, value in self._cron.env.items():
output += f"name: {name}, value: {value}\n"
return output

async def clear_global_env_vars(self):
self._cron.env.clear()
if self._cron.env:
self._cron.env.clear()
self._cron.write_to_user(user=self._user)

async def validate_cron_string(self, timestring: str):
is_valid = CronSlices.is_valid(timestring)
return is_valid
return is_valid
Loading

0 comments on commit 0763cf2

Please sign in to comment.