Compare commits

...

5 Commits

  1. 52
      Dockerfile
  2. 9
      MANIFEST.in
  3. 2
      README.md
  4. 0
      asl_rulebook2/extract/__init__.py
  5. 1
      asl_rulebook2/webapp/data/doc
  6. 3
      asl_rulebook2/webapp/data/doc.txt
  7. 15
      asl_rulebook2/webapp/doc.py
  8. 2
      asl_rulebook2/webapp/run_server.py
  9. 24
      asl_rulebook2/webapp/search.py
  10. 1
      asl_rulebook2/webapp/static/css/prepare.css
  11. 10
      asl_rulebook2/webapp/static/prepare.js
  12. 8
      asl_rulebook2/webapp/tests/test_annotations.py
  13. 6
      asl_rulebook2/webapp/tests/test_linkify_ruleids.py
  14. 2
      asl_rulebook2/webapp/tests/test_sr_filters.py
  15. BIN
      doc/features/images/download.png
  16. 17
      doc/features/index.html
  17. 3
      setup.py

@ -1,49 +1,39 @@
# NOTE: Use the run-container.sh script to build and launch this container.
# NOTE: Multi-stage builds require Docker >= 17.05.
FROM centos:8 AS base
# update packages
RUN dnf -y upgrade-minimal
# update packages and install requirements
RUN dnf -y upgrade-minimal && \
dnf install -y python38 && \
dnf install -y ghostscript && \
dnf clean all
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FROM base AS build
# install Python
# NOTE: The version of Python we want is newer than what's in Centos 8,
# so we have to install from source :-/
RUN dnf -y groupinstall "Development Tools" && \
dnf -y install openssl-devel bzip2-devel libffi-devel sqlite-devel
RUN cd /tmp && \
dnf -y install wget && \
wget https://www.python.org/ftp/python/3.8.7/Python-3.8.7.tgz && \
tar xvf Python-3.8.7.tgz && \
cd Python-3.8.7/ && \
./configure --enable-optimizations && \
make install
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FROM base
# copy the Python installation from the build image
COPY --from=build /usr/local/bin/python3.8 /usr/local/bin/python3.8
COPY --from=build /usr/local/lib/python3.8 /usr/local/lib/python3.8
COPY --from=build /usr/local/bin/pip3 /usr/local/bin/pip3
RUN ln -s /usr/local/bin/python3.8 /usr/local/bin/python3
# install requirements
RUN dnf -y install ghostscript && \
dnf clean all
# set up a virtualenv
RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
RUN pip install --upgrade pip
# install the application requirements
COPY requirements.txt requirements-dev.txt ./
RUN pip3 install -r requirements.txt
COPY requirements.txt requirements-dev.txt /tmp/
RUN pip3 install -r /tmp/requirements.txt
ARG CONTROL_TESTS_PORT
RUN if [ -n "$CONTROL_TESTS_PORT" ]; then \
pip3 install -r requirements-dev.txt \
pip3 install -r /tmp/requirements-dev.txt \
; fi
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FROM base
# copy the virtualenv from the build image
COPY --from=build /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# install the application
WORKDIR /app
COPY asl_rulebook2/ ./asl_rulebook2/

@ -0,0 +1,9 @@
recursive-include asl_rulebook2/webapp/config *.*
recursive-include asl_rulebook2/webapp/data *.*
recursive-include asl_rulebook2/webapp/static *.*
recursive-include asl_rulebook2/webapp/templates *.*
recursive-include asl_rulebook2/extract/data *.*
recursive-include asl_rulebook2/webapp/tests/fixtures *.*
recursive-include asl_rulebook2/bin *.*

@ -3,7 +3,7 @@
<img align="right" src="doc/features/images/asl-rulebook2.small.png">
This program lets you search through the ASL Rulebook index, and jump directly to the rules you're looking for.
Click [here](doc/features/) for more details.
Click [here](https://htmlpreview.github.io/?https://github.com/pacman-ghost/asl-rulebook2/blob/master/doc/features/index.html) for more details.
<br clear="all">
With [some work](doc/extend.md), you can also:

@ -0,0 +1,3 @@
The doc/ symlink is to allow documents in the root doc/ directory to be served, even if this package has been installed in non-editable mode (i.e. into site-packages).
See get_doc() for more details.

@ -16,10 +16,19 @@ def get_doc( path ):
"""Return the specified documentation file."""
# locate the documentation file
doc_dir = os.path.join( os.path.dirname( __file__ ), "../../doc/" )
fname = safe_join( doc_dir, path )
dname = os.path.join( os.path.dirname( __file__ ), "../../doc/" )
fname = safe_join( dname, path )
if not os.path.isfile( fname ):
abort( 404 )
# FUDGE! If this package has been installed in non-editable mode (i.e. into site-packages, while it's possible
# to get the root doc/ directory included in the installation (by adding a __init__.py file :-/, then including
# it in MANIFEST.in), it ends up in asl-rulebook2's parent directory (i.e. the main site-packages directory),
# which is definitely not what we want.
# We work-around this my creating a symlink to the doc/ directory, which will get followed when the package
# is installed. This won't work on Windows, but we'll do the necessary penance, and just live with it... :-/
dname = os.path.join( os.path.dirname( __file__ ), "data/doc/" )
fname = safe_join( dname, path )
if not os.path.isfile( fname ):
abort( 404 )
# check if the file is Markdown
if os.path.splitext( path )[1] == ".md":

@ -20,7 +20,7 @@ from asl_rulebook2.webapp import app, globvars
@click.option( "--force-init-delay", default=0, help="Force the webapp to initialize (#seconds delay)." )
@click.option( "--debug","flask_debug", is_flag=True, default=False, help="Run Flask in debug mode." )
def main( bind_addr, data_dir, force_init_delay, flask_debug ):
"""Run the webapp server."""
"""Run the asl-rulebook2 webapp server."""
# initialize
flask_port = None

@ -381,15 +381,16 @@ def _adjust_sort_order( results ):
"""Adjust the sort order of the search results."""
results2 = []
def extract_sr( func ):
def extract_sr( func, force=False ):
# move results that pass the filter function to the new list
i = 0
while True:
if i >= len(results):
break
# NOTE: We never prefer small entries (i.e .have no ruleref's)
# e.g. those that only contain a "see also".
if func( results[i] ) and len(results[i].get("rulerefs",[])) > 0:
# NOTE: We don't want to prefer useless entries e.g. those that only contain a "see also".
nruleids = len( results[i].get( "ruleids", [] ) )
nrulerefs = len( results[i].get( "rulerefs", [] ) )
if func( results[i] ) and ( force or nruleids > 0 or nrulerefs > 0 ):
results2.append( results[i] )
del results[i]
else:
@ -415,6 +416,21 @@ def _adjust_sort_order( results ):
extract_sr(
lambda sr: _BEGIN_HIGHLIGHT in get(sr,"subtitle")
)
# prefer user annotations
extract_sr(
lambda sr: get(sr,"sr_type") == "user-anno",
force = True
)
# prefer errata
extract_sr(
lambda sr: get(sr,"sr_type") == "errata",
force = True
)
# prefer rules
extract_sr(
lambda sr: get(sr,"sr_type") == "index",
force = True
)
# include any remaining search results
results2.extend( results )

@ -33,6 +33,7 @@ code { display: block ; margin: 5px 0 5px 20px ; }
padding: 10px ;
background: #f0f0f0 ;
font-size: 80% ; font-style: italic ; text-align: center ;
transition: opacity 5s ;
}
#download-panel {

@ -185,13 +185,15 @@ gPrepareApp.component( "progress-panel", {
data() { return {
socketIOClient: null,
statusBlocks: [],
isDone: false,
isDone: false, isError: false
} ; },
// FUDGE! Opening the PDF is synchronous, which makes the webserver unresponsive while it's happening,
// so we delay showing the "features" link to the user until we get past that point.
template: `
<div id="progress-panel">
<status-block v-for="sb in statusBlocks" :statusBlock=sb :key=sb />
<div v-if="!isDone" class="loading">
<div v-if="!isDone && !isError" :style="{ opacity: statusBlocks.length >= 3 ? 1 : 0 }" class="loading">
<img src="/static/images/loading.gif" />
<div style="margin-top:3px;">
While you're waiting, you can <br> check out the features <a href="/doc/features/index.html" target="_blank">here</a>.
@ -211,8 +213,10 @@ gPrepareApp.component( "progress-panel", {
// initialize the socketio client
this.socketIOClient = io.connect() ; //eslint-disable-line no-undef
this.socketIOClient.on( "disconnect", () => {
if ( ! this.isDone )
if ( ! this.isDone ) {
this.$emit( "fatal", "The server has gone away. Please restart it, then reload this page." ) ;
this.isError = true ;
}
} ) ;
this.socketIOClient.on( "status", (msg) => { this.addStatusBlock( msg ) ; } ) ;
this.socketIOClient.on( "progress", (msg) => { this.addProgressMsg( "info", msg ) ; } ) ;

@ -15,20 +15,20 @@ def test_full_errata( webapp, webdriver ):
check_sr_filters( [ "index", "errata" ] )
# bring up the errata and check it in the search results
results = do_search( "test" )
results = do_search( "erratum" )
expected = {
"sr_type": "anno",
"caption": "E1",
"icon": "errata.png",
"content": "This is a ((test)) erratum.",
"content": "This is a test ((erratum)).",
"source": "Test Fixture"
}
assert len(results) == 2
assert len(results) == 1
result = results[0]
assert result == expected
# bring up the errata in the rule info popup and check it there
find_child( "#search-results .ruleid a" ).click()
find_child( "#search-results .auto-ruleid" ).click()
anno = _unload_rule_info_anno()
expected = {
"caption": "E1",

@ -85,9 +85,9 @@ def test_errata( webdriver, webapp ):
init_webapp( webapp, webdriver )
# test ruleid's in an errata's search result
results = _do_search( "errata", True )
results = _do_search( "errata", False )
assert len(results) == 2
sr_elem = find_children( "#search-results .sr" )[ 1 ]
sr_elem = find_children( "#search-results .sr" )[ 0 ]
_check_ruleid( find_child(".caption",sr_elem), ("asl-rulebook!","A3.8") )
_dismiss_rule_info_popup()
_check_ruleid( find_child(".content",sr_elem), ("asl-rulebook!","A.2") )
@ -98,7 +98,7 @@ def test_errata( webdriver, webapp ):
( ".content", ("asl-rulebook!","A.2") )
]
for sel, target in expected:
_do_search( "errata", False )
_do_search( "errata attached", False )
sr_elem = find_child( "#rule-info .rule-info" )
_check_ruleid( find_child(sel,sr_elem), target )
_dismiss_rule_info_popup()

@ -73,8 +73,8 @@ def test_sr_filtering( webdriver, webapp ):
# test filtering errata search results
do_test( "errata", "errata", [
{ "sr_type": "index", "title": "CCPh" },
{ "sr_type": "anno", "caption": "A3.8" },
{ "sr_type": "index", "title": "CCPh" },
] )
# test filtering ASOP search results

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@ -1,12 +1,9 @@
<!DOCTYPE html>
<!-- IMPORTANT! This needs to be on the gh-pages branch to be viewable as HTML! :-/
FIXME! Or we might be able to do in the repo's Settings.
-->
<html lang="en">
<head>
<meta charset="utf-8">
<title> ASL Rulebook 2 features </title>
<title> ASL Rulebook 2 </title>
<link rel="stylesheet" type="text/css" href="imageZoom/jquery.imageZoom.css" />
<link rel="stylesheet" type="text/css" href="global.css" />
</head>
@ -14,7 +11,9 @@
<body>
<p> <img src="images/search-heat.png" class="imageZoom" style="float:right;width:40%;margin-left:1em;">
<h2> Basic features </h2>
<h2> ASL Rulebook 2
<a href="https://github.com/pacman-ghost/asl-rulebook2/releases" target="_blank"><img src="images/download.png" style="height:0.75em;"></a>
</h2>
<p> Out-of-the-box, this program gives you full-text search over the ASLRB index.
<p> It will jump to the exact position in the eASLRB PDF for a rule when you click on a search result.
<p> And if the rule has any associated footnotes, these will be shown in a popup.
@ -26,7 +25,7 @@
<p> <img src="images/search-cellar.png" class="imageZoom" style="float:right;width:40%;margin-left:1em;">
<h2> Adding rules for other modules </h2>
<h3> Adding rules for other modules </h3>
<p> Once you've got the program up and running, you can then think about extending it. It's a lot of work, but the results are insanely cool!
<p> To the right, I've searched for <em>"cellar"</em>, and the program has found results from <em>Red Barricades</em>. The rules for this are referenced in the ASLRB index, but the content is not yet in the MMP eASLRB.
<p> However, I've installed a PDF scan of the rules, plus information about where each rule is within that PDF (a <em>"targets file"</em>), and so when I click on a search result, it seamlessly opens the <em>Red Barricades</em> PDF and jumps to that rule.
@ -43,7 +42,7 @@ You can also include third-party modules that are not referenced in the ASLRB in
<p> <img src="images/ruleinfo-encircled.png" class="imageZoom" style="float:right;width:30%;margin-left:1em;">
<h2> Showing Q+A and errata </h2>
<h3> Showing Q+A and errata </h3>
Q+A and errata can also be included. This is a <em>lot</em> of work, but the results are amazing. If you click on a rule that has Q+A and/or errata associated with it, they will be shown, alongside the rule you're looking for.
<p> Here, I've searched for <em>"encircled"</em>, and the program has automatically shown Q+A and errata for rule <span class="ruleid">A7.7</span>.
<div class="info"> Note that this errata is actually obsolete, since it's already been incorporated into the current MMP eASLRB, but it's shown here as an example. </div>
@ -56,14 +55,14 @@ Going back to the search results, you can see these Q+A entries included in ther
<p> <img src="images/user-anno.png" class="imageZoom" style="float:left;width:30%;margin-right:1em;">
<h2> User annotations </h2>
<h3> User annotations </h3>
You can also add your own notes to the search engine.
<p> Here, I've added a note about what <em>Majority Squad Type</em> means, and a link back to the Game Squad post that talks about it.
<br clear="all">
<p> <img src="images/asop.png" class="imageZoom" style="float:right;width:40%;margin-left:1em;">
<h2> Advanced Sequence Of Play </h2>
<h3> Advanced Sequence Of Play </h3>
Finally, the ASOP can also be included, with clickable links to each of the referenced rules.
<p> ASOP entries are also included in search results: <br>
<img src="images/asop-sr.png" class="imageZoom" style="margin:1em 0 0 2em;width:30%;">

@ -40,4 +40,7 @@ setup(
data_files = [
( "asl-rulebook2", ["LICENSE.txt"] ),
],
entry_points = {
"console_scripts": "asl-rulebook2 = asl_rulebook2.webapp.run_server:main",
}
)

Loading…
Cancel
Save