Compare commits

..

5 Commits

Author SHA1 Message Date
Alex 608981eadc new READ 3 years ago
Alex 12d0848290 server install requirements 3 years ago
Alex 8148674fad new requirements 3 years ago
Alex e171ab6247 new requirements 3 years ago
Alex 27376f4a88 run on sqlite and be more stable 3 years ago

1
.gitignore vendored

@ -9,3 +9,4 @@ pyrqlite/
whoosh/ whoosh/
sqlalchemy-rqlite/ sqlalchemy-rqlite/
rqlite* rqlite*
venv/

@ -1,38 +1,49 @@
# XPUB Library # XPPL version alt
Library running on Flask and SQLight (maybe to be replaced with a python shelve) Library to hold books / knowledge
## Installation ## TO DOs
- [x] fix adding stacks
- [x] update requirements
- [ ] generate new requirements.txt and installation process?
- [ ] fix stacks layout
- [ ] remove autocomplete? and training at the start of app
- [ ] update layout navigation
Install the required dependencies:
$ pip3 install -r requirements.txt
## Installation
Initialise database sudo apt install python3-virtualenv
sudo virtualenv venv
source venv/bin/activate
$ bash init_db.sh sudo chmod -R 777 XPPL/
pip3 install flask
pip3 install flask_sqlalchemy
pip3 install marshmallow
pip3 install flask_socketio
pip3 install python-dotenv
pip3 install flask_weasyprint
pip3 install flask_wtf
pip3 install wand
pip3 install PyPDF2
pip3 install requests
pip3 install autocomplete
### Install rqlite sudo apt-get install libpangocairo-1.0-0
sudo apt-get install libmagickwand-dev
#### Linux bash init_db.sh
To download and start rqlite on Linux, execute the following in a shell.
curl -L https://github.com/rqlite/rqlite/releases/download/v4.3.0/rqlite-v4.3.0-linux-amd64.tar.gz -o rqlite-v4.3.0-linux-amd64.tar.gz
tar xvfz rqlite-v4.3.0-linux-amd64.tar.gz
cd rqlite-v4.3.0-linux-amd64
./rqlited ~/node.1
Install the required dependencies:
#### OSX $ pip3 install -r requirements.txt
To download and start rqlite on OSX, execute the following in a shell.
curl -L https://github.com/rqlite/rqlite/releases/download/v4.3.0/rqlite-v4.3.0-darwin-amd64.tar.gz -o rqlite-v4.3.0-darwin-amd64.tar.gz
tar xvfz rqlite-v4.3.0-darwin-amd64.tar.gz
cd rqlite-v4.3.0-darwin-amd64
./rqlited ~/node.1
Initialise database / Why is this needed again, could be checked in flask?
$ bash init_db.sh
### Further install notes (bugs) ### Further install notes (bugs)
@ -40,36 +51,23 @@ cd rqlite-v4.3.0-darwin-amd64
* create the covers folder inside the uploadsfolder * create the covers folder inside the uploadsfolder
* don't forget to chmod the uploads and coverfolder ;-) * don't forget to chmod the uploads and coverfolder ;-)
* For Mac users -> brew install imagemagick@6 in order to install wand * For Mac users -> brew install imagemagick@6 in order to install wand (should not be relevant for debian server install)
For those on mac and using homebrew, it seems like Wand doesn't support imagemagick 7 yet as mentioned in other answers.
There's a new brew formula for Imagemagick 6 which can be used to install the older version in the meanwhile:
`brew install imagemagick@6`
Create a symlink to this newly installed dylib file as mentioned in other answer to get things working.
ln -s /usr/local/Cellar/imagemagick@6/<your specific 6 version>/lib/libMagickWand-6.Q16.dylib /usr/local/lib/libMagickWand.dylib
## Run the program ## Run the program
Initialize rqlite database on one terminal (from rqlite install directory)
$ ./rqlited ~.node
Run the script in another terminal (from XPPL directory): Run the script in another terminal (from XPPL directory):
python3 run.py python3 run.py
## Deploy on server
(this will be added soon)
## API ## REST API
Has currently 2 entrypoints: Has currently 2 entrypoints:

@ -23,11 +23,11 @@ app = Flask(__name__)
app.config['SECRET_KEY'] = 'super secret key' app.config['SECRET_KEY'] = 'super secret key'
#app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/mydatabase.db' #app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/mydatabase.db'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['SQLALCHEMY_DATABASE_URI'] = 'rqlite+pyrqlite://localhost:4001/' #app.config['SQLALCHEMY_DATABASE_URI'] = 'rqlite+pyrqlite://localhost:4001/'
app.config['DEBUG'] = True app.config['DEBUG'] = True
app.config['PORT'] = 80 app.config['PORT'] = 80
#app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'mydatabase.db') app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'mydatabase.db')
db = SQLAlchemy(app) db = SQLAlchemy(app)
light = not os.path.isdir(UPLOAD_FOLDER) light = not os.path.isdir(UPLOAD_FOLDER)
DOMAIN = environ.get('DOMAIN') DOMAIN = environ.get('DOMAIN')

@ -5,7 +5,7 @@ from wtforms import FieldList
from wtforms import Form as NoCsrfForm from wtforms import Form as NoCsrfForm
from wtforms.fields import StringField, FormField, SubmitField, SelectField, RadioField from wtforms.fields import StringField, FormField, SubmitField, SelectField, RadioField
from app.models import Book, BookSchema, Author, Stack, StackSchema from app.models import Book, BookSchema, Author, Stack, StackSchema
from wtforms.fields.html5 import DecimalRangeField from wtforms.fields import DecimalRangeField
# - - - Forms - - - # - - - Forms - - -
@ -80,6 +80,6 @@ class SearchForm(FlaskForm):
('Outliers', 'Outliers')] ('Outliers', 'Outliers')]
select = SelectField('', choices=choices, default='All') select = SelectField('', choices=choices, default='All')
search = StringField('', validators=[InputRequired()]) search = StringField('', validators=[InputRequired()])
grid = SubmitField('Grid') # grid = SubmitField('Grid')
listview = SubmitField('List') # listview = SubmitField('List')
randomize = SubmitField('Order differently') randomize = SubmitField('Order differently')

@ -1,8 +1,7 @@
from app import db from app import db
from marshmallow import Schema, fields, ValidationError, pre_load from marshmallow import Schema, fields, ValidationError, pre_load
import datetime import datetime
from sqlalchemy import Column, Integer, DateTime from sqlalchemy import Column, DateTime
import flask_whooshalchemyplus
authors = db.Table('books_authors', authors = db.Table('books_authors',

@ -1,22 +1,23 @@
@import url("../fonts/fonts_style.css"); @import url("../fonts/fonts_style.css");
*{ *{
font-family: "Archivo Narrow"; font-family: "Archivo Narrow", Helvetica, sans-serif;
}
body{
background-color: #f1f1f1;
} }
p{ p{
font-size: 20px; font-size: 20px;
} }
a{ a{
text-decoration: underline; text-decoration: underline;
color: black; color: black;
} }
a:hover{
a:hover{
text-decoration: underline; text-decoration: underline;
color: #0000FF; color: #0000FF;
} }
@ -291,7 +292,8 @@ font-size: 12px;
left:0; left:0;
position: fixed; position: fixed;
font-size: 18px; font-size: 18px;
background-color: yellow; background-color: rgb(0, 3, 170);
color: white;
} }
#annotindication{ #annotindication{

@ -50,7 +50,8 @@
<script type="text/javascript" src="{{ url_for("static", filename="js/jquery.tablesorter.js") }}"></script> <script type="text/javascript" src="{{ url_for("static", filename="js/jquery.tablesorter.js") }}"></script>
<script src="{{ url_for("static", filename="js/app.js") }}"></script> <script src="{{ url_for("static", filename="js/app.js") }}"></script>
<script src="{{ url_for("static", filename="js/vendor/socket.io.slim.js") }}"></script> <!-- <script src="{{ url_for("static", filename="js/vendor/socket.io.slim.js") }}"></script> -->
<script src="https://cdn.socket.io/4.4.0/socket.io.min.js" integrity="sha384-1fOn6VtTq3PWwfsOrk45LnYcGosJwzMHv+Xh/Jx5303FVOXzEnw0EpLv30mtjmlj" crossorigin="anonymous"></script>
<script src="{{ url_for("static", filename="js/vendor/vue.min.js") }}"></script> <script src="{{ url_for("static", filename="js/vendor/vue.min.js") }}"></script>
<script> <script>

@ -2,13 +2,14 @@
<ul> <ul>
<li><a href="{{ url_for('home') }}">Home</a></li> <li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="{{ url_for('show_books') }}">Catalogue</a></li> <li><a href="{{ url_for('show_books') }}">Catalogue</a></li>
<li><a href="{{ url_for('show_stacks') }}">Stacks</a></li>
{%if light%} {%if light%}
{%else%} {%else%}
<li><a href="{{ url_for('add_book') }}">Add Book</a></li> <li><a href="{{ url_for('add_book') }}">Add Book</a></li>
<li><a href="{{ url_for('show_stacks') }}">Stacks</a></li>
<li><a href="{{ url_for ('add_stack') }}">Add Stack</a></li> <li><a href="{{ url_for ('add_stack') }}">Add Stack</a></li>
{%endif%} {%endif%}
<li><a href="{{ url_for('annotations') }}">Annotations</a></li> <!-- <li><a href="{{ url_for('annotations') }}">Annotations</a></li> -->
<li><a href="{{ url_for('about') }}">About</a></li> <li><a href="{{ url_for('about') }}">About</a></li>
{%if light%} {%if light%}
{%else%} {%else%}

@ -40,7 +40,7 @@ fill: yellow;
<body> <body>
<script> <script>
console.log("hello");
// d3.json("/api/books").then(function(data){ // d3.json("/api/books").then(function(data){
// console.log("loaded"); // console.log("loaded");
// console.log(data) // console.log(data)

@ -8,10 +8,8 @@
<div>{{ form.select(style="width: 100px; margin: 10px; float: left; font-size: 20px") }}</div> <div>{{ form.select(style="width: 100px; margin: 10px; float: left; font-size: 20px") }}</div>
<div class="search"> <div class="search">
{{ render_field(form.search) }} </div> {{ render_field(form.search) }} </div>
<button type="submit" @click="sendMessage" class="button is-info" >browse</button> <button type="submit" @click="sendMessage" class="button is-info" >find</button>
<p><br> <p><br>
{{ form.grid(style="font-size:20px")}}{{ form.listview(style="font-size:20px")}}</p>
</form> </form>
<h1 class="page-header">All Books</h1> <h1 class="page-header">All Books</h1>

@ -33,7 +33,7 @@ import sys
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
# import sqlite3 # import sqlite3
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'epub', 'chm', 'mobi']) ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'epub', 'chm', 'mobi', "png", "mp3"])
author_schema = AuthorSchema() author_schema = AuthorSchema()
authors_schema = AuthorSchema(many=True) authors_schema = AuthorSchema(many=True)
@ -123,17 +123,6 @@ def annotations_pdf():
html = render_template(('annotations.html'), annot=annot, light=light) html = render_template(('annotations.html'), annot=annot, light=light)
return render_pdf(HTML(string=html)) return render_pdf(HTML(string=html))
# @app.route('/myannotations.pdf')
# def myannotations_pdf():
# books = db.session.query(Book).all()
# name=str(request.args.get('query'))
# annot = get_annotations()
# res = get_annot_results(annot,name)
# # Make a PDF straight from HTML in a string.
# html = render_template('results_annot.html', name=name, annot=annot, res=res, books=books)
# return render_pdf(HTML(string=html))
@app.route('/viewpdf/<filename>') @app.route('/viewpdf/<filename>')
def viewtestfile1_file(filename): def viewtestfile1_file(filename):
return redirect("/static/viewer/web/viewer.html?file=%2Fuploads%2F"+urlquote(filename)) return redirect("/static/viewer/web/viewer.html?file=%2Fuploads%2F"+urlquote(filename))
@ -446,6 +435,8 @@ def edit_author_by_id(id):
@app.route('/stacks') @app.route('/stacks')
def show_stacks(): def show_stacks():
stacks = db.session.query(Stack).all() stacks = db.session.query(Stack).all()
print("stacks looooooook")
print(stacks)
return render_template('show_stacks.html', stacks=stacks, light=light) return render_template('show_stacks.html', stacks=stacks, light=light)
@app.route('/stacks/add_stack', methods=['POST', 'GET']) @app.route('/stacks/add_stack', methods=['POST', 'GET'])
@ -462,6 +453,7 @@ def add_stack():
if form.stack_name.data: if form.stack_name.data:
stack = Stack(stack_name, stack_description, stack_author) stack = Stack(stack_name, stack_description, stack_author)
db.session.add(stack) db.session.add(stack)
db.session.commit()
stacks = db.session.query(Stack).all() stacks = db.session.query(Stack).all()
return redirect(url_for('show_stacks')) return redirect(url_for('show_stacks'))
flash("%s stack created" % (stack_name)) flash("%s stack created" % (stack_name))
@ -561,15 +553,15 @@ def show_books():
view.append('1') view.append('1')
viewby = '1' viewby = '1'
if search.grid.data: # if search.grid.data:
viewby = '2' # viewby = '2'
view.append('2') # view.append('2')
return render_template ('show_books_grid.html', books=books, form=search, light=light) # return render_template ('show_books_grid.html', books=books, form=search, light=light)
if search.listview.data: # if search.listview.data:
viewby = '1' # viewby = '1'
view.append('1') # view.append('1')
return render_template ('show_books.html', books=books, form=search, light=light) # return render_template ('show_books.html', books=books, form=search, light=light)
if request.method == 'POST': if request.method == 'POST':
newmsg = 'searched for: ' + search.search.data newmsg = 'searched for: ' + search.search.data

@ -1,26 +1,41 @@
appdirs==1.4.0
click==6.7
Flask==0.12
Flask-SQLAlchemy==2.1
Flask-WTF==0.14.2
gunicorn==19.6.0
itsdangerous==0.24
Jinja2==2.9.4
MarkupSafe==0.23
packaging==16.8
pyparsing==2.1.10
six==1.10.0
SQLAlchemy==1.1.5
Werkzeug==0.11.15
WTForms==2.1
flask-marshmallow==0.9.0
Wand==0.4.4
PyPDF2==1.26.0
flask-socketio==2.9.2
flask-whooshalchemyplus==0.7.5
python-dotenv==0.7.1
autocomplete==0.0.104 autocomplete==0.0.104
git+https://github.com/rqlite/pyrqlite.git bidict==0.21.4
git+https://github.com/rqlite/sqlalchemy-rqlite.git bottle==0.12.19
git+https://github.com/Kozea/Flask-WeasyPrint.git Brotli==1.0.9
requests=2.20.1 certifi==2021.10.8
cffi==1.15.0
charset-normalizer==2.0.8
click==8.0.3
cssselect2==0.4.1
Flask==2.0.2
Flask-SocketIO==5.1.1
Flask-SQLAlchemy==2.5.1
Flask-WeasyPrint==0.6
Flask-WTF==1.0.0
fonttools==4.28.2
greenlet==1.1.2
html5lib==1.1
idna==3.3
itsdangerous==2.0.1
Jinja2==3.0.3
MarkupSafe==2.0.1
marshmallow==3.14.1
Pillow==8.4.0
pycparser==2.21
pydyf==0.1.2
PyPDF2==1.26.0
pyphen==0.11.0
python-dotenv==0.19.2
python-engineio==4.3.0
python-socketio==5.5.0
requests==2.26.0
six==1.16.0
SQLAlchemy==1.4.27
tinycss2==1.1.1
urllib3==1.26.7
Wand==0.6.7
weasyprint==53.4
webencodings==0.5.1
Werkzeug==2.0.2
WTForms==3.0.0
zopfli==0.1.9

Loading…
Cancel
Save