Compare commits
9 Commits
f45c744d4d
...
5082836714
Author | SHA1 | Date |
---|---|---|
urosm | 5082836714 | |
urosm | ca4e65d504 | |
urosm | 33af19bcd1 | |
urosm | 8ae1474d77 | |
mknurs | d3bc656fc1 | |
mknurs | fa689bb7ba | |
mknurs | 11f372e125 | |
mknurs | 2d90e979a1 | |
mknurs | 4e2337540c |
|
@ -1,4 +1,3 @@
|
|||
# ---> Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
@ -93,9 +92,24 @@ ipython_config.py
|
|||
# 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
|
||||
Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
|
@ -138,16 +152,9 @@ dmypy.json
|
|||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
*.pyc
|
||||
__pycache__/
|
||||
|
||||
instance/
|
||||
|
||||
.pytest_cache/
|
||||
.coverage
|
||||
htmlcov/
|
||||
|
||||
dist/
|
||||
build/
|
||||
temp/
|
||||
*.egg-info/
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
flask = "*"
|
||||
pymysql = "*"
|
||||
sqlalchemy = "*"
|
||||
numpy = "*"
|
||||
pyncclient = "*"
|
||||
python-magic = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.10"
|
18
README.md
18
README.md
|
@ -1,4 +1,22 @@
|
|||
# Contentmatcher
|
||||
|
||||
## Development quickstart
|
||||
|
||||
Setup a database (...). Configure a `.env` file (see `.env.dist`) (...).
|
||||
|
||||
Install dependencies with `pipenv`.
|
||||
|
||||
```
|
||||
$ pipenv install
|
||||
```
|
||||
|
||||
Run `app.py`.
|
||||
|
||||
```
|
||||
$ python app.py
|
||||
```
|
||||
|
||||
|
||||
## Try it
|
||||
Usually there is a running instance [here](https://cm.kompot.si).
|
||||
|
||||
|
|
93
app.py
93
app.py
|
@ -28,100 +28,9 @@ def create_app(test_config=None):
|
|||
session.rollback()
|
||||
return render_template('500.html'), 500
|
||||
|
||||
@app.route('/deck/index', methods=["GET", "POST"])
|
||||
@app.route('/deck', methods=["GET", "POST"])
|
||||
def deck():
|
||||
return prob_session()
|
||||
"""
|
||||
this is commented out because it was moved to pro_session.py.
|
||||
dbsession = get_session()
|
||||
if not 'user_id' in session:
|
||||
return index()
|
||||
|
||||
user_id = session['user_id']
|
||||
username = session['username']
|
||||
|
||||
#pokliče na bazo, da dobi str card idjev, ga spremeni v list in srevira karte po idjih
|
||||
deck_query = dbsession.query(Deck).filter(Deck.owner_id == user_id)
|
||||
deck_object = deck_query.filter(Deck.completed == False).first()
|
||||
# @TODO: ce deck, ne obstaja, kaj naj zaj jas?
|
||||
if len(deck_object.cards_by_id.split(",")) == 0:
|
||||
deck_query.filter(Deck)
|
||||
return index()
|
||||
|
||||
# Smo oddali obrazec?
|
||||
if request.method == 'POST':
|
||||
card_id = request.form.get('card_id', None)
|
||||
if not card_id:
|
||||
raise Exception("card_id je nujen!")
|
||||
|
||||
|
||||
submit_card = dbsession.query(Card).get(card_id)
|
||||
# @TODO preveri, ali je card del trenutnega decka!
|
||||
|
||||
# Ali damo share? Potem nastavi na share in ponovi obrazec
|
||||
share_request = request.form.get("share", None)
|
||||
if share_request:
|
||||
# @TODO logika za share!
|
||||
share(submit_card, user_id)
|
||||
|
||||
# Če ne, gre za rate!
|
||||
else:
|
||||
rate = request.form.get('rate', None) #je to nevarno??
|
||||
print(rate)
|
||||
|
||||
if not rate:
|
||||
raise Exception("manjka rate info!")
|
||||
|
||||
if rate == "Yes":
|
||||
submit_card.interest_rate = 1
|
||||
|
||||
elif rate == "Maybe":
|
||||
k = 0.5
|
||||
print(submit_card)
|
||||
submit_card.interest_rate= abs(submit_card.interest_rate*k)
|
||||
|
||||
elif rate == "No":
|
||||
k = 0.1
|
||||
submit_card.interest_rate = abs(submit_card.interest_rate*k)
|
||||
|
||||
elif rate == "Delete":
|
||||
submit_card.interest_rate = 0
|
||||
#@TODO to bi lahko zbrisalo tudi file v določenih primerih
|
||||
|
||||
# zaporedno število trenutnega carda v decku
|
||||
next_card = deck_object.current_card + 1
|
||||
|
||||
# Ali je deck končan?
|
||||
if next_card >= deck_object.number_of_cards:
|
||||
deck_object.completed = True
|
||||
dbsession.commit()
|
||||
dbsession.close()
|
||||
flash("Deck rating finished!")
|
||||
return redirect(url_for("menu.index"))
|
||||
|
||||
deck_object.current_card = next_card
|
||||
dbsession.commit()
|
||||
|
||||
# Loudamo naslednjo karto v decku
|
||||
show_card_index = deck_object.current_card
|
||||
show_card_id = deck_object.cards_by_id.split(",")[show_card_index]
|
||||
print("GET CARD PLS", show_card_id)
|
||||
show_card = dbsession.query(Card).get(show_card_id)
|
||||
dbsession.close()
|
||||
|
||||
if not show_card:
|
||||
# @TODO how to handle missing card?
|
||||
#deck_object.completed = 1
|
||||
#dbsession.commit()
|
||||
#dbsession.close()
|
||||
print("show_card missing")
|
||||
return render_template("error/no_cards_in_collection.html")
|
||||
#raise Exception("Ne najdem naslednje karte")
|
||||
|
||||
# Prikaži obrazec
|
||||
return render_template("deck/index.html", username=username, card=show_card)
|
||||
"""
|
||||
|
||||
|
||||
@app.route("/share_button", methods=["GET", "POST"])
|
||||
def share_button():
|
||||
|
|
4
auth.py
4
auth.py
|
@ -53,7 +53,7 @@ def register():
|
|||
|
||||
flash(error)
|
||||
|
||||
return render_template('auth/register.html')
|
||||
return render_template('register.html')
|
||||
|
||||
|
||||
@bp.route('/login', methods=('GET', 'POST'))
|
||||
|
@ -79,7 +79,7 @@ def login():
|
|||
return redirect(url_for("menu.index")) #TODO ne dela
|
||||
flash(error)
|
||||
|
||||
return render_template('auth/login.html')
|
||||
return render_template('login.html')
|
||||
|
||||
|
||||
@bp.before_app_request
|
||||
|
|
78
bin/activate
78
bin/activate
|
@ -1,78 +0,0 @@
|
|||
# This file must be used with "source bin/activate" *from bash*
|
||||
# you cannot run it directly
|
||||
|
||||
deactivate () {
|
||||
unset -f pydoc >/dev/null 2>&1
|
||||
|
||||
# reset old environment variables
|
||||
# ! [ -z ${VAR+_} ] returns true if VAR is declared at all
|
||||
if ! [ -z "${_OLD_VIRTUAL_PATH+_}" ] ; then
|
||||
PATH="$_OLD_VIRTUAL_PATH"
|
||||
export PATH
|
||||
unset _OLD_VIRTUAL_PATH
|
||||
fi
|
||||
if ! [ -z "${_OLD_VIRTUAL_PYTHONHOME+_}" ] ; then
|
||||
PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME"
|
||||
export PYTHONHOME
|
||||
unset _OLD_VIRTUAL_PYTHONHOME
|
||||
fi
|
||||
|
||||
# This should detect bash and zsh, which have a hash command that must
|
||||
# be called to get it to forget past commands. Without forgetting
|
||||
# past commands the $PATH changes we made may not be respected
|
||||
if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ] ; then
|
||||
hash -r 2>/dev/null
|
||||
fi
|
||||
|
||||
if ! [ -z "${_OLD_VIRTUAL_PS1+_}" ] ; then
|
||||
PS1="$_OLD_VIRTUAL_PS1"
|
||||
export PS1
|
||||
unset _OLD_VIRTUAL_PS1
|
||||
fi
|
||||
|
||||
unset VIRTUAL_ENV
|
||||
if [ ! "${1-}" = "nondestructive" ] ; then
|
||||
# Self destruct!
|
||||
unset -f deactivate
|
||||
fi
|
||||
}
|
||||
|
||||
# unset irrelevant variables
|
||||
deactivate nondestructive
|
||||
|
||||
VIRTUAL_ENV="/home/jan/contentmatcher"
|
||||
export VIRTUAL_ENV
|
||||
|
||||
_OLD_VIRTUAL_PATH="$PATH"
|
||||
PATH="$VIRTUAL_ENV/bin:$PATH"
|
||||
export PATH
|
||||
|
||||
# unset PYTHONHOME if set
|
||||
if ! [ -z "${PYTHONHOME+_}" ] ; then
|
||||
_OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME"
|
||||
unset PYTHONHOME
|
||||
fi
|
||||
|
||||
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT-}" ] ; then
|
||||
_OLD_VIRTUAL_PS1="$PS1"
|
||||
if [ "x" != x ] ; then
|
||||
PS1="$PS1"
|
||||
else
|
||||
PS1="(`basename \"$VIRTUAL_ENV\"`) $PS1"
|
||||
fi
|
||||
export PS1
|
||||
fi
|
||||
|
||||
# Make sure to unalias pydoc if it's already there
|
||||
alias pydoc 2>/dev/null >/dev/null && unalias pydoc
|
||||
|
||||
pydoc () {
|
||||
python -m pydoc "$@"
|
||||
}
|
||||
|
||||
# This should detect bash and zsh, which have a hash command that must
|
||||
# be called to get it to forget past commands. Without forgetting
|
||||
# past commands the $PATH changes we made may not be respected
|
||||
if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ] ; then
|
||||
hash -r 2>/dev/null
|
||||
fi
|
|
@ -1,36 +0,0 @@
|
|||
# This file must be used with "source bin/activate.csh" *from csh*.
|
||||
# You cannot run it directly.
|
||||
# Created by Davide Di Blasi <davidedb@gmail.com>.
|
||||
|
||||
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc'
|
||||
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
setenv VIRTUAL_ENV "/home/jan/contentmatcher"
|
||||
|
||||
set _OLD_VIRTUAL_PATH="$PATH"
|
||||
setenv PATH "$VIRTUAL_ENV/bin:$PATH"
|
||||
|
||||
|
||||
|
||||
if ("" != "") then
|
||||
set env_name = ""
|
||||
else
|
||||
set env_name = `basename "$VIRTUAL_ENV"`
|
||||
endif
|
||||
|
||||
# Could be in a non-interactive environment,
|
||||
# in which case, $prompt is undefined and we wouldn't
|
||||
# care about the prompt anyway.
|
||||
if ( $?prompt ) then
|
||||
set _OLD_VIRTUAL_PROMPT="$prompt"
|
||||
set prompt = "[$env_name] $prompt"
|
||||
endif
|
||||
|
||||
unset env_name
|
||||
|
||||
alias pydoc python -m pydoc
|
||||
|
||||
rehash
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
# This file must be used using `. bin/activate.fish` *within a running fish ( http://fishshell.com ) session*.
|
||||
# Do not run it directly.
|
||||
|
||||
function deactivate -d 'Exit virtualenv mode and return to the normal environment.'
|
||||
# reset old environment variables
|
||||
if test -n "$_OLD_VIRTUAL_PATH"
|
||||
set -gx PATH $_OLD_VIRTUAL_PATH
|
||||
set -e _OLD_VIRTUAL_PATH
|
||||
end
|
||||
|
||||
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
|
||||
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
|
||||
set -e _OLD_VIRTUAL_PYTHONHOME
|
||||
end
|
||||
|
||||
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
|
||||
# Set an empty local `$fish_function_path` to allow the removal of `fish_prompt` using `functions -e`.
|
||||
set -l fish_function_path
|
||||
|
||||
# Erase virtualenv's `fish_prompt` and restore the original.
|
||||
functions -e fish_prompt
|
||||
functions -c _old_fish_prompt fish_prompt
|
||||
functions -e _old_fish_prompt
|
||||
set -e _OLD_FISH_PROMPT_OVERRIDE
|
||||
end
|
||||
|
||||
set -e VIRTUAL_ENV
|
||||
|
||||
if test "$argv[1]" != 'nondestructive'
|
||||
# Self-destruct!
|
||||
functions -e pydoc
|
||||
functions -e deactivate
|
||||
end
|
||||
end
|
||||
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
set -gx VIRTUAL_ENV "/home/jan/contentmatcher"
|
||||
|
||||
set -gx _OLD_VIRTUAL_PATH $PATH
|
||||
set -gx PATH "$VIRTUAL_ENV/bin" $PATH
|
||||
|
||||
# Unset `$PYTHONHOME` if set.
|
||||
if set -q PYTHONHOME
|
||||
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
|
||||
set -e PYTHONHOME
|
||||
end
|
||||
|
||||
function pydoc
|
||||
python -m pydoc $argv
|
||||
end
|
||||
|
||||
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
|
||||
# Copy the current `fish_prompt` function as `_old_fish_prompt`.
|
||||
functions -c fish_prompt _old_fish_prompt
|
||||
|
||||
function fish_prompt
|
||||
# Save the current $status, for fish_prompts that display it.
|
||||
set -l old_status $status
|
||||
|
||||
# Prompt override provided?
|
||||
# If not, just prepend the environment name.
|
||||
if test -n ""
|
||||
printf '%s%s' "" (set_color normal)
|
||||
else
|
||||
printf '%s(%s) ' (set_color normal) (basename "$VIRTUAL_ENV")
|
||||
end
|
||||
|
||||
# Restore the original $status
|
||||
echo "exit $old_status" | source
|
||||
_old_fish_prompt
|
||||
end
|
||||
|
||||
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
|
||||
end
|
|
@ -1,34 +0,0 @@
|
|||
"""By using execfile(this_file, dict(__file__=this_file)) you will
|
||||
activate this virtualenv environment.
|
||||
|
||||
This can be used when you must use an existing Python interpreter, not
|
||||
the virtualenv bin/python
|
||||
"""
|
||||
|
||||
try:
|
||||
__file__
|
||||
except NameError:
|
||||
raise AssertionError(
|
||||
"You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))")
|
||||
import sys
|
||||
import os
|
||||
|
||||
old_os_path = os.environ.get('PATH', '')
|
||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path
|
||||
base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
if sys.platform == 'win32':
|
||||
site_packages = os.path.join(base, 'Lib', 'site-packages')
|
||||
else:
|
||||
site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages')
|
||||
prev_sys_path = list(sys.path)
|
||||
import site
|
||||
site.addsitedir(site_packages)
|
||||
sys.real_prefix = sys.prefix
|
||||
sys.prefix = base
|
||||
# Move the added items to the front of the path:
|
||||
new_sys_path = []
|
||||
for item in list(sys.path):
|
||||
if item not in prev_sys_path:
|
||||
new_sys_path.append(item)
|
||||
sys.path.remove(item)
|
||||
sys.path[:0] = new_sys_path
|
8
bin/f2py
8
bin/f2py
|
@ -1,8 +0,0 @@
|
|||
#!/home/jan/contentmatcher/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from numpy.f2py.f2py2e import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||
#!/home/jan/contentmatcher/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from numpy.f2py.f2py2e import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||
#!/home/jan/contentmatcher/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from numpy.f2py.f2py2e import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||
#!/home/jan/contentmatcher/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from flask.cli import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
|
@ -1,8 +0,0 @@
|
|||
#!/home/jan/contentmatcher/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from charset_normalizer.cli.normalizer import cli_detect
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(cli_detect())
|
10
bin/pip
10
bin/pip
|
@ -1,10 +0,0 @@
|
|||
#!/home/jan/contentmatcher/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from pip._internal.cli.main import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
10
bin/pip3
10
bin/pip3
|
@ -1,10 +0,0 @@
|
|||
#!/home/jan/contentmatcher/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from pip._internal.cli.main import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
10
bin/pip3.10
10
bin/pip3.10
|
@ -1,10 +0,0 @@
|
|||
#!/home/jan/contentmatcher/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from pip._internal.cli.main import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
10
bin/pip3.7
10
bin/pip3.7
|
@ -1,10 +0,0 @@
|
|||
#!/home/jan/contentmatcher/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from pip._internal.cli.main import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
|
@ -1 +0,0 @@
|
|||
python3
|
|
@ -1,78 +0,0 @@
|
|||
#!/home/jan/contentmatcher/bin/python
|
||||
|
||||
import sys
|
||||
import getopt
|
||||
import sysconfig
|
||||
|
||||
valid_opts = ['prefix', 'exec-prefix', 'includes', 'libs', 'cflags',
|
||||
'ldflags', 'help']
|
||||
|
||||
if sys.version_info >= (3, 2):
|
||||
valid_opts.insert(-1, 'extension-suffix')
|
||||
valid_opts.append('abiflags')
|
||||
if sys.version_info >= (3, 3):
|
||||
valid_opts.append('configdir')
|
||||
|
||||
|
||||
def exit_with_usage(code=1):
|
||||
sys.stderr.write("Usage: {0} [{1}]\n".format(
|
||||
sys.argv[0], '|'.join('--'+opt for opt in valid_opts)))
|
||||
sys.exit(code)
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], '', valid_opts)
|
||||
except getopt.error:
|
||||
exit_with_usage()
|
||||
|
||||
if not opts:
|
||||
exit_with_usage()
|
||||
|
||||
pyver = sysconfig.get_config_var('VERSION')
|
||||
getvar = sysconfig.get_config_var
|
||||
|
||||
opt_flags = [flag for (flag, val) in opts]
|
||||
|
||||
if '--help' in opt_flags:
|
||||
exit_with_usage(code=0)
|
||||
|
||||
for opt in opt_flags:
|
||||
if opt == '--prefix':
|
||||
print(sysconfig.get_config_var('prefix'))
|
||||
|
||||
elif opt == '--exec-prefix':
|
||||
print(sysconfig.get_config_var('exec_prefix'))
|
||||
|
||||
elif opt in ('--includes', '--cflags'):
|
||||
flags = ['-I' + sysconfig.get_path('include'),
|
||||
'-I' + sysconfig.get_path('platinclude')]
|
||||
if opt == '--cflags':
|
||||
flags.extend(getvar('CFLAGS').split())
|
||||
print(' '.join(flags))
|
||||
|
||||
elif opt in ('--libs', '--ldflags'):
|
||||
abiflags = getattr(sys, 'abiflags', '')
|
||||
libs = ['-lpython' + pyver + abiflags]
|
||||
libs += getvar('LIBS').split()
|
||||
libs += getvar('SYSLIBS').split()
|
||||
# add the prefix/lib/pythonX.Y/config dir, but only if there is no
|
||||
# shared library in prefix/lib/.
|
||||
if opt == '--ldflags':
|
||||
if not getvar('Py_ENABLE_SHARED'):
|
||||
libs.insert(0, '-L' + getvar('LIBPL'))
|
||||
if not getvar('PYTHONFRAMEWORK'):
|
||||
libs.extend(getvar('LINKFORSHARED').split())
|
||||
print(' '.join(libs))
|
||||
|
||||
elif opt == '--extension-suffix':
|
||||
ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
|
||||
if ext_suffix is None:
|
||||
ext_suffix = sysconfig.get_config_var('SO')
|
||||
print(ext_suffix)
|
||||
|
||||
elif opt == '--abiflags':
|
||||
if not getattr(sys, 'abiflags', None):
|
||||
exit_with_usage()
|
||||
print(sys.abiflags)
|
||||
|
||||
elif opt == '--configdir':
|
||||
print(sysconfig.get_config_var('LIBPL'))
|
BIN
bin/python3
BIN
bin/python3
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
python3
|
10
bin/wheel
10
bin/wheel
|
@ -1,10 +0,0 @@
|
|||
#!/home/jan/contentmatcher/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from wheel.cli import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
|
@ -1 +0,0 @@
|
|||
/usr/include/python3.7m
|
|
@ -1,146 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
|
||||
|
||||
/* Greenlet object interface */
|
||||
|
||||
#ifndef Py_GREENLETOBJECT_H
|
||||
#define Py_GREENLETOBJECT_H
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This is deprecated and undocumented. It does not change. */
|
||||
#define GREENLET_VERSION "1.0.0"
|
||||
|
||||
typedef struct _greenlet {
|
||||
PyObject_HEAD
|
||||
char* stack_start;
|
||||
char* stack_stop;
|
||||
char* stack_copy;
|
||||
intptr_t stack_saved;
|
||||
struct _greenlet* stack_prev;
|
||||
struct _greenlet* parent;
|
||||
PyObject* run_info;
|
||||
struct _frame* top_frame;
|
||||
int recursion_depth;
|
||||
PyObject* weakreflist;
|
||||
#if PY_VERSION_HEX >= 0x030700A3
|
||||
_PyErr_StackItem* exc_info;
|
||||
_PyErr_StackItem exc_state;
|
||||
#else
|
||||
PyObject* exc_type;
|
||||
PyObject* exc_value;
|
||||
PyObject* exc_traceback;
|
||||
#endif
|
||||
PyObject* dict;
|
||||
#if PY_VERSION_HEX >= 0x030700A3
|
||||
PyObject* context;
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x30A00B1
|
||||
CFrame* cframe;
|
||||
#endif
|
||||
} PyGreenlet;
|
||||
|
||||
#define PyGreenlet_Check(op) PyObject_TypeCheck(op, &PyGreenlet_Type)
|
||||
#define PyGreenlet_MAIN(op) (((PyGreenlet*)(op))->stack_stop == (char*)-1)
|
||||
#define PyGreenlet_STARTED(op) (((PyGreenlet*)(op))->stack_stop != NULL)
|
||||
#define PyGreenlet_ACTIVE(op) (((PyGreenlet*)(op))->stack_start != NULL)
|
||||
#define PyGreenlet_GET_PARENT(op) (((PyGreenlet*)(op))->parent)
|
||||
|
||||
/* C API functions */
|
||||
|
||||
/* Total number of symbols that are exported */
|
||||
#define PyGreenlet_API_pointers 8
|
||||
|
||||
#define PyGreenlet_Type_NUM 0
|
||||
#define PyExc_GreenletError_NUM 1
|
||||
#define PyExc_GreenletExit_NUM 2
|
||||
|
||||
#define PyGreenlet_New_NUM 3
|
||||
#define PyGreenlet_GetCurrent_NUM 4
|
||||
#define PyGreenlet_Throw_NUM 5
|
||||
#define PyGreenlet_Switch_NUM 6
|
||||
#define PyGreenlet_SetParent_NUM 7
|
||||
|
||||
#ifndef GREENLET_MODULE
|
||||
/* This section is used by modules that uses the greenlet C API */
|
||||
static void** _PyGreenlet_API = NULL;
|
||||
|
||||
# define PyGreenlet_Type \
|
||||
(*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM])
|
||||
|
||||
# define PyExc_GreenletError \
|
||||
((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM])
|
||||
|
||||
# define PyExc_GreenletExit \
|
||||
((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM])
|
||||
|
||||
/*
|
||||
* PyGreenlet_New(PyObject *args)
|
||||
*
|
||||
* greenlet.greenlet(run, parent=None)
|
||||
*/
|
||||
# define PyGreenlet_New \
|
||||
(*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \
|
||||
_PyGreenlet_API[PyGreenlet_New_NUM])
|
||||
|
||||
/*
|
||||
* PyGreenlet_GetCurrent(void)
|
||||
*
|
||||
* greenlet.getcurrent()
|
||||
*/
|
||||
# define PyGreenlet_GetCurrent \
|
||||
(*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM])
|
||||
|
||||
/*
|
||||
* PyGreenlet_Throw(
|
||||
* PyGreenlet *greenlet,
|
||||
* PyObject *typ,
|
||||
* PyObject *val,
|
||||
* PyObject *tb)
|
||||
*
|
||||
* g.throw(...)
|
||||
*/
|
||||
# define PyGreenlet_Throw \
|
||||
(*(PyObject * (*)(PyGreenlet * self, \
|
||||
PyObject * typ, \
|
||||
PyObject * val, \
|
||||
PyObject * tb)) \
|
||||
_PyGreenlet_API[PyGreenlet_Throw_NUM])
|
||||
|
||||
/*
|
||||
* PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args)
|
||||
*
|
||||
* g.switch(*args, **kwargs)
|
||||
*/
|
||||
# define PyGreenlet_Switch \
|
||||
(*(PyObject * \
|
||||
(*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \
|
||||
_PyGreenlet_API[PyGreenlet_Switch_NUM])
|
||||
|
||||
/*
|
||||
* PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent)
|
||||
*
|
||||
* g.parent = new_parent
|
||||
*/
|
||||
# define PyGreenlet_SetParent \
|
||||
(*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \
|
||||
_PyGreenlet_API[PyGreenlet_SetParent_NUM])
|
||||
|
||||
/* Macro that imports greenlet and initializes C API */
|
||||
/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we
|
||||
keep the older definition to be sure older code that might have a copy of
|
||||
the header still works. */
|
||||
# define PyGreenlet_Import() \
|
||||
{ \
|
||||
_PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \
|
||||
}
|
||||
|
||||
#endif /* GREENLET_MODULE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* !Py_GREENLETOBJECT_H */
|
8
menu.py
8
menu.py
|
@ -45,7 +45,7 @@ def index():
|
|||
user_settings = get_settings(user_id)
|
||||
if user_settings['max_new'] == "0" and user_settings['max_due'] == "0":
|
||||
flash("Error: Attempted to make deck with 0 cards.")
|
||||
return render_template("menu/menu.html")
|
||||
return render_template("menu.html")
|
||||
|
||||
deck = probabilistic_deck_generator(user_id, int(user_settings['max_new']), int(user_settings['max_due']))
|
||||
cards_by_id = get_deck(deck)
|
||||
|
@ -71,8 +71,8 @@ def index():
|
|||
return render_template("settings.html", username=username, user_id=user_id, settings=settings)
|
||||
elif action == "instructions":
|
||||
return render_template("instructions.html", username=username, user_id=user_id)
|
||||
elif action == "about":
|
||||
return render_template("about.html", username=username, user_id=user_id)
|
||||
# elif action == "about":
|
||||
# return render_template("about.html", username=username, user_id=user_id)
|
||||
|
||||
|
||||
return render_template("menu/menu.html", username=username, deck_status=deck_status)
|
||||
return render_template("menu.html", username=username, deck_status=deck_status)
|
||||
|
|
|
@ -93,4 +93,4 @@ def prob_session():
|
|||
#raise Exception("Ne najdem naslednje karte")
|
||||
|
||||
# Prikaži obrazec
|
||||
return render_template("deck/index.html", username=username, card=show_card)
|
||||
return render_template("index.html", username=username, card=show_card)
|
||||
|
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
|
@ -1,4 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
source bin/activate
|
||||
python3 app.py
|
|
@ -0,0 +1,50 @@
|
|||
// select all `<input>` elements with the class `dropzone-input` and operate on each of them
|
||||
document.querySelectorAll(".dropzone-input").forEach((inputEl) => {
|
||||
// select the element's (closest) parent with the class name `dropzone` (the element with the actual "dropzone" functionality)
|
||||
const dropZoneEl = inputEl.closest(".dropzone");
|
||||
// select the element's (closest) parent with the class name `dropzone-form` (the container of all "dropzone" functionality and the form action, in our case this is the same element)
|
||||
const dropZoneFormEl = inputEl.closest(".dropzone-form");
|
||||
// select the info text element inside the container
|
||||
const dropZoneTextEl = dropZoneFormEl.querySelector(".dropzone-txt")
|
||||
|
||||
// add a `click` event listener on the dropzone to trigger the input's click event
|
||||
dropZoneEl.addEventListener("click", (e) => {
|
||||
inputEl.click();
|
||||
});
|
||||
|
||||
// add a `change` event listener
|
||||
inputEl.addEventListener("change", (e) => {
|
||||
e.preventDefault();
|
||||
console.log("change")
|
||||
if (inputEl.files.length) {
|
||||
// change info text
|
||||
dropZoneTextEl.innerHTML = "Uploading file ...";
|
||||
// submit form
|
||||
dropZoneFormEl.submit();
|
||||
}
|
||||
});
|
||||
|
||||
// add to class list when we drag over the element
|
||||
dropZoneEl.addEventListener("dragover", (e) => {
|
||||
e.preventDefault();
|
||||
dropZoneEl.classList.add("dropzone--over");
|
||||
});
|
||||
|
||||
// remove from class list when we leave or stop dragging
|
||||
["dragleave", "dragend"].forEach((type) => {
|
||||
dropZoneEl.addEventListener(type, (e) => {
|
||||
e.preventDefault();
|
||||
dropZoneEl.classList.remove("dropzone--over");
|
||||
});
|
||||
});
|
||||
|
||||
dropZoneEl.addEventListener("drop", (e) => {
|
||||
e.preventDefault();
|
||||
if (e.dataTransfer.files.length) {
|
||||
inputEl.files = e.dataTransfer.files;
|
||||
dropZoneTextEl.innerHTML = "Uploading file ...";
|
||||
dropZoneFormEl.submit();
|
||||
}
|
||||
dropZoneEl.classList.remove("dropzone--over");
|
||||
});
|
||||
});
|
475
static/style.css
475
static/style.css
|
@ -1,173 +1,310 @@
|
|||
/* variables */
|
||||
:root {
|
||||
--txt-width: 60ch;
|
||||
--foreground: #333333;
|
||||
--background: #eeeeee;
|
||||
--dimm: 0.7;
|
||||
--green: #00d090;
|
||||
--orange: #f08010;
|
||||
--yellow: #f0c060;
|
||||
--red: #f05030;
|
||||
--blue: #4080a0;
|
||||
}
|
||||
|
||||
/* normalize */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input {
|
||||
background: none;
|
||||
border: none;
|
||||
border-bottom: solid var(--foreground) 1px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type^=submit] {
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
background: none;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.yes,
|
||||
.green{
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
.maybe,
|
||||
.yellow {
|
||||
color: var(--yellow);
|
||||
}
|
||||
|
||||
.no,
|
||||
.orange {
|
||||
color: var(--orange);
|
||||
}
|
||||
|
||||
.delete,
|
||||
.red {
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
.share,
|
||||
.blue {
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
background: #eee;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
body {
|
||||
max-width: 960px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: serif;
|
||||
color: #000000;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #377ba8;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid lightgray;
|
||||
}
|
||||
|
||||
nav {
|
||||
background: D9D2C6;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
nav h1 {
|
||||
flex: auto;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
nav h1 a {
|
||||
text-decoration: none;
|
||||
padding: 0.25rem 0.5rem;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
nav ul li a, nav ul li span, header .action {
|
||||
display: block;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0 1rem 1rem;
|
||||
}
|
||||
|
||||
.content > header {
|
||||
border-bottom: 1px solid lightgray;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.content > header h1 {
|
||||
flex: auto;
|
||||
margin: 1rem 0 0.25rem 0;
|
||||
}
|
||||
|
||||
.flash {
|
||||
margin: 1em 0;
|
||||
padding: 1em;
|
||||
background: #cae6f6;
|
||||
border: 1px solid #377ba8;
|
||||
}
|
||||
|
||||
.post > header {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.post > header > div:first-of-type {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
.post > header h1 {
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.post .about {
|
||||
color: slategray;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.post .body {
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.content:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.content form {
|
||||
margin: 1em 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content label {
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.content input, .content textarea {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.content textarea {
|
||||
min-height: 12em;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
input.danger {
|
||||
color: #cc2f2e;
|
||||
}
|
||||
|
||||
input[type=submit] {
|
||||
align-self: start;
|
||||
min-width: 10em;
|
||||
}
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: sans-serif;
|
||||
/* font-size: clamp(16px, calc(1vw + 1vh + 0.5vmin), 22px); */
|
||||
font-size: calc(0.1rem + 1vw + 1vh + 0.5vmin);
|
||||
line-height: 1.25;
|
||||
color: var(--foreground);
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
||||
#pdf-doc {
|
||||
width: 100%;
|
||||
height: calc(100vh - 332px);
|
||||
}
|
||||
/* layout */
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
}
|
||||
|
||||
.drop-zone {
|
||||
max-width: 200px;
|
||||
height: 200px;
|
||||
padding: 25px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
font-family: "Quicksand", sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
color: #cccccc;
|
||||
border: 4px dashed #009578;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.drop-zone--over {
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.drop-zone__input {
|
||||
display: none;
|
||||
}
|
||||
body>* {
|
||||
padding: 0.5rem;
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0px;
|
||||
width: fill-available;
|
||||
width: -webkit-fill-available;
|
||||
width: -moz-available;
|
||||
height: 70px;
|
||||
font-size: 130%
|
||||
}
|
||||
/* header */
|
||||
body>header {
|
||||
border-bottom: thin solid var(--foreground);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
grid-template-areas:
|
||||
"title navigation";
|
||||
}
|
||||
|
||||
body>header>h1,
|
||||
body>header>nav {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
body>header>h1 {
|
||||
grid-area: title;
|
||||
}
|
||||
|
||||
body>header>nav {
|
||||
grid-area: navigation;
|
||||
}
|
||||
|
||||
body>header * {
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
/* main */
|
||||
body>main {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
/* footer */
|
||||
body>footer {
|
||||
border-top: thin solid var(--foreground);
|
||||
}
|
||||
|
||||
body>footer * {
|
||||
margin: 0;
|
||||
font-size: 0.5rem;
|
||||
}
|
||||
|
||||
/* deck */
|
||||
#deck article {
|
||||
max-height: 100%;
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
}
|
||||
|
||||
#deck article>main {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
/* matches */
|
||||
#matches table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#matches table tr {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr auto;
|
||||
border-bottom: thin solid var(--foreground);
|
||||
}
|
||||
|
||||
#matches table tr td:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* upload */
|
||||
#upload form {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-rows: 1fr auto;
|
||||
}
|
||||
|
||||
#upload input[type^=file] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dropzone {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* settings */
|
||||
/* TODO: arrows */
|
||||
#settings form {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
grid-gap: 0.5rem;
|
||||
}
|
||||
|
||||
#settings form input[type=submit] {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
/* instructions */
|
||||
|
||||
#instructions article h1,
|
||||
#instructions article h2,
|
||||
#instructions article h3,
|
||||
#instructions article h4,
|
||||
#instructions article h5,
|
||||
#instructions article h6 {
|
||||
font-size: 1rem;
|
||||
font-weight: normal;
|
||||
border-bottom: thin solid var(--foreground);
|
||||
}
|
||||
|
||||
/* login, register */
|
||||
#login>main,
|
||||
#register>main {
|
||||
place-self: center;
|
||||
}
|
||||
|
||||
#login form {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"user-label user-input"
|
||||
"pass-label pass-input"
|
||||
"login login";
|
||||
grid-gap: 0.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#register form {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"user-label user-input"
|
||||
"pass-label pass-input"
|
||||
"mail-label mail-input"
|
||||
"login login";
|
||||
grid-gap: 0.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#login form>input[type=text],
|
||||
#login form>input[type=password],
|
||||
#register form>input[type=text],
|
||||
#register form>input[type=password],
|
||||
#register form>input[type=email] {
|
||||
}
|
||||
|
||||
#login form>input:focus,
|
||||
#register form>input:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#login form>input[type^="submit"],
|
||||
#register form>input[type^="submit"] {
|
||||
grid-area: login;
|
||||
place-self: center;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
/* menu */
|
||||
#menu form {
|
||||
display: grid;
|
||||
grid-template-columns: auto;
|
||||
grid-gap: 0.5rem;
|
||||
justify-items: start;
|
||||
}
|
||||
|
||||
|
||||
#content>form {
|
||||
display: grid;
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
|
||||
/* flash */
|
||||
.flashes {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: none;
|
||||
max-width: var(--txt-width);
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.flashes li {
|
||||
animation: 3s 2s forwards fadeout;
|
||||
}
|
||||
|
||||
@keyframes fadeout {
|
||||
from {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
#buttonContainer {
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
}
|
||||
|
||||
#buttonContainer>button:hover {
|
||||
/* background-color: black!important; */
|
||||
}
|
||||
|
||||
button[value^="Yes"] {
|
||||
background-color: var(--green);
|
||||
}
|
||||
button[value^="No"] {
|
||||
background-color: var(--orange);
|
||||
}
|
||||
button[value^="Maybe"] {
|
||||
background-color: var(--yellow);
|
||||
}
|
||||
button[value^="Delete"] {
|
||||
background-color: var(--red);
|
||||
}
|
||||
button[value^="Share"] {
|
||||
background-color: var(--blue);
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block header %}
|
||||
<h1>About</h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>Contentmatcher is a <a href="https://gia.kompot.si/about.php">General Intelligence Agency of Ljubljana</a> prototype.</p>
|
||||
|
||||
<p>You can find the its code <a href="https://git.kompot.si/gia/contentmatcher">here</a>.</p>
|
||||
|
||||
<p>Contentmatcher is hosted by <a href="https://kompot.si/wiki/doku.php">kompot</a>, a librehosters community from Ljubljana.</p>
|
||||
|
||||
If you have any questions, feedback or if you would like contribute, please contact us at <a href="mailto:gia@kompot.si">gia@kompot.si</a>.
|
||||
|
||||
{% endblock %}
|
|
@ -1,15 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block header %}
|
||||
<h1>{% block title %}Log In{% endblock %}</h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
<label for="username">Username</label>
|
||||
<input name="username" id="username" required>
|
||||
<label for="password">Password</label>
|
||||
<input type="password" name="password" id="password" required>
|
||||
<input type="submit" value="Log In">
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -1,17 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block header %}
|
||||
<h1>{% block title %}Register{% endblock %}</h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
<label for="username">Username</label>
|
||||
<input name="username" id="username" required>
|
||||
<label for="password">Password</label>
|
||||
<input type="password" name="password" id="password" required>
|
||||
<label for="email">Email</label>
|
||||
<input type="email" name="email" id="email" required>
|
||||
<input type="submit" value="Register">
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -1,24 +0,0 @@
|
|||
<!doctype html>
|
||||
<title>{% block title %}{% endblock %} - contentmatcher </title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
<nav>
|
||||
<h1><a href="{{ url_for('menu.index') }}">contentmatcher</a></h1>
|
||||
<ul>
|
||||
{% if username %}
|
||||
<li><span>{{username}}</span>
|
||||
<li><a href="{{ url_for('auth.logout') }}">Log Out</a>
|
||||
{% else %}
|
||||
<li><a href="{{ url_for('auth.register') }}">Register</a>
|
||||
<li><a href="{{ url_for('auth.login') }}">Log In</a>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
<section class="content">
|
||||
<header>
|
||||
{% block header %}{% endblock %}
|
||||
</header>
|
||||
{% for message in get_flashed_messages() %}
|
||||
<div class="flash">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% block content %}{% endblock %}
|
||||
</section>
|
|
@ -0,0 +1,97 @@
|
|||
{% extends 'partials/base.html' %}
|
||||
|
||||
{% block name %}deck{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
<article>
|
||||
<header>
|
||||
<span>Download: <a href="{{ card['item_location'] }}">{{ card['title'] }}</a></span>
|
||||
</header>
|
||||
<main id="pdf-doc">
|
||||
</main>
|
||||
<footer>
|
||||
<form method="post">
|
||||
<input type="hidden" name="card_id" value="{{ card['id'] }}">
|
||||
<!-- <span id="buttonContainer" style="display: flex; justify-content: space-around;"> -->
|
||||
<span id="buttonContainer">
|
||||
<button type="submit" name="rate" value="Yes" accesskey="1">Yes</button> <!--ti keyi so alt+shit+key...-->
|
||||
<button type="submit" name="rate" value="Maybe" accesskey="2">Maybe</button>
|
||||
<button type="submit" name="rate" value="No" accesskey="3">No</button>
|
||||
<button type="submit" name="rate" value="Delete" accesskey="d">Delete</button>
|
||||
<button type="submit" name="share" value="Share" accesskey="s">Share</button>
|
||||
</span>
|
||||
</form>
|
||||
</footer>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/pdf.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/pdf.worker.js') }}"></script>
|
||||
<script type="text/javascript">
|
||||
document.addEventListener('DOMContentLoaded', function (){
|
||||
|
||||
var currPage = 1; //Pages are 1-based not 0-based
|
||||
var numPages = 0;
|
||||
var thePDF = null;
|
||||
|
||||
//This is where you start
|
||||
var doc = pdfjsLib.getDocument('{{ card["item_location"] }}');
|
||||
doc.promise.then(function(pdf) {
|
||||
//Set PDFJS global object (so we can easily access in our page functions
|
||||
thePDF = pdf;
|
||||
|
||||
//How many pages it has
|
||||
numPages = pdf.numPages;
|
||||
|
||||
//Start with first page
|
||||
pdf.getPage( 1 ).then( handlePages );
|
||||
});
|
||||
|
||||
function handlePages(page)
|
||||
{
|
||||
//This gives us the page's dimensions at full scale
|
||||
var scale = 1.5;
|
||||
var viewport = page.getViewport({ scale: scale, });
|
||||
|
||||
//We'll create a canvas for each page to draw it on
|
||||
var canvas = document.createElement( "canvas" );
|
||||
canvas.style.display = "block";
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
//Add it to the web page
|
||||
document.getElementById('pdf-doc').appendChild(canvas);
|
||||
|
||||
// Support HiDPI-screens.
|
||||
var outputScale = window.devicePixelRatio || 1;
|
||||
|
||||
canvas.width = Math.floor(viewport.width * outputScale);
|
||||
canvas.height = Math.floor(viewport.height * outputScale);
|
||||
canvas.style.width = "100%";
|
||||
canvas.style.height = Math.floor(canvas.style.width * viewport.width / viewport.height);
|
||||
|
||||
|
||||
var transform = outputScale !== 1
|
||||
? [outputScale, 0, 0, outputScale, 0, 0]
|
||||
: null;
|
||||
var renderContext = {
|
||||
canvasContext: context,
|
||||
viewport: viewport,
|
||||
transform: transform
|
||||
};
|
||||
|
||||
//Draw it on the canvas
|
||||
page.render(renderContext);
|
||||
|
||||
|
||||
//Move to next page
|
||||
currPage++;
|
||||
if ( thePDF !== null && currPage <= Math.min(numPages, 10) )
|
||||
{
|
||||
thePDF.getPage( currPage ).then( handlePages );
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
|
@ -1,95 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block header %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<article class="post">
|
||||
<header>
|
||||
<p>Download: <a href="{{ card['item_location'] }}">{{ card['title'] }}</a></p>
|
||||
</header>
|
||||
<div style="background-color: blue; height: fit-content;" id="pdf-doc"></div>
|
||||
</article>
|
||||
|
||||
<div style="position: fixed; bottom:0%; left:0%; width:100%">
|
||||
<form method="post" style="max-width: 960px; margin: auto; padding: 0 1rem 1rem;">
|
||||
<input type="hidden" name="card_id" value="{{ card['id'] }}">
|
||||
<span style="display: flex; justify-content: space-around;">
|
||||
<button style="background-color: #736B1E;" id="rbutton" type="submit" name="rate" value="Yes" accesskey="1">Yes</button> <!--ti keyi so alt+shit+key...-->
|
||||
<button style="background-color: #ED8008;" id="rbutton" type="submit" name="rate" value="Maybe" accesskey="2">Maybe</button>
|
||||
<button style="background-color: #ED3f1C;" id="rbutton" type="submit" name="rate" value="No" accesskey="3">No</button>
|
||||
<button style="background-color: #BF1B1B;" id="rbutton" type="submit" name="rate" value="Delete" accesskey="d">Delete</button>
|
||||
<button style="background-color: #D9D2C6;" type="submit" name="share" value="share" accesskey="s">Share</button>
|
||||
</span>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/pdf.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='js/pdf.worker.js') }}"></script>
|
||||
<script type="text/javascript">
|
||||
document.addEventListener('DOMContentLoaded', function (){
|
||||
|
||||
var currPage = 1; //Pages are 1-based not 0-based
|
||||
var numPages = 0;
|
||||
var thePDF = null;
|
||||
|
||||
//This is where you start
|
||||
var doc = pdfjsLib.getDocument('{{ card["item_location"] }}');
|
||||
doc.promise.then(function(pdf) {
|
||||
//Set PDFJS global object (so we can easily access in our page functions
|
||||
thePDF = pdf;
|
||||
|
||||
//How many pages it has
|
||||
numPages = pdf.numPages;
|
||||
|
||||
//Start with first page
|
||||
pdf.getPage( 1 ).then( handlePages );
|
||||
});
|
||||
|
||||
function handlePages(page)
|
||||
{
|
||||
//This gives us the page's dimensions at full scale
|
||||
var scale = 1.5;
|
||||
var viewport = page.getViewport({ scale: scale, });
|
||||
|
||||
//We'll create a canvas for each page to draw it on
|
||||
var canvas = document.createElement( "canvas" );
|
||||
canvas.style.display = "block";
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
//Add it to the web page
|
||||
document.getElementById('pdf-doc').appendChild(canvas);
|
||||
|
||||
// Support HiDPI-screens.
|
||||
var outputScale = window.devicePixelRatio || 1;
|
||||
|
||||
canvas.width = Math.floor(viewport.width * outputScale);
|
||||
canvas.height = Math.floor(viewport.height * outputScale);
|
||||
canvas.style.width = "100%";
|
||||
canvas.style.height = Math.floor(canvas.style.width * viewport.width / viewport.height);
|
||||
|
||||
|
||||
var transform = outputScale !== 1
|
||||
? [outputScale, 0, 0, outputScale, 0, 0]
|
||||
: null;
|
||||
var renderContext = {
|
||||
canvasContext: context,
|
||||
viewport: viewport,
|
||||
transform: transform
|
||||
};
|
||||
|
||||
//Draw it on the canvas
|
||||
page.render(renderContext);
|
||||
|
||||
|
||||
//Move to next page
|
||||
currPage++;
|
||||
if ( thePDF !== null && currPage <= Math.min(numPages, 10) )
|
||||
{
|
||||
thePDF.getPage( currPage ).then( handlePages );
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
|
@ -1,6 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Error: No cards foud</h1>
|
||||
<p>No cards were found in your collection. Consider <a href="{{ url_for('upload.index') }}">uploading</a> some.</p>
|
||||
{% endblock %}
|
|
@ -1,59 +1,40 @@
|
|||
{% extends 'base.html' %}
|
||||
{% extends 'partials/base.html' %}
|
||||
|
||||
{% block name %}instructions{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<h1>Instructions</h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
Contentmatcher is a <a href="https://gia.kompot.si/about.php">GIA</a> prototype that tries to help you engage with your content and share it with other users. It assumes that you have a heap of content that you would like to reconsider. This heap can take many forms such vast libraries of PDFs on your computer or a long lists of bookmarks.
|
||||
</p>
|
||||
<p>
|
||||
The app will help you get through this content step by step and continue to show you your content again based on the interest you express as well present you with shared content. If you and at least one more person express a high interest in an <strong>item</strong> a match will appear on your <a href="{{ url_for('matches.index') }}">matches</a> page. There you can send them an email to talk about the <strong>item</strong> your interested in.
|
||||
</p>
|
||||
<p>
|
||||
<h2>Some definitions:</h2>
|
||||
<ul>
|
||||
<li>
|
||||
An <strong>item</strong> is a unit of content (like a PDF you upload).
|
||||
</li>
|
||||
<li>
|
||||
<strong>Items</strong> are private by default but they can be shared.
|
||||
</li>
|
||||
<li>
|
||||
A <strong>collection</strong> made up of all your private items and the items shared with you.
|
||||
</li>
|
||||
<li>
|
||||
When you start a new session Contentmatcher will create a <strong>deck</strong>, which is a small part of the <strong>collection</strong>.
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
<main>
|
||||
<article>
|
||||
<p>Contentmatcher is a <a href="https://gia.kompot.si/about.php">GIA</a> prototype that tries to help you engage with your content and share it with other users. It assumes that you have a heap of content that you would like to reconsider. This heap can take many forms such vast libraries of PDFs on your computer or a long lists of bookmarks.</p>
|
||||
|
||||
<h2>Importing your content</h2>
|
||||
<p>
|
||||
For now the only way to import content is to <a href='{{ url_for('upload.index')}}'>upload</a> your PDFs. We're figuring out how to add different lists of links like browser bookmarks, liked tweets and "watch later" youtube videos.
|
||||
</p>
|
||||
<p>The app will help you get through this content step by step and continue to show you your content again based on the interest you express as well present you with shared content. If you and at least one more person express a high interest in an <em>item</em> a match will appear on your <a href="{{ url_for('matches.index') }}">matches</a> page. There you can send them an email to talk about the <em>item</em> your interested in.</p>
|
||||
|
||||
<h2>Sessions</h2>
|
||||
<p>
|
||||
Going through sessions is the main activity in using Contentmatcher.
|
||||
|
||||
A session consists of rating and potentially shareing items in a <strong>deck</strong>. You can adjust the size of your <strong>deck</strong> in the settings.
|
||||
<h2>Some definitions:</h2>
|
||||
|
||||
In sessions you rate <strong>items</strong> with <mark style="color: black; background-color: #736B1E;">yes</mark>, <mark style="color: black; background-color: #ED8008;">maybe</mark>, <mark style="color: black; background-color: #ED3f1C;">no</mark> and <mark style="color: black; background-color: #BF1B1B;">delete</mark> buttons. It's weird because there is no question, maybe think of a question like: "Are you really interested in this <strong>item</strong>?"
|
||||
</p>
|
||||
<p>
|
||||
There is also the <mark style="color: black; background-color: #D9D2C6;">share</mark> button. This will create a new <strong>item</strong> with this content for all other users, so it will appear in their decks from now on as well.
|
||||
</p>
|
||||
<ul>
|
||||
<li>An <em>item</em> is a unit of content (like a PDF you upload).</li>
|
||||
<li><em>Items</em> are private by default but they can be shared.</li>
|
||||
<li>A <em>collection</em> made up of all your private items and the items shared with you.</li>
|
||||
<li>When you start a new session Contentmatcher will create a <em>deck</em>, which is a small part of the <em>collection</em>.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Matches</h2>
|
||||
<p>
|
||||
If you and at least one other user rate an item with a <mark style="color: black; background-color: #736B1E;">yes</mark> then a match will appear on your <a href="{{ url_for('match') }}">matches</a> page. There you can send a email to talk.
|
||||
</p>
|
||||
<h2>Importing your content</h2>
|
||||
|
||||
<h2>Feedback</h2>
|
||||
<p>
|
||||
If you have any questions, feedback, ideas or if you would like contribute, please contact us at <a href="mailto:gia@kompot.si">gia@kompot.si</a>.
|
||||
</p>
|
||||
<p>For now the only way to import content is to <a href='{{ url_for('upload.index')}}'>upload</a> your PDFs. We're figuring out how to add different lists of links like browser bookmarks, liked tweets and "watch later" youtube videos.</p>
|
||||
|
||||
<h2>Sessions</h2>
|
||||
|
||||
<p>Going through sessions is the main activity in using Contentmatcher. A session consists of rating and potentially shareing items in a <em>deck</em>. You can adjust the size of your <em>deck</em> in the settings. In sessions you rate <em>items</em> with <em class="yes">yes</em>, <em class="maybe">maybe</em>, <em class="no">no</em> and <em class="delete">delete</em> buttons. It's weird because there is no question, maybe think of a question like: "Are you really interested in this <em>item</em>?"</p>
|
||||
|
||||
<p>There is also the <em class="share">share</em> button. This will create a new <em>item</em> with this content for all other users, so it will appear in their decks from now on as well.</p>
|
||||
|
||||
<h2>Matches</h2>
|
||||
|
||||
<p>If you and at least one other user rate an item with a <em class="yes">yes</em> then a match will appear on your <a href="{{ url_for('match') }}">matches</a> page. There you can send an email to talk.</p>
|
||||
|
||||
<h2>Feedback</h2>
|
||||
|
||||
<p>If you have any questions, feedback, ideas or if you would like contribute, please contact us at <a href="mailto:gia@kompot.si">gia@kompot.si</a>.</p>
|
||||
</article>
|
||||
</main>
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{% extends 'partials/base.html' %}
|
||||
|
||||
{% block name %}login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
<form method="post">
|
||||
<label for="username">username:</label>
|
||||
<input name="username" required>
|
||||
<label for="password">password:</label>
|
||||
<input type="password" name="password" required>
|
||||
<input type="submit" value="log in">
|
||||
</form>
|
||||
</main>
|
||||
{% endblock %}
|
|
@ -1,48 +1,29 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block header %}
|
||||
<head>Matches</head>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if list_of_matches %}
|
||||
<table>
|
||||
<style>
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
width: 90%;
|
||||
}
|
||||
table td {
|
||||
border: solid 1px #666;
|
||||
width: felx;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Users</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
{% for match in list_of_matches %}
|
||||
<TR>
|
||||
<TD>
|
||||
{{ match[0]['title'] }}
|
||||
</TD>
|
||||
<TD>
|
||||
{% for card in match %}
|
||||
{{ names_by_ids[card['owner_id']] }}
|
||||
{% endfor %}
|
||||
</TD>
|
||||
<TD>
|
||||
<a href="mailto:{% for card in match %}{{ emails_by_ids[card['owner_id']] }};{% endfor %}">send email</a>
|
||||
</TD>
|
||||
</TR>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% extends 'partials/base.html' %}
|
||||
|
||||
{% block name %}matches{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
{% if list_of_matches %}
|
||||
<table>
|
||||
{% for match in list_of_matches %}
|
||||
<TR>
|
||||
<TD>
|
||||
{{ match[0]['title'] }}
|
||||
</TD>
|
||||
<TD>
|
||||
{% for card in match %}
|
||||
{{ names_by_ids[card['owner_id']] }}
|
||||
{% endfor %}
|
||||
</TD>
|
||||
<TD>
|
||||
<a href="mailto:{% for card in match %}{{ emails_by_ids[card['owner_id']] }};{% endfor %}">send email</a>
|
||||
</TD>
|
||||
</TR>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>You have no matches at the moment</p>
|
||||
<p>You have no matches at the moment.</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
{% extends 'partials/base.html' %}
|
||||
|
||||
{% block name %}menu{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
<form method="post">
|
||||
{% if deck_status == "old" %}
|
||||
<button type="submit" name="menu" value="new_session">Continiue Session</button>
|
||||
{% else %}
|
||||
<button type="submit" name="menu" value="new_session">New Session</button>
|
||||
{% endif %}
|
||||
|
||||
<button type="submit" name="menu" value="matches">Matches</button>
|
||||
|
||||
<button type="submit" name="menu" value="upload">Upload</button>
|
||||
|
||||
<button type="submit" name="menu" value="settings">Settings</button>
|
||||
|
||||
<button type="submit" name="menu" value="instructions">Instructions</button>
|
||||
|
||||
<!-- <button type="submit" name="menu" value="about">About</button> -->
|
||||
</form>
|
||||
</main>
|
||||
{% endblock %}
|
|
@ -1,20 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block header %}
|
||||
<h1>Menu</h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
{% if deck_status == "old" %}
|
||||
<button type="submit" name="menu" value="new_session">Continiue Session</button> <br />
|
||||
{% else %}
|
||||
<button type="submit" name="menu" value="new_session">New Session</button> <br />
|
||||
{% endif %}
|
||||
<button type="submit" name="menu" value="matches">Matches</button> <br />
|
||||
<button type="submit" name="menu" value="upload">Upload</button> <br />
|
||||
<button type="submit" name="menu" value="settings">Settings</button> <br />
|
||||
<button type="submit" name="menu" value="instructions">Instructions</button> <br />
|
||||
<button type="submit" name="menu" value="about">About</button>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -1,66 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block header %}
|
||||
<head>
|
||||
<title>Drag and Drop File Upload</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
</body>
|
||||
<form id="form" method="post" enctype="multipart/form-data" action="/upload/uploader">
|
||||
<div class="drop-zone">
|
||||
<span id="zone-txt" class="drop-zone__prompt">Drop file here or click to upload</span>
|
||||
<input type="file" name="file" class="drop-zone__input" runat="server" accept=".pdf" multiple >
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
document.querySelectorAll(".drop-zone__input").forEach((inputElement) => {
|
||||
const dropZoneElement = inputElement.closest(".drop-zone");
|
||||
dropZoneElement.addEventListener("click", (e) => {
|
||||
inputElement.click();
|
||||
});
|
||||
|
||||
inputElement.addEventListener("change", (e) => {
|
||||
e.preventDefault();
|
||||
console.log(inputElement.files);
|
||||
if (inputElement.files.length) {
|
||||
console.log(inputElement)
|
||||
console.log("oddajam form", e);
|
||||
document.getElementById('zone-txt').innerHTML = "Uploading file...";
|
||||
document.getElementById("form").submit();
|
||||
}
|
||||
});
|
||||
|
||||
dropZoneElement.addEventListener("dragover", (e) => {
|
||||
e.preventDefault();
|
||||
dropZoneElement.classList.add("drop-zone--over");
|
||||
});
|
||||
|
||||
["dragleave", "dragend"].forEach((type) => {
|
||||
dropZoneElement.addEventListener(type, (e) => {
|
||||
dropZoneElement.classList.remove("drop-zone--over");
|
||||
});
|
||||
});
|
||||
|
||||
dropZoneElement.addEventListener("drop", (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (e.dataTransfer.files.length) {
|
||||
inputElement.files = e.dataTransfer.files;
|
||||
console.log("oddajam form", e);
|
||||
document.getElementById('zone-txt').innerHTML = "Uploading file...";
|
||||
document.getElementById("form").submit();
|
||||
}
|
||||
|
||||
dropZoneElement.classList.remove("drop-zone--over");
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
<body>
|
||||
{% endblock %}
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>contentmatcher</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
|
||||
<body id="{% block name %}{% endblock %}">
|
||||
{% block header %}
|
||||
{% include 'partials/header.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
{% include 'partials/footer.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% include 'partials/flash.html' %}
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,9 @@
|
|||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<ul class="flashes">
|
||||
{% for category, message in messages %}
|
||||
<li class="{{ category }}">{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endwith %}
|
|
@ -0,0 +1,3 @@
|
|||
<footer>
|
||||
<p>Contentmatcher is a <a href="https://gia.kompot.si/about.php">General Intelligence Agency of Ljubljana</a> prototype. You can find its code <a href="https://git.kompot.si/gia/contentmatcher">here</a>. Contentmatcher is hosted by <a href="https://kompot.si/wiki/doku.php">kompot</a>, a librehosters community from Ljubljana. If you have any questions, feedback or if you would like contribute, please contact us at <a href="mailto:gia@kompot.si">gia@kompot.si</a>.</p>
|
||||
</footer>
|
|
@ -0,0 +1,12 @@
|
|||
<header>
|
||||
<h1><a href="{{ url_for('menu.index') }}">contentmatcher</a></h1>
|
||||
<nav>
|
||||
{% if username %}
|
||||
<span>logged in as <em>{{username}}</em></span>
|
||||
<a href="{{ url_for('auth.logout') }}">log out</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('auth.register') }}">register</a>
|
||||
<a href="{{ url_for('auth.login') }}">log in</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
</header>
|
|
@ -0,0 +1,11 @@
|
|||
<nav>
|
||||
{% if username %}
|
||||
<span>logged in as <em>{{username}}</em></span>
|
||||
|
||||
<a href="{{ url_for('auth.logout') }}">Log Out</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('auth.register') }}">Register</a>
|
||||
|
||||
<a href="{{ url_for('auth.login') }}">Log In</a>
|
||||
{% endif %}
|
||||
</nav>
|
|
@ -0,0 +1,17 @@
|
|||
{% extends 'partials/base.html' %}
|
||||
|
||||
{% block name %}register{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
<form method="post">
|
||||
<label for="username">username:</label>
|
||||
<input name="username" required>
|
||||
<label for="password">password:</label>
|
||||
<input type="password" name="password" required>
|
||||
<label for="email">email:</label>
|
||||
<input type="email" name="email" required>
|
||||
<input type="submit" value="register">
|
||||
</form>
|
||||
</main>
|
||||
{% endblock %}
|
|
@ -1,10 +1,9 @@
|
|||
{% extends 'base.html' %}
|
||||
quantity
|
||||
{% block header %}
|
||||
<head>Settings</head>
|
||||
{% endblock %}
|
||||
{% extends 'partials/base.html' %}
|
||||
|
||||
{% block name %}settings{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
<form method="post" action={{ url_for('settings.save_settings') }}>
|
||||
<label for="quantity">Maximum new cards per session</label>
|
||||
<input type="number" id="quantity" name="max_new" value= '{{ settings['max_new'] }}' min="0" required="required">
|
||||
|
@ -17,4 +16,5 @@ quantity
|
|||
-->
|
||||
<input type="submit" value="Save">
|
||||
</form>
|
||||
{% endblock %}
|
||||
</main>
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
{% extends 'partials/base.html' %}
|
||||
|
||||
{% block name %}upload{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
<form class="dropzone dropzone-form" method="post" enctype="multipart/form-data" action="/upload/uploader">
|
||||
<span id="dropzone-txt" class="dropzone-txt">Drop file here or click to upload.</span>
|
||||
<input class="dropzone-input" type="file" name="file" runat="server" accept=".pdf" multiple >
|
||||
</form>
|
||||
</main>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/dropzone.js') }}"></script>
|
||||
{% endblock %}
|
|
@ -23,7 +23,7 @@ nc.login(CONFIG['NC_USER'],CONFIG['NC_PASSWORD'])
|
|||
@bp.route("/", methods=["GET", "POST"])
|
||||
def index():
|
||||
username = session["username"]
|
||||
return render_template("menu/upload.html", username=username)
|
||||
return render_template("upload.html", username=username)
|
||||
|
||||
|
||||
@bp.route('/uploader', methods = ('GET', 'POST'))
|
||||
|
@ -40,7 +40,7 @@ def upload_file():
|
|||
# Is there really a file?
|
||||
if not filename:
|
||||
flash('There is no file. Try again?')
|
||||
return render_template("menu/upload.html", username=username)
|
||||
return render_template("upload.html", username=username)
|
||||
|
||||
#prevent duplicate filenames
|
||||
print(filename)
|
||||
|
@ -69,9 +69,9 @@ def upload_file():
|
|||
dbsession.close()
|
||||
else:
|
||||
flash("Please insert a PDF file, support for other formats comming soon...")
|
||||
#return render_template("menu/upload.html", user_id=user_id, username=username)
|
||||
#return render_template("upload.html", user_id=user_id, username=username)
|
||||
|
||||
os.remove(path)
|
||||
|
||||
|
||||
return render_template("menu/upload.html", user_id=user_id, username=username)
|
||||
return render_template("upload.html", user_id=user_id, username=username)
|
||||
|
|
Loading…
Reference in New Issue