Allow external documents to be linked to.

master
Pacman Ghost 4 years ago
parent 9b76a8d51b
commit f8151c9012
  1. 1
      asl_articles/__init__.py
  2. 3
      asl_articles/config/site.cfg.example
  3. 15
      asl_articles/docs.py
  4. 4
      docker-compose.yml
  5. 2
      docker/config/site.cfg
  6. 17
      run-containers.sh
  7. 6
      web/src/App.js
  8. 17
      web/src/ArticleSearchResult.js
  9. 11
      web/src/PublicationSearchResult.js
  10. 8
      web/src/utils.js

@ -108,6 +108,7 @@ import asl_articles.authors #pylint: disable=cyclic-import
import asl_articles.scenarios #pylint: disable=cyclic-import
import asl_articles.images #pylint: disable=cyclic-import
import asl_articles.tags #pylint: disable=cyclic-import
import asl_articles.docs #pylint: disable=cyclic-import
import asl_articles.utils #pylint: disable=cyclic-import
# initialize

@ -4,3 +4,6 @@
; sqlite:////home/pacman-ghost/asl-articles.db
; postgresql://USER:PASS@localhost/asl_articles
DB_CONN_STRING = ...
; Base directory for external documents.
EXTERNAL_DOCS_BASEDIR = ...

@ -0,0 +1,15 @@
""" Provide access to external documents. """
from flask import abort, send_from_directory
from asl_articles import app
# ---------------------------------------------------------------------
@app.route( "/docs/<path:path>" )
def get_external_doc( path ):
"""Return an external document."""
base_dir = app.config.get( "EXTERNAL_DOCS_BASEDIR" )
if not base_dir:
abort( 404 )
return send_from_directory( base_dir, path )

@ -9,6 +9,9 @@
# This is done via the SQLITE variable, but since Docker doesn't allow any way to do things conditionally,
# it needs to be set even if it's not being used :-/
#
# Similarly, EXTERNAL_DOCS_BASEDIR is the base directory for external documents that we want to link to,
# but it needs to be set even if it's not being used :-/
#
# See the run-containers.sh script that manages all of this.
version: "3"
@ -29,5 +32,6 @@ services:
- "5002:5000"
volumes:
- $SQLITE:/data/sqlite.db
- $EXTERNAL_DOCS_BASEDIR:/data/docs/
environment:
- DBCONN

@ -2,3 +2,5 @@
FLASK_HOST = 0.0.0.0
IS_CONTAINER = 1
EXTERNAL_DOCS_BASEDIR = /data/docs/

@ -3,15 +3,17 @@
# parse the command-line arguments
if [ -z "$1" ]; then
echo "Usage: `basename "$0"` <db-conn>"
echo "Usage: `basename "$0"` <db-conn> <external-docs>"
echo " Build and launch the \"asl-articles\" containers, using the specified database e.g."
echo " ~/asl-articles.db (path to a SQLite database)"
echo " postgresql://USER:PASS@host/dbname (database connection string)"
echo " Note that the database server address is relative to the container i.e. NOT \"localhost\"."
echo
echo " If you want link articles to their original documents, specify a base directory for the documents."
echo
echo " The TAG env variable should also be set to specify which containers to run e.g."
echo " TAG=testing ./run.sh /tmp/asl-articles.db"
exit 1
exit 0
fi
if [ -f "$1" ]; then
# connect to a SQLite database
@ -22,6 +24,17 @@ else
export SQLITE=/dev/null
export DBCONN=$1
fi
if [ ! -z "$2" ]; then
# set the base directory for external documents
export EXTERNAL_DOCS_BASEDIR=$2
if [ ! -d "$EXTERNAL_DOCS_BASEDIR" ]; then
echo "Invalid document base directory: $EXTERNAL_DOCS_BASEDIR"
exit 1
fi
else
# FUDGE! This needs to be set, even if it's not being used :-/
export EXTERNAL_DOCS_BASEDIR=/dev/null
fi
# initialize
if [ "$TAG" == "testing" ]; then

@ -425,6 +425,12 @@ export default class App extends React.Component
url += "?foo=" + Math.random() ; // FUDGE! To bypass the cache :-/
return url ;
}
makeExternalDocUrl( url ) {
// generate a URL for an external document
if ( url.substr( 0, 2 ) === "$/" )
url = url.substr( 2 ) ;
return this.makeFlaskUrl( "/docs/" + encodeURIComponent(url) ) ;
}
_onStartupTask( taskId ) {
// flag that the specified startup task has completed

@ -4,7 +4,7 @@ import { ArticleSearchResult2 } from "./ArticleSearchResult2.js" ;
import "./ArticleSearchResult.css" ;
import { PublicationSearchResult } from "./PublicationSearchResult.js" ;
import { gAppRef } from "./index.js" ;
import { makeScenarioDisplayName, applyUpdatedVals, removeSpecialFields, makeCommaList } from "./utils.js" ;
import { makeScenarioDisplayName, applyUpdatedVals, removeSpecialFields, makeCommaList, isLink } from "./utils.js" ;
const axios = require( "axios" ) ;
@ -22,6 +22,17 @@ export class ArticleSearchResult extends React.Component
const pub = gAppRef.caches.publications[ this.props.data.pub_id ] ;
const image_url = gAppRef.makeFlaskImageUrl( "article", this.props.data.article_image_id, true ) ;
// prepare the article's URL
let article_url = this.props.data.article_url ;
if ( article_url ) {
if ( ! isLink( article_url ) )
article_url = gAppRef.makeExternalDocUrl( article_url ) ;
} else if ( pub && pub.pub_url ) {
article_url = gAppRef.makeExternalDocUrl( pub.pub_url ) ;
if ( article_url.substr( article_url.length-4 ) === ".pdf" && this.props.data.article_pageno )
article_url += "#page=" + this.props.data.article_pageno ;
}
// prepare the authors
let authors = [] ;
if ( this.props.data[ "authors!" ] ) {
@ -119,8 +130,8 @@ export class ArticleSearchResult extends React.Component
</span>
}
<span className="title name" dangerouslySetInnerHTML={{ __html: display_title }} />
{ this.props.data.article_url &&
<a href={this.props.data.article_url} className="open-link" target="_blank" rel="noopener noreferrer">
{ article_url &&
<a href={article_url} className="open-link" target="_blank" rel="noopener noreferrer">
<img src="/images/open-link.png" alt="Open article." title="Open this article." />
</a>
}

@ -4,7 +4,7 @@ import "./PublicationSearchResult.css" ;
import { PublicationSearchResult2 } from "./PublicationSearchResult2.js" ;
import { PUBLICATION_EXCESS_ARTICLE_THRESHOLD } from "./constants.js" ;
import { gAppRef } from "./index.js" ;
import { makeCollapsibleList, pluralString, applyUpdatedVals, removeSpecialFields } from "./utils.js" ;
import { makeCollapsibleList, pluralString, applyUpdatedVals, removeSpecialFields, isLink } from "./utils.js" ;
const axios = require( "axios" ) ;
@ -20,6 +20,11 @@ export class PublicationSearchResult extends React.Component
const publ = gAppRef.caches.publishers[ this.props.data.publ_id ] ;
const image_url = PublicationSearchResult.makeImageUrl( this.props.data ) ;
// prepare the publication's URL
let pub_url = this.props.data.pub_url ;
if ( pub_url && ! isLink(pub_url) )
pub_url = gAppRef.makeExternalDocUrl( pub_url ) ;
// prepare the tags
let tags = [] ;
if ( this.props.data[ "tags!" ] ) {
@ -89,8 +94,8 @@ export class PublicationSearchResult extends React.Component
onClick = { () => gAppRef.searchForPublication( this.props.data.pub_id ) }
title = "Show this publication."
/>
{ this.props.data.pub_url &&
<a href={this.props.data.pub_url} className="open-link" target="_blank" rel="noopener noreferrer">
{ pub_url &&
<a href={pub_url} className="open-link" target="_blank" rel="noopener noreferrer">
<img src="/images/open-link.png" alt="Open publication." title="Open this publication." />
</a>
}

@ -265,3 +265,11 @@ export function isNumeric( val ) {
return false ;
return ! isNaN( val ) ;
}
export function isLink( val ) {
if ( val.substr(0,7) === "http://" || val.substr(0,8) === "https://" )
return true ;
if ( val.substr(0,7) === "file://" )
return true ;
return false ;
}

Loading…
Cancel
Save