├── .eslintignore ├── src ├── snovault │ ├── tests │ │ ├── __init__.py │ │ ├── test_snowflake_hash.py │ │ ├── testing_auditor.py │ │ ├── testing_key.py │ │ ├── testing_upgrader.py │ │ ├── pyramidfixtures.py │ │ ├── test_schema_utils.py │ │ ├── test_indexer_state.py │ │ ├── test_searches_configs.py │ │ ├── test_upgrader.py │ │ ├── toolfixtures.py │ │ ├── test_searches_fields.py │ │ └── test_link.py │ ├── commands │ │ ├── __init__.py │ │ ├── es_index_data.py │ │ ├── jsonld_rdf.py │ │ └── spreadsheet_to_json.py │ ├── elasticsearch │ │ ├── searches │ │ │ ├── __init__.py │ │ │ ├── interfaces.py │ │ │ ├── fields.py │ │ │ └── configs.py │ │ ├── tests │ │ │ └── __init__.py │ │ ├── uuid_queue │ │ │ ├── tests │ │ │ │ └── __init__.py │ │ │ └── __init__.py │ │ ├── interfaces.py │ │ └── cached_views.py │ ├── interfaces.py │ ├── predicates.py │ ├── nginx-dev.conf │ ├── json_renderer.py │ ├── jsongraph.py │ ├── cache.py │ ├── snowflake_hash.py │ ├── local_storage.py │ └── validators.py └── snowflakes │ ├── tests │ ├── features │ │ ├── __init__.py │ │ ├── test_workbook.py │ │ ├── test_admin_user.py │ │ ├── test_submitter_user.py │ │ ├── test_nodata.py │ │ ├── user.feature │ │ ├── toolbar.feature │ │ ├── title.feature │ │ ├── page.feature │ │ ├── test_generics.py │ │ ├── search.feature │ │ ├── generics.feature │ │ └── forms.feature │ ├── data │ │ ├── inserts │ │ │ ├── small_db.tsv │ │ │ ├── image.json │ │ │ └── snowfort.json │ │ └── documents │ │ │ ├── selma.jpg │ │ │ ├── jocelyn.jpg │ │ │ └── frowny_gel.png │ ├── test_create_mapping.py │ ├── test_renderers.py │ ├── test_graph.py │ ├── __init__.py │ ├── test_upgrade_award.py │ ├── test_webuser_auth.py │ ├── test_schemas.py │ └── test_server_defaults.py │ ├── commands │ ├── __init__.py │ ├── es_index_data.py │ ├── create_admin_user.py │ ├── jsonld_rdf.py │ └── spreadsheet_to_json.py │ ├── static │ ├── scss │ │ ├── snowflakes │ │ │ ├── _bootstrap-lib.scss │ │ │ ├── modules │ │ │ │ ├── _lists.scss │ │ │ │ ├── _breadcrumbs.scss │ │ │ │ ├── _loading-spinner.scss │ │ │ │ ├── _modals.scss │ │ │ │ ├── _signin-box.scss │ │ │ │ ├── _lightbox.scss │ │ │ │ ├── _tooltip.scss │ │ │ │ └── _layout-editor.scss │ │ │ ├── _theme.scss │ │ │ ├── _mixins-custom.scss │ │ │ └── _state.scss │ │ ├── fontawesome │ │ │ ├── _fixed-width.scss │ │ │ ├── _core.scss │ │ │ ├── _bordered-pulled.scss │ │ │ ├── _larger.scss │ │ │ ├── _rotated-flipped.scss │ │ │ ├── _list.scss │ │ │ ├── _font-awesome.scss │ │ │ ├── _stacked.scss │ │ │ ├── _path.scss │ │ │ ├── _mixins.scss │ │ │ ├── _spinning.scss │ │ │ └── _extras.scss │ │ ├── react-forms │ │ │ ├── _CheckboxGroup.scss │ │ │ └── _RadioButtonGroup.scss │ │ └── bootstrap │ │ │ ├── _responsive-980px-1199px.scss │ │ │ ├── _wells.scss │ │ │ ├── _component-animations.scss │ │ │ ├── _breadcrumbs.scss │ │ │ ├── _close.scss │ │ │ ├── _thumbnails.scss │ │ │ ├── _utilities.scss │ │ │ ├── _jumbotron.scss │ │ │ ├── _media.scss │ │ │ ├── _pager.scss │ │ │ ├── _badges.scss │ │ │ ├── _labels.scss │ │ │ ├── _code.scss │ │ │ ├── _alerts.scss │ │ │ ├── _grid.scss │ │ │ ├── _progress-bars.scss │ │ │ ├── _print.scss │ │ │ ├── _responsive-utilities.scss │ │ │ └── _pagination.scss │ ├── dev-robots.txt │ ├── components │ │ ├── lib │ │ │ └── index.js │ │ ├── testdata │ │ │ ├── lab.js │ │ │ ├── award.js │ │ │ └── submitter.js │ │ ├── blocks │ │ │ ├── index.js │ │ │ ├── fallback.js │ │ │ └── item.js │ │ ├── inputs │ │ │ ├── index.js │ │ │ └── file.js │ │ ├── ImpersonateUserSchema.js │ │ ├── JSONNode.js │ │ ├── __tests__ │ │ │ ├── .jshintrc │ │ │ └── server-render-test.js │ │ ├── testing.js │ │ ├── index.js │ │ ├── objectutils.js │ │ ├── page.js │ │ ├── home.js │ │ ├── statuslabel.js │ │ ├── StickyHeader.js │ │ └── schema.js │ ├── google63612883561ae8ff.html │ ├── img │ │ ├── asc.gif │ │ ├── bg.gif │ │ ├── desc.gif │ │ ├── file.png │ │ ├── favicon.ico │ │ ├── file-pdf.png │ │ ├── som-logo.png │ │ ├── spinner1.gif │ │ ├── su-logo.png │ │ ├── ucsc-logo.png │ │ ├── close-icon.png │ │ ├── file-broken.png │ │ ├── som-logo-red.png │ │ ├── su-logo-white.png │ │ ├── su-logo-white-2x.png │ │ ├── ucsc-logo-white.png │ │ ├── orientation-icons.png │ │ ├── spinner-orange-bg.gif │ │ ├── ucsc-logo-white-alt.png │ │ ├── glyphicons-halflings.png │ │ ├── ucsc-logo-white-alt-2x.png │ │ ├── glyphicons-halflings-white.png │ │ ├── checker.svg │ │ ├── hiding-dots.svg │ │ └── close-icon.svg │ ├── build │ │ └── .gitignore │ ├── mime.types │ ├── robots.txt │ ├── font │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff │ ├── libs │ │ ├── react-patches.js │ │ ├── closest.js │ │ ├── noarg-memoize.js │ │ ├── offset.js │ │ ├── __tests__ │ │ │ ├── .jshintrc │ │ │ └── registry-test.js │ │ ├── jsonScriptEscape.js │ │ ├── origin.js │ │ ├── bootstrap │ │ │ ├── dropdown-menu.js │ │ │ └── panel.js │ │ ├── registry.js │ │ ├── compat.js │ │ ├── react-middleware.js │ │ └── svg-icons.js │ ├── inline.js │ ├── browser.js │ └── server.js │ ├── audit │ └── __init__.py │ ├── schemas │ ├── namespaces.json │ ├── changelogs │ │ ├── example.md │ │ └── award.md │ ├── image.json │ └── access_key.json │ ├── upgrade │ ├── user.py │ ├── snowset.py │ ├── award.py │ └── __init__.py │ ├── types │ ├── image.py │ └── __init__.py │ ├── schema_formats.py │ ├── memlimit.py │ ├── typedsheets.py │ └── authorization.py ├── MANIFEST.in ├── setup.cfg ├── demo.cfg ├── node_shims ├── ckeditor │ ├── index.js │ └── package.json └── google-analytics │ ├── index.js │ └── package.json ├── etc └── logging-apache.conf ├── test.cfg ├── Makefile ├── cloudwatchmon-requirements.txt ├── docs ├── rendering-overview.pdf └── search.rst ├── conf ├── elasticsearch.yml └── jvm.options ├── requirements.txt ├── requirements.osx.txt ├── candidate.cfg ├── .babelrc ├── .eslintrc.json ├── jest └── environment.js ├── .gitignore ├── circle-tests.sh ├── gulpfile.js ├── pytest.ini ├── config.rb ├── scripts ├── embeds.py ├── LogToCsv.py └── blackholes.py ├── LICENSE.txt ├── production.ini.in ├── examples └── s3cp.py ├── development.ini └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | **/testdata 2 | -------------------------------------------------------------------------------- /src/snovault/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/snowflakes/tests/features/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.rst 2 | include *.md 3 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 100 3 | -------------------------------------------------------------------------------- /src/snovault/commands/__init__.py: -------------------------------------------------------------------------------- 1 | # package 2 | -------------------------------------------------------------------------------- /src/snovault/elasticsearch/searches/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/snovault/elasticsearch/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo.cfg: -------------------------------------------------------------------------------- 1 | [buildout] 2 | extends = buildout.cfg 3 | -------------------------------------------------------------------------------- /src/snowflakes/commands/__init__.py: -------------------------------------------------------------------------------- 1 | # package 2 | -------------------------------------------------------------------------------- /src/snovault/elasticsearch/uuid_queue/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/snowflakes/_bootstrap-lib.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /node_shims/ckeditor/index.js: -------------------------------------------------------------------------------- 1 | module.exports = global.CKEDITOR; 2 | -------------------------------------------------------------------------------- /src/snowflakes/static/dev-robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /src/snowflakes/audit/__init__.py: -------------------------------------------------------------------------------- 1 | def includeme(config): 2 | config.scan() 3 | -------------------------------------------------------------------------------- /etc/logging-apache.conf: -------------------------------------------------------------------------------- 1 | CustomLog ${APACHE_LOG_DIR}/access.log vhost_combined_stats 2 | -------------------------------------------------------------------------------- /src/snowflakes/static/components/lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./store'); 4 | -------------------------------------------------------------------------------- /src/snowflakes/static/google63612883561ae8ff.html: -------------------------------------------------------------------------------- 1 | google-site-verification: google63612883561ae8ff.html -------------------------------------------------------------------------------- /test.cfg: -------------------------------------------------------------------------------- 1 | [buildout] 2 | extends = buildout.cfg 3 | 4 | [production-ini] 5 | indexer_processes = 16 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | rm -rf node_modules parts 3 | rm -rf .sass-cache 4 | rm -rf src/snowflakes/static/css 5 | -------------------------------------------------------------------------------- /cloudwatchmon-requirements.txt: -------------------------------------------------------------------------------- 1 | argparse==1.2.1 2 | boto==2.38.0 3 | cloudwatchmon==2.0.3 4 | wsgiref==0.1.2 5 | -------------------------------------------------------------------------------- /docs/rendering-overview.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/docs/rendering-overview.pdf -------------------------------------------------------------------------------- /src/snowflakes/schemas/namespaces.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "This should contain keys and URL references" 3 | } -------------------------------------------------------------------------------- /src/snovault/elasticsearch/searches/interfaces.py: -------------------------------------------------------------------------------- 1 | NON_SORTABLE = 'non_sortable' 2 | SEARCH_CONFIG = 'search_config' 3 | -------------------------------------------------------------------------------- /src/snowflakes/static/img/asc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/asc.gif -------------------------------------------------------------------------------- /src/snowflakes/static/img/bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/bg.gif -------------------------------------------------------------------------------- /src/snowflakes/static/img/desc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/desc.gif -------------------------------------------------------------------------------- /src/snowflakes/static/img/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/file.png -------------------------------------------------------------------------------- /src/snowflakes/static/build/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /src/snowflakes/tests/data/inserts/small_db.tsv: -------------------------------------------------------------------------------- 1 | 7a5e9183-b52f-4f75-9708-8e077b086b4e 2 | e2f35c88-a792-4dea-b5d2-30dc52ed2495 3 | -------------------------------------------------------------------------------- /src/snowflakes/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/favicon.ico -------------------------------------------------------------------------------- /src/snowflakes/static/img/file-pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/file-pdf.png -------------------------------------------------------------------------------- /src/snowflakes/static/img/som-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/som-logo.png -------------------------------------------------------------------------------- /src/snowflakes/static/img/spinner1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/spinner1.gif -------------------------------------------------------------------------------- /src/snowflakes/static/img/su-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/su-logo.png -------------------------------------------------------------------------------- /src/snowflakes/static/img/ucsc-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/ucsc-logo.png -------------------------------------------------------------------------------- /src/snowflakes/static/mime.types: -------------------------------------------------------------------------------- 1 | application/font-woff woff 2 | text/autosql as 3 | text/markdown md 4 | image/tiff svs 5 | -------------------------------------------------------------------------------- /src/snowflakes/static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /*?*limit=all 3 | Disallow: /files/*download 4 | Disallow: /cgi-bin/ 5 | -------------------------------------------------------------------------------- /src/snowflakes/static/img/close-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/close-icon.png -------------------------------------------------------------------------------- /src/snowflakes/static/img/file-broken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/file-broken.png -------------------------------------------------------------------------------- /conf/elasticsearch.yml: -------------------------------------------------------------------------------- 1 | cluster.name: elasticsearch_test_fixture 2 | discovery.type: single-node 3 | indices.query.bool.max_clause_count: 8192 -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pip==20.0.2 2 | psycopg2==2.8.4 3 | redis==3.5.3 4 | redis-server==5.0.7 5 | setuptools==45.1.0 6 | zc.buildout==2.13.2 7 | -------------------------------------------------------------------------------- /src/snowflakes/static/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/font/FontAwesome.otf -------------------------------------------------------------------------------- /src/snowflakes/static/img/som-logo-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/som-logo-red.png -------------------------------------------------------------------------------- /src/snowflakes/static/img/su-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/su-logo-white.png -------------------------------------------------------------------------------- /requirements.osx.txt: -------------------------------------------------------------------------------- 1 | pip==20.0.2 2 | psycopg2==2.8.4 3 | redis==3.5.3 4 | redis-server==5.0.7 5 | setuptools==45.1.0 6 | zc.buildout==2.13.2 7 | -------------------------------------------------------------------------------- /src/snowflakes/static/img/su-logo-white-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/su-logo-white-2x.png -------------------------------------------------------------------------------- /src/snowflakes/static/img/ucsc-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/ucsc-logo-white.png -------------------------------------------------------------------------------- /src/snowflakes/tests/data/documents/selma.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/tests/data/documents/selma.jpg -------------------------------------------------------------------------------- /src/snowflakes/static/img/orientation-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/orientation-icons.png -------------------------------------------------------------------------------- /src/snowflakes/static/img/spinner-orange-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/spinner-orange-bg.gif -------------------------------------------------------------------------------- /src/snowflakes/static/img/ucsc-logo-white-alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/ucsc-logo-white-alt.png -------------------------------------------------------------------------------- /src/snowflakes/tests/data/documents/jocelyn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/tests/data/documents/jocelyn.jpg -------------------------------------------------------------------------------- /src/snowflakes/static/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /src/snowflakes/static/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/snowflakes/static/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/snowflakes/static/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /src/snowflakes/tests/data/documents/frowny_gel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/tests/data/documents/frowny_gel.png -------------------------------------------------------------------------------- /src/snowflakes/static/img/ucsc-logo-white-alt-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/ucsc-logo-white-alt-2x.png -------------------------------------------------------------------------------- /src/snowflakes/static/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCODE-DCC/snovault/HEAD/src/snowflakes/static/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /src/snowflakes/static/components/testdata/lab.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "@id": "/labs/thomas-gingeras/", 3 | "@type": ["lab", "item"], 4 | "title": "Thomas Gingeras, CSHL" 5 | }; -------------------------------------------------------------------------------- /src/snowflakes/static/libs/react-patches.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // These patches must be executed before any call to require('react'). 3 | 4 | // There are currently no patches pending ;) 5 | -------------------------------------------------------------------------------- /src/snowflakes/static/components/blocks/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./fallback'); 4 | require('./richtext'); 5 | require('./item'); 6 | require('./search'); 7 | require('./teaser'); 8 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/fontawesome/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/react-forms/_CheckboxGroup.scss: -------------------------------------------------------------------------------- 1 | .rf-CheckboxGroup__button { 2 | @include checkbox; 3 | } 4 | 5 | .rf-CheckboxGroup__caption { 6 | margin-left: 10px; 7 | @include user-select(none); 8 | } -------------------------------------------------------------------------------- /node_shims/google-analytics/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /* global ga */ 3 | global.ga = global.ga || function () { 4 | (ga.q = ga.q || []).push(arguments); 5 | }; 6 | ga.l = +new Date(); 7 | module.exports = global.ga; 8 | -------------------------------------------------------------------------------- /src/snowflakes/static/libs/closest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = function closest(el, selector) { 3 | while (el) { 4 | if (el.matches(selector)) return el; 5 | el = el.parentElement; 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/react-forms/_RadioButtonGroup.scss: -------------------------------------------------------------------------------- 1 | .rf-RadioButtonGroup__button { 2 | @include radio; 3 | } 4 | 5 | .rf-RadioButtonGroup__caption { 6 | margin-left: 10px; 7 | @include user-select(none); 8 | } 9 | -------------------------------------------------------------------------------- /candidate.cfg: -------------------------------------------------------------------------------- 1 | [buildout] 2 | extends = buildout.cfg 3 | 4 | [production-ini] 5 | accession_factory = snowflakes.server_defaults.enc_accession 6 | file_upload_bucket = snowflake-files 7 | blob_bucket = snovault-blobs 8 | indexer_processes = 16 -------------------------------------------------------------------------------- /src/snowflakes/schemas/changelogs/example.md: -------------------------------------------------------------------------------- 1 | ================================= 2 | Example Change Log 3 | ================================= 4 | 5 | Schema version 2 6 | ---------------- 7 | 8 | * *object_type had the some properties removed -------------------------------------------------------------------------------- /src/snowflakes/static/components/testdata/award.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "@id": "/awards/RC2HG005602/", 3 | "@type": ["Award", "Item"], 4 | "name": "RC2HG005602", 5 | "project": "ENCODE", 6 | "rfa": "ENCODE3" 7 | }; 8 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | presets: [ 3 | '@babel/preset-env', 4 | '@babel/preset-react', 5 | '@babel/flow', 6 | ], 7 | plugins: [ 8 | '@babel/plugin-proposal-object-rest-spread', 9 | '@babel/plugin-transform-modules-commonjs', 10 | ] 11 | } -------------------------------------------------------------------------------- /src/snowflakes/upgrade/user.py: -------------------------------------------------------------------------------- 1 | from snovault import upgrade_step 2 | 3 | 4 | @upgrade_step('user', '', '3') 5 | def user_0_3(value, system): 6 | # http://encode.stanford.edu/issues/1307 7 | if 'status' in value: 8 | value['status'] = value['status'].lower() 9 | -------------------------------------------------------------------------------- /node_shims/ckeditor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ckeditor", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "MIT" 11 | } 12 | -------------------------------------------------------------------------------- /src/snowflakes/static/components/testdata/submitter.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "@id": "/users/0abbd494-b852-433c-b360-93996f679dae/", 3 | "@type": ["User", "Item"], 4 | "id": "0abbd494-b852-433c-b360-93996f679dae", 5 | "lab": "/labs/thomas-gingeras/", 6 | "title": "Ad Est" 7 | }; -------------------------------------------------------------------------------- /src/snowflakes/tests/features/test_workbook.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest_bdd import scenarios 3 | 4 | pytestmark = [ 5 | pytest.mark.bdd, 6 | pytest.mark.usefixtures('workbook'), 7 | ] 8 | 9 | scenarios( 10 | 'search.feature', 11 | strict_gherkin=False 12 | ) 13 | -------------------------------------------------------------------------------- /src/snowflakes/static/img/checker.svg: -------------------------------------------------------------------------------- 1 | checker -------------------------------------------------------------------------------- /node_shims/google-analytics/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "google-analytics", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "MIT" 11 | } 12 | -------------------------------------------------------------------------------- /src/snowflakes/static/components/inputs/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var FileInput = module.exports.FileInput = require('./file'); 4 | var ObjectPicker = module.exports.ObjectPicker = require('./object').ObjectPicker; 5 | var ItemPreview = module.exports.ItemPreview = require('./object').ItemPreview; 6 | -------------------------------------------------------------------------------- /src/snowflakes/tests/features/test_admin_user.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest_bdd import scenarios 3 | 4 | pytestmark = [ 5 | pytest.mark.bdd, 6 | pytest.mark.usefixtures('workbook', 'admin_user'), 7 | ] 8 | 9 | 10 | scenarios( 11 | 'forms.feature', 12 | 'page.feature', 13 | strict_gherkin=False 14 | ) 15 | -------------------------------------------------------------------------------- /src/snowflakes/static/components/ImpersonateUserSchema.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var ReactForms = require('react-forms'); 3 | 4 | module.exports = ReactForms.schema.Mapping({}, { 5 | userid: ReactForms.schema.Scalar({ 6 | label: 'User', 7 | hint: 'Enter the email of the user you want to impersonate.', 8 | }), 9 | }); 10 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/snowflakes/modules/_lists.scss: -------------------------------------------------------------------------------- 1 | // For displaying a list in a panel where you'd normally find the dl/dt/dd value pairs. 2 | .non-dl-list { 3 | list-style: none; 4 | margin: 0 0 0 60px; 5 | } 6 | 7 | // For displaying a single-item where you'd otherwise find lists 8 | .non-dl-item { 9 | margin-left: 60px; 10 | } -------------------------------------------------------------------------------- /src/snowflakes/tests/features/test_submitter_user.py: -------------------------------------------------------------------------------- 1 | 2 | # import pytest 3 | # from pytest_bdd import scenarios 4 | 5 | # pytestmark = [ 6 | # pytest.mark.bdd, 7 | # pytest.mark.usefixtures('workbook', 'submitter_user'), 8 | # ] 9 | 10 | 11 | # scenarios( 12 | # 'user.feature', 13 | # strict_gherkin=False 14 | # ) 15 | -------------------------------------------------------------------------------- /src/snowflakes/tests/features/test_nodata.py: -------------------------------------------------------------------------------- 1 | """ These scenarios do not require the workbook fixture, but get it anyway. 2 | """ 3 | import pytest 4 | from pytest_bdd import scenarios 5 | 6 | pytestmark = [ 7 | pytest.mark.bdd, 8 | ] 9 | 10 | scenarios( 11 | 'title.feature', 12 | 'toolbar.feature', 13 | strict_gherkin=False 14 | ) 15 | -------------------------------------------------------------------------------- /src/snovault/elasticsearch/interfaces.py: -------------------------------------------------------------------------------- 1 | from zope.interface import Interface 2 | 3 | # Registry tool id 4 | APP_FACTORY = 'app_factory' 5 | ELASTIC_SEARCH = 'elasticsearch' 6 | SNP_SEARCH_ES = 'snp_search' 7 | INDEXER = 'indexer' 8 | RESOURCES_INDEX = 'snovault-resources' 9 | 10 | 11 | class ICachedItem(Interface): 12 | """ Marker for cached Item 13 | """ 14 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/fontawesome/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font-family: FontAwesome; 7 | font-style: normal; 8 | font-weight: normal; 9 | line-height: 1; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | } 13 | -------------------------------------------------------------------------------- /src/snowflakes/static/libs/noarg-memoize.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Exists to work around https://github.com/prometheusresearch/react-forms/issues/70 3 | module.exports = function noarg_memoize(fn) { 4 | var value; 5 | return function () { 6 | if (value === undefined) { 7 | value = fn(); 8 | } 9 | return value; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /src/snowflakes/static/libs/offset.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // http://www.quirksmode.org/js/findpos.html 3 | module.exports = function offset(el) { 4 | var curleft = 0; 5 | var curtop = 0; 6 | do { 7 | curleft += el.offsetLeft; 8 | curtop += el.offsetTop; 9 | } while (el = el.offsetParent); 10 | return {left: curleft, top: curtop}; 11 | }; 12 | -------------------------------------------------------------------------------- /src/snowflakes/static/img/hiding-dots.svg: -------------------------------------------------------------------------------- 1 | Indicates hiddent content -------------------------------------------------------------------------------- /src/snowflakes/tests/test_create_mapping.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from ..loadxl import ORDER 3 | 4 | 5 | @pytest.mark.parametrize('item_type', ORDER) 6 | def test_create_mapping(registry, item_type): 7 | from snovault.elasticsearch.create_mapping import type_mapping 8 | from snovault import TYPES 9 | mapping = type_mapping(registry[TYPES], item_type) 10 | assert mapping 11 | -------------------------------------------------------------------------------- /src/snowflakes/static/img/close-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/snowflakes/tests/features/user.feature: -------------------------------------------------------------------------------- 1 | Feature: User Profile 2 | 3 | Scenario Outline: View profile 4 | When I visit "/" 5 | And I click the link with text that contains "J. Michael Cherry" 6 | And I click the link with text that contains "Profile" 7 | Then I should see "J. Michael Cherry, Stanford" 8 | And I should see an element with the css selector ".access-keys" 9 | -------------------------------------------------------------------------------- /src/snowflakes/static/libs/__tests__/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esnext": true, 3 | "node": true, 4 | "predef": [ 5 | "afterEach", 6 | "beforeEach", 7 | "describe", 8 | "expect", 9 | "it", 10 | "jest", 11 | "pit", 12 | "xdescribe", 13 | "xit" 14 | ], 15 | "globalstrict": true, 16 | "newcap": false, 17 | "sub": true 18 | } 19 | -------------------------------------------------------------------------------- /src/snowflakes/static/libs/jsonScriptEscape.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var SUBS = {'&': '\\u0026', '<': '\\u003C', '>': '\\u003E'}; 3 | var unsafe_re = /[\<\>\&]/g; 4 | 5 | 6 | var sub = function (match) { 7 | return SUBS[match]; 8 | }; 9 | 10 | 11 | var jsonScriptEscape = function (json_string) { 12 | return json_string.replace(unsafe_re, sub); 13 | }; 14 | 15 | 16 | module.exports = jsonScriptEscape; 17 | -------------------------------------------------------------------------------- /src/snowflakes/static/components/JSONNode.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var ReactForms = require('react-forms'); 3 | 4 | class JSONNode extends ReactForms.schema.ScalarNode { 5 | serialize(value) { 6 | return JSON.stringify(value, null, 4); 7 | } 8 | deserialize(value) { 9 | return (typeof value === 'string') ? JSON.parse(value) : value; 10 | } 11 | } 12 | 13 | module.exports = JSONNode; 14 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/snowflakes/modules/_breadcrumbs.scss: -------------------------------------------------------------------------------- 1 | .breadcrumb { 2 | padding: 5px 0; 3 | background-color: transparent; 4 | border-bottom: 1px solid #c0c0c0; 5 | 6 | > li { 7 | text-transform: uppercase; 8 | font-weight: bold; 9 | font-size: 12px; 10 | color: #808080; 11 | 12 | + li:before { 13 | padding: 0 5px 0 10px; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/snowflakes/static/components/__tests__/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esnext": true, 3 | "node": true, 4 | "predef": [ 5 | "DOMParser", 6 | "afterEach", 7 | "beforeEach", 8 | "describe", 9 | "expect", 10 | "it", 11 | "jest", 12 | "pit", 13 | "xdescribe", 14 | "xit" 15 | ], 16 | "globalstrict": true, 17 | "newcap": false, 18 | "sub": true 19 | } 20 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/fontawesome/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .pull-right { float: right; } 11 | .pull-left { float: left; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.pull-left { margin-right: .3em; } 15 | &.pull-right { margin-left: .3em; } 16 | } 17 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/fontawesome/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /src/snowflakes/static/components/testing.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var React = require('react'); 3 | var globals = require('./globals'); 4 | 5 | 6 | var TestingRenderErrorPanel = module.exports.TestingRenderErrorPanel = React.createClass({ 7 | render: function() { 8 | console.log('log'); 9 | console.warn('warn'); 10 | this.method_does_not_exist(); 11 | } 12 | }); 13 | 14 | globals.panel_views.register(TestingRenderErrorPanel, 'TestingRenderError'); 15 | -------------------------------------------------------------------------------- /src/snovault/elasticsearch/uuid_queue/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Uuid Queue Module Adapter 3 | 4 | - QueueAdapter Class allows access to all queue types 5 | defined in QueueTypes through a set of standard methods. 6 | - All queues in ./queues should adhere to QueueAdapter standards. 7 | - Adapter queue has a server and a worker. 8 | - Another important object is the meta data needed to run the queue. 9 | """ 10 | from .adapter_queue import QueueAdapter 11 | from .adapter_queue import QueueTypes 12 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/fontawesome/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | -------------------------------------------------------------------------------- /src/snowflakes/tests/features/toolbar.feature: -------------------------------------------------------------------------------- 1 | @toolbar 2 | Feature: Toolbar 3 | 4 | Scenario: Active section 5 | When I visit "/" 6 | #Then I should see an element with the css selector "#global-sections > li.active > a[href='/']" 7 | Then I should not see an element with the css selector "#global-sections > li.active > a:not([href='/'])" 8 | And I should see an element with the css selector "#loginbtn" 9 | And I should see "Where all objects are special" 10 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/fontawesome/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/snowflakes/tests/features/title.feature: -------------------------------------------------------------------------------- 1 | @title 2 | Feature: Title 3 | 4 | Scenario: Title updates 5 | When I visit "/" 6 | And I wait for the content to load 7 | Then the title should contain the text "Snowflakes... By SnoVault" 8 | When I click the link with text that contains "Data" 9 | And I click the link to "/search/?type=Snowfort" 10 | And I wait for the content to load 11 | Then the title should contain the text "Search – SNOWFLAKES" 12 | -------------------------------------------------------------------------------- /src/snowflakes/schemas/changelogs/award.md: -------------------------------------------------------------------------------- 1 | Change log for award.json 2 | ========================= 3 | 4 | 5 | Schema version 2 6 | ---------------- 7 | 8 | * Default values of '' were removed. You can no longer submit a blank url (url='') 9 | 10 | * *status* was brought into line with other objects that are shared. Disabled grants with rfa in ['ENCODE2', 'ENCODE2-Mouse']: 11 | 12 | "enum" : [ 13 | "current", 14 | "deleted", 15 | "replaced", 16 | "disabled" 17 | ] 18 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/fontawesome/_font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.1.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | //@import "larger"; 11 | //@import "fixed-width"; 12 | //@import "list"; 13 | //@import "bordered-pulled"; 14 | //@import "spinning"; 15 | //@import "rotated-flipped"; 16 | //@import "stacked"; 17 | @import "icons"; 18 | -------------------------------------------------------------------------------- /src/snowflakes/upgrade/snowset.py: -------------------------------------------------------------------------------- 1 | from snovault import upgrade_step 2 | 3 | ''' Note these are not relevant to anything beyond testing upgrader ''' 4 | 5 | 6 | @upgrade_step('snowball', '', '2') 7 | @upgrade_step('snowfort', '', '2') 8 | def snowset_0_2(value, system): 9 | # example upgrade for tests 10 | if 'status' in value: 11 | if value['status'] == 'DELETED': 12 | value['status'] = 'deleted' 13 | elif value['status'] == 'CURRENT': 14 | value['status'] = 'submitted' # there is a dependency on date_released+"released" 15 | -------------------------------------------------------------------------------- /src/snovault/tests/test_snowflake_hash.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | TEST_HASHES = { 4 | "test": "Jnh+8wNnELksNFVbxkya8RDrxJNL13dUWTXhp5DCx/quTM2/cYn7azzl2Uk3I2zc", 5 | "test2": "sh33L5uQeLr//jJULb7mAnbVADkkWZrgcXx97DCacueGtEU5G2HtqUv73UTS0EI0", 6 | "testing100" * 10: "5rznDSIcDPd/9rjom6P/qkJGtJSV47y/u5+KlkILROaqQ6axhEyVIQTahuBYerLG", 7 | } 8 | 9 | 10 | @pytest.mark.parametrize(('password', 'pwhash'), TEST_HASHES.items()) 11 | def test_snowflake_hash(password, pwhash): 12 | from snovault.snowflake_hash import SNOWHash 13 | assert SNOWHash.hash(password) == pwhash 14 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/bootstrap/_responsive-980px-1199px.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Tablet to desktop 3 | // -------------------------------------------------- 4 | 5 | 6 | @media (min-width: 980px) and (max-width: 1199px) { 7 | 8 | // Fixed grid 9 | @include grid-core($gridColumnWidth, $gridGutterWidth); 10 | 11 | // Fluid grid 12 | @include grid-fluid($fluidGridColumnWidth, $fluidGridGutterWidth); 13 | 14 | // Input grid 15 | @include grid-input($gridColumnWidth, $gridGutterWidth); 16 | 17 | // No need to reset .thumbnails here since it's the same $gridGutterWidth 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/fontawesome/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/snowflakes/modules/_loading-spinner.scss: -------------------------------------------------------------------------------- 1 | .black-overlay { 2 | display: none; 3 | background-color: black; 4 | left: 0%; 5 | opacity: 0.5; 6 | position: absolute; 7 | height: 100%; 8 | top: 0%; 9 | width: 100%; 10 | z-index: 1001; 11 | } 12 | 13 | .loading-spinner { 14 | background: url('../img/spinner1.gif') no-repeat; 15 | display: none; 16 | left: 50%; 17 | overflow: auto; 18 | position: absolute; 19 | top: 9%; 20 | width: 30px; 21 | height: 30px; 22 | z-index: 1002; 23 | } 24 | 25 | .communicating .black-overlay, .communicating .loading-spinner { 26 | display: block; 27 | } -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "indent": [2, 4, {"SwitchCase": 1}], 4 | "linebreak-style": [2, "unix"], 5 | "semi": [2, "always"], 6 | "no-console": 0, 7 | "no-unused-vars": 0, 8 | "no-empty": 0 9 | }, 10 | "env": { 11 | "es6": true, 12 | "browser": true, 13 | "commonjs": true 14 | }, 15 | "extends": "eslint:recommended", 16 | "parserOptions": { 17 | "ecmaVersion": 6, 18 | "sourceType": "module", 19 | "ecmaFeatures": { 20 | "jsx": true 21 | } 22 | }, 23 | "plugins": [ 24 | "react" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /jest/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | jest.mock('scriptjs'); 3 | var jsdom = require('jsdom').jsdom; 4 | 5 | if (window.DOMParser === undefined) { 6 | // jsdom 7 | window.DOMParser = function DOMParser() {}; 8 | window.DOMParser.prototype.parseFromString = function parseFromString(markup, type) { 9 | var parsingMode = 'auto'; 10 | type = type || ''; 11 | if (type.indexOf('xml') >= 0) { 12 | parsingMode = 'xml'; 13 | } else if (type.indexOf('html') >= 0) { 14 | parsingMode = 'html'; 15 | } 16 | var doc = jsdom(markup, {parsingMode: parsingMode}); 17 | return doc; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/snowflakes/tests/data/inserts/image.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Selma the cat", 4 | "attachment": "selma.jpg", 5 | "submitted_by": "david@glicksoftware.com", 6 | "uuid": "b4589f52-521e-45db-8dfa-378d92cbbd86" 7 | }, 8 | { 9 | "caption": "Jocelyn", 10 | "attachment": "jocelyn.jpg", 11 | "submitted_by": "fytanaka@stanford.edu", 12 | "uuid": "8a91ae78-731a-4a92-ae7c-273214be408a" 13 | }, 14 | { 15 | "caption": "frowny gel", 16 | "attachment": "frowny_gel.png", 17 | "submitted_by": "cricketsloan@stanford.edu", 18 | "uuid": "1a0df3d4-2496-4d1f-ba4f-519bc2a22cfd" 19 | } 20 | ] -------------------------------------------------------------------------------- /src/snowflakes/static/components/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Require all components to ensure javascript load ordering 4 | require('./lib'); 5 | require('./app'); 6 | require('./image'); 7 | require('./collection'); 8 | require('./errors'); 9 | require('./footer'); 10 | require('./globals'); 11 | require('./graph'); 12 | require('./doc'); 13 | require('./home'); 14 | require('./item'); 15 | require('./page'); 16 | require('./mixins'); 17 | require('./search'); 18 | require('./report'); 19 | require('./testing'); 20 | require('./edit'); 21 | require('./inputs'); 22 | require('./blocks'); 23 | require('./user'); 24 | require('./schema'); 25 | 26 | 27 | module.exports = require('./app'); 28 | -------------------------------------------------------------------------------- /src/snowflakes/tests/test_renderers.py: -------------------------------------------------------------------------------- 1 | def test_render_error(anonhtmltestapp): 2 | res = anonhtmltestapp.get('/testing-render-error', status=500) 3 | assert res.body.startswith(b'') 4 | 5 | 6 | def test_render_error_multiple_times(anonhtmltestapp): 7 | anonhtmltestapp.get('/testing-render-error', status=500) 8 | res = anonhtmltestapp.get('/testing-render-error', status=500) 9 | assert res.body.startswith(b'') 10 | 11 | 12 | def test_render_error_then_success(anonhtmltestapp): 13 | anonhtmltestapp.get('/testing-render-error', status=500) 14 | res = anonhtmltestapp.get('/', status=200) 15 | assert res.body.startswith(b'') 16 | -------------------------------------------------------------------------------- /src/snowflakes/static/libs/origin.js: -------------------------------------------------------------------------------- 1 | /*jshint scripturl:true */ 2 | 'use strict'; 3 | var url = require('url'); 4 | 5 | function same(from, to) { 6 | if (typeof to === 'undefined') { 7 | to = from; 8 | from = document.location.href; 9 | } 10 | if (typeof from === 'string') from = url.parse(from); 11 | if (typeof to === 'string') to = url.parse(url.resolve(from.href, to)); 12 | 13 | if (to.protocol === 'data:' || to.protocol === 'javascript:') return true; 14 | if (from.protocol !== to.protocol) return false; 15 | if (from.protocol === 'file:') return from.pathname === to.pathname; 16 | return from.host === to.host; 17 | } 18 | 19 | module.exports.same = same; 20 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/bootstrap/_wells.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Wells 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .well { 8 | min-height: 20px; 9 | padding: 19px; 10 | margin-bottom: 20px; 11 | background-color: $well-bg; 12 | border: 1px solid $well-border; 13 | border-radius: $border-radius-base; 14 | @include box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); 15 | blockquote { 16 | border-color: #ddd; 17 | border-color: rgba(0,0,0,.15); 18 | } 19 | } 20 | 21 | // Sizes 22 | .well-lg { 23 | padding: 24px; 24 | border-radius: $border-radius-large; 25 | } 26 | .well-sm { 27 | padding: 9px; 28 | border-radius: $border-radius-small; 29 | } 30 | -------------------------------------------------------------------------------- /src/snowflakes/static/components/objectutils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var SingleTreatment = module.exports.SingleTreatment = function(treatment) { 4 | var treatmentText = ''; 5 | 6 | if (treatment.concentration) { 7 | treatmentText += treatment.concentration + (treatment.concentration_units ? ' ' + treatment.concentration_units : '') + ' '; 8 | } 9 | treatmentText += treatment.treatment_term_name + (treatment.treatment_term_id ? ' (' + treatment.treatment_term_id + ')' : '') + ' '; 10 | if (treatment.duration) { 11 | treatmentText += 'for ' + treatment.duration + ' ' + (treatment.duration_units ? treatment.duration_units : ''); 12 | } 13 | return treatmentText; 14 | }; 15 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/bootstrap/_component-animations.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Component animations 3 | // -------------------------------------------------- 4 | 5 | // Heads up! 6 | // 7 | // We don't use the `.opacity()` mixin here since it causes a bug with text 8 | // fields in IE7-8. Source: https://github.com/twitter/bootstrap/pull/3552. 9 | 10 | .fade { 11 | opacity: 0; 12 | @include transition(opacity .15s linear); 13 | &.in { 14 | opacity: 1; 15 | } 16 | } 17 | 18 | .collapse { 19 | display: none; 20 | &.in { 21 | display: block; 22 | } 23 | } 24 | .collapsing { 25 | position: relative; 26 | height: 0; 27 | overflow: hidden; 28 | @include transition(height .35s ease); 29 | } 30 | -------------------------------------------------------------------------------- /src/snowflakes/tests/test_graph.py: -------------------------------------------------------------------------------- 1 | def test_graph_dot(testapp): 2 | res = testapp.get('/profiles/graph.dot', status=200) 3 | assert res.content_type == 'text/vnd.graphviz' 4 | assert res.text 5 | 6 | 7 | def test_graph_svg(testapp): 8 | res = testapp.get('/profiles/graph.svg', status=200) 9 | if not res.content_type == 'image/svg+xml' and res.json.get('status_code') == 404: 10 | # graphviz is probably not installed 11 | msg = res.json.get('message') 12 | assert msg == 'graph.svg is not available' 13 | # Force fail since graphviz is not installed on the system 14 | assert False 15 | assert res.content_type == 'image/svg+xml' 16 | assert res.text 17 | -------------------------------------------------------------------------------- /src/snowflakes/upgrade/award.py: -------------------------------------------------------------------------------- 1 | from snovault import upgrade_step 2 | 3 | ''' Note these are not relevant to anything beyond testing upgrader ''' 4 | 5 | 6 | @upgrade_step('award', '', '2') 7 | def award_0_2(value, system): 8 | # Sample upgrades with tests 9 | 10 | rfa_mapping = ['ENCODE2', 'ENCODE2-Mouse'] 11 | if value['rfa'] in rfa_mapping: 12 | value['status'] = 'disabled' 13 | else: 14 | value['status'] = 'current' 15 | 16 | if 'url' in value: 17 | if value['url'] == '': 18 | del value['url'] 19 | 20 | 21 | @upgrade_step('award', '2', '3') 22 | def award_2_3(value, system): 23 | 24 | if value['viewing_group'] == 'ENCODE3': 25 | value['viewing_group'] = 'ENCODE' 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .coverage 2 | /.installed.cfg 3 | /.mr.developer.cfg 4 | /.cache/ 5 | /.sass-cache/ 6 | /annotations.json 7 | /aws-ip-ranges.json 8 | /bin/ 9 | /develop/ 10 | /develop-eggs/ 11 | /downloads/ 12 | /eggs/ 13 | /extends/ 14 | /node_modules/ 15 | /npm-shrinkwrap.json 16 | /ontology.json 17 | /parts/ 18 | /production.ini 19 | /session-secret.b64 20 | /dist/ 21 | /build/ 22 | /src/snowflakes/static/css/bootstrap.css 23 | /src/snowflakes/static/css/responsive.css 24 | /src/snowflakes/static/css/style.css 25 | /src/snowflakes/static/scss/_variables.original.scss 26 | 27 | *.DS_Store 28 | *.egg-info 29 | *.pyc 30 | +.project 31 | +.pydevproject 32 | *.log 33 | .python-version 34 | ~$* 35 | .~*# 36 | 37 | .python-version 38 | .vscode 39 | venv 40 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/bootstrap/_breadcrumbs.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Breadcrumbs 3 | // -------------------------------------------------- 4 | 5 | 6 | .breadcrumb { 7 | padding: $breadcrumb-padding-vertical $breadcrumb-padding-horizontal; 8 | margin-bottom: $line-height-computed; 9 | list-style: none; 10 | background-color: $breadcrumb-bg; 11 | border-radius: $border-radius-base; 12 | 13 | > li { 14 | display: inline-block; 15 | 16 | + li:before { 17 | content: "#{$breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space 18 | padding: 0 5px; 19 | color: $breadcrumb-color; 20 | } 21 | } 22 | 23 | > .active { 24 | color: $breadcrumb-active-color; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/snovault/tests/testing_auditor.py: -------------------------------------------------------------------------------- 1 | from snovault.auditor import ( 2 | audit_checker, 3 | AuditFailure, 4 | ) 5 | 6 | 7 | def includeme(config): 8 | config.scan('.testing_views') 9 | config.scan(__name__) 10 | 11 | 12 | def has_condition1(value, system): 13 | return value.get('condition1') 14 | 15 | 16 | @audit_checker('testing_link_source', condition=has_condition1) 17 | def checker1(value, system): 18 | if not value.get('checker1'): 19 | return AuditFailure('testchecker', 'Missing checker1') 20 | 21 | 22 | @audit_checker('testing_link_target') 23 | def testing_link_target_status(value, system): 24 | if value.get('status') == 'CHECK': 25 | if not len(value['reverse']): 26 | return AuditFailure('status', 'Missing reverse items') 27 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/fontawesome/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 9 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 10 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 11 | //src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 12 | font-weight: normal; 13 | font-style: normal; 14 | } 15 | -------------------------------------------------------------------------------- /src/snowflakes/static/components/page.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var React = require('react'); 3 | var Layout = require('./layout').Layout; 4 | var globals = require('./globals'); 5 | var _ = require('underscore'); 6 | 7 | 8 | var Page = module.exports.Page = React.createClass({ 9 | render: function() { 10 | var context = this.props.context; 11 | return ( 12 |
13 |
14 |
15 |

{context.title}

16 |
17 |
18 | 19 |
20 | ); 21 | } 22 | }); 23 | 24 | 25 | globals.content_views.register(Page, 'Page'); 26 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/snowflakes/_theme.scss: -------------------------------------------------------------------------------- 1 | .btn { 2 | font-weight: bold; 3 | @include box-shadow(0 1px 1px rgba(0,0,0,.05), inset 0 -1px 0 rgba(0,0,0,.12), inset 0 1px 0 rgba(255,255,255,.3)); 4 | } 5 | 6 | .btn-link { 7 | font-weight: normal; 8 | @include box-shadow(none); 9 | } 10 | 11 | .btn-svgicon { 12 | line-height: 0.9; 13 | margin-right: 0 !important; 14 | border-radius: 0; 15 | 16 | .svg-icon { 17 | fill: #fff; 18 | } 19 | 20 | &:first-child { 21 | border-top-left-radius: $border-radius-small; 22 | border-bottom-left-radius: $border-radius-small; 23 | } 24 | 25 | &:last-child { 26 | border-top-right-radius: $border-radius-small; 27 | border-bottom-right-radius: $border-radius-small; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /circle-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## Helper to run tests locally using same commands as circle ci config 4 | # See: encoded/.circleci/config.yml 5 | # 6 | # Use Cases: No argument defaults to not bdd tests 7 | # $ circle-tests.sh bdd 8 | # $ circle-tests.sh npm 9 | # $ circle-tests.sh 10 | ## 11 | 12 | if [ "$1" == "bdd" ]; then 13 | pytest -v -v --timeout=400 -m "bdd" --tb=short --splinter-implicit-wait 10 --splinter-webdriver chrome --splinter-socket-timeout 300 --chrome-options "--headless --disable-gpu --no-sandbox --disable-dev-shm-usage --disable-extensions --whitelisted-ips --window-size=1920,1080" 14 | exit 15 | fi 16 | 17 | if [ "$1" == "npm" ]; then 18 | npm test 19 | exit 20 | fi 21 | 22 | if [ -z "$1" ]; then 23 | pytest -v -v --timeout=400 -m "not bdd" 24 | exit 25 | fi 26 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/snowflakes/modules/_modals.scss: -------------------------------------------------------------------------------- 1 | /* Modals */ 2 | .modal { 3 | border: 9px solid #333; 4 | border: 9px solid rgba(0,0,0,.4); 5 | *border: 9px solid #333; /* IE6-7 */ 6 | @include border-radius(6px); 7 | @include box-shadow(none); 8 | } 9 | 10 | /* used to mask who screen, for modals etc */ 11 | /* STILL USING THE BELOW OR JUST FOR A MOCKUP???????? */ 12 | #mask { 13 | position: absolute; 14 | z-index: 9000; 15 | background-color: rgba(0,0,0,0.6); 16 | display: none; // js switches to display: block 17 | height: 4000px; // this should be set in the js to fit screen perfectly 18 | width: 4000px; // this should be set in the js to fit screen perfectly 19 | top: 0; 20 | left: 0; 21 | } 22 | 23 | .unmask { 24 | position: relative; 25 | z-index: 9999; 26 | } -------------------------------------------------------------------------------- /src/snowflakes/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # This has to be part of a plugin to support adding the command line option 2 | import argparse 3 | 4 | 5 | class AppendInt2(argparse._AppendAction): 6 | def __call__(self, parser, namespace, values, option_string=None): 7 | values = (values[0], int(values[1])) 8 | return super(AppendInt2, self).__call__(parser, namespace, values, option_string) 9 | 10 | 11 | def pytest_addoption(parser): 12 | parser.addoption('--browser-arg', nargs=2, dest='browser_args', action='append', type='string') 13 | parser.addoption('--browser-arg-int', nargs=2, dest='browser_args', action=AppendInt2, type='string') 14 | parser.addoption('--chrome-options', action='store', type='string') 15 | parser.addoption('--wsgi-arg', nargs=2, dest='wsgi_args', action='append', type='string') 16 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/fontawesome/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon-rotate($degrees, $rotation) { 5 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); 6 | -webkit-transform: rotate($degrees); 7 | -moz-transform: rotate($degrees); 8 | -ms-transform: rotate($degrees); 9 | -o-transform: rotate($degrees); 10 | transform: rotate($degrees); 11 | } 12 | 13 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 14 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); 15 | -webkit-transform: scale($horiz, $vert); 16 | -moz-transform: scale($horiz, $vert); 17 | -ms-transform: scale($horiz, $vert); 18 | -o-transform: scale($horiz, $vert); 19 | transform: scale($horiz, $vert); 20 | } 21 | -------------------------------------------------------------------------------- /src/snovault/tests/testing_key.py: -------------------------------------------------------------------------------- 1 | from snovault import ( 2 | Item, 3 | collection, 4 | ) 5 | 6 | # Test class for keys 7 | 8 | 9 | def includeme(config): 10 | config.scan(__name__) 11 | 12 | 13 | @collection( 14 | 'testing-keys', 15 | properties={ 16 | 'title': 'Test keys', 17 | 'description': 'Testing. Testing. 1, 2, 3.', 18 | }, 19 | unique_key='testing_alias', 20 | ) 21 | class TestingKey(Item): 22 | item_type = 'testing_key' 23 | schema = { 24 | 'type': 'object', 25 | 'properties': { 26 | 'name': { 27 | 'type': 'string', 28 | 'uniqueKey': True, 29 | }, 30 | 'alias': { 31 | 'type': 'string', 32 | 'uniqueKey': 'testing_alias', 33 | }, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/snovault/tests/testing_upgrader.py: -------------------------------------------------------------------------------- 1 | from snovault import ( 2 | Item, 3 | collection, 4 | ) 5 | from snovault.upgrader import ( 6 | upgrade_step, 7 | upgrade_finalizer, 8 | ) 9 | 10 | 11 | def includeme(config): 12 | config.scan(__name__) 13 | config.add_upgrade('testing_upgrader', '3') 14 | 15 | 16 | @collection('testing-upgrader') 17 | class TestingUpgrader(Item): 18 | item_type = 'testing_upgrader' 19 | 20 | 21 | @upgrade_step('testing_upgrader', '', '2') 22 | def step1(value, system): 23 | value['step1'] = True 24 | return value 25 | 26 | 27 | @upgrade_step('testing_upgrader', '2', '3') 28 | def step2(value, system): 29 | value['step2'] = True 30 | return value 31 | 32 | 33 | @upgrade_finalizer('testing_upgrader') 34 | def finalizer(value, system, version): 35 | value['schema_version'] = version 36 | return value 37 | -------------------------------------------------------------------------------- /src/snovault/tests/pyramidfixtures.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | # Fixtures for pyramid, embedding 4 | 5 | 6 | @pytest.yield_fixture 7 | def config(): 8 | from pyramid.testing import setUp, tearDown 9 | yield setUp() 10 | tearDown() 11 | 12 | 13 | @pytest.yield_fixture 14 | def threadlocals(request, dummy_request, registry): 15 | from pyramid.threadlocal import manager 16 | manager.push({'request': dummy_request, 'registry': registry}) 17 | yield manager.get() 18 | manager.pop() 19 | 20 | 21 | @pytest.fixture 22 | def dummy_request(root, registry, app): 23 | from pyramid.request import apply_request_extensions 24 | request = app.request_factory.blank('/dummy') 25 | request.root = root 26 | request.registry = registry 27 | request._stats = {} 28 | request.invoke_subrequest = app.invoke_subrequest 29 | apply_request_extensions(request) 30 | return request 31 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/bootstrap/_close.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Close icons 3 | // -------------------------------------------------- 4 | 5 | 6 | .close { 7 | float: right; 8 | font-size: ($font-size-base * 1.5); 9 | font-weight: $close-font-weight; 10 | line-height: 1; 11 | color: $close-color; 12 | text-shadow: $close-text-shadow; 13 | @include opacity(.2); 14 | 15 | &:hover, 16 | &:focus { 17 | color: $close-color; 18 | text-decoration: none; 19 | cursor: pointer; 20 | @include opacity(.5); 21 | } 22 | 23 | // [converter] extracted button& to button.close 24 | } 25 | 26 | // Additional properties for button version 27 | // iOS requires the button element instead of an anchor tag. 28 | // If you want the anchor version, it requires `href="#"`. 29 | button.close { 30 | padding: 0; 31 | cursor: pointer; 32 | background: transparent; 33 | border: 0; 34 | -webkit-appearance: none; 35 | } 36 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/fontawesome/_spinning.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: spin 2s infinite linear; 6 | -moz-animation: spin 2s infinite linear; 7 | -o-animation: spin 2s infinite linear; 8 | animation: spin 2s infinite linear; 9 | } 10 | 11 | @-moz-keyframes spin { 12 | 0% { -moz-transform: rotate(0deg); } 13 | 100% { -moz-transform: rotate(359deg); } 14 | } 15 | @-webkit-keyframes spin { 16 | 0% { -webkit-transform: rotate(0deg); } 17 | 100% { -webkit-transform: rotate(359deg); } 18 | } 19 | @-o-keyframes spin { 20 | 0% { -o-transform: rotate(0deg); } 21 | 100% { -o-transform: rotate(359deg); } 22 | } 23 | @keyframes spin { 24 | 0% { 25 | -webkit-transform: rotate(0deg); 26 | transform: rotate(0deg); 27 | } 28 | 100% { 29 | -webkit-transform: rotate(359deg); 30 | transform: rotate(359deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/snowflakes/tests/data/inserts/snowfort.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "accession": "SNOSS727WCB", 4 | "award": "U54HG007004", 5 | "description": "Sample Snowfort", 6 | "status": "released", 7 | "lab": "michael-snyder", 8 | "submitted_by": "facilisi.tristique@potenti.vivamus", 9 | "uuid": "4eafdd35-40ea-463a-9e05-c85fb91d25d0", 10 | "method": "shovel", 11 | "size": "grande", 12 | "date_released": "2014-10-07" 13 | }, 14 | { 15 | "accession": "SNOSS000AER", 16 | "award": "U54HG007004", 17 | "description": "Sample empty snowfort", 18 | "lab": "thomas-gingeras", 19 | "status": "released", 20 | "date_released": "2016-01-01", 21 | "method": "bulldozer", 22 | "size": "venti", 23 | "submitted_by": "dignissim.euismod@amet.habitant", 24 | "uuid": "5a6d5a57-e62d-44b9-a1bd-5d1815247348" 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /src/snowflakes/static/libs/bootstrap/dropdown-menu.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var React = require('react'); 3 | 4 | 5 | // Render a dropdown menu. All components within the dropdown get wrapped in
  • tags, so the 'a' elements in: 6 | // 7 | // 8 | // First 9 | // Second 10 | // 11 | // 12 | // ...get rendered as 13 | //
  • First
  • 14 | //
  • Second
  • 15 | 16 | var DropdownMenu = module.exports.DropdownMenu = React.createClass({ 17 | propTypes: { 18 | label: React.PropTypes.string.isRequired // id attribute value for the button that controls this menu 19 | }, 20 | 21 | render: function() { 22 | return ( 23 | 26 | ); 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /src/snovault/elasticsearch/searches/fields.py: -------------------------------------------------------------------------------- 1 | from snosearch.fields import ResponseField 2 | from snovault.elasticsearch.create_mapping import TEXT_FIELDS 3 | from snovault.elasticsearch.searches.interfaces import NON_SORTABLE 4 | 5 | 6 | class NonSortableResponseField(ResponseField): 7 | 8 | def __init__(self, *args, **kwargs): 9 | super().__init__(*args, **kwargs) 10 | 11 | def render(self, *args, **kwargs): 12 | self.parent = kwargs.get('parent') 13 | return { 14 | NON_SORTABLE: TEXT_FIELDS 15 | } 16 | 17 | 18 | class PassThroughResponseField(ResponseField): 19 | ''' 20 | Passes input values (dictionary) to output. 21 | ''' 22 | def __init__(self, *args, **kwargs): 23 | self.values_to_pass_through = kwargs.pop('values_to_pass_through', {}) 24 | super().__init__(*args, **kwargs) 25 | 26 | def render(self, *args, **kwargs): 27 | return self.values_to_pass_through 28 | -------------------------------------------------------------------------------- /src/snovault/tests/test_schema_utils.py: -------------------------------------------------------------------------------- 1 | from snovault.schema_utils import validate 2 | import pytest 3 | 4 | 5 | targets = [ 6 | {'name': 'one', 'uuid': '775795d3-4410-4114-836b-8eeecf1d0c2f'}, 7 | ] 8 | 9 | 10 | @pytest.fixture 11 | def content(testapp): 12 | url = '/testing-link-targets/' 13 | for item in targets: 14 | testapp.post_json(url, item, status=201) 15 | 16 | 17 | def test_uniqueItems_validates_normalized_links(content, threadlocals): 18 | schema = { 19 | 'uniqueItems': True, 20 | 'items': { 21 | 'linkTo': 'TestingLinkTarget', 22 | } 23 | } 24 | uuid = targets[0]['uuid'] 25 | data = [ 26 | uuid, 27 | '/testing-link-targets/{}'.format(uuid), 28 | ] 29 | validated, errors = validate(schema, data) 30 | assert len(errors) == 1 31 | assert ( 32 | errors[0].message == "['{}', '{}'] has non-unique elements".format( 33 | uuid, uuid) 34 | ) 35 | -------------------------------------------------------------------------------- /src/snovault/interfaces.py: -------------------------------------------------------------------------------- 1 | # Tool names 2 | AUDITOR = 'auditor' 3 | BLOBS = 'blobs' 4 | CALCULATED_PROPERTIES = 'calculated_properties' 5 | COLLECTIONS = 'collections' 6 | CONNECTION = 'connection' 7 | DBSESSION = 'dbsession' 8 | STORAGE = 'storage' 9 | ROOT = 'root' 10 | TYPES = 'types' 11 | UPGRADER = 'upgrader' 12 | 13 | # Constants 14 | PHASE1_5_CONFIG = -15 15 | PHASE2_5_CONFIG = -5 16 | 17 | 18 | # Events 19 | class Created(object): 20 | def __init__(self, object, request): 21 | self.object = object 22 | self.request = request 23 | 24 | 25 | class BeforeModified(object): 26 | def __init__(self, object, request): 27 | self.object = object 28 | self.request = request 29 | 30 | 31 | class AfterModified(object): 32 | def __init__(self, object, request): 33 | self.object = object 34 | self.request = request 35 | 36 | 37 | class AfterUpgrade(object): 38 | def __init__(self, object): 39 | self.object = object 40 | -------------------------------------------------------------------------------- /src/snovault/predicates.py: -------------------------------------------------------------------------------- 1 | def includeme(config): 2 | config.add_view_predicate('subpath_segments', SubpathSegmentsPredicate) 3 | config.add_view_predicate('additional_permission', AdditionalPermissionPredicate) 4 | 5 | 6 | class SubpathSegmentsPredicate(object): 7 | def __init__(self, val, config): 8 | if isinstance(val, int): 9 | val = (val,) 10 | self.val = frozenset(val) 11 | 12 | def text(self): 13 | return 'subpath_segments in %r' % sorted(self.val) 14 | 15 | phash = text 16 | 17 | def __call__(self, context, request): 18 | return len(request.subpath) in self.val 19 | 20 | 21 | class AdditionalPermissionPredicate(object): 22 | def __init__(self, val, config): 23 | self.val = val 24 | 25 | def text(self): 26 | return 'additional_permission = %r' % self.val 27 | 28 | phash = text 29 | 30 | def __call__(self, context, request): 31 | return request.has_permission(self.val, context) 32 | -------------------------------------------------------------------------------- /src/snowflakes/types/image.py: -------------------------------------------------------------------------------- 1 | from snovault import ( 2 | collection, 3 | load_schema, 4 | ) 5 | from .base import ( 6 | Item, 7 | ) 8 | from snovault.attachment import ItemWithAttachment 9 | 10 | 11 | @collection( 12 | name='images', 13 | unique_key='image:filename', 14 | properties={ 15 | 'title': 'Image', 16 | 'description': 'Listing of portal images', 17 | }) 18 | class Image(ItemWithAttachment, Item): 19 | item_type = 'image' 20 | schema = load_schema('snowflakes:schemas/image.json') 21 | schema['properties']['attachment']['properties']['type']['enum'] = [ 22 | 'image/png', 23 | 'image/jpeg', 24 | 'image/gif', 25 | ] 26 | embedded = ['submitted_by'] 27 | 28 | def unique_keys(self, properties): 29 | keys = super(Image, self).unique_keys(properties) 30 | value = properties['attachment']['download'] 31 | keys.setdefault('image:filename', []).append(value) 32 | return keys 33 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/snowflakes/_mixins-custom.scss: -------------------------------------------------------------------------------- 1 | // Custom Mixins 2 | // ----------------------------------------------- 3 | 4 | // STICKY FOOTER 5 | // Compass' sticky footer with added top-border variable to allow use of a top border on your footer. 6 | // @include sticky-footer(54px, "#my-root", "#my-root-footer", "#my-footer") 7 | @mixin sticky-footer( 8 | $footer-height, 9 | $footer-border-top, 10 | $root-selector: unquote("#root"), 11 | $root-footer-selector: unquote("#root_footer"), 12 | $footer-selector: unquote("#footer")) { 13 | html, body { 14 | height: 100%; 15 | } 16 | #{$root-selector} { 17 | clear: both; 18 | min-height: 100%; 19 | height: auto !important; 20 | height: 100%; 21 | margin-bottom: (-$footer-height) - $footer-border-top; 22 | #{$root-footer-selector} { 23 | height: $footer-height; } 24 | } 25 | #{$footer-selector} { 26 | clear: both; 27 | position: relative; 28 | height: $footer-height; 29 | } 30 | } -------------------------------------------------------------------------------- /src/snovault/tests/test_indexer_state.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | def test_heterogeneous_stream(): 5 | from snovault.elasticsearch.indexer_state import heterogeneous_stream 6 | gm = {'e': (x for x in [1, 2, 3, 4, 5])} 7 | assert list(heterogeneous_stream(gm)) == [1, 2, 3, 4, 5] 8 | gm = { 9 | 'e': (x for x in [1, 2, 3, 4, 5]), 10 | 'f': (x for x in ['a', 'b', 'c']) 11 | } 12 | assert list(heterogeneous_stream(gm)) == [1, 'a', 2, 'b', 3, 'c', 4, 5] 13 | gm = { 14 | 'e': (x for x in [1, 2, 3, 4, 5]), 15 | 'f': (x for x in ['a', 'b', 'c']), 16 | 'g': (x for x in (t for t in (None, True, False, None, None, True))) 17 | } 18 | assert list(heterogeneous_stream(gm)) == [ 19 | 1, 'a', 2, 'b', True, 3, 'c', False, 4, 5, True 20 | ] 21 | gm = { 22 | 'e': [1.0, 2.0, 3.0], 23 | 'f': [x for x in range(10)] 24 | } 25 | assert list(heterogeneous_stream(gm)) == [ 26 | 1.0, 0, 2.0, 1, 3.0, 2, 3, 4, 5, 6, 7, 8, 9 27 | ] 28 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/snowflakes/modules/_signin-box.scss: -------------------------------------------------------------------------------- 1 | /* Sign in box (as used on home page) */ 2 | #signin-box { 3 | @include background-image(linear-gradient(rgba(255,255,255,0.1), rgba(0,0,0,0.1))); 4 | @include border-radius(5px); 5 | border: 1px solid #cacaca; 6 | display: inline-block; 7 | padding: 20px; 8 | float: right; 9 | @include box-shadow(rgba(180,180,180,0.9) 0 2px 10px, 0 1px 0 #fff inset); 10 | h4 { 11 | margin: 0 0 10px 0; 12 | padding: 0; 13 | } 14 | } 15 | .signin-button { 16 | display: block !important; 17 | @include font-size(1.4); 18 | font-weight: bold; 19 | margin-bottom: 7px; 20 | } 21 | 22 | .three-d-box { 23 | @include background-image(linear-gradient(rgba(255,255,255,0.1), rgba(0,0,0,0.1))); 24 | @include border-radius(5px); 25 | border: 1px solid #cacaca; 26 | display: block; 27 | padding: 20px; 28 | @include box-shadow(rgba(180,180,180,0.9) 0 2px 10px, 0 1px 0 #fff inset); 29 | margin-bottom: 20px; 30 | form { 31 | margin: 0; 32 | input { margin: 0; width: 98.5%;} 33 | } 34 | } -------------------------------------------------------------------------------- /src/snowflakes/schemas/image.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Image", 3 | "description": "Schema for images embedded in page objects", 4 | "id": "/profiles/image.json", 5 | "$schema": "http://json-schema.org/draft-04/schema#", 6 | "type": "object", 7 | "required": [ "attachment" ], 8 | "identifyingProperties": ["uuid"], 9 | "additionalProperties": false, 10 | "mixinProperties": [ 11 | { "$ref": "mixins.json#/schema_version" }, 12 | { "$ref": "mixins.json#/uuid" }, 13 | { "$ref": "mixins.json#/attachment" }, 14 | { "$ref": "mixins.json#/submitted" }, 15 | { "$ref": "mixins.json#/standard_status"} 16 | ], 17 | "properties": { 18 | "schema_version": { 19 | "default": "1" 20 | }, 21 | "status": { 22 | "default": "released" 23 | }, 24 | "caption": { 25 | "title": "Caption", 26 | "type": "string" 27 | } 28 | }, 29 | "boost_values": { 30 | "caption": 1.0 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/snowflakes/tests/features/page.feature: -------------------------------------------------------------------------------- 1 | @page 2 | Feature: Portal pages 3 | 4 | Scenario: Render page layout 5 | When I visit "/" 6 | And I wait for the content to load 7 | Then I should see 3 elements with the css selector "div.col-md-4" 8 | And I should see an element with the css selector ".project-info" 9 | 10 | Scenario: Override column class 11 | When I visit "/test-section/" 12 | And I wait for the content to load 13 | Then I should see an element with the css selector ".class_override" 14 | 15 | Scenario: Add a page 16 | When I visit "/pages/" 17 | And I wait for the table to fully load 18 | And I press "Add" 19 | And I wait for the form to fully load 20 | And I fill in "name" with "test" 21 | And I fill in "title" with "Test" 22 | And I press "Save" 23 | And I wait for the content to load 24 | Then the browser's URL should contain "/test/" 25 | And the title should contain the text "Test" 26 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const log = require('fancy-log'); 3 | const webpack = require('webpack'); 4 | 5 | const setProduction = function (cb) { 6 | process.env.NODE_ENV = 'production'; 7 | if (cb) { 8 | cb(); 9 | } 10 | }; 11 | 12 | const webpackOnBuild = function (done) { 13 | return function (err, stats) { 14 | if (err) { 15 | throw new log.error(err); 16 | } 17 | log(stats.toString({ 18 | colors: true 19 | })); 20 | if (done) { done(err); } 21 | }; 22 | }; 23 | 24 | const webpackSetup = function (cb) { 25 | var webpackConfig = require('./webpack.config.js'); 26 | webpack(webpackConfig).run(webpackOnBuild(cb)); 27 | }; 28 | 29 | const watch = function (cb) { 30 | var webpackConfig = require('./webpack.config.js'); 31 | webpack(webpackConfig).watch(300, webpackOnBuild(cb)); 32 | }; 33 | 34 | const series = gulp.series; 35 | 36 | gulp.task('default', series(webpackSetup, watch)); 37 | gulp.task('dev', series('default')); 38 | gulp.task('build', series(setProduction, webpackSetup)); -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | addopts = 3 | --pyargs snowflakes.tests 4 | --pyargs snovault.tests 5 | --pyargs snovault.elasticsearch.tests 6 | # --pyargs snovault.elasticsearch.uuid_queue.tests 7 | -p snowflakes.tests 8 | --instafail 9 | --splinter-make-screenshot-on-failure=false 10 | --splinter-implicit-wait=5 11 | # Ignore warnings from splinter, we don't use browser.find_by_{href,link} directly 12 | filterwarnings = 13 | error 14 | ignore:browser\.find_link_by_href is deprecated\. Use browser\.links\.find_by_href instead\.:FutureWarning 15 | ignore:browser\.find_link_by_text is deprecated\. Use browser\.links\.find_by_text instead\.:FutureWarning 16 | markers = 17 | bdd: Encoded Scenario 18 | forms: Encoded Scenario 19 | generics: Encoded Scenario 20 | indexing: Encoded Scenario 21 | page: Encoded Scenario 22 | report: Encoded Scenario 23 | search: Encoded Scenario 24 | slow: Encoded Scenario 25 | storage: storage tests 26 | title: Encoded Scenario 27 | toolbar: Encoded Scenario 28 | -------------------------------------------------------------------------------- /src/snovault/tests/test_searches_configs.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | def included(config): 5 | def new_item_search_config(): 6 | return { 7 | 'facets': {'a': 'b'} 8 | } 9 | config.register_search_config( 10 | 'OtherConfigItem', new_item_search_config 11 | ) 12 | 13 | 14 | def test_searches_configs_search_config_decorator(config, dummy_request): 15 | from snovault.elasticsearch.searches.interfaces import SEARCH_CONFIG 16 | from snovault.elasticsearch.searches.configs import search_config 17 | assert dummy_request.registry[SEARCH_CONFIG].get('TestConfigItem').facets == {'a': 'b'} 18 | config.include('snovault.elasticsearch.searches.configs') 19 | config.include(included) 20 | config.commit() 21 | assert config.registry[SEARCH_CONFIG].registry.get('OtherConfigItem').facets == {'a': 'b'} 22 | config.register_search_config('OtherConfigItem', lambda: {'facets': {'c': 'd'}}) 23 | config.commit() 24 | assert config.registry[SEARCH_CONFIG].registry.get('OtherConfigItem').facets == {'c': 'd'} 25 | -------------------------------------------------------------------------------- /src/snovault/elasticsearch/searches/configs.py: -------------------------------------------------------------------------------- 1 | import venusian 2 | 3 | from snosearch.configs import SearchConfigRegistry 4 | from snovault.elasticsearch.searches.interfaces import SEARCH_CONFIG 5 | 6 | 7 | def includeme(config): 8 | registry = config.registry 9 | registry[SEARCH_CONFIG] = SearchConfigRegistry() 10 | config.add_directive('register_search_config', register_search_config) 11 | 12 | 13 | def register_search_config(config, name, factory): 14 | config.action( 15 | ('set-search-config', name), 16 | config.registry[SEARCH_CONFIG].register_from_func, 17 | args=( 18 | name, 19 | factory 20 | ) 21 | ) 22 | 23 | 24 | def search_config(name, **kwargs): 25 | ''' 26 | Register a custom search config by name. 27 | ''' 28 | def decorate(config): 29 | def callback(scanner, factory_name, factory): 30 | scanner.config.register_search_config(name, factory) 31 | venusian.attach(config, callback, category='pyramid') 32 | return config 33 | return decorate 34 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/bootstrap/_thumbnails.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Thumbnails 3 | // -------------------------------------------------- 4 | 5 | 6 | // Mixin and adjust the regular image class 7 | .thumbnail { 8 | display: block; 9 | padding: $thumbnail-padding; 10 | margin-bottom: $line-height-computed; 11 | line-height: $line-height-base; 12 | background-color: $thumbnail-bg; 13 | border: 1px solid $thumbnail-border; 14 | border-radius: $thumbnail-border-radius; 15 | @include transition(all .2s ease-in-out); 16 | 17 | > img, 18 | a > img { 19 | @include img-responsive(); 20 | margin-left: auto; 21 | margin-right: auto; 22 | } 23 | 24 | // [converter] extracted a&:hover, a&:focus, a&.active to a.thumbnail:hover, a.thumbnail:focus, a.thumbnail.active 25 | 26 | // Image captions 27 | .caption { 28 | padding: $thumbnail-caption-padding; 29 | color: $thumbnail-caption-color; 30 | } 31 | } 32 | 33 | // Add a hover state for linked versions only 34 | a.thumbnail:hover, 35 | a.thumbnail:focus, 36 | a.thumbnail.active { 37 | border-color: $link-color; 38 | } 39 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/bootstrap/_utilities.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Utility classes 3 | // -------------------------------------------------- 4 | 5 | 6 | // Floats 7 | // ------------------------- 8 | 9 | .clearfix { 10 | @include clearfix(); 11 | } 12 | .center-block { 13 | @include center-block(); 14 | } 15 | .pull-right { 16 | float: right !important; 17 | } 18 | .pull-left { 19 | float: left !important; 20 | } 21 | 22 | 23 | // Toggling content 24 | // ------------------------- 25 | 26 | // Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1 27 | .hide { 28 | display: none !important; 29 | } 30 | .show { 31 | display: block !important; 32 | } 33 | .invisible { 34 | visibility: hidden; 35 | } 36 | .text-hide { 37 | @include text-hide(); 38 | } 39 | 40 | 41 | // Hide from screenreaders and browsers 42 | // 43 | // Credit: HTML5 Boilerplate 44 | 45 | .hidden { 46 | display: none !important; 47 | visibility: hidden !important; 48 | } 49 | 50 | 51 | // For Affix plugin 52 | // ------------------------- 53 | 54 | .affix { 55 | position: fixed; 56 | } 57 | -------------------------------------------------------------------------------- /docs/search.rst: -------------------------------------------------------------------------------- 1 | Search Documentation: 2 | ===================== 3 | 4 | **URIS** 5 | 6 | 1. http://{SERVER_NAME}/search/?searchTerm={term} 7 | Fetches all the documents which contain the text 'term'. 8 | The result set includes wild card searches and the 'term' should be atleast 3 characters long. 9 | 10 | - SERVER_NAME: ENCODE server 11 | - term: string that can be searched accross four item_types (i.e., experiment, biosample, antibody_approval, target) 12 | 13 | 2. http://{SERVER_NAME}/search/?type={item_type} 14 | Fetches all the documents of that particular 'item_type' 15 | 16 | - SERVER_NAME: ENCODE server 17 | - item_type: ENCODE item type (values can be: biosample, experiment, antibody_approval and target) 18 | 19 | 3. http://{SERVER_NAME}/search/?type={item_type}&{field_name}={text} 20 | Fetches and then filters all the documents of a particular item_type on that field 21 | 22 | - SERVER_NAME: ENCODE server 23 | - item_type: ENCODE item type (values can be: biosample, experiment, antibody_approval and target) 24 | - field_name: Any of the json property in the ENCODE 'item_type' schema 25 | -------------------------------------------------------------------------------- /src/snowflakes/static/components/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var React = require('react'); 3 | var globals = require('./globals'); 4 | 5 | var Home = module.exports.Home = React.createClass({ 6 | render: function() { 7 | return ( 8 |
    9 |
    10 |
    11 |
    12 |
    13 |

    Snowflakes: Where every object is unique

    14 |
    15 |
    16 |

    Snowflake Portal

    17 |

    Enter a search term in the toolbar above.

    18 |
    19 |
    20 |
    21 |
    22 |
    23 | ); 24 | } 25 | }); 26 | 27 | 28 | globals.content_views.register(Home, 'Portal'); 29 | -------------------------------------------------------------------------------- /src/snowflakes/static/inline.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Read and clear stats cookie 4 | import * as cookie from 'js-cookie'; 5 | window.stats_cookie = cookie.get('X-Stats') || ''; 6 | cookie.set('X-Stats', '', {path: '/', expires: new Date(0)}); 7 | 8 | // Use a separate tracker for dev / test 9 | var ga = require('google-analytics'); 10 | var trackers = {'www.encodeproject.org': 'UA-47809317-1'}; 11 | var tracker = trackers[document.location.hostname] || 'UA-47809317-2'; 12 | ga('create', tracker, {'cookieDomain': 'none', 'siteSpeedSampleRate': 100}); 13 | ga('send', 'pageview'); 14 | 15 | // Need to know if onload event has fired for safe history api usage. 16 | window.onload = function () { 17 | window._onload_event_fired = true; 18 | }; 19 | 20 | var $script = require('scriptjs'); 21 | $script.path('/static/build/'); 22 | $script('https://login.persona.org/include.js', 'persona'); 23 | 24 | // Load the rest of the app as a separate chunk. 25 | require.ensure(['./libs/compat', './browser'], function(require) { 26 | require('./libs/compat'); // Shims first 27 | require('./browser'); 28 | }, 'bundle'); 29 | -------------------------------------------------------------------------------- /config.rb: -------------------------------------------------------------------------------- 1 | # Require any additional compass plugins here. 2 | 3 | # Set this to the root of your project when deployed: 4 | http_path = "/" 5 | css_dir = "src/snowflakes/static/css" 6 | sass_dir = "src/snowflakes/static/scss" 7 | images_dir = "src/snowflakes/static/img" 8 | javascripts_dir = "src/snowflakes/static/modules" 9 | fonts_dir = "src/snowflakes/static/fonts" 10 | 11 | # To export minified css, uncomment :compress, and comments out :nested 12 | output_style = :compressed 13 | # output_style = :nested 14 | 15 | # To enable relative paths to assets via compass helper functions. Uncomment: 16 | # relative_assets = true 17 | 18 | # To disable debugging comments that display the original location of your selectors. Uncomment: 19 | # line_comments = false 20 | color_output = false 21 | 22 | 23 | # If you prefer the indented syntax, you might want to regenerate this 24 | # project again passing --syntax sass, or you can uncomment this: 25 | # preferred_syntax = :sass 26 | # and then run: 27 | # sass-convert -R --from scss --to sass src/snowflakes/static/sass scss && rm -rf sass && mv scss sass 28 | preferred_syntax = :scss -------------------------------------------------------------------------------- /src/snowflakes/types/__init__.py: -------------------------------------------------------------------------------- 1 | from snovault.attachment import ItemWithAttachment 2 | from snovault import ( 3 | calculated_property, 4 | collection, 5 | load_schema, 6 | ) 7 | from pyramid.traversal import find_root 8 | from .base import ( 9 | Item, 10 | paths_filtered_by_status, 11 | ) 12 | 13 | 14 | def includeme(config): 15 | config.scan() 16 | 17 | 18 | @collection( 19 | name='labs', 20 | unique_key='lab:name', 21 | properties={ 22 | 'title': 'Labs', 23 | 'description': 'Listing of Snowflake labs', 24 | }) 25 | class Lab(Item): 26 | item_type = 'lab' 27 | schema = load_schema('snowflakes:schemas/lab.json') 28 | name_key = 'name' 29 | embedded = ['awards'] 30 | 31 | 32 | @collection( 33 | name='awards', 34 | unique_key='award:name', 35 | properties={ 36 | 'title': 'Awards (Grants)', 37 | 'description': 'Listing of awards (aka grants)', 38 | }) 39 | class Award(Item): 40 | item_type = 'award' 41 | schema = load_schema('snowflakes:schemas/award.json') 42 | name_key = 'name' 43 | embedded = ['pi'] 44 | -------------------------------------------------------------------------------- /src/snowflakes/static/browser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Entry point for browser 3 | require('./libs/react-patches'); 4 | var React = require('react'); 5 | var ReactMount = require('react/lib/ReactMount'); 6 | ReactMount.allowFullPageRender = true; 7 | 8 | var App = require('./components'); 9 | var domready = require('domready'); 10 | 11 | // Treat domready function as the entry point to the application. 12 | // Inside this function, kick-off all initialization, everything up to this 13 | // point should be definitions. 14 | if (!window.TEST_RUNNER) domready(function ready() { 15 | console.log('ready'); 16 | // Set class depending on browser features 17 | var BrowserFeat = require('./components/browserfeat').BrowserFeat; 18 | BrowserFeat.setHtmlFeatClass(); 19 | var props = App.getRenderedProps(document); 20 | var server_stats = require('querystring').parse(window.stats_cookie); 21 | App.recordServerStats(server_stats, 'html'); 22 | 23 | var app = React.render(, document); 24 | 25 | // Simplify debugging 26 | window.app = app; 27 | window.React = React; 28 | }); 29 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/bootstrap/_jumbotron.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Jumbotron 3 | // -------------------------------------------------- 4 | 5 | 6 | .jumbotron { 7 | padding: $jumbotron-padding; 8 | margin-bottom: $jumbotron-padding; 9 | color: $jumbotron-color; 10 | background-color: $jumbotron-bg; 11 | 12 | h1, 13 | .h1 { 14 | color: $jumbotron-heading-color; 15 | } 16 | p { 17 | margin-bottom: ($jumbotron-padding / 2); 18 | font-size: $jumbotron-font-size; 19 | font-weight: 200; 20 | } 21 | 22 | .container & { 23 | border-radius: $border-radius-large; // Only round corners at higher resolutions if contained in a container 24 | } 25 | 26 | .container { 27 | max-width: 100%; 28 | } 29 | 30 | @media screen and (min-width: $screen-sm-min) { 31 | padding-top: ($jumbotron-padding * 1.6); 32 | padding-bottom: ($jumbotron-padding * 1.6); 33 | 34 | .container & { 35 | padding-left: ($jumbotron-padding * 2); 36 | padding-right: ($jumbotron-padding * 2); 37 | } 38 | 39 | h1, 40 | .h1 { 41 | font-size: ($font-size-base * 4.5); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/bootstrap/_media.scss: -------------------------------------------------------------------------------- 1 | // Media objects 2 | // Source: http://stubbornella.org/content/?p=497 3 | // -------------------------------------------------- 4 | 5 | 6 | // Common styles 7 | // ------------------------- 8 | 9 | // Clear the floats 10 | .media, 11 | .media-body { 12 | overflow: hidden; 13 | zoom: 1; 14 | } 15 | 16 | // Proper spacing between instances of .media 17 | .media, 18 | .media .media { 19 | margin-top: 15px; 20 | } 21 | .media:first-child { 22 | margin-top: 0; 23 | } 24 | 25 | // For images and videos, set to block 26 | .media-object { 27 | display: block; 28 | } 29 | 30 | // Reset margins on headings for tighter default spacing 31 | .media-heading { 32 | margin: 0 0 5px; 33 | } 34 | 35 | 36 | // Media image alignment 37 | // ------------------------- 38 | 39 | .media { 40 | > .pull-left { 41 | margin-right: 10px; 42 | } 43 | > .pull-right { 44 | margin-left: 10px; 45 | } 46 | } 47 | 48 | 49 | // Media list variation 50 | // ------------------------- 51 | 52 | // Undo default ul/ol styles 53 | .media-list { 54 | padding-left: 0; 55 | list-style: none; 56 | } 57 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/bootstrap/_pager.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Pager pagination 3 | // -------------------------------------------------- 4 | 5 | 6 | .pager { 7 | padding-left: 0; 8 | margin: $line-height-computed 0; 9 | list-style: none; 10 | text-align: center; 11 | @include clearfix(); 12 | li { 13 | display: inline; 14 | > a, 15 | > span { 16 | display: inline-block; 17 | padding: 5px 14px; 18 | background-color: $pager-bg; 19 | border: 1px solid $pager-border; 20 | border-radius: $pager-border-radius; 21 | } 22 | 23 | > a:hover, 24 | > a:focus { 25 | text-decoration: none; 26 | background-color: $pager-hover-bg; 27 | } 28 | } 29 | 30 | .next { 31 | > a, 32 | > span { 33 | float: right; 34 | } 35 | } 36 | 37 | .previous { 38 | > a, 39 | > span { 40 | float: left; 41 | } 42 | } 43 | 44 | .disabled { 45 | > a, 46 | > a:hover, 47 | > a:focus, 48 | > span { 49 | color: $pager-disabled-color; 50 | background-color: $pager-bg; 51 | cursor: not-allowed; 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/snowflakes/tests/features/test_generics.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest_bdd import ( 3 | scenarios, 4 | then, 5 | when, 6 | ) 7 | from . import browsersteps 8 | 9 | pytestmark = [ 10 | pytest.mark.bdd, 11 | pytest.mark.usefixtures('workbook'), 12 | ] 13 | 14 | scenarios('generics.feature', strict_gherkin=False) 15 | 16 | 17 | # https://github.com/pytest-dev/pytest-bdd/issues/124 18 | 19 | 20 | @when('I visit "//"') 21 | def i_visit_the_collection_for_type_name(browser, base_url, type_name): 22 | url = '/{}/'.format(type_name) 23 | browsersteps.when_i_visit_url(browser, base_url, url) 24 | 25 | 26 | @when('I click the link with text that contains ""') 27 | def click_link_with_text_that_contains_link_text(browser, link_text): 28 | browsersteps.click_link_with_text_that_contains(browser, link_text) 29 | 30 | 31 | @then('I should see an element with the css selector ".view-item.type-"') 32 | def should_see_element_with_css_type_name(browser, type_name): 33 | css = ".view-item.type-{}".format(type_name) 34 | browsersteps.should_see_element_with_css(browser, css) 35 | -------------------------------------------------------------------------------- /scripts/embeds.py: -------------------------------------------------------------------------------- 1 | ''' 2 | For each object, count the number of objects in which it is embedded. 3 | 4 | Usage: python embeds.py > embeds.jsonlines 5 | ''' 6 | 7 | from elasticsearch import Elasticsearch 8 | from elasticsearch.helpers import scan 9 | import json 10 | 11 | es = Elasticsearch('localhost:9200') 12 | 13 | 14 | def embeds_uuid(es, uuid, item_type): 15 | query = { 16 | 'query': {'terms': {'embedded_uuids': [uuid]}}, 17 | 'aggregations': { 18 | 'item_type': {'terms': {'field': 'item_type'}}, 19 | }, 20 | } 21 | res = es.search(index='encoded', search_type='count', body=query) 22 | return { 23 | 'uuid': uuid, 24 | 'item_type': item_type, 25 | 'embeds': res['hits']['total'], 26 | 'buckets': res['aggregations']['item_type']['buckets'], 27 | } 28 | 29 | 30 | uuid_type = [(hit['_id'], hit['_type']) for hit in scan(es, query={'fields': []})] 31 | 32 | 33 | # rows = [embeds_uuid(es, uuid, item_type) for uuid, item_type in uuid_type] 34 | for uuid, item_type in uuid_type: 35 | data = embeds_uuid(es, uuid, item_type) 36 | print(json.dumps(data)) 37 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013 Stanford University 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/snowflakes/static/server.js: -------------------------------------------------------------------------------- 1 | // Entry point for server rendering subprocess 2 | 3 | /* jshint strict: false */ 4 | 5 | if (process.env.NODE_ENV === undefined) { 6 | require("@babel/register")({ 7 | only: ['react-forms', 'src/snowflakes/static'], 8 | }); 9 | } else { 10 | require('source-map-support').install(); 11 | } 12 | 13 | require('./libs/react-patches'); 14 | 15 | var argv = process.argv.slice(2); 16 | var debug = (argv[0] === '--debug'); 17 | 18 | var app = require('./libs/react-middleware').build(require('./components')); 19 | var http_stream = require('subprocess-middleware').HTTPStream({app: app, captureConsole: !debug}); 20 | http_stream.pipe(process.stdout); 21 | if (debug) { 22 | var value = argv[1] || '{}'; 23 | if (value.slice(0, 5) === 'file:') { 24 | value = require('fs').readFileSync(value.slice(5)); 25 | } else { 26 | value = new Buffer(value, 'utf8'); 27 | } 28 | http_stream.write('HTTP/1.1 200 OK\r\nX-Request-URL: http://localhost/\r\nContent-Length: ' + value.length + '\r\n\r\n'); 29 | http_stream.write(value); 30 | http_stream.end(); 31 | } else { 32 | process.stdin.pipe(http_stream); 33 | process.stdin.resume(); 34 | } 35 | -------------------------------------------------------------------------------- /scripts/LogToCsv.py: -------------------------------------------------------------------------------- 1 | import re 2 | #regex = '([(\d\.)]+) - - \[(.*?)\] "(.*?)" (\d+) "-" (.*?) "(.*?)" "(.*?)"' 3 | pattern = re.compile('([(\d\.)]+) - - \[(.*?)\] "(.*?)" (\d+) (\d+) "-" "(.*?)" "(.*?)"') 4 | pattern_trim = re.compile('([(\d\.)]+) - (.*?) \[(.*?)\] "(.*?)" (\d+) (\d+) "(.*?)" "(.*?)" (.*?)') 5 | 6 | none_count = 0 7 | elif_count = 0 8 | 9 | file = open('encodeproject.org.log', 'r') 10 | 11 | outputFile = open('encodeProjectToCSV.csv', 'w') 12 | 13 | for line in file: 14 | result = re.search(pattern, line) 15 | result_trim = re.search(pattern_trim, line) 16 | 17 | if result: 18 | split_line = result.group(7) 19 | do_split = re.split(r'[-&?()]', split_line) 20 | completed_line = result.group(1,2,3,4,5,6), do_split 21 | 22 | outputFile.write(str(completed_line)) 23 | outputFile.write("\n") 24 | 25 | elif not result: 26 | elif_count = +1 27 | split_line = result_trim.group(7) 28 | do_split = re.split(r'[-&?()]', split_line) 29 | completed_line = result_trim.group(1,3,4,5,6,8), do_split 30 | 31 | outputFile.write(str(completed_line)) 32 | outputFile.write("\n") 33 | 34 | else: 35 | none_count = +1 36 | outputFile.write(line) 37 | 38 | print("None count: %d" % none_count) 39 | file.close() 40 | outputFile.close() -------------------------------------------------------------------------------- /conf/jvm.options: -------------------------------------------------------------------------------- 1 | -Xms2g 2 | -Xmx2g 3 | 4 | ## GC configuration 5 | -XX:+UseConcMarkSweepGC 6 | -XX:CMSInitiatingOccupancyFraction=75 7 | -XX:+UseCMSInitiatingOccupancyOnly 8 | 9 | # disable calls to System#gc 10 | -XX:+DisableExplicitGC 11 | 12 | # pre-touch memory pages used by the JVM during initialization 13 | -XX:+AlwaysPreTouch 14 | 15 | # force the server VM (remove on 32-bit client JVMs) 16 | -server 17 | 18 | # explicitly set the stack size (reduce to 320k on 32-bit client JVMs) 19 | -Xss1m 20 | 21 | # set to headless, just in case 22 | -Djava.awt.headless=true 23 | 24 | # ensure UTF-8 encoding by default (e.g. filenames) 25 | -Dfile.encoding=UTF-8 26 | 27 | # use our provided JNA always versus the system one 28 | -Djna.nosys=true 29 | 30 | # use old-style file permissions on JDK9 31 | -Djdk.io.permissionsUseCanonicalPath=true 32 | 33 | # flags to configure Netty 34 | -Dio.netty.noUnsafe=true 35 | -Dio.netty.noKeySetOptimization=true 36 | -Dio.netty.recycler.maxCapacityPerThread=0 37 | 38 | # log4j 2 39 | -Dlog4j.shutdownHookEnabled=false 40 | -Dlog4j2.disable.jmx=true 41 | -Dlog4j.skipJansi=true 42 | 43 | # generate a heap dump when an allocation from the Java heap fails 44 | # heap dumps are created in the working directory of the JVM 45 | -XX:+HeapDumpOnOutOfMemoryError -------------------------------------------------------------------------------- /scripts/blackholes.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Report on 'blackhole' objects, those which are embedded in over many other objects. 3 | 4 | Care should be taken with the reverse links from blackhole objects. 5 | ''' 6 | 7 | from collections import defaultdict 8 | import json 9 | 10 | 11 | rows = [json.loads(line) for line in open('embeds.txt')] 12 | uuid_row = {row['uuid']: row for row in rows} 13 | 14 | CUTOFF = 1000 15 | 16 | by_type = defaultdict(list) 17 | for row in rows: 18 | if row['embeds'] >= CUTOFF: 19 | by_type[row['item_type']].append(row) 20 | 21 | print(json.dumps({k: len(v) for k, v in by_type.items()}, sort_keys=True, indent=4)) 22 | 23 | ''' 24 | Report on number of transacations that invalidate many objects. 25 | 26 | $ sudo -u encoded psql -tAc "select row_to_json(transactions) from transactions where timestamp::date = '2016-01-20'::date;" > transactions.txt 27 | 28 | Beware that reverse link invalidations are entered into the transaction log, so any changes will not be reflected. 29 | ''' 30 | 31 | transactions = [json.loads(line) for line in open('transactions.txt')] 32 | 33 | sum_txn = [(sum(uuid_row[uuid]['embeds'] for uuid in txn['data']['updated']), txn) for txn in transactions] 34 | print('Transactions > {}'.format(CUTOFF), sum(s > CUTOFF for s, row in sum_txn)) 35 | -------------------------------------------------------------------------------- /src/snowflakes/static/scss/bootstrap/_badges.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Badges 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base classes 7 | .badge { 8 | display: inline-block; 9 | min-width: 10px; 10 | padding: 3px 7px; 11 | font-size: $font-size-small; 12 | font-weight: $badge-font-weight; 13 | color: $badge-color; 14 | line-height: $badge-line-height; 15 | vertical-align: baseline; 16 | white-space: nowrap; 17 | text-align: center; 18 | background-color: $badge-bg; 19 | border-radius: $badge-border-radius; 20 | 21 | // Empty badges collapse automatically (not available in IE8) 22 | &:empty { 23 | display: none; 24 | } 25 | 26 | // Quick fix for badges in buttons 27 | .btn & { 28 | position: relative; 29 | top: -1px; 30 | } 31 | .btn-xs & { 32 | top: 0; 33 | padding: 1px 5px; 34 | } 35 | } 36 | 37 | // Hover state, but only for links 38 | a.badge { 39 | &:hover, 40 | &:focus { 41 | color: $badge-link-hover-color; 42 | text-decoration: none; 43 | cursor: pointer; 44 | } 45 | } 46 | 47 | // Account for counters in navs 48 | a.list-group-item.active > .badge, 49 | .nav-pills > .active > a > .badge { 50 | color: $badge-active-color; 51 | background-color: $badge-active-bg; 52 | } 53 | .nav-pills > li > a > .badge { 54 | margin-left: 3px; 55 | } 56 | -------------------------------------------------------------------------------- /src/snovault/nginx-dev.conf: -------------------------------------------------------------------------------- 1 | # Minimal nginx proxy for development 2 | # brew install nginx 3 | # nginx -p . nginx-dev.conf 4 | 5 | events { 6 | worker_connections 2048; 7 | } 8 | error_log stderr info; 9 | http { 10 | access_log /dev/stdout; 11 | 12 | resolver 8.8.8.8; 13 | upstream app { 14 | server 127.0.0.1:6543; 15 | keepalive 10; 16 | } 17 | 18 | map $http_x_forwarded_proto $forwarded_proto { 19 | default $http_x_forwarded_proto; 20 | '' $scheme; 21 | } 22 | 23 | server { 24 | listen 8000; 25 | location / { 26 | # Normalize duplicate slashes 27 | if ($request ~ ^(GET|HEAD)\s([^?]*)//(.*)\sHTTP/[0-9.]+$) { 28 | return 301 $2/$3; 29 | } 30 | proxy_set_header Host $http_host; 31 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 32 | proxy_set_header X-Forwarded-Proto $forwarded_proto; 33 | proxy_pass http://app; 34 | proxy_set_header Connection ""; 35 | } 36 | location ~ ^/_proxy/(.*)$ { 37 | internal; 38 | proxy_set_header Authorization ""; 39 | proxy_set_header Content-Type ""; 40 | proxy_buffering off; 41 | proxy_pass $1$is_args$args; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/snowflakes/static/components/blocks/fallback.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var React = require('react'); 3 | var globals = require('../globals'); 4 | var item = require('../item'); 5 | var noarg_memoize = require('../../libs/noarg-memoize'); 6 | 7 | var FallbackBlockView = React.createClass({ 8 | render: function() { 9 | var Panel = item.Panel; 10 | return ( 11 |
    12 |

    {this.props.blocktype.label}

    13 | 14 |
    15 | ); 16 | } 17 | }); 18 | 19 | var FallbackBlockEdit = module.exports.FallbackBlockEdit = React.createClass({ 20 | render: function() { 21 | var ReactForms = require('react-forms'); 22 | return ; 23 | } 24 | }); 25 | 26 | 27 | // Use this as a fallback for any block we haven't registered 28 | globals.blocks.fallback = function (obj) { 29 | return { 30 | label: obj['@type'].join(','), 31 | schema: noarg_memoize(function() { 32 | var JSONNode = require('../JSONNode'); 33 | return JSONNode.create({ 34 | label: 'JSON', 35 | input: