21 | {% endblock %}
22 |
23 |
--------------------------------------------------------------------------------
/test/base.py:
--------------------------------------------------------------------------------
1 | import os
2 | import json
3 |
4 | from bibserver import dao
5 | from bibserver.config import config
6 |
7 | TESTDB = 'bibserver-test'
8 |
9 | here = os.path.dirname(__file__)
10 | fixtures_path = os.path.join(here, 'fixtures.json')
11 | fixtures = json.load(open(fixtures_path))
12 |
13 | config["ELASTIC_SEARCH_DB"] = TESTDB
14 | dao.init_db()
15 |
16 |
17 | class Fixtures(object):
18 | raw = fixtures
19 |
20 | @classmethod
21 | def create_account(cls):
22 | accountdict = dict(fixtures['accounts'][0])
23 | pw = accountdict['password_raw']
24 | del accountdict['password_raw']
25 | cls.account = dao.Account(**accountdict)
26 | cls.account.set_password(pw)
27 | cls.account.save()
28 |
29 | __all__ = ['config', 'fixtures', 'Fixtures', 'dao', 'TESTDB', 'json']
30 |
31 |
--------------------------------------------------------------------------------
/parserscrapers_plugins/bibjson.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | '''
4 | BibJSON identity parser.
5 | Reads a valid BibJSON input on stdin, parses it as a JSON file.
6 | Performs some basic validation, and outputs the serialised BibJSON on stdout.
7 | '''
8 |
9 | import sys
10 | import json
11 |
12 |
13 | def parse():
14 | data = sys.stdin.read()
15 | data_json = json.loads(data)
16 | sys.stdout.write(json.dumps(data_json, indent=2))
17 |
18 |
19 | def main():
20 | conf = {"display_name": "BibJSON",
21 | "format": "jsoncheck",
22 | "contact": "openbiblio-dev@lists.okfn.org",
23 | "bibserver_plugin": True,
24 | "BibJSON_version": "0.81"}
25 | for x in sys.argv[1:]:
26 | if x == '-bibserver':
27 | sys.stdout.write(json.dumps(conf))
28 | sys.exit()
29 | parse()
30 |
31 |
32 | if __name__ == '__main__':
33 | main()
34 |
--------------------------------------------------------------------------------
/bibserver/static/vendor/jtedit/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | jtedit
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, find_packages
2 |
3 | setup(
4 | name = 'bibserver',
5 | version = '0.5.1',
6 | packages = find_packages(),
7 | install_requires = [
8 | "Flask",
9 | "Flask-Login",
10 | "Flask-WTF",
11 | "pyes",
12 | "chardet",
13 | "requests",
14 | ],
15 | url = 'http://bibserver.okfn.org/',
16 | author = 'Open Knowledge Foundation',
17 | author_email = 'openbiblio@okfn.org',
18 | description = 'BibServer is a RESTful bibliographic data server.',
19 | license = 'AGPL',
20 | classifiers = [
21 | 'Development Status :: 3 - Alpha',
22 | 'Environment :: Console',
23 | 'Intended Audience :: Developers',
24 | 'License :: OSI Approved :: MIT License',
25 | 'Operating System :: OS Independent',
26 | 'Programming Language :: Python',
27 | 'Topic :: Software Development :: Libraries :: Python Modules'
28 | ],
29 | )
30 |
--------------------------------------------------------------------------------
/test/fixtures.json:
--------------------------------------------------------------------------------
1 | {
2 | "accounts": [
3 | {
4 | "_id": "tester",
5 | "fullname": "The Tester",
6 | "email": "tester@okfn.org",
7 | "password_raw": "pass"
8 | }
9 | ],
10 | "records": [
11 | {
12 | "id":"someID",
13 | "type": "book",
14 | "title":"Great Unwritten Collaborations",
15 | "author": [{"name":"Leo Tolstoy"},{"name":"Robert Musil"}],
16 | "journal": {"name":"journal_name"},
17 | "collection": "great_novels",
18 | "moreinfo":"some more information about this collection",
19 | "owner": "tester",
20 | "ns1:thing":"some thing"
21 | },
22 | {
23 | "type": "article",
24 | "title":"A mathematical theory of communication",
25 | "author": [{"name":"Claude Shannon"}],
26 | "journal": {"name":"Bell System Technical Journal"},
27 | "id": "otherid",
28 | "owner": "tester",
29 | "collection": "information_theory"
30 | }
31 | ]
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/bibserver/static/vendor/facetview/vendor/d3/d3.csv.min.js:
--------------------------------------------------------------------------------
1 | (function(){function b(a){return/[",\n]/.test(a)?'"'+a.replace(/\"/g,'""')+'"':a}function a(a){return a.map(b).join(",")}d3.csv=function(a,b){d3.text(a,"text/csv",function(a){b(a&&d3.csv.parse(a))})},d3.csv.parse=function(a){var b;return d3.csv.parseRows(a,function(a,c){if(c){var d={},e=-1,f=b.length;while(++e=a.length)return d;if(i){i=!1;return c}var b=f.lastIndex;if(a.charCodeAt(b)===34){var e=b;while(e++@$2$3'
19 | },
20 | twitterHashtag: {
21 | // /\B#\w*[a-zA-Z]+\w*/gi // start at word boundry - must include at least one a-z - ends at word boundry
22 | re: /(^|["'(]|<|\s)(#.+?)((?:[:?]|\.+)?(?:\s|$)|>|[)"',])/gi,
23 | tmpl: function (match, pre, hashTag, post) {
24 | return pre+''+hashTag+''+post;
25 | }
26 | }
27 | });
--------------------------------------------------------------------------------
/doc/config.rst:
--------------------------------------------------------------------------------
1 | =============
2 | Configuration
3 | =============
4 |
5 | Configuration is managed via some key files. To make changes, just use
6 | local_config.json.
7 |
8 |
9 | config.json
10 | ===========
11 |
12 | The main default config - does not need to be altered. Instead, it is updated
13 | by local_config.json
14 |
15 |
16 | local_config.json
17 | =================
18 |
19 | This is where configurations should be set for you particular instances. These
20 | are the various values you can set:
21 |
22 |
23 | config.py
24 | =========
25 |
26 | This is the config class - it loads config in from config.json, then overrides
27 | with updates from local_config.json. The config object is then made available
28 | and can be imported elsewhere in the app. Changes to config need only happen
29 | in local_config.json.
30 |
31 |
32 | core.py
33 | =======
34 |
35 | This is where configure_app and create_app are definedm which prepare the flask
36 | settings for the app to run. This is imported by web.py when the app is created.
37 | Settings are read from config.
38 |
39 |
40 | default_settings.py
41 | ===================
42 |
43 | Contains a "secure-key" setting for flask config
44 |
--------------------------------------------------------------------------------
/bibserver/core.py:
--------------------------------------------------------------------------------
1 | import os
2 | from flask import Flask
3 |
4 | from bibserver import default_settings
5 | from flask_login import LoginManager, current_user
6 | login_manager = LoginManager()
7 |
8 | def create_app():
9 | app = Flask(__name__)
10 | configure_app(app)
11 | setup_error_email(app)
12 | login_manager.setup_app(app)
13 | return app
14 |
15 | def configure_app(app):
16 | app.config.from_object(default_settings)
17 | # parent directory
18 | here = os.path.dirname(os.path.abspath( __file__ ))
19 | config_path = os.path.join(os.path.dirname(here), 'app.cfg')
20 | if os.path.exists(config_path):
21 | app.config.from_pyfile(config_path)
22 |
23 | def setup_error_email(app):
24 | ADMINS = app.config.get('ADMINS', '')
25 | if not app.debug and ADMINS:
26 | import logging
27 | from logging.handlers import SMTPHandler
28 | mail_handler = SMTPHandler('127.0.0.1',
29 | 'server-error@no-reply.com',
30 | ADMINS, 'error')
31 | mail_handler.setLevel(logging.ERROR)
32 | app.logger.addHandler(mail_handler)
33 |
34 | app = create_app()
35 |
36 |
--------------------------------------------------------------------------------
/bibserver/static/vendor/facetview/css/style.css:
--------------------------------------------------------------------------------
1 | /**********************************************
2 | * Generic Mods to Bootstrap
3 | *********************************************/
4 |
5 | html, body {
6 | background-color: #eee;
7 | }
8 | body {
9 | padding-top: 40px; /* 40px to make the container go all the way to the bottom of the topbar */
10 | }
11 |
12 | .content {
13 | background-color: #fff;
14 | padding: 20px;
15 | margin: 0 -20px; /* negative indent the amount of the padding to maintain the grid system */
16 | -webkit-border-radius: 0 0 6px 6px;
17 | -moz-border-radius: 0 0 6px 6px;
18 | border-radius: 0 0 6px 6px;
19 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.15);
20 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.15);
21 | box-shadow: 0 1px 2px rgba(0,0,0,.15);
22 | }
23 |
24 | .page-header {
25 | background-color: #f5f5f5;
26 | padding: 20px 20px 10px;
27 | margin: -20px -20px 20px;
28 | }
29 |
30 | .container > footer p {
31 | text-align: center;
32 | }
33 |
34 | /* specific additions for the example index page */
35 | .nav-logo img {
36 | margin-top: 4px;
37 | }
38 |
39 | h4 {
40 | line-height: 28px;
41 | margin-bottom: 10px;
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/parserscrapers_plugins/plugins.json:
--------------------------------------------------------------------------------
1 | {"wikipedia": {"display_name": "Wikipedia search to citations", "format": "wikipedia", "downloads": true, "bibserver_plugin": true, "BibJSON_version": "0.81", "contact": "openbiblio-dev@lists.okfn.org", "_path": "parserscrapers_plugins/wikipedia.py"}, "ris": {"display_name": "RIS", "format": "ris", "bibserver_plugin": true, "BibJSON_version": "0.81", "contact": "openbiblio-dev@lists.okfn.org", "_path": "parserscrapers_plugins/RISParser.py"}, "jsoncheck": {"display_name": "BibJSON", "format": "jsoncheck", "bibserver_plugin": true, "BibJSON_version": "0.81", "contact": "openbiblio-dev@lists.okfn.org", "_path": "parserscrapers_plugins/bibjson.py"}, "json": {"display_name": "JSON", "format": "json", "bibserver_plugin": true, "BibJSON_version": "0.81", "contact": "openbiblio-dev@lists.okfn.org", "_path": "parserscrapers_plugins/JSONParser.py"}, "bibtex": {"display_name": "BibTex", "format": "bibtex", "bibserver_plugin": true, "BibJSON_version": "0.81", "contact": "openbiblio-dev@lists.okfn.org", "_path": "parserscrapers_plugins/bibtex.py"}, "csv": {"display_name": "CSV", "format": "csv", "bibserver_plugin": true, "BibJSON_version": "0.81", "contact": "openbiblio-dev@lists.okfn.org", "_path": "parserscrapers_plugins/csvparser.py"}}
--------------------------------------------------------------------------------
/bibserver/config.py:
--------------------------------------------------------------------------------
1 | import os
2 | import json
3 |
4 | '''read the config.json file and make available as a config dict'''
5 |
6 | def load_config(path):
7 | fileobj = open(path)
8 | c = ""
9 | for line in fileobj:
10 | if line.strip().startswith("#"):
11 | continue
12 | else:
13 | c += line
14 | out = json.loads(c)
15 |
16 | # add some critical defaults if necessary
17 | if 'facet_field' not in out:
18 | out['facet_field'] = ''
19 |
20 | return out
21 |
22 | here = os.path.dirname(__file__)
23 | parent = os.path.dirname(here)
24 | config_path = os.path.join(parent, 'config.json')
25 | config = load_config(config_path)
26 |
27 | if os.path.exists(os.path.join(parent, 'local_config.json')):
28 | local_config = load_config(os.path.join(parent, 'local_config.json'))
29 | config.update(local_config)
30 |
31 | __all__ = ['config']
32 |
33 |
34 | ''' wrap a config dict in a class if required'''
35 |
36 | class Config(object):
37 | def __init__(self,confdict=config):
38 | '''Create Configuration object from a configuration dictionary.'''
39 | self.cfg = confdict
40 |
41 | def __getattr__(self, attr):
42 | return self.cfg.get(attr, None)
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist = py{27,34,36,37,py},pep8
3 | skip_missing_interpreters=true
4 |
5 | [testenv]
6 | # Most of these are defaults but if you specify any you can't fall back
7 | # to defaults for others.
8 | basepython =
9 | py27: python2.7
10 | py34: python3.4
11 | py35: python3.5
12 | py36: python3.6
13 | py37: python3.7
14 | py38: python3.8
15 | pypy: pypy
16 | pypy3: pypy3
17 | py2: python2.7
18 | py3: python3.6
19 |
20 | passenv = PYTHONPATH
21 | deps = -r{toxinidir}/requirements.txt
22 | -r{toxinidir}/requirements.test.txt
23 | #TODO: Un-ignore test failures below once they pass
24 | whitelist_externals = {toxinidir}/parserscrapers_plugins/bibtex.py
25 | commands = {toxinidir}/parserscrapers_plugins/bibtex.py test/data/sample.bibtex
26 | {toxinidir}/parserscrapers_plugins/bibtex.py test/data/sampleutf8.bibtex
27 | - nosetests --with-coverage {posargs}
28 |
29 | [testenv:pep8]
30 | skip_install = true
31 | basepython = python2.7
32 | deps = flake8
33 | # TODO: Unignore flake8 errors for bibserver and test
34 | commands = - flake8 bibserver {posargs}
35 | flake8 parserscrapers_plugins {posargs}
36 | - flake8 test
37 |
38 | [flake8]
39 | exclude =
40 | .tox
41 | show-source = true
42 |
43 | [testenv:py27-osx-builtin]
44 | basepython = /usr/bin/python2.7
45 |
--------------------------------------------------------------------------------
/doc/index.rst:
--------------------------------------------------------------------------------
1 | ====================================
2 | Welcome to BibServer's documentation
3 | ====================================
4 |
5 | BibServer_ is an open-source RESTful bibliographic data server. BibServer makes
6 | it easy to create and manage collections of bibliographic records such as
7 | reading lists, publication lists and even complete library catalogs.
8 |
9 | Main features:
10 |
11 | * Create and manage bibliographic collections simply and easily
12 | * Import (and export) your collection from bibtex, MARC, RIS, BibJSON, RDF or
13 | other bibliogrpaphic formats in a matter of seconds
14 | * Browse collection via an elegant faceted interface
15 | * Embed the collection browser in other websites
16 | * Full RESTful API
17 | * Open-source and free to use
18 | * ~~Hosted service available at http://bibsoup.net/~~
19 |
20 | .. _BibServer: http://bibserver.org/~~
21 |
22 |
23 | Quick Links
24 | ===========
25 |
26 | * Code: http://github.com/okfn/bibserver
27 | * Mailing list: http://lists.okfn.org/mailman/listinfo/openbiblio-dev
28 | * ~~Live demo: http://dev.bibsoup.net/ (sandbox) or http://bibsoup.net/~~
29 |
30 |
31 | Installation
32 | ============
33 |
34 | .. toctree::
35 | :maxdepth: 2
36 |
37 | install
38 | deploy
39 | config
40 | upload
41 | frontend
42 | api
43 | parsers
44 | auth
45 | bibjson
46 | licenses
47 |
48 | Indices and tables
49 | ==================
50 |
51 | * :ref:`genindex`
52 | * :ref:`modindex`
53 | * :ref:`search`
54 |
55 |
--------------------------------------------------------------------------------
/bibserver/static/vendor/facetview/vendor/d3/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010, Michael Bostock
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * The name Michael Bostock may not be used to endorse or promote products
15 | derived from this software without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 |
--------------------------------------------------------------------------------
/bibserver/static/vendor/facetview/css/facetview.css:
--------------------------------------------------------------------------------
1 | #facetview_freetext{
2 | -moz-border-radius: 0px;
3 | -webkit-border-radius: 0px;
4 | border-radius: 0px;
5 | }
6 | #facetview_filters h3{
7 | margin:40px 0 20px 0;
8 | }
9 | #facetview_advanced{
10 | float:left;
11 | clear:left;
12 | margin:10px;
13 | padding:3px 5px 5px 5px;
14 | -moz-border-radius: 5px;
15 | -webkit-border-radius: 5px;
16 | border-radius: 5px;
17 | border:1px solid #a1a1a1;
18 | color:#a1a1a1;
19 | overflow:hidden;
20 | width:165px;
21 | }
22 | #facetview_advanced select{
23 | width:160px;
24 | background:#fff;
25 | border:1px solid #a1a1a1;
26 | color:#a1a1a1;
27 | font-size:11px;
28 | -moz-border-radius: 2px;
29 | -webkit-border-radius: 2px;
30 | border-radius: 2px;
31 | }
32 | #facetview_visualisation{
33 | border:1px solid #ccc;
34 | margin:10px 0 10px 0;
35 | -moz-border-radius: 5px;
36 | -webkit-border-radius: 5px;
37 | border-radius: 5px;
38 | }
39 | .node{
40 | cursor:pointer;
41 | }
42 | .facetview_filterchoice{
43 | text-decoration:none;
44 | color:#373737;
45 | }
46 | .facetview_filterselected{
47 | margin:5px;
48 | }
49 | .facetview_freetext_filterdiv{
50 | float:left;
51 | clear:both;
52 | background:#eee;
53 | padding:0;
54 | color:green;
55 | width:100%;
56 | }
57 | .facetview_advancedshow{
58 | text-decoration:none;
59 | color:#a1a1a1;
60 | }
61 |
62 | .facetview_resultactions a{
63 | color:#353535;
64 | font-weight:bold;
65 | text-decoration:none;
66 | margin:0 5px 0 5px;
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 |
3 | language: python
4 |
5 | # Run each tox environment separately
6 | matrix:
7 | include:
8 | - os: osx
9 | language: generic
10 | env: # System-provided
11 | - TOX_ENV=py27-osx-builtin
12 | - BREW_PYTHON_PACKAGE=
13 | - os: osx
14 | language: generic
15 | env: # Homebrew-provided
16 | - TOX_ENV=py27
17 | - BREW_PYTHON_PACKAGE=python@2
18 | # - os: osx
19 | # language: generic
20 | # env: # Python 3 from Homebrew
21 | # - TOX_ENV=py37
22 | # - BREW_PYTHON_PACKAGE=python@3
23 | - os: linux
24 | python: 2.7
25 | env: TOX_ENV=py27
26 | # - os: linux
27 | # python: 3.7
28 | # env: TOX_ENV=py37
29 | # sudo: true # Required for python 3.7
30 | # dist: xenial
31 |
32 | services:
33 | - elasticsearch
34 |
35 | # Cache pip requirements for faster builds
36 | cache: pip
37 |
38 | install:
39 | # Python test requirements
40 | - |
41 | if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
42 | if [[ -n "$BREW_PYTHON_PACKAGE" ]]; then
43 | brew update
44 | if ! brew list --versions "$BREW_PYTHON_PACKAGE" >/dev/null; then
45 | brew install "$BREW_PYTHON_PACKAGE"
46 | elif ! brew outdated "$BREW_PYTHON_PACKAGE"; then
47 | brew upgrade "$BREW_PYTHON_PACKAGE"
48 | fi
49 | fi
50 | sudo pip2 install tox
51 | else
52 | pip install tox
53 | fi
54 |
55 | # Wait for elasticsearch to start up
56 | - sleep 10
57 |
58 | script:
59 | - PATH="/usr/local/bin:$PATH" tox -e "$TOX_ENV"
60 |
--------------------------------------------------------------------------------
/test/test_importer.py:
--------------------------------------------------------------------------------
1 | from base import *
2 |
3 | from bibserver.importer import Importer
4 | import bibserver.dao
5 | import os
6 |
7 | class TestImporter:
8 | @classmethod
9 | def setup_class(cls):
10 | pass
11 |
12 | @classmethod
13 | def teardown_class(cls):
14 | conn, db = dao.get_conn()
15 | conn.delete_index(TESTDB)
16 |
17 | def test_upload(self):
18 | owner = dao.Account(id='testaccount1')
19 | owner.save()
20 | i = Importer(owner=owner)
21 | data = open('test/data/sample.bibtex.bibjson')
22 | collection_in = {
23 | 'label': u'My Test Collection'
24 | }
25 | coll, records = i.upload(data, collection_in)
26 | assert coll.id
27 | assert owner.collections[0].id == coll.id, owner.collections
28 |
29 | assert len(records) == 1, records
30 | recid = records[0]['_id']
31 | out = bibserver.dao.Record.get(recid)
32 | assert out["year"] == '2008', out
33 | assert out['collection'] == coll['collection']
34 |
35 | # now try uploading exactly the same data again
36 | data = open('test/data/sample.bibtex.bibjson')
37 | newcoll, records = i.upload(data, collection_in)
38 | # still should have only one collection
39 | assert len(owner.collections) == 1
40 | assert newcoll.id == coll.id
41 | assert len(records) == 1
42 | assert records[0]['collection'] == coll['collection']
43 | # still should have only one record in it
44 | recs_for_collection = dao.Record.query('collection:"' + coll['collection'] + '"')
45 | assert recs_for_collection.total == 1, recs_for_collection
46 |
47 |
--------------------------------------------------------------------------------
/bibserver/static/vendor/facetview/vendor/linkify/1.0/jquery.linkify-1.0-min.js:
--------------------------------------------------------------------------------
1 | // encoding: utf-8
2 | // $.fn.linkify 1.0 - MIT/GPL Licensed - More info: http://github.com/maranomynet/linkify/
3 | (function(b){var x=/(^|["'(\s]|<)(www\..+?\..+?)((?:[:?]|\.+)?(?:\s|$)|>|[)"',])/g,y=/(^|["'(\s]|<)((?:(?:https?|ftp):\/\/|mailto:).+?)((?:[:?]|\.+)?(?:\s|$)|>|[)"',])/g,z=function(h){return h.replace(x,'$1$2$3').replace(y,'$1$2$3').replace(/"<``>/g,'"http')},s=b.fn.linkify=function(c){if(!b.isPlainObject(c)){c={use:(typeof c=='string')?c:undefined,handleLinks:b.isFunction(c)?c:arguments[1]}}var d=c.use,k=s.plugins||{},l=[z],f,m=[],n=c.handleLinks;if(d==undefined||d=='*'){for(var i in k){l.push(k[i])}}else{d=b.isArray(d)?d:b.trim(d).split(/ *, */);var o,i;for(var p=0,A=d.length;p1&&/\S/.test(a)){var q,r;f=f||b('')[0];f.innerHTML='';f.appendChild(e.cloneNode(false));var u=f.childNodes;for(var v=0,g;(g=l[v]);v++){var w=u.length,j;while(w--){j=u[w];if(j.nodeType==3){a=j.nodeValue;if(a.length>1&&/\S/.test(a)){r=a;a=a.replace(/&/g,'&').replace(//g,'>');a=b.isFunction(g)?g(a):a.replace(g.re,g.tmpl);q=q||r!=a;r!=a&&b(j).after(a).remove()}}}}a=f.innerHTML;if(n){a=b('').html(a);m=m.concat(a.find('a').toArray().reverse());a=a.contents()}q&&b(e).after(a).remove()}}else if(e.nodeType==1&&!/^(a|button|textarea)$/i.test(e.tagName)){arguments.callee.call(e)}}});n&&n(b(m.reverse()));return this};s.plugins={mailto:{re:/(^|["'(\s]|<)([^"'(\s&]+?@.+\.[a-z]{2,7})(([:?]|\.+)?(\s|$)|>|[)"',])/gi,tmpl:'$1$2$3'}}})(jQuery);
4 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | .. image:: https://travis-ci.org/okfn/bibserver.svg?branch=master
2 | :target: https://travis-ci.org/okfn/bibserver
3 |
4 | BibServer is an open-source RESTful bibliographic data server. BibServer makes
5 | it easy to create and manage collections of bibliographic records such as
6 | reading lists, publication lists and even complete library catalogs.
7 |
8 | Main features:
9 |
10 | * Create and manage bibliographic collections simply and easily
11 | * Import (and export) your collection from bibtex, MARC, RIS, BibJSON, RDF or
12 | other bibliographic formats in a matter of seconds
13 | * Browse collection via an elegant faceted interface
14 | * Embed the collection browser in other websites
15 | * Full RESTful API
16 | * Open-source and free to use
17 |
18 |
19 | Quick Links
20 | ===========
21 |
22 | * Code: http://github.com/okfn/bibserver
23 | * Documentation: https://bibserver.readthedocs.io/
24 | * Mailing list: http://lists.okfn.org/mailman/listinfo/openbiblio-dev
25 |
26 |
27 | Installation
28 | ============
29 |
30 | See doc/install.rst or
31 | https://bibserver.readthedocs.io/en/latest/install.html
32 |
33 |
34 | Command Line Usage
35 | ==================
36 |
37 | Command link script in `cli.py`. To see commands do::
38 |
39 | ./cli.py -h
40 |
41 |
42 | Developers
43 | ==========
44 |
45 | To run the tests:
46 |
47 | 1. Install nose (python-nose)
48 | 2. Run the following command::
49 |
50 | nosetests -v test/
51 |
52 |
53 | Copyright and License
54 | =====================
55 |
56 | Copyright 2011-2012 Open Knowledge Foundation.
57 |
58 | Licensed under the MIT license
59 |
60 |
61 |
62 | Vendor packages
63 | ===============
64 |
65 | This BibServer repository also includes the following vendor packages, all of
66 | which are JavaScript plugins available under open source license:
67 |
68 | * http://jquery.com
69 | * http://jqueryui.com
70 | * http://twitter.github.com/bootstrap
71 | * http://github.com/okfn/facetview
72 | * http://d3js.org
73 | * http://code.google.com/p/jquery-linkify/
74 |
75 |
--------------------------------------------------------------------------------
/bibserver/static/vendor/facetview/simple.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | FacetView
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
45 |
46 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/parserscrapers_plugins/csvparser.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import csv
3 | import sys
4 | import json
5 | import chardet
6 | import cStringIO
7 |
8 |
9 | class CSVParser(object):
10 |
11 | def __init__(self, fileobj):
12 |
13 | data = fileobj.read()
14 | self.encoding = chardet.detect(data).get('encoding', 'ascii')
15 |
16 | # Some files have Byte-order marks inserted at the start
17 | if data[:3] == '\xef\xbb\xbf':
18 | data = data[3:]
19 | self.fileobj = cStringIO.StringIO(data)
20 |
21 | def parse(self):
22 | # dialect = csv.Sniffer().sniff(fileobj.read(1024))
23 | d = csv.DictReader(self.fileobj)
24 | data = []
25 |
26 | # do any required conversions
27 | for row in d:
28 | for k, v in row.items():
29 | del row[k]
30 | row[k.lower()] = v
31 | if "author" in row:
32 | row["author"] = [{"name": i} for i in row["author"].split(",")]
33 | if "editor" in row:
34 | row["editor"] = [{"name": i} for i in row["editor"].split(",")]
35 | if "journal" in row:
36 | row["journal"] = {"name": row["journal"]}
37 | data.append(row)
38 | return data, {}
39 |
40 |
41 | def parse():
42 | parser = CSVParser(sys.stdin)
43 | records, metadata = parser.parse()
44 | if len(records) > 0:
45 | sys.stdout.write(json.dumps({'records': records, 'metadata': metadata})) # noqa E501
46 | else:
47 | sys.stderr.write('Zero records were parsed from the data')
48 |
49 |
50 | def main():
51 | conf = {"display_name": "CSV",
52 | "format": "csv",
53 | "contact": "openbiblio-dev@lists.okfn.org",
54 | "bibserver_plugin": True,
55 | "BibJSON_version": "0.81"}
56 | for x in sys.argv[1:]:
57 | if x == '-bibserver':
58 | sys.stdout.write(json.dumps(conf))
59 | sys.exit()
60 | parse()
61 |
62 |
63 | if __name__ == '__main__':
64 | main()
65 |
--------------------------------------------------------------------------------
/bibserver/static/vendor/facetview/local.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | FacetView
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
45 |
46 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/doc/install.rst:
--------------------------------------------------------------------------------
1 | ============
2 | Installation
3 | ============
4 |
5 | Simple Setup
6 | ============
7 |
8 | 1. Install pre-requisites:
9 |
10 | * Python (>= 2.7), pip and virtualenv.
11 | * git
12 | * ElasticSearch_ (> 0.17 series)
13 |
14 | 2. [optional] Create a virtualenv and enable it::
15 |
16 | # in bash
17 | virtualenv {myenv}
18 | . {myenv}/bin/activate
19 |
20 | 3. Get the source::
21 |
22 | # by convention we put it in the virtualenv but you can put anywhere
23 | # mkdir {myenv}/src
24 | # git clone https://github.com/okfn/bibserver {myenv}/src/
25 | git clone https://github.com/okfn/bibserver
26 |
27 | 3. Install the app::
28 |
29 | # move to your checkout of bibserver
30 | # cd {myenv}/src/bibserver
31 | cd bibserver
32 | # do a development install from current directory
33 | pip install -e .
34 | # alternatively if you do not want a development install
35 | # note there is an error with this at the moment - do dev install
36 | # python setup.py install
37 |
38 | 4. Run the webserver::
39 |
40 | python bibserver/web.py
41 |
42 | .. _ElasticSearch: http://www.elasticsearch.org/
43 |
44 |
45 | See doc/deploy.rst or https://bibserver.readthedocs.io/en/latest/deploy.html
46 | for more details on a full installation
47 |
48 |
49 | Install example
50 | ===============
51 |
52 | Install commands on a clean installation of Ubuntu_11.10_::
53 |
54 | sudo apt-get install python-pip python-dev build-essential
55 | sudo pip install --upgrade pip
56 | sudo pip install --upgrade virtualenv
57 | sudo apt-get install git
58 |
59 | wget https://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.18.2.tar.gz
60 | tar -xzvf elasticsearch-0.18.2.tar.gz
61 | ./elasticsearch-0.18.2/bin/elasticsearch start
62 |
63 | virtualenv .
64 | . ./bin/activate
65 |
66 | git clone https://github.com/okfn/bibserver
67 | cd bibserver
68 | pip install -e .
69 |
70 | python bibserver/web.py
71 |
72 | You will now find your bibserver running at localhost:5000.
73 |
74 | .. _Ubuntu_11.10: http:ubuntu.com
75 |
76 |
77 |
--------------------------------------------------------------------------------
/bibserver/templates/account/register.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% from "_formhelpers.html" import render_field %}
5 |
6 |
28 |
29 |
30 |
31 |
32 |
43 |
44 |
45 |
It is necessary to register to use this service. This is only so that
46 | your collections can be allocated to you. There is no cost. You will only be emailed about service issues.
47 |
48 |
After registering and signing in, you can view your user information
49 | by clicking your username on the top right menu. This includes your api_key,
50 | which you will need if you want to send data via the API.
51 |
52 |
Don't get your username wrong! We can't change it! (If you do, just
53 | create a new account for yourself.)
54 |
55 |
56 |
57 |
58 | {% endblock %}
59 |
60 |
--------------------------------------------------------------------------------
/bibserver/util.py:
--------------------------------------------------------------------------------
1 | from urllib import urlopen, urlencode
2 | import md5
3 | import re
4 | from unicodedata import normalize
5 | from functools import wraps
6 | from flask import request, current_app
7 |
8 |
9 | def jsonp(f):
10 | """Wraps JSONified output for JSONP"""
11 | @wraps(f)
12 | def decorated_function(*args, **kwargs):
13 | callback = request.args.get('callback', False)
14 | if callback:
15 | content = str(callback) + '(' + str(f(*args,**kwargs).data) + ')'
16 | return current_app.response_class(content, mimetype='application/javascript')
17 | else:
18 | return f(*args, **kwargs)
19 | return decorated_function
20 |
21 |
22 | # derived from http://flask.pocoo.org/snippets/45/ (pd) and customised
23 | def request_wants_json():
24 | best = request.accept_mimetypes.best_match(['application/json', 'text/html'])
25 | if best == 'application/json' and request.accept_mimetypes[best] > request.accept_mimetypes['text/html']:
26 | best = True
27 | else:
28 | best = False
29 | if request.values.get('format','').lower() == 'json' or request.path.endswith(".json"):
30 | best = True
31 | return best
32 |
33 |
34 | # derived from http://flask.pocoo.org/snippets/5/ (public domain)
35 | # changed delimiter to _ instead of - due to ES search problem on the -
36 | _punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')
37 | def slugify(text, delim=u'_'):
38 | """Generates an slightly worse ASCII-only slug."""
39 | result = []
40 | for word in _punct_re.split(text.lower()):
41 | word = normalize('NFKD', word).encode('ascii', 'ignore')
42 | if word:
43 | result.append(word)
44 | return unicode(delim.join(result))
45 |
46 |
47 | # get gravatar for email address
48 | def get_gravatar(email, size=None, default=None, border=None):
49 | email = email.lower().strip()
50 | hash = md5.md5(email).hexdigest()
51 | args = {'gravatar_id':hash}
52 | if size and 1 <= int(size) <= 512:
53 | args['size'] = size
54 | if default: args['default'] = default
55 | if border: args['border'] = border
56 |
57 | url = 'http://www.gravatar.com/avatar.php?' + urlencode(args)
58 |
59 | response = urlopen(url)
60 | image = response.read()
61 | response.close()
62 |
63 | return image
64 |
65 |
--------------------------------------------------------------------------------
/doc/upload.rst:
--------------------------------------------------------------------------------
1 | .. _upload:
2 |
3 | =====================
4 | Uploading collections
5 | =====================
6 |
7 | When a bibserver instance is configured to allow uploads, it is possible to
8 | upload from a source URL or file from PC into the instance via the /upload page.
9 |
10 | A typical bibserver will support upload from the parsers it has available to it
11 | - read more about the parsers and running them independently, or writing new ones,
12 | on the parsers documentation page - :ref:`parsers`
13 |
14 |
15 | The upload page
16 | ===============
17 |
18 | To upload, just go to the upload page. Provide a URL or file, a collection name
19 | and description, confirm the license and the format type.
20 |
21 | The Upload form can either be given a URL from which the Bibserver will retrieve the data to import, or a user can upload a file from her local machine to be imported. Bibserver tries to guess the format of the supplied URL by looking at the filename extension of the supplied URL. (this is unreliable and might be removed in future).
22 | If the fileformat can not be guessed, a list of supported fileformats for that install of Bibserver is shown.
23 |
24 | If a converter of the right format is not available, your source file can be
25 | converted elsewhere into JSON following the bibJSON standard, then the JSON
26 | file can be imported directly.
27 |
28 |
29 | Upload from other online services
30 | =================================
31 |
32 | Examples of providing URLs for uploading directly from other online sources
33 | such as bibsonomy.
34 |
35 |
36 | Monitoring tickets
37 | ==================
38 |
39 | Explain the tickets page, and the info that can be got there.
40 |
41 |
42 | Viewing an uploaded collection
43 | ==============================
44 |
45 | On upload, a tidy version of collection name is made for URL.
46 |
47 | Once a collection has uploaded, it can be found at /username/collection.
48 |
49 |
50 |
51 | Multiple files to same collection
52 | =================================
53 |
54 | Confirm what happens when uploading mutliple files of different content to the
55 | same collection name
56 |
57 |
58 | Overwriting records and internal IDs
59 | ====================================
60 |
61 | Mention the method by which internal IDs are allocated, and how records can be
62 | overwritten if an upload is performed of records that are somewhat identical to
63 | current records. Point out what this means for local edits.
64 |
65 |
66 |
--------------------------------------------------------------------------------
/cli.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 | import optparse
5 | import inspect
6 |
7 | # does setup of cfg
8 | from bibserver import dao
9 |
10 |
11 | def rebuild_db():
12 | '''Rebuild the db'''
13 | conn, db = dao.get_conn()
14 | conn.delete_index(db)
15 | conn.create_index(db)
16 |
17 | def fixtures():
18 | import test.base
19 | for dict_ in test.base.fixtures['records']:
20 | dao.Record.upsert(dict_)
21 |
22 | def convert(inpath):
23 | '''Convert from bibtex to bibjson. One argument expected: path to bibtext
24 | file.
25 | '''
26 | import bibserver.parsers.BibTexParser
27 | import json
28 | parser = parsers.BibTexParser.BibTexParser()
29 | bibtex = open(inpath).read()
30 | print json.dumps(parser.parse(bibtex), indent=2, sort_keys=True)
31 |
32 | def bulk_upload(colls_list):
33 | '''Take a collections list in a JSON file and use the bulk_upload importer.
34 | colls_list described in importer.py
35 | '''
36 | import bibserver.importer
37 | return bibserver.importer.bulk_upload(colls_list)
38 |
39 |
40 | ## ==================================================
41 | ## Misc stuff for setting up a command line interface
42 |
43 | def _module_functions(functions):
44 | local_functions = dict(functions)
45 | for k,v in local_functions.items():
46 | if not inspect.isfunction(v) or k.startswith('_'):
47 | del local_functions[k]
48 | return local_functions
49 |
50 | def _main(functions_or_object):
51 | isobject = inspect.isclass(functions_or_object)
52 | if isobject:
53 | _methods = _object_methods(functions_or_object)
54 | else:
55 | _methods = _module_functions(functions_or_object)
56 |
57 | usage = '''%prog {action}
58 |
59 | Actions:
60 | '''
61 | usage += '\n '.join(
62 | [ '%s: %s' % (name, m.__doc__.split('\n')[0] if m.__doc__ else '') for (name,m)
63 | in sorted(_methods.items()) ])
64 | parser = optparse.OptionParser(usage)
65 | # Optional: for a config file
66 | # parser.add_option('-c', '--config', dest='config',
67 | # help='Config file to use.')
68 | options, args = parser.parse_args()
69 |
70 | if not args or not args[0] in _methods:
71 | parser.print_help()
72 | sys.exit(1)
73 |
74 | method = args[0]
75 | if isobject:
76 | getattr(functions_or_object(), method)(*args[1:])
77 | else:
78 | _methods[method](*args[1:])
79 |
80 | __all__ = [ '_main' ]
81 |
82 | if __name__ == '__main__':
83 | _main(locals())
84 |
85 |
86 |
--------------------------------------------------------------------------------
/bibserver/templates/tickets/view.html:
--------------------------------------------------------------------------------
1 | {% extends "/base.html" %}
2 |
3 | {% block content %}
4 |
You are not logged in as this user. Use the login page if you want to change this
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | {% endif %}
92 |
93 | {% endblock %}
94 |
95 |
--------------------------------------------------------------------------------
/doc/parsers.rst:
--------------------------------------------------------------------------------
1 | .. _parsers:
2 |
3 | ===============
4 | Parsing sources
5 | ===============
6 |
7 | The most common way of importing bibliographic records into Bibserver is using the Upload form in the web interface.
8 | See :ref:`upload`. When you run the Bibserver application from the command line, an ingest system is started in a separate process, which handles the processing of uploads asynchronously. This is done to keep the web interface responsive as some data uploads may involved downloading and processing very large data files.
9 |
10 | To run the ingest process manually separate from the Bibserver application, start it up with a -d flag.
11 | For example:
12 |
13 | python bibserver/ingest.py -d
14 |
15 | Note that it is normally not required to run the ingest manually, the startup of ingest should be done by the main bibserver command line web script. See: :ref:`deploy`
16 |
17 | The parsers
18 | ===========
19 |
20 | For each kind of file that can be imported into a Bibserver, a 'parser' exists.
21 | A parser is an executable file that accepts a file format on standard input and always outputs Bibjson.
22 | The parsers are stored in a directory called 'parserscrapers_plugins' by default.
23 |
24 | When the importing subsystem of Bibserver (named 'ingest') is initialised, all the executable files
25 | found in the parserscrapers_plugins directory are executed with a -bibserver command line parameter.
26 | A parser **must** recognise this parameter and output a JSON config section in response, indicating if this is a valid Bibserver parser and the format that is supported.
27 | All the parsers found are stored in a json data snippet named 'plugins.json' which can be used to determine what the current list of supported data formats for a given instance are. (this is used for example in the Upload forms)
28 |
29 | The download cache
30 | ==================
31 |
32 | When a data import is submitted to Bibserver, a 'ticket' is made which tracks the progress of the upload.
33 | The ticket lists the format of the imported data, who requested it, the time it was made and the progress of the import. When an import is completed, it is also possible to see the raw data, plus the resulting Bibjson data.
34 |
35 | The ingest tickets, downloaded data plus resulting Bibjson are all stored in a directory named 'download_cache' by default. (this location can be changed in the config.json file)
36 | The list of tickets in a system can be viewed on the /ticket/ URL. Each ticket has an ID, and one could then view either the source data /ticket//data or the resulting Bibjson /ticket//bibjson
37 |
38 | All the data in a Bibserver instance can be listed by looking at a URL: /data.txt. This produces a text file with the URL for each Bibjson data file per line. This can be used for automated buld data downloads of Bibserver data.
39 |
40 | Making a new parser
41 | ===================
42 |
43 | Even though Bibserver is written in Python, it is not necessary to write a parser in Python - it can be written in any programming language. At the time of writing there is one example parser written in Perl to support the MARC format, which is commonly found in library automation systems.
44 |
45 | To make a new parser:
46 |
47 | - you should be able to make standalone executable in the parserscrapers_plugins that can be called from a shell
48 |
49 | - the parser must support the -bibserver command line paramater which gives details about the data format supported
50 |
51 | - read data from standard input, parse and convert the data to Bibjson, and print the resulting Bibjson to standard output.
52 |
53 | TODO: how to submit a pull request or email to include it in the repo.
54 |
--------------------------------------------------------------------------------
/bibserver/importer.py:
--------------------------------------------------------------------------------
1 | # the data import manager
2 | # gets an uploaded file or retrieves a file from a URL
3 | # indexes the records found in the file by upserting via the DAO
4 | import urllib2
5 | import re
6 | from cStringIO import StringIO
7 | import unicodedata
8 | import uuid
9 | import json
10 |
11 | import bibserver.dao
12 | import bibserver.util as util
13 | from bibserver.config import config
14 |
15 | class Importer(object):
16 | def __init__(self, owner, requesturl=False):
17 | self.owner = owner
18 | self.requesturl = requesturl
19 |
20 | def upload(self, fileobj, collection=None):
21 | '''Import a bibjson collection into the database.
22 |
23 | :param fileobj: a fileobj pointing to file from which to import
24 | collection records (and possibly collection metadata)
25 | :param collection: collection dict for use when creating collection. If
26 | undefined collection must be extractable from the fileobj.
27 |
28 | :return: same as `index` method.
29 | '''
30 | jsonin = json.load(fileobj)
31 | metadata = jsonin.get('metadata',False)
32 | record_dicts = jsonin.get('records', jsonin)
33 |
34 | # if metadata provided from file, roll it into the collection object
35 | if metadata:
36 | metadata.update(collection)
37 | collection = metadata
38 |
39 | return self.index(collection, record_dicts)
40 |
41 | def index(self, collection_dict, record_dicts):
42 | '''Add this collection and its records to the database index.
43 | :return: (collection, records) tuple of collection and associated
44 | record objects.
45 | '''
46 | col_label_slug = util.slugify(collection_dict['label'])
47 | collection = bibserver.dao.Collection.get_by_owner_coll(self.owner.id, col_label_slug)
48 | if not collection:
49 | collection = bibserver.dao.Collection(**collection_dict)
50 | assert 'label' in collection, 'Collection must have a label'
51 | if not 'collection' in collection:
52 | collection['collection'] = col_label_slug
53 | collection['owner'] = self.owner.id
54 |
55 | collection.save()
56 |
57 | for rec in record_dicts:
58 | if not type(rec) is dict: continue
59 | rec['owner'] = collection['owner']
60 | if 'collection' in rec:
61 | if collection['collection'] != rec['collection']:
62 | rec['collection'] = collection['collection']
63 | else:
64 | rec['collection'] = collection['collection']
65 | if not self.requesturl and 'SITE_URL' in config:
66 | self.requesturl = str(config['SITE_URL'])
67 | if self.requesturl:
68 | if not self.requesturl.endswith('/'):
69 | self.requesturl += '/'
70 | if '_id' not in rec:
71 | rec['_id'] = bibserver.dao.make_id(rec)
72 | rec['url'] = self.requesturl + collection['owner'] + '/' + collection['collection'] + '/'
73 | if 'id' in rec:
74 | rec['url'] += rec['id']
75 | elif '_id' in rec:
76 | rec['url'] += rec['_id']
77 | bibserver.dao.Record.bulk_upsert(record_dicts)
78 | return collection, record_dicts
79 |
80 | def findformat(filename):
81 | if filename.endswith(".json"): return "json"
82 | if filename.endswith(".bibtex"): return "bibtex"
83 | if filename.endswith(".bib"): return "bibtex"
84 | if filename.endswith(".csv"): return "csv"
85 | return "bibtex"
86 |
87 |
--------------------------------------------------------------------------------
/bibserver/templates/home/faq.html:
--------------------------------------------------------------------------------
1 | {% extends "/base.html" %}
2 |
3 | {% block content %}
4 |
5 |
BibSoup uses bibJSON to represent bibliographic records; so in order to upload a collection,
63 | it needs to be in bibJSON.
64 |
If your collection is available online, then you can upload directly from the URL of the online file -
65 | and this also enables you to one-click refresh your collection whenever you make changes to that source file.
66 |
If your collection is not already in bibJSON, then try using one of our parsers to convert it.
Once you start an upload, a ticket will be created to track your upload request. You can
71 | then track your upload progress via the upload tickets info page.
78 | FacetView Pure Javascript Frontend for SOLR and ElasticSearch
79 |
80 |
81 |
82 | FacetView is a pure javascript frontend for ElasticSearch or SOLR
83 | search indices.
84 |
85 |
86 | It lets you easily embed a faceted browser and search front end into any web page. It also provides a micro-framework you can build on when creating user interfaces to SOLR and ElasticSearch.
87 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/doc/deploy.rst:
--------------------------------------------------------------------------------
1 | .. _deploy:
2 |
3 | ==========
4 | Deployment
5 | ==========
6 |
7 | Pre-requisites
8 | ==============
9 |
10 | This example is for installing bibserver to run bibsoup.net, but applies to
11 | other instances - just change relevant parts e.g. domain name and so on.
12 |
13 | These instructions work on an ubuntu / debian machine, and explain how to get a
14 | stable deployment using:
15 |
16 | * git (to get latest copy of code)
17 | * nginx (the web server that proxies to the web app)
18 | * python2.7+, pip, virtualenv (required to run the app)
19 | * gunicorn (runs the web app that receives the proxy from nginx)
20 | * supervisord (keeps everything up and running)
21 |
22 |
23 | nginx config
24 | ============
25 |
26 | Create an nginx site config named e.g. bibsoup.net
27 | default location is /etc/nginx/sites-available
28 | (for OKF machines should be in ~/etc/nginx/sites-available then symlinked)
29 | then symlink from /etc/nginx/sites-enabled
30 |
31 | upstream bibsoup_app_server {
32 | server 127.0.0.1:5050 fail_timeout=0;
33 | }
34 |
35 | server {
36 | server_name bibsoup.net;
37 |
38 | access_log /var/log/nginx/bibsoup.net.access.log;
39 |
40 | server_name_in_redirect off;
41 |
42 | client_max_body_size 20M;
43 |
44 | location / {
45 | ## straight-forward proxy
46 | proxy_redirect off;
47 | proxy_connect_timeout 75s;
48 | proxy_read_timeout 180s;
49 | proxy_set_header Host $host;
50 | proxy_set_header X-Real-IP $remote_addr;
51 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
52 |
53 | proxy_pass http://bibsoup_app_server;
54 | }
55 | }
56 |
57 |
58 | supervisord config
59 | ==================
60 |
61 | Create a supervisord config named e.g. bibsoup.net.conf
62 | - the default location for this is /etc/supervisor/conf.d
63 | (for OKF machines, should be put in ~/etc/supervisor/conf.d then symlinked)
64 |
65 | [program:bibsoup.net]
66 | command=/home/okfn/var/srvc/%(program_name)s/bin/gunicorn -w 4 -b 127.0.0.1:5050 bibserver.web:app
67 | user=www-data
68 | directory=/home/okfn/var/srvc/%(program_name)s/src/bibserver
69 | stdout_logfile=/var/log/supervisor/%(program_name)s-access.log
70 | stderr_logfile=/var/log/supervisor/%(program_name)s-error.log
71 | autostart=true
72 |
73 |
74 | Install bibserver
75 | =================
76 |
77 | Create a virtualenv and get the latest bibserver code installed.
78 | Bibserver requires python2.7+ so make sure that is available on your system,
79 | then start a virtualenv to run it in
80 |
81 | virtualenv -p python2.7 bibsoup.net --no-site-packages
82 | cd bibsoup.net
83 | mkdir src
84 | cd bin
85 | source activate
86 | cd ../src
87 | git clone https://github.com/okfn/bibserver
88 | cd bibserver
89 | python setup.py install
90 |
91 |
92 | Currently, setup.py install does not result in running system because
93 | config.json cannot be found. So, do dev install. This will be fixed asap
94 |
95 | pip install -e .
96 |
97 |
98 | Then install gunicorn into the virtualenv
99 |
100 | pip install gunicorn
101 |
102 |
103 | Now create a local_config.json with details as necessary
104 | for example check the ES index you with to use for this instance (default is bibserver)
105 |
106 | {
107 | "debug": false,
108 | "port": 5050,
109 | "ELASTIC_SEARCH_DB" : "bibserver_something",
110 | "ELASTIC_SEARCH_HOST" : "localhost:9200"
111 | }
112 |
113 |
114 | Now run bibserver directly to check it is working
115 | - this requires elasticsearch to be up and running, as it attempts to create indices.
116 |
117 | If it works, you should see confirmation of creation of the index and the mappings;
118 | if all good, kill it and move on. If not, debug the issues.
119 |
120 | python bibserver/web.py
121 |
122 |
123 | If the above step failed to push the mappings, you can do so manually.
124 | A command such as the following, augmented for your ES index URL and your index name,
125 | should do the job for you (default mappings are in config.json)
126 | (remember to do record and collection)
127 |
128 | curl -X PUT localhost:9200/bibserver/record/_mapping -d '{
129 | "record" : {
130 | "date_detection" : false,
131 | "dynamic_templates" : [
132 | {
133 | "default" : {
134 | "match" : "*",
135 | "match_mapping_type": "string",
136 | "mapping" : {
137 | "type" : "multi_field",
138 | "fields" : {
139 | "{name}" : {"type" : "{dynamic_type}", "index" : "analyzed", "store" : "no"},
140 | "exact" : {"type" : "{dynamic_type}", "index" : "not_analyzed", "store" : "yes"}
141 | }
142 | }
143 | }
144 | }
145 | ]
146 | }
147 | }'
148 |
149 |
150 | Enable everything
151 | =================
152 |
153 | In the case of OKF service deployment, make symbolic links from the supervisor
154 | and nginx files which should be in the ~/etc folder into the /etc/nginx/sites-available
155 | and /etc/supervisor/conf.d folders, then make symbolic link from /etc/nginx/sites-available
156 | into /etc/nginx/sites-enabled - if you do not use this pattern, just put the config
157 | directly in /etc/nginx/sites-available and symlink from there into sites-enabled
158 |
159 | cd /etc/nginx/sites-available
160 | ln -s ~/etc/nginx/sites-available/bibsoup.net .
161 | cd /etc/supervisor/conf.d
162 | ln -s ~/etc/supervisor/conf.d/bibsoup.net.conf .
163 |
164 |
165 | Then enable the new nginx and supervisor settings
166 |
167 | cd /etc/nginx/sites-enabled
168 | ln -s ../sites-available/bibsoup.net .
169 | /etc/init.d/nginx reload
170 | supervisorctl reread
171 | supervisorctl update
172 |
173 |
174 | Configure your domain name to point at your server, and it should work.
175 |
176 |
177 |
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 |
10 | # Internal variables.
11 | PAPEROPT_a4 = -D latex_paper_size=a4
12 | PAPEROPT_letter = -D latex_paper_size=letter
13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
14 | # the i18n builder cannot share the environment and doctrees with the others
15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
16 |
17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
18 |
19 | help:
20 | @echo "Please use \`make ' where is one of"
21 | @echo " html to make standalone HTML files"
22 | @echo " dirhtml to make HTML files named index.html in directories"
23 | @echo " singlehtml to make a single large HTML file"
24 | @echo " pickle to make pickle files"
25 | @echo " json to make JSON files"
26 | @echo " htmlhelp to make HTML files and a HTML help project"
27 | @echo " qthelp to make HTML files and a qthelp project"
28 | @echo " devhelp to make HTML files and a Devhelp project"
29 | @echo " epub to make an epub"
30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
31 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
32 | @echo " text to make text files"
33 | @echo " man to make manual pages"
34 | @echo " texinfo to make Texinfo files"
35 | @echo " info to make Texinfo files and run them through makeinfo"
36 | @echo " gettext to make PO message catalogs"
37 | @echo " changes to make an overview of all changed/added/deprecated items"
38 | @echo " linkcheck to check all external links for integrity"
39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
40 |
41 | clean:
42 | -rm -rf $(BUILDDIR)/*
43 |
44 | html:
45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
46 | @echo
47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
48 |
49 | dirhtml:
50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
51 | @echo
52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
53 |
54 | singlehtml:
55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
56 | @echo
57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
58 |
59 | pickle:
60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
61 | @echo
62 | @echo "Build finished; now you can process the pickle files."
63 |
64 | json:
65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
66 | @echo
67 | @echo "Build finished; now you can process the JSON files."
68 |
69 | htmlhelp:
70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
71 | @echo
72 | @echo "Build finished; now you can run HTML Help Workshop with the" \
73 | ".hhp project file in $(BUILDDIR)/htmlhelp."
74 |
75 | qthelp:
76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
77 | @echo
78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/BibServer.qhcp"
81 | @echo "To view the help file:"
82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/BibServer.qhc"
83 |
84 | devhelp:
85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
86 | @echo
87 | @echo "Build finished."
88 | @echo "To view the help file:"
89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/BibServer"
90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/BibServer"
91 | @echo "# devhelp"
92 |
93 | epub:
94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
95 | @echo
96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
97 |
98 | latex:
99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
100 | @echo
101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
103 | "(use \`make latexpdf' here to do that automatically)."
104 |
105 | latexpdf:
106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
107 | @echo "Running LaTeX files through pdflatex..."
108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
110 |
111 | text:
112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
113 | @echo
114 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
115 |
116 | man:
117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
118 | @echo
119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
120 |
121 | texinfo:
122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
123 | @echo
124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
125 | @echo "Run \`make' in that directory to run these through makeinfo" \
126 | "(use \`make info' here to do that automatically)."
127 |
128 | info:
129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
130 | @echo "Running Texinfo files through makeinfo..."
131 | make -C $(BUILDDIR)/texinfo info
132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
133 |
134 | gettext:
135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
136 | @echo
137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
138 |
139 | changes:
140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
141 | @echo
142 | @echo "The overview file is in $(BUILDDIR)/changes."
143 |
144 | linkcheck:
145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
146 | @echo
147 | @echo "Link check complete; look for any errors in the above output " \
148 | "or in $(BUILDDIR)/linkcheck/output.txt."
149 |
150 | doctest:
151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
152 | @echo "Testing of doctests in the sources finished, look at the " \
153 | "results in $(BUILDDIR)/doctest/output.txt."
154 |
--------------------------------------------------------------------------------
/bibserver/templates/record.html:
--------------------------------------------------------------------------------
1 | {% extends "/base.html" %}
2 |
3 | {% block content %}
4 |
5 | {% if multiple %}
6 |
7 |
8 |
You have requested a record based on the identifier it has in its' collection.
9 | Unfortunately, there are multiple records in the collection with the same identifier.
10 | If you are the collection owner, you should fix this (every record should have a
11 | unique identifier within your collection).
12 |
However, we allocate unique identifiers to each record ourselves, too. So, you
13 | can choose which record you would like to view and access it via the unique
14 | identifier we assigned it: