Skip to content

Commit ea196c0

Browse files
authored
Merge pull request #12 from PoofyEnigma/users/poofy/issue_11
added safe update to ActionLog.user parameter
2 parents d0032b1 + 501217f commit ea196c0

12 files changed

Lines changed: 1175 additions & 1175 deletions

File tree

Makefile

Lines changed: 99 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,99 @@
1-
SRC_CORE=src
2-
SRC_TEST=tests
3-
SRC_RESOURCES=resources
4-
PYTHON=python3
5-
PYDOC=pydoc3
6-
PIP=pip3
7-
8-
9-
help: ## Print help for each target
10-
$(info Things3 low-level Python API.)
11-
$(info =============================)
12-
$(info )
13-
$(info Available commands:)
14-
$(info )
15-
@grep '^[[:alnum:]_-]*:.* ##' $(MAKEFILE_LIST) \
16-
| sort | awk 'BEGIN {FS=":.* ## "}; {printf "%-25s %s\n", $$1, $$2};'
17-
18-
run: ## Run the code
19-
@$(PYTHON) $(SRC_CORE)/hello.py -f -n Foo test
20-
21-
test: ## Test the code
22-
@type coverage >/dev/null 2>&1 || (echo "Run '$(PIP) install coverage' first." >&2 ; exit 1)
23-
@coverage run --source . -m unittest
24-
@coverage report
25-
@coverage html
26-
27-
test_integration: ## Test the code
28-
@type coverage >/dev/null 2>&1 || (echo "Run '$(PIP) install coverage' first." >&2 ; exit 1)
29-
@coverage run --source . -m $(SRC_TEST).integration.test_api_integration
30-
@coverage report
31-
32-
doc: ## Document the code
33-
@$(PYDOC) src
34-
35-
clean: ## Cleanup
36-
@rm -f $(SRC_CORE)/*.pyc
37-
@rm -rf $(SRC_CORE)/__pycache__
38-
@rm -f $(SRC_TEST)/*.pyc
39-
@rm -rf $(SRC_TEST)/__pycache__
40-
41-
auto-style: ## Style the code
42-
@if type autopep8 >/dev/null 2>&1 ; then autopep8 -i -r $(SRC_CORE) ; \
43-
else echo "SKIPPED. Run '$(PIP) install autopep8' first." >&2 ; fi
44-
45-
code-style: ## Test the code style
46-
@if type pycodestyle >/dev/null 2>&1 ; then pycodestyle --max-line-length=80 $(SRC_CORE) ; \
47-
else echo "SKIPPED. Run '$(PIP) install pycodestyle' first." >&2 ; fi
48-
49-
code-count: ## Count the lines of code
50-
@if type cloc >/dev/null 2>&1 ; then cloc $(SRC_CORE) ; \
51-
else echo "SKIPPED. Run 'brew install cloc' first." >&2 ; fi
52-
53-
code-lint: ## Lint the code
54-
@if type pyflakes >/dev/null 2>&1 ; then pyflakes $(SRC_CORE) ; \
55-
else echo "SKIPPED. Run '$(PIP) install pyflakes' first." >&2 ; fi
56-
@if type pylint >/dev/null 2>&1 ; then pylint $(SRC_CORE) ; \
57-
else echo "SKIPPED. Run '$(PIP) install pylint' first." >&2 ; fi
58-
@if type flake8 >/dev/null 2>&1 ; then flake8 --max-complexity 10 $(SRC_CORE) ; \
59-
else echo "SKIPPED. Run '$(PIP) install flake8' first." >&2 ; fi
60-
@if type pyright >/dev/null 2>&1 ; then pyright $(SRC_CORE) ; \
61-
else echo "SKIPPED. Run 'npm install -f pyright' first." >&2 ; fi
62-
@if type mypy >/dev/null 2>&1 ; then mypy --ignore-missing-imports $(SRC_CORE) ; \
63-
else echo "SKIPPED. Run '$(PIP) install mypy' first." >&2 ; fi
64-
65-
css-lint: ## Lint the CSS code
66-
@if type csslint >/dev/null 2>&1 ; then csslint --format=compact $(SRC_RESOURCES)/*.css ; \
67-
else echo "SKIPPED. Run 'npm install -g csslint' first." >&2 ; fi
68-
69-
js-lint: ## Lint the JavaScript code
70-
@if type jslint >/dev/null 2>&1 ; then jslint $(SRC_RESOURCES)/*.js ; \
71-
else echo "SKIPPED. Run 'npm install -g jslint' first." >&2 ; fi
72-
73-
html-lint: ## Lint the HTML code
74-
@if type tidy >/dev/null 2>&1 ; then tidy -qe $(SRC_RESOURCES)/*.html ; \
75-
else echo "SKIPPED. Run 'brew install tidy' first." >&2 ; fi
76-
77-
lint: code-style code-lint css-lint js-lint html-lint ## Run all linters
78-
79-
deps-update: ## Update the dependencies
80-
@if type pur >/dev/null 2>&1 ; then pur -r requirements.txt ; \
81-
else echo "SKIPPED. Run '$(PIP) install pur' first." >&2 ; fi
82-
83-
deps-install: ## Install the dependencies
84-
@type $(PIP) >/dev/null 2>&1 || (echo "Run 'curl https://bootstrap.pypa.io/get-pip.py|sudo python3' first." >&2 ; exit 1)
85-
@$(PIP) install -r requirements.txt
86-
87-
deps-create: ## Create the dependencies
88-
@if type pipreqs >/dev/null 2>&1 ; then pipreqs --use-local --force . ; \
89-
else echo "SKIPPED. Run '$(PIP) install pipreqs' first." >&2 ; fi
90-
91-
feedback: ## Provide feedback
92-
@open https://github.com/AlexanderWillner/python-boilerplate/issues
93-
94-
build: ## build project
95-
python3 -m pip install --upgrade build ; \
96-
python3 -m build
97-
98-
upload:
99-
python3 -m twine upload dist/*
1+
SRC_CORE=src
2+
SRC_TEST=tests
3+
SRC_RESOURCES=resources
4+
PYTHON=python3
5+
PYDOC=pydoc3
6+
PIP=pip3
7+
8+
9+
help: ## Print help for each target
10+
$(info Things3 low-level Python API.)
11+
$(info =============================)
12+
$(info )
13+
$(info Available commands:)
14+
$(info )
15+
@grep '^[[:alnum:]_-]*:.* ##' $(MAKEFILE_LIST) \
16+
| sort | awk 'BEGIN {FS=":.* ## "}; {printf "%-25s %s\n", $$1, $$2};'
17+
18+
run: ## Run the code
19+
@$(PYTHON) $(SRC_CORE)/hello.py -f -n Foo test
20+
21+
test: ## Test the code
22+
@type coverage >/dev/null 2>&1 || (echo "Run '$(PIP) install coverage' first." >&2 ; exit 1)
23+
@coverage run --source . -m unittest
24+
@coverage report
25+
@coverage html
26+
27+
test_integration: ## Test the code
28+
@type coverage >/dev/null 2>&1 || (echo "Run '$(PIP) install coverage' first." >&2 ; exit 1)
29+
@coverage run --source . -m $(SRC_TEST).integration.test_api_integration
30+
@coverage report
31+
32+
doc: ## Document the code
33+
@$(PYDOC) src
34+
35+
clean: ## Cleanup
36+
@rm -f $(SRC_CORE)/*.pyc
37+
@rm -rf $(SRC_CORE)/__pycache__
38+
@rm -f $(SRC_TEST)/*.pyc
39+
@rm -rf $(SRC_TEST)/__pycache__
40+
41+
auto-style: ## Style the code
42+
@if type autopep8 >/dev/null 2>&1 ; then autopep8 -i -r $(SRC_CORE) ; \
43+
else echo "SKIPPED. Run '$(PIP) install autopep8' first." >&2 ; fi
44+
45+
code-style: ## Test the code style
46+
@if type pycodestyle >/dev/null 2>&1 ; then pycodestyle --max-line-length=80 $(SRC_CORE) ; \
47+
else echo "SKIPPED. Run '$(PIP) install pycodestyle' first." >&2 ; fi
48+
49+
code-count: ## Count the lines of code
50+
@if type cloc >/dev/null 2>&1 ; then cloc $(SRC_CORE) ; \
51+
else echo "SKIPPED. Run 'brew install cloc' first." >&2 ; fi
52+
53+
code-lint: ## Lint the code
54+
@if type pyflakes >/dev/null 2>&1 ; then pyflakes $(SRC_CORE) ; \
55+
else echo "SKIPPED. Run '$(PIP) install pyflakes' first." >&2 ; fi
56+
@if type pylint >/dev/null 2>&1 ; then pylint $(SRC_CORE) ; \
57+
else echo "SKIPPED. Run '$(PIP) install pylint' first." >&2 ; fi
58+
@if type flake8 >/dev/null 2>&1 ; then flake8 --max-complexity 10 $(SRC_CORE) ; \
59+
else echo "SKIPPED. Run '$(PIP) install flake8' first." >&2 ; fi
60+
@if type pyright >/dev/null 2>&1 ; then pyright $(SRC_CORE) ; \
61+
else echo "SKIPPED. Run 'npm install -f pyright' first." >&2 ; fi
62+
@if type mypy >/dev/null 2>&1 ; then mypy --ignore-missing-imports $(SRC_CORE) ; \
63+
else echo "SKIPPED. Run '$(PIP) install mypy' first." >&2 ; fi
64+
65+
css-lint: ## Lint the CSS code
66+
@if type csslint >/dev/null 2>&1 ; then csslint --format=compact $(SRC_RESOURCES)/*.css ; \
67+
else echo "SKIPPED. Run 'npm install -g csslint' first." >&2 ; fi
68+
69+
js-lint: ## Lint the JavaScript code
70+
@if type jslint >/dev/null 2>&1 ; then jslint $(SRC_RESOURCES)/*.js ; \
71+
else echo "SKIPPED. Run 'npm install -g jslint' first." >&2 ; fi
72+
73+
html-lint: ## Lint the HTML code
74+
@if type tidy >/dev/null 2>&1 ; then tidy -qe $(SRC_RESOURCES)/*.html ; \
75+
else echo "SKIPPED. Run 'brew install tidy' first." >&2 ; fi
76+
77+
lint: code-style code-lint css-lint js-lint html-lint ## Run all linters
78+
79+
deps-update: ## Update the dependencies
80+
@if type pur >/dev/null 2>&1 ; then pur -r requirements.txt ; \
81+
else echo "SKIPPED. Run '$(PIP) install pur' first." >&2 ; fi
82+
83+
deps-install: ## Install the dependencies
84+
@type $(PIP) >/dev/null 2>&1 || (echo "Run 'curl https://bootstrap.pypa.io/get-pip.py|sudo python3' first." >&2 ; exit 1)
85+
@$(PIP) install -r requirements.txt
86+
87+
deps-create: ## Create the dependencies
88+
@if type pipreqs >/dev/null 2>&1 ; then pipreqs --use-local --force . ; \
89+
else echo "SKIPPED. Run '$(PIP) install pipreqs' first." >&2 ; fi
90+
91+
feedback: ## Provide feedback
92+
@open https://github.com/AlexanderWillner/python-boilerplate/issues
93+
94+
build: ## build project
95+
python3 -m pip install --upgrade build ; \
96+
python3 -m build
97+
98+
upload:
99+
python3 -m twine upload dist/*

demos/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
`docker compose up --build --detach`
2-
1+
`docker compose up --build --detach`
2+
33
- *.env needs filled before running

demos/TrapBotDockerfile

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
# syntax=docker/dockerfile:1.4
2-
FROM --platform=$BUILDPLATFORM python:3.10-alpine AS builder
3-
4-
WORKDIR /trap_bot
5-
6-
COPY . /trap_bot
7-
ENV PYTHONPATH=/trap_bot
8-
RUN --mount=type=cache,target=/root/.cache/pip \
9-
pip3 install -r ./shared/requirements.txt
10-
RUN --mount=type=cache,target=/root/.cache/pip \
11-
pip3 install -r ./trap_bot/requirements.txt
12-
13-
ENTRYPOINT ["python3"]
14-
CMD ["./trap_bot/app.py"]
15-
1+
# syntax=docker/dockerfile:1.4
2+
FROM --platform=$BUILDPLATFORM python:3.10-alpine AS builder
3+
4+
WORKDIR /trap_bot
5+
6+
COPY . /trap_bot
7+
ENV PYTHONPATH=/trap_bot
8+
RUN --mount=type=cache,target=/root/.cache/pip \
9+
pip3 install -r ./shared/requirements.txt
10+
RUN --mount=type=cache,target=/root/.cache/pip \
11+
pip3 install -r ./trap_bot/requirements.txt
12+
13+
ENTRYPOINT ["python3"]
14+
CMD ["./trap_bot/app.py"]
15+

demos/compose.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
services:
2-
trap-bot:
3-
build:
4-
dockerfile: ./TrapBotDockerfile
5-
env_file:
1+
services:
2+
trap-bot:
3+
build:
4+
dockerfile: ./TrapBotDockerfile
5+
env_file:
66
- ./trap_bot.env

demos/shared/shared.py

Lines changed: 74 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,74 @@
1-
import logging
2-
import datetime
3-
4-
from chaster import api, extensions, lock
5-
6-
7-
def publish_shared_lock(chaster_api: api.ChasterAPI, create_shared_lock: lock.CreateSharedLock,
8-
ext: extensions.Extensions) -> lock.SharedLock | None:
9-
logger = logging.getLogger()
10-
logger.debug(f'creating a new shared lock {create_shared_lock.name}')
11-
resp, shared_lock_id = chaster_api.create_shared_lock(create_shared_lock)
12-
if resp.status_code != 201:
13-
logger.error(f'could not create new shared lock for {create_shared_lock.name}')
14-
return None
15-
16-
resp = chaster_api.put_shared_lock_extensions(shared_lock_id, ext)
17-
if resp.status_code != 200:
18-
logger.error(f'could not edit the extensions of the new lock for {create_shared_lock.name}')
19-
resp = chaster_api.archive_shared_lock(shared_lock_id)
20-
if resp.status_code != 201:
21-
logger.error(f'failed to archive newly created but invalid shared lock for {create_shared_lock.name}')
22-
return None
23-
24-
resp, data = chaster_api.get_shared_lock_details(shared_lock_id)
25-
if resp.status_code != 200:
26-
logger.warning(f'failed to get the shared lock after creating it for {create_shared_lock.name}')
27-
return None
28-
return data
29-
30-
31-
def resolve_shared_lock(chaster_api: api.ChasterAPI, create_shared_lock: lock.CreateSharedLock,
32-
ext: extensions.Extensions, lock_name: str) -> lock.SharedLock | None:
33-
logger = logging.getLogger()
34-
resp, shared_locks = chaster_api.get_user_shared_locks()
35-
if resp.status_code != 200:
36-
logger.error('could not get shared locks')
37-
return None
38-
logger.debug(f'Finding the existing shared lock from {len(shared_locks)} shared locks')
39-
for shared_lock in shared_locks:
40-
if shared_lock.name == lock_name:
41-
trap_shared_lock = shared_lock
42-
break
43-
else:
44-
trap_shared_lock = publish_shared_lock(chaster_api, create_shared_lock, ext)
45-
46-
if trap_shared_lock is None:
47-
logger.warning('could not resolve the shared lock')
48-
return trap_shared_lock
49-
50-
if trap_shared_lock.lastSavedAt + datetime.timedelta(days=7) <= datetime.datetime.now().astimezone():
51-
logger.debug(f'shared lock {create_shared_lock.name} is out of date. Republishing.')
52-
resp = chaster_api.archive_shared_lock(trap_shared_lock._id)
53-
if resp.status_code != 201:
54-
logger.error(
55-
f'could not archive shared lock {trap_shared_lock.name} due to {resp.status_code} - {resp.text}')
56-
trap_shared_lock = None
57-
else:
58-
trap_shared_lock = publish_shared_lock(chaster_api, create_shared_lock, ext)
59-
60-
return trap_shared_lock
61-
62-
63-
def get_locked_users(chaster_api: api.ChasterAPI):
64-
logger = logging.getLogger()
65-
logger.debug(f'getting first page of locked users')
66-
resp, locked_users_page = chaster_api.find_locked_users()
67-
locked_users = locked_users_page.locks
68-
69-
for page in range(1, locked_users_page.pages):
70-
logger.debug(f'getting page {page} of locked users')
71-
resp, locked_users_page = chaster_api.find_locked_users(page=page)
72-
locked_users.extend(locked_users_page.locks)
73-
74-
return locked_users
1+
import logging
2+
import datetime
3+
4+
from chaster import api, extensions, lock
5+
6+
7+
def publish_shared_lock(chaster_api: api.ChasterAPI, create_shared_lock: lock.CreateSharedLock,
8+
ext: extensions.Extensions) -> lock.SharedLock | None:
9+
logger = logging.getLogger()
10+
logger.debug(f'creating a new shared lock {create_shared_lock.name}')
11+
resp, shared_lock_id = chaster_api.create_shared_lock(create_shared_lock)
12+
if resp.status_code != 201:
13+
logger.error(f'could not create new shared lock for {create_shared_lock.name}')
14+
return None
15+
16+
resp = chaster_api.put_shared_lock_extensions(shared_lock_id, ext)
17+
if resp.status_code != 200:
18+
logger.error(f'could not edit the extensions of the new lock for {create_shared_lock.name}')
19+
resp = chaster_api.archive_shared_lock(shared_lock_id)
20+
if resp.status_code != 201:
21+
logger.error(f'failed to archive newly created but invalid shared lock for {create_shared_lock.name}')
22+
return None
23+
24+
resp, data = chaster_api.get_shared_lock_details(shared_lock_id)
25+
if resp.status_code != 200:
26+
logger.warning(f'failed to get the shared lock after creating it for {create_shared_lock.name}')
27+
return None
28+
return data
29+
30+
31+
def resolve_shared_lock(chaster_api: api.ChasterAPI, create_shared_lock: lock.CreateSharedLock,
32+
ext: extensions.Extensions, lock_name: str) -> lock.SharedLock | None:
33+
logger = logging.getLogger()
34+
resp, shared_locks = chaster_api.get_user_shared_locks()
35+
if resp.status_code != 200:
36+
logger.error('could not get shared locks')
37+
return None
38+
logger.debug(f'Finding the existing shared lock from {len(shared_locks)} shared locks')
39+
for shared_lock in shared_locks:
40+
if shared_lock.name == lock_name:
41+
trap_shared_lock = shared_lock
42+
break
43+
else:
44+
trap_shared_lock = publish_shared_lock(chaster_api, create_shared_lock, ext)
45+
46+
if trap_shared_lock is None:
47+
logger.warning('could not resolve the shared lock')
48+
return trap_shared_lock
49+
50+
if trap_shared_lock.lastSavedAt + datetime.timedelta(days=7) <= datetime.datetime.now().astimezone():
51+
logger.debug(f'shared lock {create_shared_lock.name} is out of date. Republishing.')
52+
resp = chaster_api.archive_shared_lock(trap_shared_lock._id)
53+
if resp.status_code != 201:
54+
logger.error(
55+
f'could not archive shared lock {trap_shared_lock.name} due to {resp.status_code} - {resp.text}')
56+
trap_shared_lock = None
57+
else:
58+
trap_shared_lock = publish_shared_lock(chaster_api, create_shared_lock, ext)
59+
60+
return trap_shared_lock
61+
62+
63+
def get_locked_users(chaster_api: api.ChasterAPI):
64+
logger = logging.getLogger()
65+
logger.debug(f'getting first page of locked users')
66+
resp, locked_users_page = chaster_api.find_locked_users()
67+
locked_users = locked_users_page.locks
68+
69+
for page in range(1, locked_users_page.pages):
70+
logger.debug(f'getting page {page} of locked users')
71+
resp, locked_users_page = chaster_api.find_locked_users(page=page)
72+
locked_users.extend(locked_users_page.locks)
73+
74+
return locked_users

0 commit comments

Comments
 (0)