Init
This commit is contained in:
commit
f78c9d349a
27 changed files with 4998 additions and 0 deletions
427
.gitignore
vendored
Normal file
427
.gitignore
vendored
Normal file
|
@ -0,0 +1,427 @@
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/python,flask,node,emacs,linux,windows,macos
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=python,flask,node,emacs,linux,windows,macos
|
||||||
|
|
||||||
|
### Emacs ###
|
||||||
|
# -*- mode: gitignore; -*-
|
||||||
|
*~
|
||||||
|
\#*\#
|
||||||
|
/.emacs.desktop
|
||||||
|
/.emacs.desktop.lock
|
||||||
|
*.elc
|
||||||
|
auto-save-list
|
||||||
|
tramp
|
||||||
|
.\#*
|
||||||
|
|
||||||
|
# Org-mode
|
||||||
|
.org-id-locations
|
||||||
|
*_archive
|
||||||
|
|
||||||
|
# flymake-mode
|
||||||
|
*_flymake.*
|
||||||
|
|
||||||
|
# eshell files
|
||||||
|
/eshell/history
|
||||||
|
/eshell/lastdir
|
||||||
|
|
||||||
|
# elpa packages
|
||||||
|
/elpa/
|
||||||
|
|
||||||
|
# reftex files
|
||||||
|
*.rel
|
||||||
|
|
||||||
|
# AUCTeX auto folder
|
||||||
|
/auto/
|
||||||
|
|
||||||
|
# cask packages
|
||||||
|
.cask/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Flycheck
|
||||||
|
flycheck_*.el
|
||||||
|
|
||||||
|
# server auth directory
|
||||||
|
/server/
|
||||||
|
|
||||||
|
# projectiles files
|
||||||
|
.projectile
|
||||||
|
|
||||||
|
# directory configuration
|
||||||
|
.dir-locals.el
|
||||||
|
|
||||||
|
# network security
|
||||||
|
/network-security.data
|
||||||
|
|
||||||
|
|
||||||
|
### Flask ###
|
||||||
|
instance/*
|
||||||
|
!instance/.gitignore
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
### Flask.Python Stack ###
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
pytestdebug.log
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
doc/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
### Linux ###
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
### macOS ###
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
### Node ###
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env.test
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
### Python ###
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
|
||||||
|
### Windows ###
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/python,flask,node,emacs,linux,windows,macos
|
15
Pipfile
Normal file
15
Pipfile
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[[source]]
|
||||||
|
name = "pypi"
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
flask = "*"
|
||||||
|
walrus = "*"
|
||||||
|
flask-wtf = "*"
|
||||||
|
wtforms = "*"
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.8"
|
125
Pipfile.lock
generated
Normal file
125
Pipfile.lock
generated
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "f58e03f82108622c44893db80327f71087a066a46a5232716aa9e9f3e0cfcdb5"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.8"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"click": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||||
|
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||||
|
],
|
||||||
|
"version": "==7.1.2"
|
||||||
|
},
|
||||||
|
"flask": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060",
|
||||||
|
"sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.1.2"
|
||||||
|
},
|
||||||
|
"flask-wtf": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:57b3faf6fe5d6168bda0c36b0df1d05770f8e205e18332d0376ddb954d17aef2",
|
||||||
|
"sha256:d417e3a0008b5ba583da1763e4db0f55a1269d9dd91dcc3eb3c026d3c5dbd720"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.14.3"
|
||||||
|
},
|
||||||
|
"itsdangerous": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
|
||||||
|
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
|
||||||
|
],
|
||||||
|
"version": "==1.1.0"
|
||||||
|
},
|
||||||
|
"jinja2": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0",
|
||||||
|
"sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"
|
||||||
|
],
|
||||||
|
"version": "==2.11.2"
|
||||||
|
},
|
||||||
|
"markupsafe": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
|
||||||
|
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
|
||||||
|
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
|
||||||
|
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
|
||||||
|
"sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
|
||||||
|
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
|
||||||
|
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
|
||||||
|
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
|
||||||
|
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
|
||||||
|
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
|
||||||
|
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
|
||||||
|
"sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
|
||||||
|
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
|
||||||
|
"sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
|
||||||
|
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
|
||||||
|
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
|
||||||
|
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
|
||||||
|
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
|
||||||
|
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
|
||||||
|
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
|
||||||
|
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
|
||||||
|
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
|
||||||
|
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
|
||||||
|
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
|
||||||
|
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
|
||||||
|
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
|
||||||
|
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
|
||||||
|
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
|
||||||
|
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
|
||||||
|
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
|
||||||
|
"sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
|
||||||
|
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
|
||||||
|
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"
|
||||||
|
],
|
||||||
|
"version": "==1.1.1"
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2",
|
||||||
|
"sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"
|
||||||
|
],
|
||||||
|
"version": "==3.5.3"
|
||||||
|
},
|
||||||
|
"walrus": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6752420331b0110af6b3c6d32e61252dbafbd05ae2fc1a5fbfa6d42d2382062a"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.8.1"
|
||||||
|
},
|
||||||
|
"werkzeug": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43",
|
||||||
|
"sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"
|
||||||
|
],
|
||||||
|
"version": "==1.0.1"
|
||||||
|
},
|
||||||
|
"wtforms": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:7b504fc724d0d1d4d5d5c114e778ec88c37ea53144683e084215eed5155ada4c",
|
||||||
|
"sha256:81195de0ac94fbc8368abbaf9197b88c4f3ffd6c2719b5bf5fc9da744f3d829c"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.3.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {}
|
||||||
|
}
|
31
api.py
Normal file
31
api.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
from flask import request, jsonify
|
||||||
|
from walrus import Walrus
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from countdown import api_api
|
||||||
|
|
||||||
|
db = Walrus(host='localhost', port=6379, db=0)
|
||||||
|
|
||||||
|
@app.route('/api/vi1/<uuid:id>', methods=['GET'])
|
||||||
|
def get_countdown(id):
|
||||||
|
ct = db.Hash(str(id))
|
||||||
|
|
||||||
|
resp = ct.as_dict(decode=True)
|
||||||
|
resp['left'] = float(ct['total']) - (time() - float(ct['start']))
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@api_v1.route('/api/v1', methods=['POST'])
|
||||||
|
def create_countdown():
|
||||||
|
countdown = request.json
|
||||||
|
ct_id = str(uuid.uuid4())
|
||||||
|
ct = db.Hash(ct_id)
|
||||||
|
ct.update(start=time(), total=countdown['total'])
|
||||||
|
|
||||||
|
resp = ct.as_dict(decode=True)
|
||||||
|
resp['id'] = ct_id
|
||||||
|
|
||||||
|
return resp
|
0
api/__init__.py
Normal file
0
api/__init__.py
Normal file
7
api/v1/__init__.py
Normal file
7
api/v1/__init__.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from flask import Blueprint
|
||||||
|
|
||||||
|
api_v1 = Blueprint('api.v1', __name__)
|
||||||
|
|
||||||
|
import api.v1.clock
|
||||||
|
import api.v1.countdown
|
||||||
|
|
7
api/v1/clock.py
Normal file
7
api/v1/clock.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
from api.v1 import api_v1
|
||||||
|
|
||||||
|
@api_v1.route('/time/<float:t1>')
|
||||||
|
def netime_time(t1: float) -> str:
|
||||||
|
return str(time())
|
31
api/v1/countdown.py
Normal file
31
api/v1/countdown.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
from flask import request, jsonify
|
||||||
|
from walrus import Walrus
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from api.v1 import api_v1
|
||||||
|
|
||||||
|
db = Walrus(host='localhost', port=6379, db=0)
|
||||||
|
|
||||||
|
@api_v1.route('/countdown/<uuid:id>', methods=['GET'])
|
||||||
|
def get_countdown(id):
|
||||||
|
ct = db.Hash(str(id))
|
||||||
|
|
||||||
|
resp = ct.as_dict(decode=True)
|
||||||
|
resp['left'] = float(ct['total']) - (time() - float(ct['start']))
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@api_v1.route('/countdown', methods=['POST'])
|
||||||
|
def create_countdown():
|
||||||
|
countdown = request.json
|
||||||
|
ct_id = str(uuid.uuid4())
|
||||||
|
ct = db.Hash(ct_id)
|
||||||
|
ct.update(start=time(), total=countdown['total'])
|
||||||
|
|
||||||
|
resp = ct.as_dict(decode=True)
|
||||||
|
resp['id'] = ct_id
|
||||||
|
|
||||||
|
return resp
|
6
countdown/__init__.py
Normal file
6
countdown/__init__.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from flask import Blueprint
|
||||||
|
|
||||||
|
app = Blueprint('countdown', __name__)
|
||||||
|
|
||||||
|
import views
|
||||||
|
import apii
|
4
countdown/forms.py
Normal file
4
countdown/forms.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
from flask_wtf import FlaskForm, TimeField
|
||||||
|
|
||||||
|
class CountdownAdminForm(FlaskForm):
|
||||||
|
totalTime = TimeField('Time')
|
19
countdown/views.py
Normal file
19
countdown/views.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from flask import render_template, request, flash, redirect, url_for
|
||||||
|
|
||||||
|
from countdown import app, forms
|
||||||
|
|
||||||
|
@app.route('/<uuid:id>', methods=['GET'])
|
||||||
|
def countdown(id):
|
||||||
|
return render_template('countdown.html', id)
|
||||||
|
|
||||||
|
@app.route('/', methods=['GET', 'POST', 'PUT'])
|
||||||
|
def countdown_admin():
|
||||||
|
form = CountdownAdminForm(request.form)
|
||||||
|
if request.method == 'POST' and form.validate():
|
||||||
|
user = User(form.username.data, form.email.data,
|
||||||
|
form.password.data)
|
||||||
|
db_session.add(user)
|
||||||
|
flash('Thanks for registering')
|
||||||
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
|
return render_template('countdown_admin.html', form=form, clock=None)
|
3
css/netclock.scss
Normal file
3
css/netclock.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
body {
|
||||||
|
color: red;
|
||||||
|
}
|
4
forms.py
Normal file
4
forms.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
from flask_wtf import FlaskForm, TimeField
|
||||||
|
|
||||||
|
class CountdownAdminForm(FlaskForm):
|
||||||
|
totalTime = TimeField('Time')
|
24
js/countdown.js
Normal file
24
js/countdown.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import log from 'loglevel';
|
||||||
|
import $ from 'jquery';
|
||||||
|
|
||||||
|
|
||||||
|
const updateCountdown = () => $.getJSON({
|
||||||
|
url: "api/v1/countdown/070f478f-e168-488c-918e-adb37c9c0cbd",
|
||||||
|
data: Date.now(),
|
||||||
|
success: function(countdown) {
|
||||||
|
if(countdown.left <= 0) {
|
||||||
|
clearInterval(scheduledUpdater);
|
||||||
|
$('#clock').text(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let floor = Math.floor(countdown.left);
|
||||||
|
|
||||||
|
let frac = countdown.left - floor;
|
||||||
|
let milli = Math.floor(frac * 1000); // get in millisecond resolution
|
||||||
|
|
||||||
|
setTimeout(() => $('#clock').text(floor), milli);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let scheduledUpdater = setInterval(updateCountdown, 1000);
|
6
js/netclock.js
Normal file
6
js/netclock.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import '../css/netclock.scss';
|
||||||
|
import log from 'loglevel';
|
||||||
|
|
||||||
|
if (process.env.LOG_LEVEL) {
|
||||||
|
log.setDefaultLevel(process.env.LOG_LEVEL);
|
||||||
|
}
|
7
netclock.py
Normal file
7
netclock.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from flask import Flask
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
from api.v1 import api_v1
|
||||||
|
app.register_blueprint(api_v1, url_prefix="/api/v1")
|
||||||
|
|
||||||
|
import views
|
4155
package-lock.json
generated
Normal file
4155
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
27
package.json
Normal file
27
package.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"name": "netclock",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "A collection of time widgets for the web",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack --config webpack.dev.js",
|
||||||
|
"watch": "webpack --watch --config webpack.dev.js",
|
||||||
|
"publish": "webpack --config webpack.prod.js"
|
||||||
|
},
|
||||||
|
"author": "Armin Friedl",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
|
"css-loader": "^4.2.2",
|
||||||
|
"sass": "^1.26.10",
|
||||||
|
"sass-loader": "^10.0.2",
|
||||||
|
"style-loader": "^1.2.1",
|
||||||
|
"webpack": "^4.44.1",
|
||||||
|
"webpack-cli": "^3.3.12",
|
||||||
|
"webpack-merge": "^5.1.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jquery": "^3.5.1",
|
||||||
|
"loglevel": "^1.7.0"
|
||||||
|
}
|
||||||
|
}
|
BIN
static/favicon.ico
Normal file
BIN
static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
16
templates/base.html
Normal file
16
templates/base.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Netclock {% if self.title() %} - {% endif %}{% block title %}{% endblock title %}</title>
|
||||||
|
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
{% block body %}{% endblock body %}
|
||||||
|
|
||||||
|
<script src="{{ url_for('static', filename='dist/netclock.bundle.js') }}"></script>
|
||||||
|
{% block scripts %}{% endblock scripts %}
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
11
templates/countdown.html
Normal file
11
templates/countdown.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}Countdown{% endblock title %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
Hello from Countdown
|
||||||
|
<div id="clock"></div>
|
||||||
|
{% endblock body %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<script src="{{ url_for('static', filename='dist/countdown.bundle.js') }}"></script>
|
||||||
|
{% endblock scripts %}
|
11
templates/countdown_admin.html
Normal file
11
templates/countdown_admin.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}Countdown{% endblock title %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
Hello from Countdown
|
||||||
|
<div id="clock"></div>
|
||||||
|
{% endblock body %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<script src="{{ url_for('static', filename='dist/countdown.bundle.js') }}"></script>
|
||||||
|
{% endblock scripts %}
|
3
templates/netclock.html
Normal file
3
templates/netclock.html
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block body %}Index{% endblock body %}
|
9
views.py
Normal file
9
views.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from flask import Flask, render_template, request, flash
|
||||||
|
from netclock import app
|
||||||
|
|
||||||
|
from forms import CountdownAdminForm
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('netclock.html')
|
||||||
|
|
29
webpack.common.js
Normal file
29
webpack.common.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: {
|
||||||
|
netclock: './js/netclock.js',
|
||||||
|
countdown: './js/countdown.js'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CleanWebpackPlugin()
|
||||||
|
],
|
||||||
|
output: {
|
||||||
|
filename: '[name].bundle.js',
|
||||||
|
path: path.resolve(__dirname, 'static', 'dist')
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [{
|
||||||
|
test: /\.s[ac]ss$/i,
|
||||||
|
use: [
|
||||||
|
// Creates `style` nodes from JS strings
|
||||||
|
'style-loader',
|
||||||
|
// Translates CSS into CommonJS
|
||||||
|
'css-loader',
|
||||||
|
// Compiles Sass to CSS
|
||||||
|
'sass-loader',
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
14
webpack.dev.js
Normal file
14
webpack.dev.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
const common = require('./webpack.common.js');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const { merge } = require('webpack-merge');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
|
mode: 'development',
|
||||||
|
devtool: 'eval-source-map',
|
||||||
|
plugins: [
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
LOG_LEVEL: 'trace'
|
||||||
|
})
|
||||||
|
]
|
||||||
|
});
|
7
webpack.prod.js
Normal file
7
webpack.prod.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
const common = require('./webpack.common.js');
|
||||||
|
const { merge } = require('webpack-merge');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
|
mode: 'production'
|
||||||
|
});
|
Loading…
Reference in a new issue