├── .browserslistrc ├── .gitignore ├── .rails_footnotes ├── .rspec ├── .ruby-version ├── Gemfile ├── Gemfile.lock ├── LICENSE.txt ├── Procfile ├── Procfile.dev ├── README.md ├── Rakefile ├── app.json ├── app ├── admin │ ├── admin_user.rb │ ├── annotation_category.rb │ ├── dashboard.rb │ ├── dashboard.rb.orig │ ├── documents.rb │ ├── groups.rb │ ├── tenants.rb │ └── users.rb ├── assets │ ├── images │ │ ├── aai-logo.png │ │ ├── annotator-glyph-sprite.png │ │ ├── annotator-icon-sprite.png │ │ ├── ans-next.png │ │ ├── external-link.png │ │ ├── file-image.png │ │ ├── footer-logo3.png │ │ ├── home.png │ │ ├── logo_mit.png │ │ ├── neh_at_logo.png │ │ ├── rails.png │ │ └── twitter │ │ │ └── bootstrap │ │ │ ├── glyphicons-halflings-f6675c325532ec11a984d58e172b8e2a.png │ │ │ ├── glyphicons-halflings-white-13553a5bf21ae3cc374006592488ec64.png │ │ │ ├── glyphicons-halflings-white.png │ │ │ └── glyphicons-halflings.png │ ├── javascripts │ │ ├── active_admin.js │ │ ├── admin-annotator-category.js │ │ ├── annotation_studio.js │ │ ├── annotator-category.js │ │ ├── application.js │ │ ├── bootstrap-tagsinput.js │ │ ├── collections │ │ │ ├── local_annotation_list.js │ │ │ └── remote_annotation_list.js │ │ ├── dashboard.js │ │ ├── filter.js │ │ ├── format_date.js │ │ ├── groups.js.erb │ │ ├── invites.coffee │ │ ├── jasny-bootstrap-modded.js │ │ ├── jqColorPicker.js.map │ │ ├── jquery.treegrid.bootstrap3.js │ │ ├── jquery.treegrid.js │ │ ├── models │ │ │ ├── annotation.js │ │ │ └── annotation_rows.js │ │ ├── routers │ │ │ └── sidebar_router.js.erb │ │ ├── self_removing.js │ │ ├── show_password_fields.js │ │ ├── sidebar.js │ │ ├── sign-in.js │ │ ├── snapshot.js │ │ ├── summernote-en-US.js │ │ ├── typeahead │ │ │ └── typeahead.bundle.js │ │ ├── unload_confirmation.js │ │ ├── views │ │ │ ├── annotation_list_view.js │ │ │ └── annotation_view.js │ │ └── widget.js │ └── stylesheets │ │ ├── active_admin.css.scss │ │ ├── annotations.css.scss │ │ ├── application.css.scss │ │ ├── boot-docs.css.scss │ │ ├── bootstrap-tagsinput.css │ │ ├── catalog.css.scss │ │ ├── doc-body.css.scss │ │ ├── documents.css.scss │ │ ├── groups.css.scss │ │ ├── introjs-overrides.css │ │ ├── invites.scss │ │ ├── jquery.treegrid.css │ │ ├── navbar-overrides.css.scss │ │ ├── offcanvas.css │ │ ├── scaffolds.css.scss │ │ ├── semantic-ui-overrides.css.scss │ │ ├── sticky-footer.css │ │ ├── summernote-overrides.css.scss │ │ └── users.css.scss ├── controllers │ ├── annotations_controller.rb │ ├── api │ │ └── v1 │ │ │ ├── api_controller.rb │ │ │ ├── credentials_controller.rb │ │ │ └── docmeta_controller.rb │ ├── application_controller.rb │ ├── custom_sessions_controller.rb │ ├── documents_controller.rb │ ├── groups_controller.rb │ ├── invites_controller.rb │ ├── omniauth_callbacks_controller.rb │ ├── public_documents_controller.rb │ ├── registrations_controller.rb │ ├── sessions_controller.rb │ └── users_controller.rb ├── helpers │ ├── api_helper.rb │ ├── application_helper.rb │ ├── devise_mailer_url_helper.rb │ └── invites_helper.rb ├── javascript │ └── packs │ │ └── application.js ├── jobs │ ├── application_job.rb │ └── document_processor.rb ├── mailers │ ├── .gitkeep │ ├── application_mailer.rb │ └── invite_mailer.rb ├── models │ ├── .gitkeep │ ├── ability.rb │ ├── admin_user.rb │ ├── annotation.rb │ ├── annotation_category.rb │ ├── application_record.rb │ ├── document.rb │ ├── documents_group.rb │ ├── group.rb │ ├── invite.rb │ ├── membership.rb │ ├── tag.rb │ ├── tagging.rb │ ├── tenant.rb │ └── user.rb └── views │ ├── admin │ └── users │ │ └── _show_annotations.html.erb │ ├── annotations │ ├── _leftnav.html.erb │ ├── _rightnav.html.erb │ ├── index.html.erb │ ├── search.html.erb │ └── show.html.erb │ ├── api │ └── me.rabl │ ├── application │ └── 404.html.erb │ ├── devise │ ├── _links.erb │ ├── confirmations │ │ └── new.html.erb │ ├── mailer │ │ ├── confirmation_instructions.html.erb │ │ ├── reset_password_instructions.html.erb │ │ └── unlock_instructions.html.erb │ ├── passwords │ │ ├── edit.html.erb │ │ └── new.html.erb │ ├── registrations │ │ ├── edit.html.erb │ │ └── new.html.erb │ ├── sessions │ │ ├── _sign_in.html.erb │ │ ├── _sign_up.html.erb │ │ └── new.html.erb │ └── unlocks │ │ └── new.html.erb │ ├── documents │ ├── _annotation_sidebar.html.erb │ ├── _document_content.html.erb │ ├── _document_table.html.erb │ ├── _form.html.erb │ ├── _help.html.erb │ ├── _leftnav.html.erb │ ├── _metadata.html.erb │ ├── _processed_message.html.erb │ ├── _rightnav.html.erb │ ├── _snapshot_progress.html.erb │ ├── _spinner_modal.html.erb │ ├── _status.html.erb │ ├── _survey_button.html.erb │ ├── _tagfilter.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ ├── preview.html.erb │ └── show.html.erb │ ├── groups │ ├── _leftnav.html.erb │ ├── _permissions.html.erb │ ├── _rightnav.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── invite_mailer │ ├── notify_existing_user.html.erb │ └── notify_existing_user.text.erb │ ├── layouts │ ├── application.html.erb │ ├── mailer.html.erb │ └── mailer.text.erb │ ├── pages │ ├── cookiepolicy.html.erb │ ├── maintenance.html.erb │ ├── offcanvas.html.erb │ ├── privacypolicy.html.erb │ └── terms.html.erb │ ├── public_documents │ ├── _annotation_sidebar.html.erb │ ├── _help.html.erb │ ├── _leftnav.html.erb │ ├── _metadata.html.erb │ ├── _processed_message.html.erb │ ├── _rightnav.html.erb │ └── show.html.erb │ ├── shared │ ├── _annotation_header.html.erb │ ├── _annotator_base.html.erb │ ├── _backbone_libraries.html.erb │ ├── _breadcrumbs.html.erb │ ├── _default_brand.html.erb │ ├── _default_footer.html.erb │ ├── _document_titles.html.erb │ ├── _flash_messages.html.erb │ ├── _noscript.html.erb │ └── _user_menu.html.erb │ └── users │ ├── _annotation_list.html.erb │ ├── _joined_groups.html.erb │ ├── _leftnav.html.erb │ ├── _my_documents.html.erb │ ├── _my_groups.html.erb │ ├── _rightnav.html.erb │ ├── _shared_documents.html.erb │ ├── _side_search_options.html.erb │ ├── show.html.erb │ ├── show.js.erb │ └── show.rabl ├── babel.config.js ├── bin ├── bundle ├── rails ├── rake ├── setup ├── setup.new ├── spring ├── start_data_store.sh ├── update ├── webpack ├── webpack-dev-server └── yarn ├── config.ru ├── config ├── application.rb ├── application.sample.yml ├── boot.rb ├── cable.yml ├── database.sample.yml ├── domain_specific │ └── config.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ ├── staging.rb │ └── test.rb ├── initializers │ ├── active_admin.rb │ ├── apartment.rb │ ├── application_controller_renderer.rb │ ├── assets.rb │ ├── aws.rb │ ├── backtrace_silencers.rb │ ├── carrierwave.rb │ ├── content_security_policy.rb │ ├── cookies_serializer.rb │ ├── devise.rb │ ├── document_processor.rb │ ├── doorkeeper.rb │ ├── exception_notification.rb │ ├── filter_parameter_logging.rb │ ├── friendly_id.rb │ ├── inflections.rb │ ├── kaminari.rb │ ├── lograge.rb │ ├── mail.rb │ ├── mime_types.rb │ ├── new_framework_defaults.rb │ ├── new_framework_defaults_5_2.rb │ ├── paperclip.rb │ ├── rails_footnotes.rb │ ├── secret_token.rb │ ├── session_store.rb │ ├── subdomain_specific.rb │ ├── switch_user.rb │ ├── will_paginate_array.rb │ └── wrap_parameters.rb ├── locales │ ├── devise.en.yml │ ├── doorkeeper.en.yml │ ├── en.bootstrap.yml │ └── en.yml ├── newrelic.yml ├── puma.rb ├── rails_best_practices.yml ├── routes.rb ├── scout_apm.yml ├── secrets.yml ├── spring.rb ├── storage.yml ├── webpack │ ├── development.js │ ├── environment.js │ ├── production.js │ └── test.js └── webpacker.yml ├── db ├── development.sqlite3 ├── migrate │ ├── 20120326153645_create_documents.rb │ ├── 20120326153731_create_collections.rb │ ├── 20120326164812_add_collection_id_to_document.rb │ ├── 20120718162103_devise_create_users.rb │ ├── 20120727191634_repertoire_groups_migration.rb │ ├── 20120727192756_acts_as_taggable_on_migration.rb │ ├── 20120823160312_add_author_to_documents.rb │ ├── 20120823162007_add_year_published_to_documents.rb │ ├── 20120823162021_add_edition_to_documents.rb │ ├── 20120823162026_add_publisher_to_documents.rb │ ├── 20120823162031_add_source_to_documents.rb │ ├── 20120823162118_add_rights_status_to_documents.rb │ ├── 20120823204038_add_slug_to_documents.rb │ ├── 20120823204608_create_friendly_id_slugs.rb │ ├── 20120827182156_rename_document_description_and_add_user_id.rb │ ├── 20120827183349_remove_collection_id_from_documents.rb │ ├── 20120827183632_remove_collections.rb │ ├── 20121017192341_devise_create_admin_users.rb │ ├── 20121017192344_create_admin_notes.rb │ ├── 20121017192345_move_admin_notes_to_comments.rb │ ├── 20121018184226_add_publication_date_to_documents.rb │ ├── 20121121165006_add_chapters_to_documents.rb │ ├── 20130128172206_add_affiliation_to_users.rb │ ├── 20130825195003_add_state_to_documents.rb │ ├── 20130903205508_add_slug_to_users.rb │ ├── 20130910111145_create_redactor_assets.rb │ ├── 20131030185352_add_attachment_upload_to_documents.rb │ ├── 20131030192740_add_processed_at_to_documents.rb │ ├── 20131030202337_create_delayed_jobs.rb │ ├── 20140624195339_create_tenants.rb │ ├── 20140625181144_add_agreement_to_user.rb │ ├── 20141010190718_add_survey_link_to_documents.rb │ ├── 20150219165541_create_annotation_categories.rb │ ├── 20150324173818_add_default_state_to_documents.rb │ ├── 20150506143606_add_missing_unique_indices.acts_as_taggable_on_engine.rb │ ├── 20150506143607_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb │ ├── 20150506143608_add_missing_taggable_index.acts_as_taggable_on_engine.rb │ ├── 20150506143609_change_collation_for_tag_names.acts_as_taggable_on_engine.rb │ ├── 20160107155128_add_tenant_config_fields.rb │ ├── 20160119182435_create_doorkeeper_tables.rb │ ├── 20160808210812_add_snapshot_to_documents.rb │ ├── 20160912201159_add_auth_to_users.rb │ ├── 20161018191136_add_cove_uri_to_documents.rb │ ├── 20161018195535_add_cove_info_to_users.rb │ ├── 20161028195936_add_origin_to_documents.rb │ ├── 20190531191825_remove_mel_catalog_stuff.rb │ ├── 20190531192055_remove_cove_integration.rb │ ├── 20190617185106_drop_extension_pg_stat_statements.rb │ ├── 20190710191012_add_missing_indexes.acts_as_taggable_on_engine.rb │ ├── 20190710191857_create_groups.rb │ ├── 20190710200313_create_memberships.rb │ ├── 20190710201111_add_index_to_memberships.rb │ ├── 20190710202451_create_join_table_document_group.rb │ ├── 20190711192830_make_group_name_unique.rb │ ├── 20190711193546_add_index_to_groups.rb │ ├── 20190712193103_create_invites.rb │ ├── 20190712193820_add_index_to_invites.rb │ ├── 20190717172928_add_index_to_documents_groups.rb │ ├── 20190722224656_make_publication_date_string.rb │ ├── 20190729161242_add_page_numbers_to_documents.rb │ ├── 20190729161513_add_metadata_to_documents.rb │ ├── 20190729213030_add_owner_to_groups.rb │ ├── 20190731184827_add_idea_space_toggle_to_groups.rb │ ├── 20190802202325_add_resource_type_to_documents.rb │ ├── 20190806204634_add_user_foreign_key_to_memberships.rb │ ├── 20190806205016_add_group_foreign_key_to_memberships.rb │ ├── 20191125040751_change_publication_date_type_to_text.rb │ ├── 20200124025912_remove_unique_name_index_from_groups.rb │ ├── 20200216012538_add_cascade_on_delete_to_foreign_keys.rb │ ├── 20200413035045_add_confidential_boolean_to_oauth_applications.rb │ └── 20200529183409_add_timestamps_to_groups.rb ├── schema.rb ├── seeds.rb └── test.sqlite3 ├── doc └── README_FOR_APP ├── documents └── uploads │ ├── public │ └── 000 │ │ └── 000 │ │ ├── 002 │ │ └── original │ │ │ └── Bonwell.pdf │ │ └── 003 │ │ └── original │ │ └── Bonwell.pdf │ └── www │ └── 000 │ └── 000 │ ├── 001 │ └── original │ │ ├── example.docx │ │ └── example.pdf │ ├── 002 │ └── original │ │ ├── example.docx │ │ └── example.pdf │ ├── 003 │ └── original │ │ ├── example.docx │ │ └── example.pdf │ ├── 004 │ └── original │ │ ├── example.docx │ │ └── example.pdf │ ├── 005 │ └── original │ │ ├── example.docx │ │ └── example.pdf │ ├── 006 │ └── original │ │ ├── example.docx │ │ └── example.pdf │ └── 007 │ └── original │ └── example.pdf ├── get_body.rb ├── lib ├── api_requester.rb ├── assets │ ├── .gitkeep │ ├── javascripts │ │ ├── richText-annotator.js.coffee │ │ └── tiny_mce_popup.js │ └── stylesheets │ │ └── richText-annotator.css ├── document_processor_dispatcher.rb ├── local-data-store.cert ├── local-only.cert ├── local-only.key ├── null_processor.rb ├── pdf_processor.rb ├── processor_fake.rb ├── tasks │ ├── .gitkeep │ └── annotation-studio.rake └── yomu_processor.rb ├── package.json ├── postcss.config.js ├── public ├── 404.html ├── 422.html ├── 500.html ├── cove_favicon.png ├── favicon.ico └── robots.txt ├── script ├── delayed_job └── rails ├── spec ├── controllers │ ├── api_controller_spec.rb │ ├── documents_controller_spec.rb │ ├── groups_controller_spec.rb │ └── invites_controller_spec.rb ├── factories.rb ├── helpers │ ├── api_helper_spec.rb │ └── invites_helper_spec.rb ├── integration │ ├── user_sees_annotation_sidebar_spec.rb │ ├── user_uploads_documents_spec.rb │ └── user_views_dashboard_spec.rb ├── jobs │ └── document_processor_spec.rb ├── lib │ ├── document_processor_dispatcher_spec.rb │ ├── null_processor_spec.rb │ ├── pdf_processor_spec.rb │ └── processor_fake_spec.rb ├── mailers │ ├── invite_spec.rb │ └── previews │ │ └── invite_preview.rb ├── models │ ├── annotation_category_spec.rb │ ├── document_spec.rb │ ├── documents_group_spec.rb │ ├── group_spec.rb │ ├── invite_spec.rb │ ├── membership_spec.rb │ └── tenant_spec.rb ├── spec_helper.rb └── support │ ├── database_cleaner.rb │ ├── example_files │ ├── annotation-studio-white-paper.docx │ ├── example.docx │ ├── example.html │ └── example.pdf │ ├── factory_girl.rb │ ├── file_helpers.rb │ ├── integration.rb │ └── user_helper.rb ├── vendor ├── assets │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ ├── glyphicons-halflings-regular.woff2 │ │ ├── summernote.eot │ │ ├── summernote.ttf │ │ └── summernote.woff │ ├── javascripts │ │ ├── .gitkeep │ │ ├── Math.uuid.js │ │ ├── annotator-full.min.js │ │ ├── annotator-full.min.map │ │ ├── annotator.touch.min.js │ │ ├── async.min.js │ │ ├── backbone.js │ │ ├── bootstrap.js │ │ ├── ekko-lightbox.min.js │ │ ├── gettext.js │ │ ├── highlighter.js │ │ ├── intro.min.js │ │ ├── jasny-fileinput.js │ │ ├── jqColorPicker.min.js │ │ ├── jquery.fileupload.js │ │ ├── jquery.slimscroll.min.js │ │ ├── jquery.xcolor.js │ │ ├── json2.min.js │ │ ├── klaro-config.js │ │ ├── klaro-no-css.js │ │ ├── moment.min.js │ │ ├── mustache.js │ │ ├── semantic-ui-dropdown.js │ │ ├── semantic-ui-transition.min.js │ │ ├── showdown.js │ │ ├── summernote-cleaner.js │ │ ├── summernote.js │ │ ├── underscore.js │ │ └── xpath.js │ └── stylesheets │ │ ├── .gitkeep │ │ ├── annotator.min.css │ │ ├── annotator.touch.css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap.css.erb │ │ ├── ekko-lightbox.min.css │ │ ├── font-awesome.css.erb │ │ ├── font-awesome.min.css │ │ ├── introjs.min.css │ │ ├── jasny-bootstrap.css │ │ ├── jasny-fileinput.css │ │ ├── klaro.css │ │ ├── semantic-ui-dropdown.scss │ │ ├── semantic-ui-transition.min.css │ │ └── summernote.css.erb ├── plugins │ └── .gitkeep └── repertoire-groups-0.0.1 │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.rdoc │ ├── Rakefile │ ├── app │ ├── assets │ │ └── stylesheets │ │ │ └── user_set.css │ ├── controllers │ │ ├── application_controller_extension.rb │ │ └── user_sets_controller.rb │ ├── helpers │ │ └── groups_helper.rb │ ├── models │ │ ├── application_record.rb │ │ ├── assignment.rb │ │ ├── role.rb │ │ └── user_set.rb │ └── views │ │ └── user_sets │ │ ├── edit.html.erb │ │ └── index.html.erb │ ├── init.rb │ ├── lib │ ├── generators │ │ └── repertoire │ │ │ ├── groups_migration_generator.rb │ │ │ └── templates │ │ │ └── migration.rb │ ├── repertoire-groups.rb │ └── repertoire-groups │ │ ├── ability.rb │ │ ├── acts_as_role_user.rb │ │ └── engine.rb │ ├── repertoire-groups.gemspec │ └── spec │ ├── database.yml │ ├── factories.rb │ ├── models.rb │ ├── repertoire-groups │ ├── ability_spec.rb │ ├── groups_helper_spec.rb │ ├── role_spec.rb │ ├── user_set_spec.rb │ └── user_spec.rb │ ├── schema.rb │ ├── spec.rb │ └── spec_helper.rb └── yarn.lock /.browserslistrc: -------------------------------------------------------------------------------- 1 | defaults 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile ~/.gitignore_global 6 | 7 | ans_dev 8 | *.swp 9 | # Ignore bundler config. 10 | /.bundle 11 | 12 | /log/* 13 | !/log/.keep 14 | logger.txt 15 | tmp/ 16 | ./documents/ 17 | .DS_Store 18 | public/assets/ 19 | vendor/assets/javascripts/annotator.js 20 | _archive/* 21 | vendor/assets/javascripts/_archive/* 22 | db/backups/* 23 | 24 | # Ignore application & database configuration 25 | vendor/assets/javascripts/_attic 26 | vendor/assets/stylesheets/_attic 27 | Gemfile.lock.temp 28 | *.p12 29 | coverage 30 | .gitignore.rej 31 | loadable_libraries.txt 32 | pg_upgrade_dump_all.sql 33 | pg_upgrade_dump_db.sql 34 | pg_upgrade_dump_globals.sql 35 | pg_upgrade_internal.log 36 | pg_upgrade_restore.log 37 | pg_upgrade_server.log 38 | public/system 39 | *.rej 40 | .rvmrc 41 | coverage/ 42 | .powenv 43 | Gemfile.lock.rej 44 | Gemfile.rej 45 | app/assets/javascripts/application.js.rej 46 | app/views/documents/index.html.erb.rej 47 | patch.diff 48 | .env* 49 | .idea 50 | /deploy.sh 51 | devnotes.md 52 | groom.txt 53 | 54 | # Ignore application configuration 55 | /config/application.yml 56 | /config/database.yml 57 | 58 | deploy-checklist.txt 59 | flags.txt 60 | rslt-db.txt 61 | 62 | # Webpacker 63 | /public/packs 64 | /public/packs-test 65 | /node_modules 66 | /yarn-error.log 67 | yarn-debug.log* 68 | .yarn-integrity 69 | -------------------------------------------------------------------------------- /.rails_footnotes: -------------------------------------------------------------------------------- 1 | #this code temporarily disables notes for all controllers 2 | # Footnotes::Filter.notes = [] 3 | 4 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | -fd 3 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.5.8 -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec puma -C config/puma.rb 2 | worker: bundle exec rake jobs:work 3 | -------------------------------------------------------------------------------- /Procfile.dev: -------------------------------------------------------------------------------- 1 | web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb 2 | worker: bundle exec rake jobs:work 3 | api: ./bin/start_data_store.sh 4 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require 'rake/dsl_definition' 6 | require File.expand_path('../config/application', __FILE__) 7 | 8 | AnnotationStudio::Application.load_tasks 9 | -------------------------------------------------------------------------------- /app/admin/admin_user.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register AdminUser do 2 | permit_params :email, :password, :password_confirmation 3 | 4 | filter :email 5 | 6 | index do 7 | column :email 8 | column :current_sign_in_at 9 | column :last_sign_in_at 10 | column :sign_in_count 11 | actions 12 | end 13 | 14 | show do |user| 15 | attributes_table do 16 | row :email 17 | row :current_sign_in_at 18 | row :last_sign_in_at 19 | row :sign_in_count 20 | end 21 | end 22 | 23 | 24 | form do |f| 25 | f.inputs "Admin Details" do 26 | f.input :email 27 | f.input :password 28 | f.input :password_confirmation 29 | end 30 | f.actions do 31 | f.action :submit 32 | f.action :cancel, :wrapper_html => { :class => "cancel" } 33 | end 34 | end 35 | 36 | controller do 37 | def create 38 | user = User.find_by(:email => params['admin_user'][:email]) 39 | if user 40 | user.set_roles = ['admin'] 41 | user.save 42 | super 43 | else 44 | flash[:error] = "Could not create AdminUsesr: User with the email "+params['admin_user'][:email].to_s+" not found." 45 | redirect_to new_admin_admin_user_path 46 | end 47 | end 48 | end 49 | 50 | end 51 | -------------------------------------------------------------------------------- /app/admin/annotation_category.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register AnnotationCategory do 2 | permit_params :name, :hex, :css_classes 3 | 4 | menu false 5 | 6 | scope :all, :default => true 7 | 8 | filter :name 9 | filter :hex 10 | filter :css_classes 11 | 12 | index do |t| 13 | selectable_column 14 | id_column 15 | column "Name", :name 16 | column "Hex", :hex 17 | column "CSS Classes", :css_classes 18 | actions 19 | end 20 | 21 | show do |document| 22 | attributes_table do 23 | row :name 24 | row :hex 25 | row :css_classes 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/admin/dashboard.rb.orig: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register_page "Dashboard" do 2 | 3 | menu :priority => 1, :label => proc{ I18n.t("active_admin.dashboard") } 4 | 5 | content :title => proc{ I18n.t("active_admin.dashboard") } do 6 | div :class => "blank_slate_container", :id => "dashboard_default_message" do 7 | span :class => "blank_slate" do 8 | <<<<<<< HEAD 9 | span "Welcome to Active Admin. This is the default dashboard page." 10 | small "To add dashboard sections, checkout 'app/admin/dashboards.rb'" 11 | ======= 12 | span I18n.t("active_admin.dashboard_welcome.welcome") 13 | small I18n.t("active_admin.dashboard_welcome.call_to_action") 14 | >>>>>>> development 15 | end 16 | end 17 | 18 | # Here is an example of a simple dashboard with columns and panels. 19 | <<<<<<< HEAD 20 | # columns do 21 | # column do 22 | # panel "Recent Students" do 23 | # ul do 24 | # User.map do |user| 25 | # li link_to(user.fullname, admin_user_path(user)) 26 | ======= 27 | # 28 | # columns do 29 | # column do 30 | # panel "Recent Posts" do 31 | # ul do 32 | # Post.recent(5).map do |post| 33 | # li link_to(post.title, admin_post_path(post)) 34 | >>>>>>> development 35 | # end 36 | # end 37 | # end 38 | # end 39 | <<<<<<< HEAD 40 | # 41 | ======= 42 | 43 | >>>>>>> development 44 | # column do 45 | # panel "Info" do 46 | # para "Welcome to ActiveAdmin." 47 | # end 48 | # end 49 | # end 50 | end # content 51 | end 52 | -------------------------------------------------------------------------------- /app/admin/documents.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Document do 2 | 3 | scope :all, :default => true 4 | actions :all, :except => [:edit, :new] 5 | 6 | filter :title 7 | filter :author 8 | filter :publication_date 9 | filter :created_at 10 | filter :updated_at 11 | filter :state 12 | filter :groups, label: 'Group', collection: proc { Group.order(:name) } 13 | 14 | index do |t| 15 | selectable_column 16 | id_column 17 | column "Title", :title 18 | column "Groups", :groups, :sortable => false 19 | column "Creation date", :created_at 20 | column "State", :state 21 | actions 22 | end 23 | 24 | show do |document| 25 | attributes_table do 26 | row :resource_type 27 | row :title 28 | row :author 29 | row :publication_date 30 | row :edition 31 | row :publisher 32 | row :source 33 | row :rights_status 34 | row :page_numbers 35 | row :series 36 | row :location 37 | row :journal_title 38 | row :notes 39 | row('User') { |d| link_to d.user.fullname.to_s, admin_user_path(d.user.id) } 40 | row :groups 41 | row :state 42 | row :created_at 43 | row :updated_at 44 | end 45 | end 46 | 47 | controller do 48 | def find_resource 49 | Document.friendly.find(params[:id]) 50 | end 51 | def permitted_params 52 | params.permit! 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /app/admin/tenants.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Tenant do 2 | permit_params :domain, :database_name, :annotation_categories_enabled 3 | 4 | form do |f| 5 | f.inputs "Tenant Details" do 6 | f.input :domain, :as => :string, label: 'The domain, ex - "app.example.com":' 7 | f.input :annotation_categories_enabled, :as => :boolean, label: 'Enables Annotation Categories' 8 | f.input :database_name, :as => :string, label: 'The internal database name, ex - "app":' 9 | end 10 | f.actions do 11 | f.action :submit 12 | f.action :cancel, :wrapper_html => { :class => "cancel" } 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/assets/images/aai-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/aai-logo.png -------------------------------------------------------------------------------- /app/assets/images/annotator-glyph-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/annotator-glyph-sprite.png -------------------------------------------------------------------------------- /app/assets/images/annotator-icon-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/annotator-icon-sprite.png -------------------------------------------------------------------------------- /app/assets/images/ans-next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/ans-next.png -------------------------------------------------------------------------------- /app/assets/images/external-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/external-link.png -------------------------------------------------------------------------------- /app/assets/images/file-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/file-image.png -------------------------------------------------------------------------------- /app/assets/images/footer-logo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/footer-logo3.png -------------------------------------------------------------------------------- /app/assets/images/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/home.png -------------------------------------------------------------------------------- /app/assets/images/logo_mit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/logo_mit.png -------------------------------------------------------------------------------- /app/assets/images/neh_at_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/neh_at_logo.png -------------------------------------------------------------------------------- /app/assets/images/rails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/rails.png -------------------------------------------------------------------------------- /app/assets/images/twitter/bootstrap/glyphicons-halflings-f6675c325532ec11a984d58e172b8e2a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/twitter/bootstrap/glyphicons-halflings-f6675c325532ec11a984d58e172b8e2a.png -------------------------------------------------------------------------------- /app/assets/images/twitter/bootstrap/glyphicons-halflings-white-13553a5bf21ae3cc374006592488ec64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/twitter/bootstrap/glyphicons-halflings-white-13553a5bf21ae3cc374006592488ec64.png -------------------------------------------------------------------------------- /app/assets/images/twitter/bootstrap/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/twitter/bootstrap/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /app/assets/images/twitter/bootstrap/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/assets/images/twitter/bootstrap/glyphicons-halflings.png -------------------------------------------------------------------------------- /app/assets/javascripts/active_admin.js: -------------------------------------------------------------------------------- 1 | //= require active_admin/base 2 | //= require select2 3 | //= require format_date 4 | //= require moment.min 5 | 6 | $(document).ready(function() { 7 | }); -------------------------------------------------------------------------------- /app/assets/javascripts/admin-annotator-category.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $('#annotation_category_hex').colorPicker(); 3 | }); 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/collections/local_annotation_list.js: -------------------------------------------------------------------------------- 1 | var Sidebar = Sidebar || {}; 2 | 3 | Sidebar.LocalAnnotationList = Backbone.Collection.extend({ 4 | model: Sidebar.Annotation 5 | }); 6 | -------------------------------------------------------------------------------- /app/assets/javascripts/collections/remote_annotation_list.js: -------------------------------------------------------------------------------- 1 | var Sidebar = Sidebar || {}; 2 | 3 | Sidebar.RemoteAnnotationList = Backbone.Collection.extend({ 4 | model: Sidebar.Annotation, 5 | url: 'https://localhost:3000/api/search', 6 | // url: 'https://localhost:5000/api/search', 7 | // comparator: function(annotation) { 8 | // try { 9 | // var startOffset = annotation.get("ranges")[0].startOffset; 10 | // } 11 | // catch(e) { 12 | // console.info("startOffset issue." + e.toString()); 13 | // } 14 | // finally { 15 | // return startOffset; // change to startOffset 16 | // } 17 | // }, 18 | initialize: function(options) { 19 | this.fetch({ 20 | data: options, 21 | success: this.fetchSuccess, 22 | error: this.fetchError 23 | }); 24 | this.deferred = new $.Deferred(); 25 | }, 26 | deferred: Function.constructor.prototype, 27 | fetchSuccess: function(collection, response) { 28 | collection.deferred.resolve(); 29 | }, 30 | fetchError: function(collection, response) { 31 | throw new Error("Fetch did not get annotations from the API"); 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /app/assets/javascripts/dashboard.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | //sidebar visibility toggle 4 | var active = false 5 | function openSideMenu(){ 6 | if (active){ 7 | document.getElementById('side-menu').style.width = '0'; 8 | active= false; 9 | return; 10 | } 11 | document.getElementById('side-menu').style.width = '350px'; 12 | active = true 13 | } 14 | function closeSideMenu(){ 15 | document.getElementById('side-menu').style.width = '0'; 16 | } 17 | 18 | //group join form visibility toggle 19 | function on(){ 20 | 21 | //turn off create form 22 | document.getElementById("create-background").style.display = "none"; 23 | document.getElementById("new-group-form").style.display = "none"; 24 | 25 | document.getElementById("join-form").style.display = "block"; 26 | document.getElementById("join-background").style.display = "block"; 27 | } 28 | 29 | function off(){ 30 | document.getElementById("join-form").style.display = "none"; 31 | document.getElementById("join-background").style.display = "none"; 32 | } 33 | 34 | //autocomplete for joining groups? 35 | // $(document.getElementById("groupName")).autocomplete({ 36 | // source: <%= raw(Group.all.pluck(:name)) %> 37 | // }) 38 | 39 | 40 | //create group form visibility toggle. 41 | function show(){ 42 | off(); //turn off join form 43 | document.getElementById("create-background").style.display = "block"; 44 | document.getElementById("new-group-form").style.display = "block"; 45 | 46 | } 47 | 48 | function hide(){ 49 | document.getElementById("create-background").style.display = "none"; 50 | document.getElementById("new-group-form").style.display = "none"; 51 | 52 | } -------------------------------------------------------------------------------- /app/assets/javascripts/format_date.js: -------------------------------------------------------------------------------- 1 | window.formatDateTime = function(date) { 2 | "use strict"; 3 | return moment(date).format('MM/DD/YYYY HH:mm'); 4 | }; 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/assets/javascripts/groups.js.erb: -------------------------------------------------------------------------------- 1 | jQuery(function ($) { 2 | var widget = new Widget.App(); 3 | var endpoint = location.protocol+'//'+'<%= ENV["API_URL"] %>'; 4 | var token = '<%= session["jwt"] %>'; 5 | // Backbone.history.start({pushState: true, root: window.location}) 6 | 7 | var loadOptions = { 8 | 'limit': 20, 9 | 'host': location.host, 10 | 'user': "<%= current_user.email %>", 11 | 'mode': 'user', 12 | 'context': 'dashboard', 13 | }; 14 | widget.listAnnotations(loadOptions, endpoint, token); 15 | }); 16 | -------------------------------------------------------------------------------- /app/assets/javascripts/invites.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/jquery.treegrid.bootstrap3.js: -------------------------------------------------------------------------------- 1 | $.extend($.fn.treegrid.defaults, { 2 | expanderExpandedClass: 'glyphicon glyphicon-chevron-down', 3 | expanderCollapsedClass: 'glyphicon glyphicon-chevron-right' 4 | }); 5 | -------------------------------------------------------------------------------- /app/assets/javascripts/models/annotation.js: -------------------------------------------------------------------------------- 1 | var Sidebar = Sidebar || {}; 2 | 3 | Sidebar.Annotation = Backbone.Model.extend({ 4 | initialize: function(annotationObject) { 5 | // this.set(annotationObject); 6 | }, 7 | defaults: { 8 | user: null, 9 | quote: null, 10 | text: null, 11 | id: null, 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /app/assets/javascripts/models/annotation_rows.js: -------------------------------------------------------------------------------- 1 | var Sidebar = Sidebar || {}; 2 | 3 | Sidebar.AnnotationRows = Backbone.Model.extend({ 4 | defaults: { 5 | rows: null, 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /app/assets/javascripts/routers/sidebar_router.js.erb: -------------------------------------------------------------------------------- 1 | var Sidebar = Sidebar || {}; 2 | 3 | Sidebar.App = Backbone.Router.extend({ 4 | // Not currently being invoked. 5 | routes: { 6 | 'list': 'listAnnotations', 7 | 'update': 'updateAnnotations' 8 | }, 9 | // takes an array of existing annotation object literals. 10 | listAnnotations: function(annotationArray) { 11 | Sidebar.annotations = new Sidebar.LocalAnnotationList(annotationArray); 12 | var annotationsList = new Sidebar.AnnotationListView({ 13 | "container": $('#annotation-well'), 14 | "collection": Sidebar.annotations 15 | }); 16 | annotationsList.render(); 17 | // console.info("Local: "+ Sidebar.annotations.toJSON()); 18 | }, 19 | // takes an object literal of options for an XHR request. 20 | updateAnnotations: function(options) { 21 | Sidebar.annotations = new Sidebar.RemoteAnnotationList(options); 22 | var annotationsList = new Sidebar.AnnotationListView({ 23 | "container": $('#annotation-well'), 24 | "collection": Sidebar.annotations 25 | }); 26 | Sidebar.annotations.deferred.done(function() { 27 | annotationsList.render(); 28 | // console.info("Remote: "+ Sidebar.annotations.toJSON()); 29 | }); 30 | }, 31 | 32 | showAndHideAnnotations: function() { 33 | if(this.filtered) { 34 | $('ul#annotation-list li').each(function(index, element){ 35 | highlight_id = $(element).find('span.highlightlink').data('highlight'); 36 | if(isScrolledIntoView($(highlight_id))){ 37 | $(element).show(); 38 | }else{ 39 | $(element).hide(); 40 | }; 41 | }); 42 | } 43 | }, 44 | showAllAnnotations: function() { 45 | $('ul#annotation-list li').show() 46 | }, 47 | }); 48 | -------------------------------------------------------------------------------- /app/assets/javascripts/self_removing.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | "use strict"; 3 | 4 | // hide all divs that contain the class "self_removing" after a time period. 5 | setTimeout(function() { 6 | var el = $(".self_removing"); 7 | el.alert('close'); 8 | }, 5000); 9 | }); 10 | -------------------------------------------------------------------------------- /app/assets/javascripts/show_password_fields.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | "use strict"; 3 | 4 | var body = $("body"); 5 | 6 | body.on('click', '.show-password-fields', function(e) { 7 | var el = $(this); 8 | var passwordFields = '\n'; 9 | passwordFields += '\n'; 10 | passwordFields += '\n'; 11 | passwordFields += ""; 12 | el.closest(".form-group").html(passwordFields); 13 | return false; 14 | }); 15 | 16 | body.on('click', '.cancel-password-fields', function(e) { 17 | var el = $(this); 18 | var passwordFields = ''; 19 | el.closest(".form-group").html(passwordFields); 20 | return false; 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /app/assets/javascripts/sidebar.js: -------------------------------------------------------------------------------- 1 | var Sidebar; 2 | 3 | function isScrolledIntoView(elem) { 4 | if (typeof elem !== 'undefined' && $(elem).length > 0) { 5 | var docViewTop = $(window).scrollTop(); 6 | var docViewBottom = docViewTop + $(window).height(); 7 | var elemTop = $(elem).offset().top; 8 | var elemBottom = elemTop + $(elem).height(); 9 | 10 | return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop)); 11 | } 12 | else { 13 | return false 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/assets/javascripts/sign-in.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $("#manual-login-toggle").click(function(event) { 3 | event.preventDefault(); 4 | $("#manual-login").slideToggle(); 5 | return false; 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /app/assets/javascripts/summernote-en-US.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | $.extend(true, $.summernote.lang, { 3 | 'en-US': { 4 | cleaner: { 5 | tooltip: 'Cleaner', 6 | not: 'Pasted successfully.', 7 | limitText: 'Text', 8 | limitHTML: 'HTML' 9 | } 10 | } 11 | }); 12 | })(jQuery); 13 | -------------------------------------------------------------------------------- /app/assets/javascripts/unload_confirmation.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | "use strict"; 3 | var body = $('body'); 4 | 5 | var confirmationMessage; // This is undefined to start with, which tells the unload function not to pop up a dialog. 6 | 7 | body.on('change', '.confirm-changes input,.confirm-changes select', function() { 8 | var form = $(this).closest('form'); 9 | var submit = form.find('input[type=submit]'); 10 | var submitName = submit.val(); 11 | confirmationMessage = "You have unsaved changes on this page. You will lose them unless you stay on this page and click \"" + submitName + "\"."; 12 | }); 13 | 14 | body.on('submit', '.confirm-changes', function() { 15 | var form = $(this); 16 | var tagFields = form.find('.bootstrap-tagsinput input'); 17 | if (tagFields.length > 0) { 18 | for (var i = 0; i < tagFields.length; i++) { 19 | var field = $(tagFields[i]); 20 | var val = field.val(); 21 | if (val.length > 0) { 22 | alert("You haven't finished creating the class. Put the cursor after the word \"" + val + "\" and type the \"enter\" key to get it recognized."); 23 | return false; 24 | } 25 | } 26 | } 27 | confirmationMessage = undefined; 28 | }); 29 | 30 | $(window).on('beforeunload', function(){ 31 | return confirmationMessage; 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /app/assets/stylesheets/annotations.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the annotations controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | 5 | .user-highlight { 6 | font-style: italic; 7 | } 8 | 9 | #annotation-list li { 10 | margin: 0 8px; 11 | padding: 8px; 12 | border-bottom: 1px solid #ddd; 13 | } 14 | 15 | #annotation-list { 16 | border: 1px solid #dddddd; 17 | border-collapse: separate; 18 | -webkit-border-radius: 4px; 19 | -moz-border-radius: 4px; 20 | border-radius: 4px; 21 | } 22 | 23 | .viewer_indicator { 24 | display: inline-block; 25 | width: 10px; 26 | height: 10px; 27 | border-radius: 5px; 28 | margin: 0px 15px 0px 5px; 29 | } 30 | 31 | .annotator-item button.btn { 32 | margin: 5px; 33 | padding: 2px 5px; 34 | } 35 | 36 | .annotator-item button.btn-default:focus { 37 | background-color: #FFF; 38 | outline: none; 39 | } 40 | 41 | .annotator-adder, .annotator-outer, .annotator-notice { 42 | z-index: 2020 !important; 43 | } 44 | 45 | .annotator-viewer div:first-of-type.richText-annotation p { 46 | max-width: 400px; 47 | word-wrap: break-word; 48 | } 49 | 50 | .nav-tabs > li.active a, .nav-tabs > li.active a:hover { 51 | background-color: rgb(238, 238, 238); 52 | } 53 | 54 | .loading { 55 | background-color: white; 56 | text-align: center; 57 | .fa-spin{ 58 | font-size: 24px; 59 | color: gray; 60 | } 61 | } -------------------------------------------------------------------------------- /app/assets/stylesheets/bootstrap-tagsinput.css: -------------------------------------------------------------------------------- 1 | .bootstrap-tagsinput { 2 | background-color: #fff; 3 | border: 1px solid #ccc; 4 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 5 | display: inline-block; 6 | padding: 4px 6px; 7 | margin-bottom: 10px; 8 | color: #555; 9 | vertical-align: middle; 10 | border-radius: 4px; 11 | max-width: 100%; 12 | line-height: 22px; 13 | width:100%; 14 | } 15 | .bootstrap-tagsinput input { 16 | border: none; 17 | box-shadow: none; 18 | outline: none; 19 | background-color: transparent; 20 | padding: 0; 21 | margin: 0; 22 | width: auto !important; 23 | max-width: inherit; 24 | } 25 | .bootstrap-tagsinput input:focus { 26 | border: none; 27 | box-shadow: none; 28 | } 29 | .bootstrap-tagsinput .tag { 30 | margin-right: 2px; 31 | color: white; 32 | } 33 | .bootstrap-tagsinput .tag [data-role="remove"] { 34 | margin-left: 8px; 35 | cursor: pointer; 36 | } 37 | .bootstrap-tagsinput .tag [data-role="remove"]:after { 38 | content: "x"; 39 | padding: 0px 2px; 40 | } 41 | .bootstrap-tagsinput .tag [data-role="remove"]:hover { 42 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 43 | } 44 | .bootstrap-tagsinput .tag [data-role="remove"]:hover:active { 45 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); 46 | } 47 | 48 | /*autocomplete styling*/ 49 | .tt-menu{ 50 | background-color: #fcfcfc; 51 | padding: 3px; 52 | border: #EEEEEE 1px solid; 53 | } 54 | 55 | .tt-cursor{ 56 | background-color: #FCEE02; 57 | } -------------------------------------------------------------------------------- /app/assets/stylesheets/catalog.css.scss: -------------------------------------------------------------------------------- 1 | body#catalog { 2 | padding: 10px; 3 | } 4 | 5 | .catalog-container { 6 | 7 | padding-left: 0; 8 | padding-right: 0; 9 | 10 | .col-lg-8 { 11 | padding-left: 0; 12 | padding-right: 0; 13 | } 14 | 15 | .form-horizontal .form-group { 16 | margin-left: 0; 17 | margin-right: 0; 18 | } 19 | 20 | .browse-panel { 21 | padding-top: 5px; 22 | width: 30%; 23 | 24 | .list-group-item { 25 | padding-top: 3px; 26 | padding-bottom: 3px; 27 | font-size: 12px; 28 | } 29 | 30 | .icon { 31 | font-size: 10px; 32 | } 33 | } 34 | 35 | .results-panel { 36 | padding-top: 5px; 37 | margin-left: 5px; 38 | margin-right: 5px; 39 | width: 65%; 40 | height: 490px !important; 41 | } 42 | 43 | // general helper classes 44 | .scrollable { 45 | overflow-y: scroll; 46 | } 47 | 48 | } 49 | 50 | .button-column { 51 | min-width: 114px; 52 | white-space: nowrap; 53 | } 54 | 55 | .same-line { 56 | float: left; 57 | margin-right: 10px; 58 | } 59 | 60 | .next-line { 61 | clear: both; 62 | } 63 | -------------------------------------------------------------------------------- /app/assets/stylesheets/groups.css.scss: -------------------------------------------------------------------------------- 1 | .user-highlight { 2 | font-style: italic; 3 | } 4 | 5 | #annotation-list li { 6 | margin: 0 8px; 7 | padding: 8px; 8 | border-bottom: 1px solid #ddd; 9 | } 10 | #annotation-list { 11 | border: 1px solid #dddddd; 12 | border-collapse: separate; 13 | -webkit-border-radius: 4px; 14 | -moz-border-radius: 4px; 15 | border-radius: 4px; 16 | } 17 | 18 | #group-management-tour { 19 | position: absolute; 20 | right: 15px; 21 | top: 5.5px; 22 | } 23 | 24 | .editable-title{ 25 | background-color: transparent; 26 | min-width:0 !important; 27 | padding: 0 !important; 28 | margin: 0 !important; 29 | max-height: 20px !important; 30 | border-top: none; 31 | border-left: none; 32 | border-right:none; 33 | border-bottom: 1px dashed gray; 34 | font-weight: 400 !important; 35 | overflow: hidden; 36 | text-overflow: ellipsis; 37 | max-width: 60%; 38 | } 39 | 40 | 41 | #edit-title-btn{ 42 | cursor: pointer; 43 | } 44 | 45 | .form-control-inline { 46 | display:inline; 47 | } 48 | .editing-title{ 49 | background-color: white; 50 | font-weight: 400 !important; 51 | white-space: nowrap; 52 | } 53 | 54 | .editing-title-btns { 55 | display:inline; 56 | margin-left: 5px; 57 | } 58 | .editing-group { 59 | display:flex; 60 | flex-direction: row; 61 | max-width: 65%; 62 | } 63 | 64 | @media (min-width: 767px) { 65 | .editable-title{ 66 | max-width: 70%; 67 | } 68 | 69 | .editing-group { 70 | max-width: 75%; 71 | } 72 | } 73 | @media (min-width: 979px) { 74 | .editable-title{ 75 | max-width: 80%; 76 | } 77 | .editing-group { 78 | max-width: 85%; 79 | } 80 | } -------------------------------------------------------------------------------- /app/assets/stylesheets/introjs-overrides.css: -------------------------------------------------------------------------------- 1 | .introjs-button { 2 | color: #333; 3 | font-size: 13px; 4 | border-color: #cccccc; 5 | padding: 6px 12px; 6 | border-radius: 4px; 7 | margin-left: 5px; 8 | background-color: #fff; 9 | } 10 | 11 | .introjs-prevbutton { 12 | border: 1px solid #cccccc; 13 | color: #333; 14 | } 15 | 16 | .introjs-disabled { 17 | border: 1px solid #cccccc; 18 | color: #9a9a9a; 19 | } 20 | 21 | .introjs-skipbutton { 22 | margin-right: 0px; 23 | margin-left: 0px; 24 | float: left; 25 | } 26 | 27 | .introjs-tooltip { 28 | min-width: 230px; 29 | } 30 | -------------------------------------------------------------------------------- /app/assets/stylesheets/invites.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the invites controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/jquery.treegrid.css: -------------------------------------------------------------------------------- 1 | .treegrid-indent {width:16px; height: 16px; display: inline-block; position: relative;} 2 | 3 | .treegrid-expander {width:16px; height: 16px; display: inline-block; position: relative; cursor: pointer;} 4 | 5 | .treegrid-expander-expanded{background-image: url(../img/collapse.png); } 6 | .treegrid-expander-collapsed{background-image: url(../img/expand.png);} 7 | -------------------------------------------------------------------------------- /app/assets/stylesheets/scaffolds.css.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fff; 3 | color: #333; 4 | font-family: verdana, arial, helvetica, sans-serif; 5 | font-size: 13px; 6 | line-height: 18px; } 7 | p, ol, ul, td { 8 | font-family: verdana, arial, helvetica, sans-serif; 9 | font-size: 13px; 10 | line-height: 18px; } 11 | 12 | pre { 13 | background-color: #eee; 14 | padding: 10px; 15 | font-size: 11px; } 16 | 17 | a { 18 | color: #000; 19 | &:visited { 20 | color: #666; } 21 | &:hover { 22 | color: #fff; 23 | background-color: #000; } } 24 | 25 | div { 26 | &.field, &.actions { 27 | margin-bottom: 10px; } } 28 | 29 | #notice { 30 | color: green; } 31 | 32 | .field_with_errors { 33 | padding: 2px; 34 | background-color: red; 35 | display: table; } 36 | 37 | #error_explanation { 38 | width: 450px; 39 | border: 2px solid red; 40 | padding: 7px; 41 | padding-bottom: 0; 42 | margin-bottom: 20px; 43 | background-color: #f0f0f0; 44 | h2 { 45 | text-align: left; 46 | font-weight: bold; 47 | padding: 5px 5px 5px 15px; 48 | font-size: 12px; 49 | margin: -7px; 50 | margin-bottom: 0px; 51 | background-color: #c00; 52 | color: #fff; } 53 | ul li { 54 | font-size: 12px; 55 | list-style: square; } } 56 | -------------------------------------------------------------------------------- /app/assets/stylesheets/semantic-ui-overrides.css.scss: -------------------------------------------------------------------------------- 1 | // Semantic UI overrides 2 | .ui.label { 3 | background-color: #eee; 4 | color: #666 !important; 5 | font-size: 13px; 6 | } 7 | .label-wrapper { 8 | display: flex; 9 | flex-direction: row; 10 | } 11 | 12 | .ui.label div.text { 13 | max-width: 250px; 14 | white-space: nowrap !important; 15 | overflow: hidden; 16 | text-overflow: ellipsis; 17 | } 18 | .ui.label .icon:before { 19 | content: "\f00d"; 20 | font-family: fontAwesome; 21 | font-style: normal; 22 | font-size: 12px; 23 | padding-left: 5px; 24 | position: relative; 25 | top: -1px; 26 | } 27 | .ui.label .icon:hover:before { 28 | color: #f00; 29 | } 30 | .ui.dropdown .menu > .item { 31 | font-size: 14px !important; 32 | white-space: nowrap !important; 33 | overflow: hidden; 34 | text-overflow: ellipsis; 35 | } 36 | .ui.selection.active.dropdown { 37 | border-color: #66afe9 !important; 38 | outline: 0 !important; 39 | } 40 | 41 | .ui.selection.active.dropdown .menu { 42 | border-color: #66afe9 !important; 43 | outline: 0 !important; 44 | } 45 | -------------------------------------------------------------------------------- /app/assets/stylesheets/sticky-footer.css: -------------------------------------------------------------------------------- 1 | /* Sticky footer styles 2 | -------------------------------------------------- */ 3 | html { 4 | position: relative; 5 | min-height: 100%; 6 | } 7 | body { 8 | /* Margin bottom by footer height */ 9 | margin-bottom: 60px; 10 | } 11 | .footer { 12 | position: absolute; 13 | bottom: 0; 14 | width: 100%; 15 | /* Set the fixed height of the footer here */ 16 | height: 60px; 17 | background-color: #f5f5f5; 18 | } 19 | 20 | 21 | /* Custom page CSS 22 | -------------------------------------------------- */ 23 | /* Not required for template or sticky footer method. */ 24 | 25 | .container { 26 | width: auto; 27 | max-width: 680px; 28 | padding: 0 15px; 29 | } 30 | .container .text-muted { 31 | margin: 20px 0; 32 | } 33 | -------------------------------------------------------------------------------- /app/assets/stylesheets/summernote-overrides.css.scss: -------------------------------------------------------------------------------- 1 | .note-editable{ 2 | font-size: 1.15em; 3 | font-family: "calluna"; 4 | } -------------------------------------------------------------------------------- /app/assets/stylesheets/users.css.scss: -------------------------------------------------------------------------------- 1 | .user-highlight { 2 | font-style: italic; 3 | } 4 | 5 | .nav-tabs { 6 | border-bottom: 0; 7 | } 8 | 9 | .nav-tabs > li.active { 10 | border-bottom: 1px solid #fff; 11 | z-index: 10; 12 | } 13 | 14 | .note-toolbar-wrapper.panel-default { 15 | margin-top: 0; 16 | } 17 | .note-popover .popover-content, .panel-heading.note-toolbar{ 18 | z-index:2; 19 | } 20 | 21 | .panel-heading{ 22 | position: relative; 23 | } 24 | 25 | #groups-tour{ 26 | position: absolute; 27 | right: 15px; 28 | top: 5.5px; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /app/controllers/api/v1/api_controller.rb: -------------------------------------------------------------------------------- 1 | module Api::V1 2 | class ApiController < ::ApplicationController 3 | private 4 | def current_resource_owner 5 | User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token 6 | end 7 | end 8 | end -------------------------------------------------------------------------------- /app/controllers/api/v1/credentials_controller.rb: -------------------------------------------------------------------------------- 1 | module Api::V1 2 | class CredentialsController < ApiController 3 | before_action :doorkeeper_authorize! 4 | respond_to :json, :html 5 | 6 | def me 7 | respond_with current_resource_owner 8 | end 9 | 10 | def my_groups 11 | @user = current_resource_owner 12 | my_groups = [] 13 | @user.group_ids.each do |g| 14 | my_groups << {id: g, name: Group.where(id: g).first.name} 15 | end 16 | respond_to do |format| 17 | format.json do 18 | render json: { 19 | email: @user.email, 20 | groups: my_groups 21 | }.to_json 22 | end 23 | end 24 | end 25 | 26 | def group_members 27 | my_group_ids = current_resource_owner.group_ids 28 | if !params[:ids] 29 | respond_to do |format| 30 | format.json do 31 | render json: {error: 'The request is missing a required parameter.'} 32 | end 33 | end 34 | else 35 | group_members = {} 36 | params[:ids].each do |id| 37 | if !id.to_i.in?(my_group_ids) 38 | group_members[id] = {error: 'The authenticated user is not in group with id = ' + id.to_s} 39 | else 40 | group = Group.where(id: id.to_i).first 41 | memberships = group.memberships 42 | members = [] 43 | memberships.includes(:user).each do |m| 44 | members << m.user 45 | end 46 | group_members[id] = members 47 | end 48 | end 49 | respond_to do |format| 50 | format.json do 51 | render json: group_members.to_json 52 | end 53 | end 54 | end 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /app/controllers/api/v1/docmeta_controller.rb: -------------------------------------------------------------------------------- 1 | module Api::V1 2 | class DocmetaController < ApiController 3 | before_action :doorkeeper_authorize! 4 | respond_to :json 5 | 6 | def docmeta 7 | json_params = JSON.parse(request.raw_post) 8 | if !json_params["slugs"].nil? 9 | @doc = Hash.new 10 | for slug in json_params["slugs"] 11 | @doc[slug] = Document.where(:slug => slug).select( 12 | :id, :resource_type, :title, :author, :publication_date, 13 | :edition, :publisher, :source, :rights_status, 14 | :page_numbers, :series, :location, :journal_title, 15 | :notes 16 | ).first 17 | end 18 | respond_to do |format| 19 | format.json do 20 | render json: @doc.to_json 21 | end 22 | end 23 | else 24 | respond_to do |format| 25 | format.json do 26 | render json: { error: "The request is missing a required parameter." } 27 | end 28 | end 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /app/controllers/custom_sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class CustomSessionsController < Devise::SessionsController 2 | after_action :after_login, :only => :create 3 | 4 | def after_login 5 | @now = DateTime.current().to_time.iso8601 6 | @jwt = JWT.encode( 7 | { 8 | 'consumerKey' => ENV["API_CONSUMER"], 9 | 'userId' => current_user.email, 10 | 'issuedAt' => @now, 11 | 'ttl' => 86400 12 | }, 13 | ENV["API_SECRET"] 14 | ) 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/controllers/invites_controller.rb: -------------------------------------------------------------------------------- 1 | class InvitesController < ApplicationController 2 | def create 3 | @invite = Invite.new(invite_params) #make new invite 4 | 5 | #set to 1 month for now. 6 | @invite.expiration_date = Time.now + 1.month 7 | 8 | respond_to do |format| 9 | if @invite.save 10 | format.html { redirect_to edit_group_path(:id=>invite_params[:group_id], :destroy_invite => "false"), notice: 'Invite link generated.' } 11 | else 12 | format.html { redirect_to request.referrer, notice: 'Error creating invite link.'} 13 | end 14 | 15 | end 16 | 17 | end 18 | 19 | private 20 | def invite_params 21 | params.require(:invite).permit(:group_id, :token, :created_at, :updated_at, :expiration_date) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/controllers/omniauth_callbacks_controller.rb: -------------------------------------------------------------------------------- 1 | class OmniauthCallbacksController < Devise::OmniauthCallbacksController 2 | def wordpress_hosted 3 | @user = User.find_for_wordpress_oauth2(request.env["omniauth.auth"], current_user) 4 | 5 | if @user.persisted? 6 | flash[:notice] = I18n.t "devise.omniauth_callbacks.success" 7 | sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated 8 | else 9 | session["devise.wordpress_oauth2_data"] = request.env["omniauth.auth"] 10 | redirect_to new_user_registration_url 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/controllers/public_documents_controller.rb: -------------------------------------------------------------------------------- 1 | class PublicDocumentsController < ApplicationController 2 | skip_before_action :authenticate_user!, :only => [:show, :index], :raise => false 3 | 4 | def show 5 | @now = DateTime.current().to_time.iso8601 6 | session['guest_jwt'] = JWT.encode( 7 | { 8 | 'consumerKey' => ENV["API_CONSUMER"], 9 | 'userId' => "guest@example.com", 10 | 'issuedAt' => @now, 11 | 'ttl' => 86400 12 | }, 13 | ENV["API_SECRET"] 14 | ) 15 | 16 | @document = Document.publicly.friendly.find(params[:id]) 17 | 18 | respond_to do |format| 19 | format.html # show.html.erb 20 | format.json { render json: @document } 21 | end 22 | end 23 | 24 | before_action :prepare_for_mobile 25 | 26 | def prepare_for_mobile 27 | session[:mobile_param] = params[:mobile] if params[:mobile] 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < Devise::SessionsController 2 | 3 | def new 4 | super 5 | end 6 | 7 | def create 8 | # #copied from devise github. can't just call super or else will throw "too many redirects error" 9 | self.resource = warden.authenticate!(auth_options) 10 | set_flash_message!(:notice, :signed_in) 11 | sign_in(resource_name, resource) 12 | yield resource if block_given? 13 | 14 | #custom logic: pass in :invite_token if found 15 | if params[:invite_token] 16 | @location= dashboard_path(invite_token: params[:invite_token]) 17 | elsif session[:ideaspace] 18 | puts 'got session[:ideaspace] in sessions controller' 19 | @location= session.delete(:return_to) 20 | session.delete(:ideaspace) 21 | else 22 | @location= after_sign_in_path_for(resource) 23 | end 24 | respond_with resource, location: @location 25 | end 26 | 27 | end -------------------------------------------------------------------------------- /app/helpers/api_helper.rb: -------------------------------------------------------------------------------- 1 | module ApiHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/devise_mailer_url_helper.rb: -------------------------------------------------------------------------------- 1 | module DeviseMailerUrlHelper 2 | def multitenant_domain 3 | protocol = Rails.application.config.default_email_link_protocol 4 | if tenant = Tenant.where(database_name: Apartment::Tenant.current).first 5 | "#{protocol}://#{tenant.domain}" 6 | else 7 | "#{protocol}://#{ENV['EMAIL_DOMAIN']}" 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/helpers/invites_helper.rb: -------------------------------------------------------------------------------- 1 | module InvitesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/javascript/packs/application.js: -------------------------------------------------------------------------------- 1 | // This file is automatically compiled by Webpack, along with any other files 2 | // present in this directory. You're encouraged to place your actual application logic in 3 | // a relevant structure within app/javascript and only use these pack files to reference 4 | // that code so it'll be compiled. 5 | // 6 | // To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate 7 | // layout file, like app/views/layouts/application.html.erb 8 | 9 | console.log('Hello World from Webpacker') 10 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/jobs/document_processor.rb: -------------------------------------------------------------------------------- 1 | class DocumentProcessor < ApplicationJob 2 | attr_reader :document_id 3 | 4 | around_perform :around_process 5 | 6 | def perform(document_id, document_state, tenant) 7 | Apartment::Tenant.switch!(tenant) 8 | document = Document.find(document_id) 9 | 10 | processor_class = DocumentProcessorDispatcher.processor_for(document.upload.content_type) 11 | processor = processor_class.new(document, document_state) 12 | 13 | processor.work 14 | end 15 | 16 | private 17 | 18 | def around_process 19 | original_tenant = Apartment::Tenant.current 20 | yield 21 | Apartment::Tenant.switch!(original_tenant) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/mailers/.gitkeep -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | # app/mailers/application_mailer.rb 2 | class ApplicationMailer < ActionMailer::Base 3 | default from: 'from@example.com' 4 | layout 'mailer' 5 | end 6 | -------------------------------------------------------------------------------- /app/mailers/invite_mailer.rb: -------------------------------------------------------------------------------- 1 | class InviteMailer < ApplicationMailer 2 | def notify_existing_user(user, group) 3 | @user = user 4 | @group = group 5 | mail(to: @user.email, subject: 'You were added to a group') 6 | end 7 | 8 | end 9 | 10 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/app/models/.gitkeep -------------------------------------------------------------------------------- /app/models/ability.rb: -------------------------------------------------------------------------------- 1 | class Ability 2 | include CanCan::Ability 3 | include Repertoire::Groups::Ability 4 | 5 | def initialize(user) 6 | user ||= User.new # guest user (not logged in) 7 | 8 | # If CanCan doesn't find a match for the above, it falls through 9 | # to the default abilities provided by Repertoire Groups: 10 | defaults_for user 11 | 12 | if user.has_role? :admin 13 | can :manage, :all 14 | can :publicize, Document, { :user_id => user.id } 15 | 16 | elsif user.has_role? :teacher 17 | cannot :manage, Document do |tors| 18 | if tors.user.nil? # This has been driving me insane. 19 | false 20 | else 21 | tors.user.id == user.id 22 | end 23 | end 24 | can :create, Document 25 | can [:read, :update, :publish, :archive, :preview, :export, :set_default_state, :snapshot], Document, { :user_id => user.id } 26 | can :destroy, Document, { :user_id => user.id, :published? => false } 27 | 28 | elsif user.has_role? :student 29 | cannot :manage, Document 30 | can :create, Document 31 | can [:read, :update, :publish, :archive], Document, { :user_id => user.id } 32 | can :destroy, Document, { :user_id => user.id, :published? => false } 33 | can :read, Document do |tors| 34 | !(user.groups & tors.groups).empty? 35 | end 36 | 37 | else 38 | cannot :manage, :all 39 | can :read, Document, { :public? => true } 40 | end 41 | 42 | can :index, Document 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /app/models/admin_user.rb: -------------------------------------------------------------------------------- 1 | class AdminUser < ApplicationRecord 2 | devise :database_authenticatable, 3 | :recoverable, :rememberable, :trackable, :validatable 4 | end 5 | -------------------------------------------------------------------------------- /app/models/annotation.rb: -------------------------------------------------------------------------------- 1 | class Annotation < ApplicationRecord 2 | def self.new 3 | 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/models/annotation_category.rb: -------------------------------------------------------------------------------- 1 | class AnnotationCategory < ApplicationRecord 2 | # attr_accessible :title, :body 3 | def self.to_plugin_init 4 | AnnotationCategory.all.inject({}) { |h, ac| h[ac.id] = { "name" => ac.name, "hex" => ac.hex, "css_classes" => ac.css_classes }; h }.to_json 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | # app/models/application_record.rb 2 | class ApplicationRecord < ActiveRecord::Base 3 | self.abstract_class = true 4 | end 5 | -------------------------------------------------------------------------------- /app/models/documents_group.rb: -------------------------------------------------------------------------------- 1 | class DocumentsGroup < ApplicationRecord 2 | belongs_to :document 3 | belongs_to :group 4 | end 5 | -------------------------------------------------------------------------------- /app/models/group.rb: -------------------------------------------------------------------------------- 1 | class Group < ApplicationRecord 2 | has_many :memberships, :foreign_key => "group_id" 3 | has_many :users, through: :memberships 4 | accepts_nested_attributes_for :memberships 5 | 6 | has_and_belongs_to_many :documents 7 | 8 | has_many :invites 9 | end 10 | -------------------------------------------------------------------------------- /app/models/invite.rb: -------------------------------------------------------------------------------- 1 | class Invite < ApplicationRecord 2 | 3 | belongs_to :group 4 | 5 | before_create :generate_token 6 | 7 | def generate_token 8 | self.token = Digest::SHA1.hexdigest([self.group_id, Time.now, rand].join) 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/models/membership.rb: -------------------------------------------------------------------------------- 1 | class Membership < ApplicationRecord 2 | belongs_to :user 3 | belongs_to :group 4 | end 5 | -------------------------------------------------------------------------------- /app/models/tag.rb: -------------------------------------------------------------------------------- 1 | class Tag < ApplicationRecord 2 | end 3 | -------------------------------------------------------------------------------- /app/models/tagging.rb: -------------------------------------------------------------------------------- 1 | class Tagging < ApplicationRecord 2 | end 3 | -------------------------------------------------------------------------------- /app/models/tenant.rb: -------------------------------------------------------------------------------- 1 | class Tenant < ApplicationRecord 2 | 3 | after_create :initialize_apartment_schema 4 | after_destroy :drop_apartment_schema 5 | 6 | validates :domain, presence: true, uniqueness: true 7 | validates :database_name, presence: true, uniqueness: true 8 | 9 | def self.current_tenant 10 | Tenant.where({ database_name: Apartment::Tenant.current }).first 11 | end 12 | 13 | def self.annotation_categories_enabled 14 | tenant = self.current_tenant 15 | if !tenant.present? 16 | return false 17 | else 18 | return tenant.annotation_categories_enabled? 19 | end 20 | end 21 | 22 | 23 | def initialize_apartment_schema 24 | return if database_name == 'public' 25 | 26 | begin 27 | Apartment::Tenant.create(database_name) 28 | rescue Apartment::TenantExists => e 29 | Rails.logger.warn "Schema already existed: #{e.inspect}" 30 | end 31 | end 32 | 33 | def drop_apartment_schema 34 | return if database_name == 'public' 35 | 36 | begin 37 | Apartment::Tenant.drop(database_name) 38 | rescue Apartment::TenantNotFound => e 39 | Rails.logger.warn "Schema can't be destroyed as it wasn't there: #{e.inspect}" 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /app/views/annotations/_leftnav.html.erb: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/views/annotations/_rightnav.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /app/views/api/me.rabl: -------------------------------------------------------------------------------- 1 | object @user 2 | attributes :id, :firstname, :lastname, :email 3 | -------------------------------------------------------------------------------- /app/views/application/404.html.erb: -------------------------------------------------------------------------------- 1 |

Not Found

2 | -------------------------------------------------------------------------------- /app/views/devise/_links.erb: -------------------------------------------------------------------------------- 1 |
2 | 19 |
20 | -------------------------------------------------------------------------------- /app/views/devise/confirmations/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= content_for :page_title, "Confirm account" %> 2 | <%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post, :class => "form-horizontal"}) do |f| %> 3 | <%= render "devise/shared/error_messages" %> 4 |
5 | Resend confirmation instructions 6 |
7 | <%= f.label :email, :class => "control-label" %> 8 |
9 | <%= f.email_field :email %> 10 |
11 |
12 |
13 |
<%= f.submit "Resend confirmation instructions", :class => "btn btn-default btn btn-default-primary" %>
14 |
15 |
16 | <% end %> 17 | -------------------------------------------------------------------------------- /app/views/devise/mailer/confirmation_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Welcome <%= @resource.firstname %>!

2 | 3 |

Please confirm your Annotation Studio account by clicking the link below:

4 | 5 | <% protocol = Rails.application.config.default_email_link_protocol %> 6 | <% tenant = Tenant.where(database_name: Apartment::Tenant.current).first %> 7 | <% if tenant %> 8 | <% multitenant_domain = protocol + "://" + tenant.domain %> 9 | <% else %> 10 | <% multitenant_domain = protocol + "://" + ENV['EMAIL_DOMAIN'] %> 11 | <% end %> 12 | 13 |

<%= link_to 'Confirm my account', multitenant_domain + confirmation_path(@resource, :confirmation_token => @token) %>

14 | 15 |

– The Annotation Studio Team at the Active Archives Initiative at MIT

16 | 17 | " id="aai-logo" /> -------------------------------------------------------------------------------- /app/views/devise/mailer/reset_password_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

Someone has requested a link to change your Annotation Studio password. You can do this through the link below.

4 | 5 | <% protocol = Rails.application.config.default_email_link_protocol %> 6 | <% tenant = Tenant.where(database_name: Apartment::Tenant.current).first %> 7 | <% if tenant %> 8 | <% multitenant_domain = protocol + "://" + tenant.domain %> 9 | <% else %> 10 | <% multitenant_domain = protocol + "://" + ENV['EMAIL_DOMAIN'] %> 11 | <% end %> 12 | 13 |

<%= link_to 'Change my password', multitenant_domain + edit_password_path(@resource, :reset_password_token => @token) %>

14 | 15 |

If you didn't request this, please ignore this email.

16 | 17 |

Your password won't change until you access the link above and create a new one.

18 | -------------------------------------------------------------------------------- /app/views/devise/mailer/unlock_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

Your account in Annotation Studio has been locked due to an excessive amount of unsuccessful sign in attempts.

4 | 5 |

Click the link below to unlock your account:

6 | 7 | <% protocol = Rails.application.config.default_email_link_protocol %> 8 | <% tenant = Tenant.where(database_name: Apartment::Tenant.current).first %> 9 | <% if tenant %> 10 | <% multitenant_domain = protocol + "://" + tenant.domain %> 11 | <% else %> 12 | <% multitenant_domain = protocol + "://" + ENV['EMAIL_DOMAIN'] %> 13 | <% end %> 14 | 15 |

<%= link_to 'Unlock my account', multitenant_domain + unlock_path(@resource, :unlock_token => @resource.unlock_token) %>

16 | -------------------------------------------------------------------------------- /app/views/devise/passwords/edit.html.erb: -------------------------------------------------------------------------------- 1 | <%= content_for :page_title, "Change your password" %> 2 |
3 |
4 | 5 | <%= render "devise/shared/error_messages" %> 6 | 7 | 10 | 11 | <%= form_for(resource, :as => 12 | resource_name, :url => password_path(resource_name), :html => { :method => :put, :role => "form" }) do |f| %> 13 | <%= f.hidden_field :reset_password_token %> 14 | 15 |
16 | <%= f.label :password, :class => 17 | "control-label" %>
18 | <%= f.password_field :password %>
19 | 20 |
21 | <%= f.label :password_confirmation, :class => 22 | "control-label" %>
23 | <%= f.password_field :password_confirmation %>
24 | 25 | <%= f.submit "Change my password", :class => 26 | "btn btn-default btn btn-default-primary" %> 27 | <% end %> 28 | 29 | <%#= render "links" %>
30 | 31 |
32 | 33 | -------------------------------------------------------------------------------- /app/views/devise/passwords/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= content_for :page_title, "Forgot your password?" %> 2 |
3 |
4 | <%= render "devise/shared/error_messages" %> 5 | 6 | 9 | 10 | <%= form_for(resource, :as => 11 | resource_name, :url => password_path(resource_name), :html => { :method => :post, :role => 'form' }) do |f| %> 12 |
13 | <%= f.label :email %> 14 | <%= f.email_field :email, :class =>"form-control" %>
15 | 16 | <%= f.submit "Send password reset link", :class => 17 | "btn btn-default btn btn-default-primary" %> 18 | <% end %>
19 | 20 |
21 | 22 | -------------------------------------------------------------------------------- /app/views/devise/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= content_for :page_title, "Sign up" %> 2 | <%= content_for :body_id, 'registrations' %> 3 | <%= content_for :body_class, 'new' %> 4 | 5 | 6 |
7 | <%= render "/devise/sessions/sign_up" %> 8 |
-------------------------------------------------------------------------------- /app/views/devise/unlocks/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= content_for :page_title, "Resend unlock instructions" %> 2 |
3 |
4 |

Resend unlock instructions

5 | 6 | <%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %> 7 | <%= render "devise/shared/error_messages" %> 8 | 9 |
<%= f.label :email %>
10 | <%= f.email_field :email %>
11 | 12 |
<%= f.submit "Resend unlock instructions" %>
13 | <% end %> 14 | 15 | <%= render "links" %> 16 |
17 |
18 | -------------------------------------------------------------------------------- /app/views/documents/_processed_message.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Please wait.

3 | The document is being converted. 4 |
5 | -------------------------------------------------------------------------------- /app/views/documents/_snapshot_progress.html.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/documents/_spinner_modal.html.erb: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /app/views/documents/_status.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | Document statuses explained 6 |
7 | 12 |
13 | -------------------------------------------------------------------------------- /app/views/documents/_survey_button.html.erb: -------------------------------------------------------------------------------- 1 | <% if !@document.nil? %> 2 |
3 | Take the survey 4 |
5 | <% end %> -------------------------------------------------------------------------------- /app/views/documents/_tagfilter.html.erb: -------------------------------------------------------------------------------- 1 | 44 | -------------------------------------------------------------------------------- /app/views/documents/edit.html.erb: -------------------------------------------------------------------------------- 1 | <%= content_for :page_title, "Editing #{@document.title}" %> 2 | <%= content_for :body_id, 'documents' %> 3 | <%= content_for :body_class, 'edit' %> 4 |
5 | 6 |
7 |

Create/Edit Document

8 |
9 |
10 | <%= render :partial => 'form', :locals => {:create => false} %> 11 |
12 | 13 |
14 | -------------------------------------------------------------------------------- /app/views/documents/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= content_for :page_title, 'New Document' %> 2 | <%= content_for :body_id, 'documents' %> 3 | <%= content_for :body_class, 'new' %> 4 |
5 | 6 |
7 |

Create/Edit Document

8 |
9 |
10 | <%= render :partial => 'form', :locals => {:create => true} %> 11 |
12 | 13 |
14 | -------------------------------------------------------------------------------- /app/views/documents/preview.html.erb: -------------------------------------------------------------------------------- 1 | <%= content_for :body_id, 'documents' %> 2 | <%= content_for :body_class, 'show' %> 3 | <%= content_for :page_title, @document.title %> 4 | <%= stylesheet_link_tag "documents" %> 5 |
6 |
7 |
8 |
9 | <% if ! @document.processed? %> 10 | <%= render 'processed_message' %> 11 | <% end %> 12 |
13 |
14 | <%= @document.snapshot.html_safe %> 15 |
16 |
17 |
18 |
19 | <%= link_to("Download", document_export_path(@document), class: "btn btn-default btn-sm", role: "button") %> 20 |
21 |
22 | <%= render "documents/help" %> 23 | -------------------------------------------------------------------------------- /app/views/groups/_leftnav.html.erb: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/views/groups/_permissions.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | Group role permissions explained 6 |
7 | 12 |
13 | -------------------------------------------------------------------------------- /app/views/groups/_rightnav.html.erb: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/views/groups/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= content_for :page_title, 'New Group' %> 2 | <%= content_for :body_id, 'groups' %> 3 | <%= content_for :body_class, 'new' %> 4 |
5 |
Create a New Group
6 |
7 |
8 | <%= form_for Group.new do |f| %> 9 |

<%= f.label :group, 'Name' %>

10 |
11 | <%= f.text_field :name, class: "form-control", placeholder: "Group name" %> 12 | <%= f.hidden_field :owner_id, value: current_user.id %> 13 | 14 | <%= f.submit 'Create', class: "btn btn-primary"%> 15 | 16 |
17 | <% end %> 18 |
19 |
20 |

Choose a name for your Group. You can start adding members after you click Create.

21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /app/views/invite_mailer/notify_existing_user.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Hi <%= @user.firstname %>,

8 |

You were added to <%= @group.name %> on Annotation Studio.

9 | 10 | -------------------------------------------------------------------------------- /app/views/invite_mailer/notify_existing_user.text.erb: -------------------------------------------------------------------------------- 1 | Hi <%= @user.firstname %>, 2 | You were added to <%= @group.name %> on Annotation Studio. -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= yield %> 8 | 9 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /app/views/public_documents/_leftnav.html.erb: -------------------------------------------------------------------------------- 1 | 2 | <% if params[:action] == 'show' && !@document.nil? %> 3 |

Info

4 | 29 | 30 |

Chapters

31 | 34 | 41 | <% end %> 42 | -------------------------------------------------------------------------------- /app/views/public_documents/_processed_message.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Please wait.

3 | The document is being converted. 4 |
-------------------------------------------------------------------------------- /app/views/public_documents/_rightnav.html.erb: -------------------------------------------------------------------------------- 1 | ../documents/_rightnav.html.erb -------------------------------------------------------------------------------- /app/views/shared/_annotation_header.html.erb: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /app/views/shared/_backbone_libraries.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/views/shared/_default_footer.html.erb: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /app/views/shared/_document_titles.html.erb: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /app/views/shared/_flash_messages.html.erb: -------------------------------------------------------------------------------- 1 | <% flash.each do |type, message| %> 2 | <%- next if type.to_s == 'timedout' %><%# per https://github.com/plataformatec/devise/issues/1777 %> 3 |
4 | 5 | <%= message %> 6 |
7 | <% end %> 8 | -------------------------------------------------------------------------------- /app/views/shared/_noscript.html.erb: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /app/views/shared/_user_menu.html.erb: -------------------------------------------------------------------------------- 1 | 31 | -------------------------------------------------------------------------------- /app/views/users/_annotation_list.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 9 | 14 | -------------------------------------------------------------------------------- /app/views/users/_joined_groups.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <% @joinedGroups.each do |g| %> 3 |
4 |
<%= link_to g.name, group_path(id: g.id) %>
5 | 6 |
7 | 8 | 9 | <% myRole = Membership.find_by(group_id: g.id, user_id: current_user.id).role %> 10 | Role: <%= myRole %>
11 | 12 | Owner: <%= User.find(g.owner_id).firstname %>
13 | 14 | <% m = Membership.where(group_id: g.id) %> 15 | Members: <%= m.size %> 16 | 17 |
18 | <% end %> 19 | 20 |
21 | 22 |
23 |
24 | <%= will_paginate @joinedGroups, renderer: BootstrapPagination::Rails %> 25 |
26 |
27 | -------------------------------------------------------------------------------- /app/views/users/_leftnav.html.erb: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/views/users/_my_groups.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 | <% @mygroups.includes(:memberships).each do |g| %> 4 |
5 |
<%= link_to g.name, group_path(id: g.id) %>
6 | 7 | 8 |
9 |
10 | Owner: <%=current_user.firstname=%>
11 | Members: <%= g.memberships.size %>
12 | Editors: <%= g.memberships.where(role: "manager").size %> 13 | 14 |
15 | 16 |
17 |
18 | 19 | 20 | 21 |
22 | <% end %> 23 |
24 | 25 |
26 |
27 | <%= will_paginate @mygroups, renderer: BootstrapPagination::Rails %> 28 |
29 |
30 | -------------------------------------------------------------------------------- /app/views/users/_rightnav.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 20 | -------------------------------------------------------------------------------- /app/views/users/_shared_documents.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 | <% @sharedDocs.each do |doc| %> 4 | 5 |
6 | 7 |
<%= link_to doc.title, document_path(id: doc.id) %>
8 |
9 | 10 |
11 | 12 | <% if doc.author != "" %> 13 | Author: <%= doc.author %>
14 | <%end%> 15 | 16 | 17 | 18 | <% if doc.publication_date && doc.publication_date != "" %> 19 | Date: <%= doc.publication_date %>
20 | <% end %> 21 | 22 | <% if !doc.groups.empty? %> 23 | Group(s): <%= doc.groups.pluck(:name).join(", ") %>
24 | <% end %> 25 | 26 | Status: 27 | 28 | <% case doc.state %> 29 | <% when 'draft' %> 30 | 31 | <% when 'published' %> 32 | 33 | <% when 'archived' %> 34 | 35 | <% when 'public' %> 36 | 37 | <% else %> 38 | <%= doc.state %> 39 | <% end %> 40 | 41 | 42 |
43 |
44 | 45 | <% end %> 46 | 47 |
48 | 49 |
50 |
51 | <%= will_paginate @sharedDocs, renderer: BootstrapPagination::Rails %> 52 |
53 |
54 | -------------------------------------------------------------------------------- /app/views/users/show.js.erb: -------------------------------------------------------------------------------- 1 | //ajax response 2 | 3 | var option = "<%= @ajaxOption %>"; 4 | 5 | if(option == "group"){ 6 | var mode = "<%= @groupMode %>"; 7 | if (mode == "mygroups"){ 8 | $(document.getElementById("my-groups")).html("<%= j render 'my_groups' %>"); 9 | } else{ 10 | $(document.getElementById("joined-groups")).html("<%= j render 'joined_groups' %>"); 11 | } //end else 12 | } //end if option 13 | 14 | else{ 15 | var mode = "<%= @docMode %>"; 16 | if (mode == "mydocuments"){ 17 | $(document.getElementById("my-docs")).html("<%= j render 'my_documents' %>"); 18 | } else{ 19 | $(document.getElementById("shared-docs")).html("<%= j render 'shared_documents' %>"); 20 | } //end else 21 | 22 | } // end else 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/views/users/show.rabl: -------------------------------------------------------------------------------- 1 | object @user 2 | attributes :id, :firstname, :lastname, :first_name_last_initial 3 | 4 | node(:first_name_last_initial) { |user| user.first_name_last_initial() } 5 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | APP_PATH = File.expand_path('../config/application', __dir__) 8 | require_relative '../config/boot' 9 | require 'rails/commands' 10 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | require_relative '../config/boot' 8 | require 'rake' 9 | Rake.application.run 10 | -------------------------------------------------------------------------------- /bin/setup.new: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | 4 | # path to your application root. 5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 6 | 7 | Dir.chdir APP_ROOT do 8 | # This script is a starting point to setup your application. 9 | # Add necessary setup steps to this file: 10 | 11 | puts "== Installing dependencies ==" 12 | system "gem install bundler --conservative" 13 | system "bundle check || bundle install" 14 | 15 | # puts "\n== Copying sample files ==" 16 | # unless File.exist?("config/database.yml") 17 | # system "cp config/database.yml.sample config/database.yml" 18 | # end 19 | 20 | puts "\n== Preparing database ==" 21 | system "bin/rake db:setup" 22 | 23 | puts "\n== Removing old logs and tempfiles ==" 24 | system "rm -f log/*" 25 | system "rm -rf tmp/cache" 26 | 27 | puts "\n== Restarting application server ==" 28 | system "touch tmp/restart.txt" 29 | end 30 | -------------------------------------------------------------------------------- /bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads spring without using Bundler, in order to be fast. 4 | # It gets overwritten when you run the `spring binstub` command. 5 | 6 | unless defined?(Spring) 7 | require 'rubygems' 8 | require 'bundler' 9 | 10 | if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)) 11 | Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) } 12 | gem 'spring', match[1] 13 | require 'spring/binstub' 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /bin/start_data_store.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | cd tmp/annotation-data-store && foreman start 3 | -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | include FileUtils 4 | 5 | # path to your application root. 6 | APP_ROOT = File.expand_path('..', __dir__) 7 | 8 | def system!(*args) 9 | system(*args) || abort("\n== Command #{args} failed ==") 10 | end 11 | 12 | chdir APP_ROOT do 13 | # This script is a way to update your development environment automatically. 14 | # Add necessary update steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # Install JavaScript dependencies if using Yarn 21 | # system('bin/yarn') 22 | 23 | puts "\n== Updating database ==" 24 | system! 'bin/rails db:migrate' 25 | 26 | puts "\n== Removing old logs and tempfiles ==" 27 | system! 'bin/rails log:clear tmp:clear' 28 | 29 | puts "\n== Restarting application server ==" 30 | system! 'bin/rails restart' 31 | end 32 | -------------------------------------------------------------------------------- /bin/webpack: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" 4 | ENV["NODE_ENV"] ||= "development" 5 | 6 | require "pathname" 7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 8 | Pathname.new(__FILE__).realpath) 9 | 10 | require "bundler/setup" 11 | 12 | require "webpacker" 13 | require "webpacker/webpack_runner" 14 | 15 | APP_ROOT = File.expand_path("..", __dir__) 16 | Dir.chdir(APP_ROOT) do 17 | Webpacker::WebpackRunner.run(ARGV) 18 | end 19 | -------------------------------------------------------------------------------- /bin/webpack-dev-server: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" 4 | ENV["NODE_ENV"] ||= "development" 5 | 6 | require "pathname" 7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 8 | Pathname.new(__FILE__).realpath) 9 | 10 | require "bundler/setup" 11 | 12 | require "webpacker" 13 | require "webpacker/dev_server_runner" 14 | 15 | APP_ROOT = File.expand_path("..", __dir__) 16 | Dir.chdir(APP_ROOT) do 17 | Webpacker::DevServerRunner.run(ARGV) 18 | end 19 | -------------------------------------------------------------------------------- /bin/yarn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_ROOT = File.expand_path('..', __dir__) 3 | Dir.chdir(APP_ROOT) do 4 | begin 5 | exec "yarnpkg", *ARGV 6 | rescue Errno::ENOENT 7 | $stderr.puts "Yarn executable was not detected in the system." 8 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" 9 | exit 1 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run AnnotationStudio::Application 5 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | require 'bootsnap/setup' # Speed up boot time by caching expensive operations. 5 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: redis://localhost:6379/1 10 | -------------------------------------------------------------------------------- /config/database.sample.yml: -------------------------------------------------------------------------------- 1 | development: &default 2 | adapter: postgresql 3 | encoding: utf8 4 | database: 5 | host: localhost 6 | pool: 5 7 | timeout: 5000 8 | 9 | 10 | production: 11 | adapter: postgresql 12 | encoding: utf8 13 | database: 14 | pool: 5 15 | username: 16 | password: 17 | 18 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/initializers/apartment.rb: -------------------------------------------------------------------------------- 1 | require "apartment/elevators/generic" 2 | 3 | Apartment.configure do |config| 4 | 5 | # These models will not be multi-tenanted, 6 | # but remain in the global (public) namespace 7 | # 8 | config.excluded_models = %w{Tenant AdminUser Delayed::Backend::ActiveRecord::Job} 9 | 10 | config.use_schemas = true 11 | 12 | # configure persistent schemas (E.g. hstore ) 13 | # config.persistent_schemas = %w{ hstore } 14 | 15 | # supply list of database names for migrations to run on 16 | config.tenant_names = lambda { Tenant.pluck :database_name } 17 | end 18 | 19 | Rails.application.config.middleware.use Apartment::Elevators::Generic, lambda { |request| 20 | domain = request.host 21 | if tenant = Tenant.where(domain: domain).first 22 | tenant.database_name 23 | else 24 | "public" 25 | end 26 | } 27 | 28 | Rails.application.config.default_email_link_protocol = (ENV["DEFAULT_EMAIL_LINK_PROTOCOL"] || "https") 29 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = "1.0" 5 | 6 | # Add additional assets to the asset load path 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | Rails.application.config.assets.precompile += %w(fontawesome-webfont.eot fontawesome-webfont.woff fontawesome-webfont.ttf fontawesome-webfont.svg active_admin.js active_admin.css users.css annotation_studio.js annotator-category.js bootstrap-tagsinput.js jquery.treegrid.js snapshot.js widget.js summernote.eot summernote.ttf summernote.woff glyphicons-halflings-regular.eot glyphicons-halflings-regular.woff2 glyphicons-halflings-regular.woff glyphicons-halflings-regular.ttf documents.css catalog.css tiny_mce_popup.js groups.css annotations.css *.png) 10 | 11 | Rails.application.config.assets.enabled = true 12 | Rails.application.config.assets.digest = true 13 | Rails.application.config.assets.initialize_on_precompile = false 14 | -------------------------------------------------------------------------------- /config/initializers/aws.rb: -------------------------------------------------------------------------------- 1 | Aws.config.update({ 2 | region: "us-east-1", 3 | credentials: Aws::Credentials.new(ENV["AWS_ACCESS_KEY_ID"], ENV["AWS_SECRET_ACCESS_KEY"]), 4 | }) 5 | S3_BUCKET = Aws::S3::Resource.new.bucket(ENV["S3_BUCKET_NAME"]) 6 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/carrierwave.rb: -------------------------------------------------------------------------------- 1 | if Rails.env.to_s != "development" and (not ENV["DISABLE_AWS"] or ENV["DISABLE_AWS"] != "true") 2 | CarrierWave.configure do |config| 3 | config.fog_credentials = { 4 | :provider => "AWS", 5 | :aws_access_key_id => ENV["AWS_ACCESS_KEY_ID"], 6 | :aws_secret_access_key => ENV["AWS_SECRET_ACCESS_KEY"], 7 | :region => ENV["AWS_REGION"], 8 | } 9 | # config.cache_dir = "#{Rails.root}/tmp/uploads" 10 | config.fog_directory = ENV["AWS_BIN_NAME"] # required 11 | config.fog_public = false # optional, defaults to true 12 | config.fog_attributes = { "Cache-Control" => "max-age=315576000" } # optional, defaults to {} 13 | config.storage = :fog 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy 4 | # For further information see the following documentation 5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy 6 | 7 | Rails.application.config.content_security_policy do |policy| 8 | policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development? 9 | policy.frame_src :self, :https, "*.vimeo.com", "*.youtube.com", "*.vine.co", "*.instagram.com", "*.dailymotion.com", "*.youku.com" 10 | # policy.default_src :self, :https 11 | # policy.font_src :self, :https, :data 12 | # policy.img_src :self, :https, :data 13 | # policy.object_src :none 14 | # policy.script_src :self, :https 15 | # policy.style_src :self, :https 16 | 17 | # # Specify URI for violation reports 18 | # # policy.report_uri "/csp-violation-report-endpoint" 19 | end 20 | # If you are using UJS then enable automatic nonce generation 21 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } 22 | 23 | # Report CSP violations to a specified URI 24 | # For further information see the following documentation: 25 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only 26 | # Rails.application.config.content_security_policy_report_only = true 27 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :hybrid 6 | -------------------------------------------------------------------------------- /config/initializers/document_processor.rb: -------------------------------------------------------------------------------- 1 | Rails.application.config.use_fake_document_processor = false 2 | -------------------------------------------------------------------------------- /config/initializers/exception_notification.rb: -------------------------------------------------------------------------------- 1 | if Rails.env.to_s != 'development' 2 | AnnotationStudio::Application.config.middleware.use ExceptionNotification::Rack, 3 | :email => { 4 | :email_prefix => ENV['EXCEPTION_PREFIX'], 5 | :sender_address => ENV['EXCEPTION_SENDER'], 6 | :exception_recipients => ENV['EXCEPTION_RECIPIENTS'].split(' ') 7 | } 8 | end 9 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/kaminari.rb: -------------------------------------------------------------------------------- 1 | # per: https://github.com/gregbell/active_admin/wiki/How-to-work-with-will_paginate 2 | Kaminari.configure do |config| 3 | config.page_method_name = :per_page_kaminari 4 | 5 | if defined?(WillPaginate) 6 | module WillPaginate 7 | module ActiveRecord 8 | module RelationMethods 9 | def per(value = nil) per_page(value) end 10 | def total_count() count end 11 | end 12 | end 13 | module CollectionMethods 14 | alias_method :num_pages, :total_pages 15 | end 16 | end 17 | end 18 | end -------------------------------------------------------------------------------- /config/initializers/lograge.rb: -------------------------------------------------------------------------------- 1 | # config/initializers/lograge.rb 2 | 3 | Rails.application.configure do 4 | config.lograge.enabled = true 5 | 6 | # add timestamp 7 | config.lograge.custom_options = lambda do |event| 8 | { time: Time.now } 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /config/initializers/mail.rb: -------------------------------------------------------------------------------- 1 | if ['production', 'staging', 'public'].include?(Rails.env) 2 | ActionMailer::Base.smtp_settings = { 3 | :address => 'smtp.sendgrid.net', 4 | :port => '587', 5 | :authentication => :plain, 6 | :user_name => ENV['SENDGRID_USERNAME'], 7 | :password => ENV['SENDGRID_PASSWORD'], 8 | :domain => 'heroku.com' 9 | } 10 | ActionMailer::Base.delivery_method = :smtp 11 | end 12 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /config/initializers/new_framework_defaults.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains migration options to ease your Rails 5.0 upgrade. 4 | # 5 | # Once upgraded flip defaults one by one to migrate to the new default. 6 | # 7 | # Read the Rails 5.0 release notes for more info on each option. 8 | 9 | # Enable per-form CSRF tokens. Previous versions had false. 10 | Rails.application.config.action_controller.per_form_csrf_tokens = false 11 | 12 | # Enable origin-checking CSRF mitigation. Previous versions had false. 13 | Rails.application.config.action_controller.forgery_protection_origin_check = false 14 | 15 | # Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`. 16 | # Previous versions had false. 17 | ActiveSupport.to_time_preserves_timezone = false 18 | 19 | # Require `belongs_to` associations by default. Previous versions had false. 20 | Rails.application.config.active_record.belongs_to_required_by_default = false 21 | -------------------------------------------------------------------------------- /config/initializers/paperclip.rb: -------------------------------------------------------------------------------- 1 | Paperclip.interpolates :tenant do |attachment, style| 2 | Apartment::Tenant.current 3 | end 4 | 5 | Paperclip::Attachment.default_options[:path] = ":class/:attachment/:tenant/:id_partition/:style/:filename" 6 | 7 | if ["production", "staging", "public"].include?(Rails.env) and (not ENV["DISABLE_AWS"] or ENV["DISABLE_AWS"] != "true") 8 | Paperclip::Attachment.default_options[:storage] = :s3 9 | Paperclip::Attachment.default_options[:s3_credentials] = { 10 | :bucket => ENV["S3_BUCKET_NAME"], 11 | :access_key_id => ENV["AWS_ACCESS_KEY_ID"], 12 | :secret_access_key => ENV["AWS_SECRET_ACCESS_KEY"], 13 | } 14 | Paperclip::Attachment.default_options[:s3_region] = ENV["AWS_REGION"] 15 | Paperclip::Attachment.default_options[:s3_permissions] = "public-read" 16 | end 17 | -------------------------------------------------------------------------------- /config/initializers/rails_footnotes.rb: -------------------------------------------------------------------------------- 1 | if defined?(Footnotes) && Rails.env.development? 2 | Footnotes.run! # first of all 3 | 4 | # ... other init code 5 | end 6 | -------------------------------------------------------------------------------- /config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | AnnotationStudio::Application.config.secret_token = '0f2112881009aa0c4e57b532eb25bb79d9bb5a88d063509bd96e36c93bdfa20242f20e2ad5521bd018fcb307e01ce342b3b8786ba2c1fa1137b064e25dfff17e' 8 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_AnnotationStudio_session' 4 | -------------------------------------------------------------------------------- /config/initializers/subdomain_specific.rb: -------------------------------------------------------------------------------- 1 | DOMAIN_CONFIGS = YAML.load_file(Rails.root.join('config', 'domain_specific' , 'config.yml')) 2 | -------------------------------------------------------------------------------- /config/initializers/will_paginate_array.rb: -------------------------------------------------------------------------------- 1 | require 'will_paginate/array' -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /config/locales/en.bootstrap.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | helpers: 6 | actions: "Actions" 7 | links: 8 | back: "Back" 9 | cancel: "Cancel" 10 | confirm: "Are you sure?" 11 | destroy: "Delete" 12 | new: "New" 13 | edit: "Edit" 14 | titles: 15 | edit: "Edit %{model}" 16 | save: "Save %{model}" 17 | new: "New %{model}" 18 | delete: "Delete %{model}" 19 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | unauthorized: 6 | manage: 7 | all: "You don't have permission to %{action} %{subject}." 8 | user: "You don't have permission to manage other user accounts." 9 | document: "You don't have permission to manage this document." 10 | read: 11 | user: "You don't have permission to view other user accounts." 12 | document: "You don't have permission to view this document." 13 | update: 14 | user: "You don't have permission to modify other user accounts." 15 | document: "You don't have permission to modify this document." 16 | destroy: 17 | user: "You don't have permission to delete other user accounts." 18 | document: "You don't have permission to delete this document." 19 | helpers: 20 | submit: 21 | update: "Save changes" -------------------------------------------------------------------------------- /config/newrelic.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This file configures the New Relic Agent. New Relic monitors Ruby, Java, 3 | # .NET, PHP, Python, Node, and Go applications with deep visibility and low 4 | # overhead. For more information, visit www.newrelic.com. 5 | # 6 | # Generated June 03, 2019 7 | # 8 | # This configuration file is custom generated for app135370019@heroku.com 9 | # 10 | # For full documentation of agent configuration options, please refer to 11 | # https://docs.newrelic.com/docs/agents/ruby-agent/installation-configuration/ruby-agent-configuration 12 | 13 | common: &default_settings 14 | # Required license key associated with your New Relic account. 15 | license_key: <%= ENV["NEW_RELIC_LICENSE_KEY"] %> 16 | 17 | # Your application name. Renaming here affects where data displays in New 18 | # Relic. For more details, see https://docs.newrelic.com/docs/apm/new-relic-apm/maintenance/renaming-applications 19 | app_name: Annotation Studio 2.0 20 | 21 | # To disable the agent regardless of other settings, uncomment the following: 22 | # agent_enabled: false 23 | 24 | # Logging level for log/newrelic_agent.log 25 | log_level: info 26 | 27 | 28 | # Environment-specific settings are in this section. 29 | # RAILS_ENV or RACK_ENV (as appropriate) is used to determine the environment. 30 | # If your application has other named environments, configure them here. 31 | development: 32 | <<: *default_settings 33 | app_name: Annotation Studio 2.0 (Development) 34 | 35 | test: 36 | <<: *default_settings 37 | # It doesn't make sense to report to New Relic from automated test runs. 38 | monitor_mode: false 39 | 40 | staging: 41 | <<: *default_settings 42 | app_name: Annotation Studio 2.0 (Staging) 43 | 44 | production: 45 | <<: *default_settings 46 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i 2 | threads threads_count, threads_count 3 | 4 | preload_app! 5 | 6 | rackup DefaultRackup 7 | port ENV.fetch("PORT") { 3000 } 8 | environment ENV.fetch("RAILS_ENV") { "development" } 9 | # On development, run ssl server on port 3001 10 | if ENV.fetch("RAILS_ENV") == "development" 11 | ssl_bind "localhost", "3001", { 12 | key: ENV.fetch("SSL_KEY_PATH"), 13 | cert: ENV.fetch("SSL_CERT_PATH"), 14 | verify_mode: "none", 15 | } 16 | end 17 | 18 | # Windows only: 19 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 20 | 21 | on_worker_boot do 22 | # Worker specific setup for Rails 4.1+ 23 | # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot 24 | ActiveRecord::Base.establish_connection 25 | end 26 | 27 | # Allow puma to be restarted by `rails restart` command. 28 | plugin :tmp_restart -------------------------------------------------------------------------------- /config/rails_best_practices.yml: -------------------------------------------------------------------------------- 1 | AddModelVirtualAttributeCheck: { } 2 | AlwaysAddDbIndexCheck: { } 3 | #CheckSaveReturnValueCheck: { } 4 | DefaultScopeIsEvilCheck: { } 5 | DryBundlerInCapistranoCheck: { } 6 | #HashSyntaxCheck: { } 7 | IsolateSeedDataCheck: { } 8 | KeepFindersOnTheirOwnModelCheck: { } 9 | LawOfDemeterCheck: { } 10 | #LongLineCheck: { max_line_length: 80 } 11 | MoveCodeIntoControllerCheck: { } 12 | MoveCodeIntoHelperCheck: { array_count: 3 } 13 | MoveCodeIntoModelCheck: { use_count: 2 } 14 | MoveFinderToNamedScopeCheck: { } 15 | MoveModelLogicIntoModelCheck: { use_count: 4 } 16 | NeedlessDeepNestingCheck: { nested_count: 2 } 17 | NotRescueExceptionCheck: { } 18 | NotUseDefaultRouteCheck: { } 19 | NotUseTimeAgoInWordsCheck: { } 20 | OveruseRouteCustomizationsCheck: { customize_count: 3 } 21 | ProtectMassAssignmentCheck: { } 22 | RemoveEmptyHelpersCheck: { } 23 | #RemoveTabCheck: { } 24 | RemoveTrailingWhitespaceCheck: { } 25 | RemoveUnusedMethodsInControllersCheck: { except_methods: [] } 26 | RemoveUnusedMethodsInHelpersCheck: { except_methods: [] } 27 | RemoveUnusedMethodsInModelsCheck: { except_methods: [] } 28 | ReplaceComplexCreationWithFactoryMethodCheck: { attribute_assignment_count: 2 } 29 | ReplaceInstanceVariableWithLocalVariableCheck: { } 30 | RestrictAutoGeneratedRoutesCheck: { } 31 | SimplifyRenderInControllersCheck: { } 32 | SimplifyRenderInViewsCheck: { } 33 | #UseBeforeFilterCheck: { customize_count: 2 } 34 | UseModelAssociationCheck: { } 35 | UseMultipartAlternativeAsContentTypeOfEmailCheck: { } 36 | #UseParenthesesInMethodDefCheck: { } 37 | UseObserverCheck: { } 38 | UseQueryAttributeCheck: { } 39 | UseSayWithTimeInMigrationsCheck: { } 40 | UseScopeAccessCheck: { } 41 | UseTurboSprocketsRails3Check: { } 42 | -------------------------------------------------------------------------------- /config/scout_apm.yml: -------------------------------------------------------------------------------- 1 | common: &defaults 2 | name: "annotation-studio-2-0" 3 | key: <%= ENV['SCOUT_KEY'] %> 4 | monitor: <%= ENV['SCOUT_MONITOR'] %> 5 | 6 | test: 7 | monitor: false 8 | 9 | production: 10 | <<: *defaults 11 | 12 | development: 13 | <<: *defaults 14 | -------------------------------------------------------------------------------- /config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rails secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: b58789056dea61ec9adcd0cca6281c5b66ca33355b9afd0f4fe97a376707f9d60b8a40b51de0bf95e002476fb2e7385a099deb2ad82ebe3e38931bfec479a54b 15 | 16 | test: 17 | secret_key_base: 6b7c79c4781fbc25bb02a69d7a6fc0e5c0905bea46bf75fd15c67d9857a0a195eaa74da2f33b2f54807ff0bf012e9fe00b0858cecf5294efe8000a3c9923e42b 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | %w[ 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ].each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket 23 | 24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /config/webpack/development.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development' 2 | 3 | const environment = require('./environment') 4 | 5 | module.exports = environment.toWebpackConfig() 6 | -------------------------------------------------------------------------------- /config/webpack/environment.js: -------------------------------------------------------------------------------- 1 | const { environment } = require('@rails/webpacker') 2 | 3 | module.exports = environment 4 | -------------------------------------------------------------------------------- /config/webpack/production.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV || 'production' 2 | 3 | const environment = require('./environment') 4 | 5 | module.exports = environment.toWebpackConfig() 6 | -------------------------------------------------------------------------------- /config/webpack/test.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development' 2 | 3 | const environment = require('./environment') 4 | 5 | module.exports = environment.toWebpackConfig() 6 | -------------------------------------------------------------------------------- /db/development.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/db/development.sqlite3 -------------------------------------------------------------------------------- /db/migrate/20120326153645_create_documents.rb: -------------------------------------------------------------------------------- 1 | class CreateDocuments < ActiveRecord::Migration 2 | def change 3 | create_table :documents do |t| 4 | t.string :title 5 | t.text :description 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20120326153731_create_collections.rb: -------------------------------------------------------------------------------- 1 | class CreateCollections < ActiveRecord::Migration 2 | def change 3 | create_table :collections do |t| 4 | t.string :title 5 | t.text :description 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20120326164812_add_collection_id_to_document.rb: -------------------------------------------------------------------------------- 1 | class AddCollectionIdToDocument < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :collection_id, :integer 4 | 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20120727191634_repertoire_groups_migration.rb: -------------------------------------------------------------------------------- 1 | class RepertoireGroupsMigration < ActiveRecord::Migration 2 | def self.up 3 | create_table :roles, :force => true do |t| 4 | t.string :name 5 | t.string :description 6 | end 7 | 8 | create_table :assignments, :force => true do |t| 9 | t.integer :user_id 10 | t.integer :role_id 11 | t.timestamps 12 | end 13 | end 14 | 15 | def self.down 16 | drop_table :assignments 17 | drop_table :roles 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /db/migrate/20120727192756_acts_as_taggable_on_migration.rb: -------------------------------------------------------------------------------- 1 | class ActsAsTaggableOnMigration < ActiveRecord::Migration 2 | def self.up 3 | create_table :tags do |t| 4 | t.string :name 5 | end 6 | 7 | create_table :taggings do |t| 8 | t.references :tag 9 | 10 | # You should make sure that the column created is 11 | # long enough to store the required class names. 12 | t.references :taggable, :polymorphic => true 13 | t.references :tagger, :polymorphic => true 14 | 15 | # Limit is created to prevent MySQL error on index 16 | # length for MyISAM table type: http://bit.ly/vgW2Ql 17 | t.string :context, :limit => 128 18 | 19 | t.datetime :created_at 20 | end 21 | 22 | add_index :taggings, :tag_id 23 | add_index :taggings, [:taggable_id, :taggable_type, :context] 24 | end 25 | 26 | def self.down 27 | drop_table :taggings 28 | drop_table :tags 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /db/migrate/20120823160312_add_author_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddAuthorToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :author, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20120823162007_add_year_published_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddYearPublishedToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :year_published, :datetime 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20120823162021_add_edition_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddEditionToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :edition, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20120823162026_add_publisher_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddPublisherToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :publisher, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20120823162031_add_source_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddSourceToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :source, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20120823162118_add_rights_status_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddRightsStatusToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :rights_status, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20120823204038_add_slug_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddSlugToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :slug, :string 4 | add_index :documents, :slug, unique: true 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20120823204608_create_friendly_id_slugs.rb: -------------------------------------------------------------------------------- 1 | class CreateFriendlyIdSlugs < ActiveRecord::Migration 2 | 3 | def self.up 4 | create_table :friendly_id_slugs do |t| 5 | t.string :slug, :null => false 6 | t.integer :sluggable_id, :null => false 7 | t.string :sluggable_type, :limit => 40 8 | t.datetime :created_at 9 | end 10 | add_index :friendly_id_slugs, :sluggable_id 11 | add_index :friendly_id_slugs, [:slug, :sluggable_type], :unique => true 12 | add_index :friendly_id_slugs, :sluggable_type 13 | end 14 | 15 | def self.down 16 | drop_table :friendly_id_slugs 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /db/migrate/20120827182156_rename_document_description_and_add_user_id.rb: -------------------------------------------------------------------------------- 1 | class RenameDocumentDescriptionAndAddUserId < ActiveRecord::Migration 2 | def up 3 | change_table :documents do |t| 4 | t.references :user 5 | end 6 | rename_column :documents, :description, :text 7 | end 8 | 9 | def down 10 | rename_column :documents, :text, :description 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20120827183349_remove_collection_id_from_documents.rb: -------------------------------------------------------------------------------- 1 | class RemoveCollectionIdFromDocuments < ActiveRecord::Migration 2 | def up 3 | remove_column :documents, :collection_id 4 | end 5 | 6 | def down 7 | add_column :documents, :collection_id, :integer 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20120827183632_remove_collections.rb: -------------------------------------------------------------------------------- 1 | class RemoveCollections < ActiveRecord::Migration 2 | def up 3 | drop_table :collections 4 | end 5 | 6 | def down 7 | create_table :collections 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20121017192344_create_admin_notes.rb: -------------------------------------------------------------------------------- 1 | class CreateAdminNotes < ActiveRecord::Migration 2 | def self.up 3 | create_table :admin_notes do |t| 4 | t.string :resource_id, :null => false 5 | t.string :resource_type, :null => false 6 | t.references :admin_user, :polymorphic => true 7 | t.text :body 8 | t.timestamps 9 | end 10 | add_index :admin_notes, [:resource_type, :resource_id] 11 | add_index :admin_notes, [:admin_user_type, :admin_user_id] 12 | end 13 | 14 | def self.down 15 | drop_table :admin_notes 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/migrate/20121017192345_move_admin_notes_to_comments.rb: -------------------------------------------------------------------------------- 1 | class MoveAdminNotesToComments < ActiveRecord::Migration 2 | def self.up 3 | remove_index :admin_notes, [:admin_user_type, :admin_user_id] 4 | rename_table :admin_notes, :active_admin_comments 5 | rename_column :active_admin_comments, :admin_user_type, :author_type 6 | rename_column :active_admin_comments, :admin_user_id, :author_id 7 | add_column :active_admin_comments, :namespace, :string 8 | add_index :active_admin_comments, [:namespace] 9 | add_index :active_admin_comments, [:author_type, :author_id] 10 | 11 | # Update all the existing comments to the default namespace 12 | say "Updating any existing comments to the #{ActiveAdmin.application.default_namespace} namespace." 13 | execute "UPDATE active_admin_comments SET namespace='#{ActiveAdmin.application.default_namespace}'" 14 | end 15 | 16 | def self.down 17 | remove_index :active_admin_comments, :column => [:author_type, :author_id] 18 | remove_index :active_admin_comments, :column => [:namespace] 19 | remove_column :active_admin_comments, :namespace 20 | rename_column :active_admin_comments, :author_id, :admin_user_id 21 | rename_column :active_admin_comments, :author_type, :admin_user_type 22 | rename_table :active_admin_comments, :admin_notes 23 | add_index :admin_notes, [:admin_user_type, :admin_user_id] 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /db/migrate/20121018184226_add_publication_date_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddPublicationDateToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :publication_date, :date 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20121121165006_add_chapters_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddChaptersToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :chapters, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130128172206_add_affiliation_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddAffiliationToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :affiliation, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130825195003_add_state_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddStateToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :state, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130903205508_add_slug_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddSlugToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :slug, :string 4 | add_index :users, :slug 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20130910111145_create_redactor_assets.rb: -------------------------------------------------------------------------------- 1 | class CreateRedactorAssets < ActiveRecord::Migration 2 | def self.up 3 | create_table :redactor_assets do |t| 4 | t.integer :user_id 5 | t.string :data_file_name, :null => false 6 | t.string :data_content_type 7 | t.integer :data_file_size 8 | 9 | t.integer :assetable_id 10 | t.string :assetable_type, :limit => 30 11 | t.string :type, :limit => 30 12 | 13 | # Uncomment it to save images dimensions, if your need it 14 | t.integer :width 15 | t.integer :height 16 | 17 | t.timestamps 18 | end 19 | 20 | # Uncomment it to add foreign key. gem 'foreigner' is required in your .Gemfile 21 | # add_foreign_key(:redactor_assets, :users, dependent: :delete) 22 | add_index "redactor_assets", ["assetable_type", "type", "assetable_id"], :name => "idx_redactor_assetable_type" 23 | add_index "redactor_assets", ["assetable_type", "assetable_id"], :name => "idx_redactor_assetable" 24 | end 25 | 26 | def self.down 27 | drop_table :redactor_assets 28 | end 29 | end 30 | 31 | -------------------------------------------------------------------------------- /db/migrate/20131030185352_add_attachment_upload_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddAttachmentUploadToDocuments < ActiveRecord::Migration 2 | def self.up 3 | change_table :documents do |t| 4 | t.attachment :upload 5 | end 6 | end 7 | 8 | def self.down 9 | drop_attached_file :documents, :upload 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20131030192740_add_processed_at_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddProcessedAtToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :processed_at, :datetime 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20131030202337_create_delayed_jobs.rb: -------------------------------------------------------------------------------- 1 | class CreateDelayedJobs < ActiveRecord::Migration 2 | def self.up 3 | create_table :delayed_jobs, :force => true do |table| 4 | table.integer :priority, :default => 0, :null => false # Allows some jobs to jump to the front of the queue 5 | table.integer :attempts, :default => 0, :null => false # Provides for retries, but still fail eventually. 6 | table.text :handler, :null => false # YAML-encoded string of the object that will do work 7 | table.text :last_error # reason for last failure (See Note below) 8 | table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future. 9 | table.datetime :locked_at # Set when a client is working on this object 10 | table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead) 11 | table.string :locked_by # Who is working on this object (if locked) 12 | table.string :queue # The name of the queue this job is in 13 | table.timestamps 14 | end 15 | 16 | add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority' 17 | end 18 | 19 | def self.down 20 | drop_table :delayed_jobs 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /db/migrate/20140624195339_create_tenants.rb: -------------------------------------------------------------------------------- 1 | class CreateTenants < ActiveRecord::Migration 2 | def change 3 | create_table :tenants do |t| 4 | t.string :domain 5 | t.string :database_name 6 | 7 | t.timestamps 8 | end 9 | 10 | add_index :tenants, :database_name 11 | add_index :tenants, :domain 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20140625181144_add_agreement_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddAgreementToUser < ActiveRecord::Migration 2 | def change 3 | add_column :users, :agreement, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20141010190718_add_survey_link_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddSurveyLinkToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :survey_link, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20150219165541_create_annotation_categories.rb: -------------------------------------------------------------------------------- 1 | class CreateAnnotationCategories < ActiveRecord::Migration 2 | def change 3 | begin # TODO-PER: this is just here because something got out of sync. 4 | create_table :annotation_categories do |t| 5 | t.string :name, :null => false 6 | t.string :hex 7 | t.string :css_classes 8 | t.timestamps null: true 9 | end 10 | rescue Exception => e 11 | # For some reason, the staging server is getting stuck on this migration, so just let it pass. 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20150324173818_add_default_state_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddDefaultStateToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :default_state, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20150506143606_add_missing_unique_indices.acts_as_taggable_on_engine.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from acts_as_taggable_on_engine (originally 2) 2 | class AddMissingUniqueIndices < ActiveRecord::Migration 3 | def self.up 4 | add_index :tags, :name, unique: true 5 | 6 | remove_index :taggings, :tag_id 7 | remove_index :taggings, [:taggable_id, :taggable_type, :context] 8 | add_index :taggings, 9 | [:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type], 10 | unique: true, name: 'taggings_idx' 11 | end 12 | 13 | def self.down 14 | remove_index :tags, :name 15 | 16 | remove_index :taggings, name: 'taggings_idx' 17 | add_index :taggings, :tag_id 18 | add_index :taggings, [:taggable_id, :taggable_type, :context] 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /db/migrate/20150506143607_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from acts_as_taggable_on_engine (originally 3) 2 | class AddTaggingsCounterCacheToTags < ActiveRecord::Migration 3 | def self.up 4 | add_column :tags, :taggings_count, :integer, default: 0 5 | 6 | ActsAsTaggableOn::Tag.reset_column_information 7 | ActsAsTaggableOn::Tag.find_each do |tag| 8 | ActsAsTaggableOn::Tag.reset_counters(tag.id, :taggings) 9 | end 10 | end 11 | 12 | def self.down 13 | remove_column :tags, :taggings_count 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20150506143608_add_missing_taggable_index.acts_as_taggable_on_engine.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from acts_as_taggable_on_engine (originally 4) 2 | class AddMissingTaggableIndex < ActiveRecord::Migration 3 | def self.up 4 | add_index :taggings, [:taggable_id, :taggable_type, :context] 5 | end 6 | 7 | def self.down 8 | remove_index :taggings, [:taggable_id, :taggable_type, :context] 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20150506143609_change_collation_for_tag_names.acts_as_taggable_on_engine.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from acts_as_taggable_on_engine (originally 5) 2 | # This migration is added to circumvent issue #623 and have special characters 3 | # work properly 4 | class ChangeCollationForTagNames < ActiveRecord::Migration 5 | def up 6 | if ActsAsTaggableOn::Utils.using_mysql? 7 | execute("ALTER TABLE tags MODIFY name varchar(255) CHARACTER SET utf8 COLLATE utf8_bin;") 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20160107155128_add_tenant_config_fields.rb: -------------------------------------------------------------------------------- 1 | class AddTenantConfigFields < ActiveRecord::Migration 2 | def change 3 | add_column :tenants, :mel_catalog_enabled, :boolean, :default => false 4 | add_column :tenants, :annotation_categories_enabled, :boolean, :default => false 5 | add_column :tenants, :mel_catalog_url, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20160808210812_add_snapshot_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddSnapshotToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :snapshot, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160912201159_add_auth_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddAuthToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :provider, :string 4 | add_column :users, :uid, :string 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20161018191136_add_cove_uri_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddCoveUriToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :cove_uri, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20161018195535_add_cove_info_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddCoveInfoToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :cove_id, :integer 4 | add_column :users, :full_name, :string 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20161028195936_add_origin_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddOriginToDocuments < ActiveRecord::Migration 2 | def change 3 | add_column :documents, :origin, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190531191825_remove_mel_catalog_stuff.rb: -------------------------------------------------------------------------------- 1 | class RemoveMelCatalogStuff < ActiveRecord::Migration 2 | def change 3 | remove_columns :tenants, :mel_catalog_enabled, :mel_catalog_url 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190531192055_remove_cove_integration.rb: -------------------------------------------------------------------------------- 1 | class RemoveCoveIntegration < ActiveRecord::Migration 2 | def change 3 | remove_columns :documents, :cove_uri 4 | remove_columns :users, :cove_id 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20190617185106_drop_extension_pg_stat_statements.rb: -------------------------------------------------------------------------------- 1 | class DropExtensionPgStatStatements < ActiveRecord::Migration 2 | def self.up 3 | disable_extension "pg_stat_statements" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190710191012_add_missing_indexes.acts_as_taggable_on_engine.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from acts_as_taggable_on_engine (originally 6) 2 | class AddMissingIndexes < ActiveRecord::Migration 3 | def change 4 | add_index :taggings, :tag_id 5 | add_index :taggings, :taggable_id 6 | add_index :taggings, :taggable_type 7 | add_index :taggings, :tagger_id 8 | add_index :taggings, :context 9 | 10 | add_index :taggings, [:tagger_id, :tagger_type] 11 | add_index :taggings, [:taggable_id, :taggable_type, :tagger_id, :context], name: 'taggings_idy' 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20190710191857_create_groups.rb: -------------------------------------------------------------------------------- 1 | class CreateGroups < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :groups do |t| 4 | t.string :name 5 | 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20190710200313_create_memberships.rb: -------------------------------------------------------------------------------- 1 | class CreateMemberships < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :memberships do |t| 4 | t.integer :group_id 5 | t.integer :user_id 6 | t.string :role, default: "member" 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20190710201111_add_index_to_memberships.rb: -------------------------------------------------------------------------------- 1 | class AddIndexToMemberships < ActiveRecord::Migration[5.0] 2 | def change 3 | add_index :memberships, [:group_id, :user_id], unique:true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190710202451_create_join_table_document_group.rb: -------------------------------------------------------------------------------- 1 | class CreateJoinTableDocumentGroup < ActiveRecord::Migration[5.0] 2 | def change 3 | create_join_table :documents, :groups do |t| 4 | # t.index [:document_id, :group_id] 5 | # t.index [:group_id, :document_id] 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20190711192830_make_group_name_unique.rb: -------------------------------------------------------------------------------- 1 | class MakeGroupNameUnique < ActiveRecord::Migration[5.0] 2 | def change 3 | change_column :groups, :name, :string, unique: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190711193546_add_index_to_groups.rb: -------------------------------------------------------------------------------- 1 | class AddIndexToGroups < ActiveRecord::Migration[5.0] 2 | def change 3 | add_index :groups, :name , unique:true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190712193103_create_invites.rb: -------------------------------------------------------------------------------- 1 | class CreateInvites < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :invites do |t| 4 | t.integer :group_id 5 | t.string :token 6 | t.datetime :expiration_date 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20190712193820_add_index_to_invites.rb: -------------------------------------------------------------------------------- 1 | class AddIndexToInvites < ActiveRecord::Migration[5.0] 2 | def change 3 | add_index :invites, :group_id , unique:true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190717172928_add_index_to_documents_groups.rb: -------------------------------------------------------------------------------- 1 | class AddIndexToDocumentsGroups < ActiveRecord::Migration[5.0] 2 | def change 3 | add_index :documents_groups, [:document_id, :group_id], unique: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190722224656_make_publication_date_string.rb: -------------------------------------------------------------------------------- 1 | class MakePublicationDateString < ActiveRecord::Migration[5.0] 2 | def change 3 | change_column :documents, :publication_date, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190729161242_add_page_numbers_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddPageNumbersToDocuments < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :documents, :page_numbers, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190729161513_add_metadata_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddMetadataToDocuments < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :documents, :series, :string 4 | add_column :documents, :location, :string 5 | add_column :documents, :journal_title, :string 6 | add_column :documents, :notes, :text 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20190729213030_add_owner_to_groups.rb: -------------------------------------------------------------------------------- 1 | class AddOwnerToGroups < ActiveRecord::Migration[5.0] 2 | def change 3 | add_reference :groups, :owner, foreign_key: { to_table: :users } 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190731184827_add_idea_space_toggle_to_groups.rb: -------------------------------------------------------------------------------- 1 | class AddIdeaSpaceToggleToGroups < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :groups, :ideaSpaceOn, :boolean, :default => false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190802202325_add_resource_type_to_documents.rb: -------------------------------------------------------------------------------- 1 | class AddResourceTypeToDocuments < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :documents, :resource_type, :string, :default => "Other" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190806204634_add_user_foreign_key_to_memberships.rb: -------------------------------------------------------------------------------- 1 | class AddUserForeignKeyToMemberships < ActiveRecord::Migration[5.0] 2 | def change 3 | add_foreign_key :memberships, :users 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190806205016_add_group_foreign_key_to_memberships.rb: -------------------------------------------------------------------------------- 1 | class AddGroupForeignKeyToMemberships < ActiveRecord::Migration[5.0] 2 | def change 3 | add_foreign_key :memberships, :groups 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20191125040751_change_publication_date_type_to_text.rb: -------------------------------------------------------------------------------- 1 | class ChangePublicationDateTypeToText < ActiveRecord::Migration[5.0] 2 | def up 3 | change_column :documents, :publication_date, :text 4 | end 5 | def down 6 | change_column :documents, :publication_date, :date 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20200124025912_remove_unique_name_index_from_groups.rb: -------------------------------------------------------------------------------- 1 | class RemoveUniqueNameIndexFromGroups < ActiveRecord::Migration[5.0] 2 | def change 3 | remove_index :groups, :name => 'index_groups_on_name' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200216012538_add_cascade_on_delete_to_foreign_keys.rb: -------------------------------------------------------------------------------- 1 | class AddCascadeOnDeleteToForeignKeys < ActiveRecord::Migration[5.0] 2 | def change 3 | # remove the old foreign_keys 4 | remove_foreign_key "groups", "users" 5 | remove_foreign_key "memberships", "groups" 6 | remove_foreign_key "memberships", "users" 7 | 8 | # add the new foreign_keys 9 | add_foreign_key "groups", "users", column: "owner_id", on_delete: :cascade 10 | add_foreign_key "memberships", "groups", on_delete: :cascade 11 | add_foreign_key "memberships", "users", on_delete: :cascade 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20200413035045_add_confidential_boolean_to_oauth_applications.rb: -------------------------------------------------------------------------------- 1 | class AddConfidentialBooleanToOauthApplications < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :oauth_applications, :confidential, :boolean, default: true, null: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200529183409_add_timestamps_to_groups.rb: -------------------------------------------------------------------------------- 1 | class AddTimestampsToGroups < ActiveRecord::Migration[5.0] 2 | def change 3 | add_timestamps :groups, null: false, default: -> { 'NOW()' } 4 | end 5 | end -------------------------------------------------------------------------------- /db/test.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/db/test.sqlite3 -------------------------------------------------------------------------------- /doc/README_FOR_APP: -------------------------------------------------------------------------------- 1 | Use this README file to introduce your application and point to useful places in the API for learning more. 2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. 3 | -------------------------------------------------------------------------------- /documents/uploads/public/000/000/002/original/Bonwell.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/public/000/000/002/original/Bonwell.pdf -------------------------------------------------------------------------------- /documents/uploads/public/000/000/003/original/Bonwell.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/public/000/000/003/original/Bonwell.pdf -------------------------------------------------------------------------------- /documents/uploads/www/000/000/001/original/example.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/001/original/example.docx -------------------------------------------------------------------------------- /documents/uploads/www/000/000/001/original/example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/001/original/example.pdf -------------------------------------------------------------------------------- /documents/uploads/www/000/000/002/original/example.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/002/original/example.docx -------------------------------------------------------------------------------- /documents/uploads/www/000/000/002/original/example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/002/original/example.pdf -------------------------------------------------------------------------------- /documents/uploads/www/000/000/003/original/example.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/003/original/example.docx -------------------------------------------------------------------------------- /documents/uploads/www/000/000/003/original/example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/003/original/example.pdf -------------------------------------------------------------------------------- /documents/uploads/www/000/000/004/original/example.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/004/original/example.docx -------------------------------------------------------------------------------- /documents/uploads/www/000/000/004/original/example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/004/original/example.pdf -------------------------------------------------------------------------------- /documents/uploads/www/000/000/005/original/example.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/005/original/example.docx -------------------------------------------------------------------------------- /documents/uploads/www/000/000/005/original/example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/005/original/example.pdf -------------------------------------------------------------------------------- /documents/uploads/www/000/000/006/original/example.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/006/original/example.docx -------------------------------------------------------------------------------- /documents/uploads/www/000/000/006/original/example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/006/original/example.pdf -------------------------------------------------------------------------------- /documents/uploads/www/000/000/007/original/example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/documents/uploads/www/000/000/007/original/example.pdf -------------------------------------------------------------------------------- /get_body.rb: -------------------------------------------------------------------------------- 1 | complete = Nokogiri::HTML(doc.text) 2 | body = complete.css("body") 3 | body_contents = complete.css("body").inner_html 4 | body_contents.to_html 5 | doc.text = body_contents 6 | doc.save 7 | -------------------------------------------------------------------------------- /lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/lib/assets/.gitkeep -------------------------------------------------------------------------------- /lib/assets/stylesheets/richText-annotator.css: -------------------------------------------------------------------------------- 1 | .annotator-viewer div:first-of-type.richText-annotation *, 2 | .annotator-viewer div:first-of-type.richText-annotation{ 3 | font-style: normal; 4 | font-weight: inherit; 5 | text-align: inherit; 6 | } 7 | .annotator-viewer div:first-of-type.richText-annotation{ 8 | padding-top: 22px; 9 | } 10 | 11 | /* Fix in the tinymce */ 12 | .annotator-viewer div:first-of-type.richText-annotation strong{ 13 | font-weight: bold; 14 | } 15 | .annotator-viewer div:first-of-type.richText-annotation em{ 16 | font-style: italic; 17 | } 18 | 19 | .mce-container { 20 | z-index:3000000000!important; /*To fix full-screen problems*/ 21 | } 22 | 23 | 24 | /* Some change in the design of Annotator */ 25 | /*.annotator-editor .annotator-widget{ 26 | min-width: 400px; 27 | }*/ 28 | 29 | /*Rubric icon*/ 30 | .mce-ico.mce-i-rubric{ 31 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QkBBB07nraNoQAAAhZJREFUKM+NkstrE1EUxr+5c08ykztpJtVoazHBF8FgQQzonyBKEZS6FrQKLl0EXBRT0ZULJSs3oii4TyHgu90IlTaL6qouWlv7Ck1N0BSnmZk714WbPHz07M4534+Pw3eAHdTY8A9+Nd9/bshU1DpnO4HXjh2ZY2J9/OSTxHTrnP8PvJYf+BDQ6qEDaQBB43jrTusUFy4oPjsYWYzF+VS91nxLYfdhKgONaQT3W/KMxr1XY5e+qj86f8zsKYYsZ6AvjWFzA8ORHkAnwN8So7evzL/8pzMAXL/Hq8mMv1up371T7Z+/c3n9cKeuDS6Xy6dN07zLuZ56Onk2Ed2/ANJsnE/PQMpgyffle+kYzwazB1+3waVS6X48Hr9BRPB9H57nYXplFKeSt8D1Hriug9XKF0x+Lmw+ys8m2m42DOOn4zhQSsGyLOi6jqONm9isbmFVFlDbaGKx8QaB1rvdlbNhGLAsC0IIGIYBIQSy2ROQ0oOp7wOPraHXEugRvDtnzjmi0SiICEIIEBGklAB9B6cmbG0AUnrY5m73h+m6DsYYTNMEYwxEBMY0hGNVhHkcZigBO9qHlDHS7cwYg23bAIBQKAQigud7IH0XwtxDoHwEIQ9SLKx0wa7rPiaivYyxESklXNeFBg0mjyNQTQSuATMSm6ipuYt//eVcLhdeXl5+UKlUlur1upqamVAv3j3/VCyOD3VqfwF6uLp3q+vMcgAAAABJRU5ErkJggg=='); 32 | background-repeat: no-repeat; 33 | } -------------------------------------------------------------------------------- /lib/document_processor_dispatcher.rb: -------------------------------------------------------------------------------- 1 | class DocumentProcessorDispatcher 2 | def self.processor_for(mime_type) 3 | if Rails.application.config.use_fake_document_processor == true 4 | return ProcessorFake 5 | end 6 | 7 | if mime_type.in?(["application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"]) 8 | YomuProcessor 9 | elsif mime_type == "application/pdf" 10 | YomuProcessor 11 | else 12 | NullProcessor 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/local-data-store.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICsDCCAZgCCQDPg5mav3RE5jANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQGEwJ1 3 | czELMAkGA1UECAwCbWEwHhcNMjAwMzE4MjEyNTIxWhcNMjAwNDE3MjEyNTIxWjAa 4 | MQswCQYDVQQGEwJ1czELMAkGA1UECAwCbWEwggEiMA0GCSqGSIb3DQEBAQUAA4IB 5 | DwAwggEKAoIBAQChlxjWlcO5FxC7XP7qjHpn45oJkJsfKue+GCSWOkaz7ITWNnkg 6 | N7SwOGbtbCJADV4qbLOq3oNHWdLTXoPoivQdObQh6MVB20WCjlwEyUKNCnBhRcO2 7 | V2churVzR982geEV7y45LtD5AfkN3vSoBCFd26QllzoNthNynlV2PePtnKsxthke 8 | yxJvbFR3Gqe1hScFL5enHBodERaARWAGl+LA+BRlkUoNWk2FYPjUp/1Z2z+1BJ05 9 | IlrvKdy3qb9SSEbgBHLwoQAOrReYWmuf/7FvJyxEzbv3vrlr2e4tolDvdZwirQHz 10 | woGFzOmzB3r4KcT3xCHIHsc23CSGxv5Elo9PAgMBAAEwDQYJKoZIhvcNAQELBQAD 11 | ggEBADs42Nd0D1XUm0YNp3m1nyBiSMapBTRULIstJ+fh2i9M0ZSd5GhSwcG9zvRj 12 | kfevYxkWUKo9MqpmrfrLtyVI1qpr3K6JqN5HWmYTwPx6vYtRXbjETmL2nHDq6s7w 13 | H3T2JMO08NsJA9v7mkjuJElQwHS2L7k7yyMMmgDheu4RrTNAVdqD7sODT/uS3cW3 14 | cCzq8K0o5dGJdGNiU2mQ7LVW7RvDm6oTfto//IsAT9jEniOHC49JkJQ2c0zjIh/G 15 | efpr7Zk/GcpopmIPxIwVg2P/eWB8kpzVQuTkQ/HJfZKZWOI75Ber+D5W4l7dOfuW 16 | uFGBknToc5OK6ojSQo3VQtOCgA4= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /lib/local-only.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICsDCCAZgCCQCljdKL6Ipz7TANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQGEwJ1 3 | czELMAkGA1UECAwCbWEwHhcNMjAwMzE5MDA0MjAzWhcNMjEwMzE5MDA0MjAzWjAa 4 | MQswCQYDVQQGEwJ1czELMAkGA1UECAwCbWEwggEiMA0GCSqGSIb3DQEBAQUAA4IB 5 | DwAwggEKAoIBAQDcJjVqijSyQoQm7YhSW3qvvoIwHv6Gum2sZkV6yt7QsyvgfOyc 6 | RyMmZ3tQBgIWLbRFwkOzZcfwrsnvbvKecwsjEKkXvD/9bhq5/gwPMDna04WcUUMP 7 | 11O+I6NiHA8gi6OCVBAqI5plu94dlyHHmTsRbROO3nC7jf9vW0dTgkjyIF2QgDwc 8 | 6UWArfYHrzpDVzbt0DVB9fOEKcikIq7OeF+FJWj3P8IOa9rt9+ixXazlRx7gajW3 9 | OJcc9vJPvdy44bcFb4LDHRHedMJ78/D6LarbHZcTxe4IubcvYYaPTbjmAiIbGf5o 10 | zftfDKzfjshVRKmZ1NeFlhdInjkDDhKVzRvjAgMBAAEwDQYJKoZIhvcNAQELBQAD 11 | ggEBAJXFYkJmFO+2lnRidUKwEAJrHzspqGKaqrBCS0R/b1lBu/i/XeAHEspPVMqH 12 | lP0vbkAl2vPKZHTAHnCJfZ8NJ7JDWt06Lnl/235+mnybQv3JMs+CRZMXovKFxQYW 13 | v3VH3vBLyXL3ww0rKZeI+0mw7RwtzBCqV0zspxQEPW5sd6DGEEY7TIoCb92ZIXXR 14 | 0v/J6ki8/31fKnedegfs04CRzGTnNhoeC45ZvkoIsTKSi0P4co7zU3cdCvA0XuBt 15 | 6d7Z5iItKeCsEz0lwnqEupJi6twjBJ0NUYQJzMRHlvTXyKg/uEJsTJZYQ/5wNa3C 16 | P81RbqRcKeHM4WYAfv7vWNkCqSw= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /lib/local-only.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcJjVqijSyQoQm 3 | 7YhSW3qvvoIwHv6Gum2sZkV6yt7QsyvgfOycRyMmZ3tQBgIWLbRFwkOzZcfwrsnv 4 | bvKecwsjEKkXvD/9bhq5/gwPMDna04WcUUMP11O+I6NiHA8gi6OCVBAqI5plu94d 5 | lyHHmTsRbROO3nC7jf9vW0dTgkjyIF2QgDwc6UWArfYHrzpDVzbt0DVB9fOEKcik 6 | Iq7OeF+FJWj3P8IOa9rt9+ixXazlRx7gajW3OJcc9vJPvdy44bcFb4LDHRHedMJ7 7 | 8/D6LarbHZcTxe4IubcvYYaPTbjmAiIbGf5ozftfDKzfjshVRKmZ1NeFlhdInjkD 8 | DhKVzRvjAgMBAAECggEAQPMI2VjS+TCEmpODn4CbrpPPBvFt+EOyLaWyo+qMWBg0 9 | PrO8ftLB/QeUquRK404ynE4W+StzFIAM1ZXvAG5Cf+LfcEA6xMMiIXNhDW4V84hq 10 | J9cVqOvHKhaLklti3yAzajTw2+3LFG6btjErZx6+/YInvgPEUKExFiJg5bNPYBc+ 11 | TAQQU4k0iaMpxDnxJNLAb6FPZTiC7M4K1+/wAfeqQ7zUIHaPuucIuLxvx0p2StI3 12 | 8Gi3K7gkWZuTK2Au7K6hsYjGmCmevy6cGxq5GvmGsebR6ne6cLby4EB9Z+qaj+43 13 | u2TzdyZSYQo/zV0jDIbBX995FzoRGkF89+/Aer8JiQKBgQDwmIEUEuHydNRJheoF 14 | ibDcsYHbqPnGWGXYnReoPIlhWGNppvsGow8TvYWEAShWH9R5QcVsgVb4zIlQ9gAa 15 | fF4BKfWNzW/pxeOpaA2fRPbLEajzn13fZ19eCoUytf94yPQKAdCxs6NngrMB7bFn 16 | zS0HEjfZcRL9qsD0EhStNHxKVQKBgQDqPpNc89S4H9Vx4yExuQdmZfaUgnbzhM5x 17 | F/eMzQQOFZKqTq8MdOzMEI/wT2tFnxWIEopCEylJcpNoWht4GyesKcynWKGPM0fm 18 | 8NQcbuMYJRxocG0GAUlaaZKY4MlJH36CGvIPwvPE7J08GkZXGIT5XThT0+/4Xbvq 19 | Bzi0kDt1VwKBgQDZ8OuMKYavQJFEgJ/6oD2rzMfbGPgZad3oGHVjmmK/4Xc8L1xZ 20 | KL/xm84kQ4Asc+zeYmvZ3FfSTEVfJ1f0pg/pcf7TkvL7ipytymn8ilYcoUSwWv6H 21 | 7nX/E/yQcTiYS0B1CCvprNYqX8STzKLVapCNRT1+JOWVD2Z2MSK1u0OTeQKBgD/I 22 | PC4CQrjECkWRd/dnD2nFd8fmYmdakS/gO8q+BE2leCMhe66jo9rI47iml2oEsEM1 23 | 8SmeuA5EwXiXmIUyt7G8S/qBOrSYXQq4Jrl7RCDN8hdKDZWmAgg5WO6Bvq1HgxYA 24 | Kks6ZVAIsaOs79xFU+fmhzDkM6JoO4O05a7c2yPPAoGBAMrAwLrtQRC1uc7PcUl6 25 | R0V5g4kU29nUOKhusi1ljpaGrqhZWvOK0U1DLKoyig04lH5G5UIMR7sZtmNMfMGQ 26 | 292X+9jNRstA+6MJgH+KqjaJ6FZT7Y7cmn8D9GTveeIO6FmhQGopHhY+ChKTVUyP 27 | i3tJbPmsz7pVayZQo9Xk73ks 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /lib/null_processor.rb: -------------------------------------------------------------------------------- 1 | class NullProcessor 2 | def initialize(*args) 3 | Rails.logger.warn "NullProcessor called with #{args.inspect}, please implement a processor for this" 4 | end 5 | 6 | def work 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/pdf_processor.rb: -------------------------------------------------------------------------------- 1 | 2 | class PdfProcessor 3 | 4 | def initialize(document, state) 5 | @document = document 6 | @state = state 7 | end 8 | 9 | def work 10 | local_copy = Tempfile.new(@document.upload_file_name) 11 | @document.upload.copy_to_local_file(:original, local_copy.path) 12 | 13 | parser = PdfParser.new(local_copy) 14 | # @document.text = parser.convert_to_html 15 | @document.text = parser.to_html 16 | 17 | @document.processed_at = DateTime.now 18 | 19 | # @document.state = @original_state 20 | @document.state = 'draft' 21 | 22 | @document.save 23 | end 24 | 25 | private 26 | 27 | class PdfParser 28 | include ActionView::Helpers::TextHelper 29 | 30 | def initialize(file_path) 31 | @pdf = PDF::Reader.new(file_path) 32 | end 33 | 34 | def pages 35 | @pdf.pages 36 | end 37 | 38 | def to_html 39 | html = @pdf.to_html.tr('▯'," ") 40 | end 41 | 42 | def pages 43 | @pdf.pages 44 | end 45 | 46 | def text_from_pdf 47 | pages.map(&:text).join("\n") 48 | end 49 | 50 | def convert_to_html 51 | temp = text_from_pdf.gsub(/▯/, " ") 52 | simple_format(temp.gsub(/\n \n/, "\n\n")) 53 | end 54 | 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /lib/processor_fake.rb: -------------------------------------------------------------------------------- 1 | class ProcessorFake 2 | def initialize(document, document_state) 3 | @document = document 4 | @original_state = document_state 5 | end 6 | 7 | def work 8 | @document.processed_at = DateTime.now 9 | @document.text = '

foo

' 10 | @document.state = @original_state 11 | @document.save 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/lib/tasks/.gitkeep -------------------------------------------------------------------------------- /lib/tasks/annotation-studio.rake: -------------------------------------------------------------------------------- 1 | namespace :annotationstudio do 2 | desc "Set all the user passwords for development" 3 | task :reset_passwords => :environment do 4 | users = User.all 5 | puts "Resetting the passwords for #{users.count} users." 6 | users.each_with_index { |user,x| 7 | user.password = "super-secret" 8 | user.save! 9 | if x % 1000 == 0 10 | puts '' 11 | print "#{x}: " 12 | elsif x % 100 == 0 13 | print '+' 14 | elsif x % 10 == 0 15 | print '.' 16 | end 17 | } 18 | end 19 | end -------------------------------------------------------------------------------- /lib/yomu_processor.rb: -------------------------------------------------------------------------------- 1 | class YomuProcessor 2 | def initialize(document, document_state) 3 | @document = document 4 | @original_state = document_state 5 | end 6 | 7 | def work 8 | local_copy = Tempfile.new(@document.upload_file_name) 9 | @document.upload.copy_to_local_file(:original, local_copy.path) 10 | 11 | yomu = Yomu.new(local_copy) 12 | complete = Nokogiri::HTML(yomu.html) 13 | @document.text = complete.css("body").inner_html 14 | @document.processed_at = DateTime.now 15 | @document.state = @original_state 16 | @document.save 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@rails/webpacker": "^^5.3.0", 4 | "pdf-parse": "^1.1.1" 5 | }, 6 | "devDependencies": { 7 | "node-forge": "^1.3.0", 8 | "selfsigned": "^1.10.8", 9 | "webpack-dev-server": "^4.0.0-beta.3" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-import'), 4 | require('postcss-flexbugs-fixes'), 5 | require('postcss-preset-env')({ 6 | autoprefixer: { 7 | flexbox: 'no-2009' 8 | }, 9 | stage: 3 10 | }) 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /public/cove_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/public/cove_favicon.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-Agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /script/delayed_job: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) 4 | require 'delayed/command' 5 | Delayed::Command.new(ARGV).daemonize 6 | -------------------------------------------------------------------------------- /script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /spec/controllers/api_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe ApiController do 4 | 5 | describe "GET 'me'" do 6 | it "returns http success" do 7 | get 'me' 8 | response.should be_success 9 | end 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /spec/controllers/documents_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe DocumentsController do 4 | include UserHelper 5 | 6 | context '#show' do 7 | it 'redirects to root' do 8 | sign_in_stubbed_user 9 | 10 | get :show, id: 100 11 | 12 | expect(response).to be_not_found 13 | end 14 | end 15 | 16 | context '#create' do 17 | it 'enqueues DocumentProcessor jobs correctly when documents are uploaded' do 18 | sign_in_stubbed_user 19 | document = build_document 20 | 21 | document_processor_double = double(perform: -> {} ) 22 | 23 | DocumentProcessor.should_receive(:new).with( 24 | document.id, 25 | document.state, 26 | Apartment::Tenant.current 27 | ).and_return(document_processor_double) 28 | 29 | post :create, { document: { upload: true }} 30 | end 31 | end 32 | 33 | def sign_in_stubbed_user 34 | user = create(:user, agreement: true) 35 | user.stub(:has_role?).and_return(true) 36 | 37 | #This uses Devise::TestHelpers to sign in the user through a backdoor. 38 | #The other "sign_in_user" helper in UserHelper is for integration specs. 39 | sign_in user 40 | end 41 | 42 | def build_document 43 | document = build(:document, id: 1, state: 'published') 44 | Document.stub(:new).and_return(document) 45 | Document.stub(:save).and_return(true) 46 | document 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/controllers/groups_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe GroupsController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/invites_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe InvitesController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/factories.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do factory :documents_group do 2 | 3 | end 4 | factory :invite do 5 | 6 | end 7 | factory :membership do 8 | group_id 1 9 | user_id 1 10 | role "MyString" 11 | end 12 | factory :group do 13 | 14 | end 15 | 16 | factory :user do 17 | email 'foo@example.com' 18 | password '123pass' 19 | end 20 | 21 | factory :document do 22 | title 'Title' 23 | text 'I am a body.' 24 | end 25 | 26 | factory :tenant do 27 | sequence (:domain) { |n| "www#{n}.example.com" } 28 | sequence (:database_name) { |n| "www#{n}" } 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/helpers/api_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the ApiHelper. For example: 5 | # 6 | # describe ApiHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # expect(helper.concat_strings("this","that")).to eq("this that") 10 | # end 11 | # end 12 | # end 13 | describe ApiHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /spec/helpers/invites_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the InvitesHelper. For example: 5 | # 6 | # describe InvitesHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # expect(helper.concat_strings("this","that")).to eq("this that") 10 | # end 11 | # end 12 | # end 13 | RSpec.describe InvitesHelper, type: :helper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /spec/integration/user_sees_annotation_sidebar_spec.rb: -------------------------------------------------------------------------------- 1 | # require 'spec_helper' 2 | # 3 | # feature 'A user visits a document', js: true do 4 | # include UserHelper 5 | # scenario 'they see a list annotations, sorted by position' do 6 | # 7 | # password = 'foobar' 8 | # user = create(:user, password: password) 9 | # user.confirm! 10 | # 11 | # visit new_user_session_path 12 | # find(:css, "input#user_email").set user.email 13 | # find(:css, "input#user_password").set password 14 | # binding.pry 15 | # find(:css, "input.btn.btn-primary").click 16 | # 17 | # page.save_screenshot('screenshot.png') 18 | # 19 | # document = create( 20 | # :document, 21 | # user: user, 22 | # text: File.read('spec/support/example_files/example.html'), 23 | # ) 24 | # 25 | # visit document_path(document) 26 | # 27 | # expect(page).to have_annotation_list_item('bviwbw', 1) 28 | # # expect(page).to have_annotation_list_item('jovnia', 2) 29 | # end 30 | # end 31 | # 32 | # def has_annotation_list_item?(id, position) 33 | # has_content?([ 34 | # 'ul#annotation-list', 35 | # "li:nth-child(#{position})", 36 | # "span[data-highlight='#hl#{id}']" 37 | # ].join(' ')) 38 | # end 39 | -------------------------------------------------------------------------------- /spec/integration/user_views_dashboard_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | feature 'A user visit their dashboard' do 4 | include UserHelper 5 | 6 | scenario 'they see a list of their documents' do 7 | user = sign_in_user 8 | document = create(:document, user: user) 9 | 10 | visit '/' 11 | 12 | expect(page).to have_content('Documents') 13 | expect(page).to have_content(document.title) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/jobs/document_processor_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe DocumentProcessor do 4 | it "should instantiate a document when performing" do 5 | document = build(:document, id: 100) 6 | Document.should_receive(:find).with(document.id).and_return(document) 7 | 8 | job = described_class.new(document.id, 'a state', 'www') 9 | job.perform 10 | end 11 | 12 | it "should use the DocumentProcessorDispatcher to find which processor to use" do 13 | document = build(:document, id: 100, upload: example_file('example.docx')) 14 | Document.stub(:find).with(document.id).and_return(document) 15 | 16 | DocumentProcessorDispatcher.should_receive(:processor_for). 17 | with(document.upload.content_type). 18 | and_return(NullProcessor) 19 | 20 | job = described_class.new(document.id, 'a state', 'www') 21 | job.perform 22 | end 23 | 24 | context 'apartment multitenancy' do 25 | it 'switches tenants when running a job' do 26 | Apartment::Tenant.switch('public') 27 | current_tenant = Apartment::Tenant.current 28 | document = build(:document, id: 100) 29 | Document.should_receive(:find).with(document.id).and_return(document) 30 | 31 | Apartment::Tenant.should_receive(:switch).with('www') 32 | Apartment::Tenant.should_receive(:switch).with(current_tenant) 33 | 34 | job = described_class.new(document.id, 'a state', 'www') 35 | job.perform 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/lib/document_processor_dispatcher_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe DocumentProcessorDispatcher do 4 | context "when a fake is configured" do 5 | it "returns the fake" do 6 | with_real_document_processors(false) do 7 | expect(described_class.processor_for("blarg")).to eq ProcessorFake 8 | end 9 | end 10 | end 11 | 12 | context ".processor_for" do 13 | it "returns YomuProcessor for .doc and .docx mime-types" do 14 | with_real_document_processors do 15 | %w( 16 | application/msword 17 | application/vnd.openxmlformats-officedocument.wordprocessingml.document 18 | ).each do |mime_type| 19 | expect(described_class.processor_for(mime_type)).to eq YomuProcessor 20 | end 21 | end 22 | end 23 | 24 | it "returns YomuProcessor for pdf mime-types" do 25 | with_real_document_processors do 26 | expect(described_class.processor_for("application/pdf")).to eq \ 27 | YomuProcessor 28 | end 29 | end 30 | 31 | it "returns NullProcessor for unknown mime-types" do 32 | with_real_document_processors do 33 | expect(described_class.processor_for("your/momma")).to eq NullProcessor 34 | end 35 | end 36 | end 37 | 38 | def with_real_document_processors(use_real = true) 39 | default_setting = Rails.application.config.use_fake_document_processor 40 | begin 41 | Rails.application.config.use_fake_document_processor = (not use_real) 42 | yield 43 | ensure 44 | Rails.application.config.use_fake_document_processor = default_setting 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /spec/lib/null_processor_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe NullProcessor do 4 | it 'can be initialized with any number of arguments' do 5 | expect { described_class.new(1, 2 ,3, 4) }.not_to raise_error 6 | end 7 | 8 | it 'responds to #work' do 9 | processor = described_class.new() 10 | 11 | expect(processor).to respond_to(:work) 12 | end 13 | 14 | it 'logs when it is called' do 15 | logger_double = double('Logger stub', warn: '') 16 | Rails.should_receive(:logger).and_return(logger_double) 17 | 18 | described_class.new(1,2) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/lib/pdf_processor_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe PdfProcessor do 4 | it 'processes pdf' do 5 | document = create(:document, upload: example_file('example.pdf')) 6 | 7 | processor = described_class.new(document, 'published') 8 | processor.work 9 | 10 | expect(document.text).to match 'Alice' 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/lib/processor_fake_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'processor_fake' 3 | 4 | describe ProcessorFake do 5 | 6 | it "should set processed_at on a document" do 7 | document = create_processed_document 8 | 9 | expect(document.processed_at).to be 10 | end 11 | 12 | it "should add content to a document" do 13 | document = create_processed_document 14 | 15 | expect(document.text).to eq '

foo

' 16 | end 17 | 18 | 19 | def create_processed_document 20 | upload_file = File.open('spec/support/example_files/example.pdf') 21 | document = create(:document, upload: upload_file, text: nil) 22 | 23 | process = ProcessorFake.new(document,'published') 24 | process.work 25 | document.reload 26 | document 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/mailers/invite_spec.rb: -------------------------------------------------------------------------------- 1 | require "rails_helper" 2 | 3 | RSpec.describe InviteMailer, type: :mailer do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/mailers/previews/invite_preview.rb: -------------------------------------------------------------------------------- 1 | # Preview all emails at http://localhost:3000/rails/mailers/invite 2 | class InvitePreview < ActionMailer::Preview 3 | 4 | end 5 | -------------------------------------------------------------------------------- /spec/models/annotation_category_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe AnnotationCategory do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/document_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Document do 4 | context 'file uploads' do 5 | it { should validate_attachment_content_type(:upload).allowing( 6 | 'application/msword', 7 | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 8 | 'text/plain', 9 | 'application/pdf' 10 | )} 11 | 12 | it 'interpolates the tenant name into the path' do 13 | Apartment::Tenant.switch('www') 14 | 15 | document = build(:document) 16 | document.upload = File.open(example_file('example.html')) 17 | 18 | expect(document.upload.path).to match '/www/' 19 | Apartment::Tenant.switch('public') 20 | end 21 | end 22 | 23 | context '#processed?' do 24 | it { subject.should_not be_processed } 25 | 26 | it "is true when processed_at? is set" do 27 | document = build(:document, processed_at: DateTime.now) 28 | expect(document).to be_processed 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /spec/models/documents_group_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe DocumentsGroup, type: :model do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/group_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Group, type: :model do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/invite_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Invite, type: :model do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/membership_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Membership, type: :model do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/models/tenant_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Tenant do 4 | it { should validate_uniqueness_of :database_name } 5 | it { should validate_presence_of :database_name } 6 | it { should validate_presence_of :domain } 7 | it { should validate_uniqueness_of :domain } 8 | 9 | it 'should create a schema after it is created' do 10 | tenant = build(:tenant, database_name: 'frapples') 11 | 12 | Apartment::Tenant.stub(:drop) 13 | Apartment::Tenant.should_receive(:create).with(tenant.database_name) 14 | 15 | tenant.save 16 | end 17 | 18 | it 'should destroy the schema when the tenant is destroyed' do 19 | tenant = create(:tenant, database_name: 'frapples') 20 | 21 | Apartment::Tenant.stub(:create) 22 | Apartment::Tenant.should_receive(:drop).with(tenant.database_name) 23 | 24 | tenant.destroy 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/support/database_cleaner.rb: -------------------------------------------------------------------------------- 1 | RSpec.configure do |config| 2 | config.before(:suite) do 3 | # Clean all tables to start 4 | DatabaseCleaner.clean_with :truncation 5 | # Use transactions for tests 6 | DatabaseCleaner.strategy = :transaction 7 | # Truncating doesn't drop schemas, ensure we're clean here, app *may not* exist 8 | Apartment::Tenant.drop('www') rescue nil 9 | # Create the default tenant for our tests 10 | Tenant.create!(database_name: 'www', domain: 'www.example.com') 11 | end 12 | 13 | config.before(:each) do 14 | # Start transaction for this test 15 | DatabaseCleaner.start 16 | # Switch into the default tenant 17 | Apartment::Tenant.switch 'www' 18 | end 19 | 20 | config.after(:each) do 21 | # Reset tenant back to `public` 22 | Apartment::Tenant.reset 23 | # Rollback transaction 24 | DatabaseCleaner.clean 25 | end 26 | end 27 | 28 | -------------------------------------------------------------------------------- /spec/support/example_files/annotation-studio-white-paper.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/spec/support/example_files/annotation-studio-white-paper.docx -------------------------------------------------------------------------------- /spec/support/example_files/example.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/spec/support/example_files/example.docx -------------------------------------------------------------------------------- /spec/support/example_files/example.html: -------------------------------------------------------------------------------- 1 |

Collaboratively administrate empowered markets via plug-and-play networks. 2 | Dynamically procrastinate B2C users after installed base benefits. 3 | Dramatically visualize customer directed convergence without revolutionary 4 | ROI.

5 | 6 |

Efficiently unleash cross-media information without cross-media value. Quickly 7 | maximize timely deliverables for real-time schemas. Dramatically maintain 8 | clicks-and-mortar solutions without functional solutions.

9 | 10 |

Completely synergize resource sucking relationships via premier niche markets. 11 | Professionally cultivate one-to-one customer service with robust ideas. 12 | Dynamically innovate resource-leveling customer service for state of the art 13 | customer service.

14 | 15 |

Objectively innovate empowered manufactured products whereas parallel 16 | platforms. Holisticly predominate extensible testing procedures for reliable 17 | supply chains. Dramatically engage top-line web services vis-a-vis 18 | cutting-edge deliverables.

19 | 20 |

Proactively envisioned multimedia based expertise and cross-media growth 21 | strategies. Seamlessly visualize quality intellectual capital without superior 22 | collaboration and idea-sharing. Holistically pontificate installed base 23 | portals after maintainable products.

24 | -------------------------------------------------------------------------------- /spec/support/example_files/example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/spec/support/example_files/example.pdf -------------------------------------------------------------------------------- /spec/support/factory_girl.rb: -------------------------------------------------------------------------------- 1 | RSpec.configure do |config| 2 | config.include FactoryGirl::Syntax::Methods 3 | end 4 | -------------------------------------------------------------------------------- /spec/support/file_helpers.rb: -------------------------------------------------------------------------------- 1 | module FileHelpers 2 | def example_file_path(file_base_name) 3 | "spec/support/example_files/#{file_base_name}" 4 | end 5 | 6 | def example_file(file_base_name) 7 | File.open(example_file_path(file_base_name)) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/support/integration.rb: -------------------------------------------------------------------------------- 1 | RSpec.configure do |config| 2 | config.include Capybara::DSL, :type => :request 3 | end 4 | -------------------------------------------------------------------------------- /spec/support/user_helper.rb: -------------------------------------------------------------------------------- 1 | module UserHelper 2 | def sign_in_user 3 | password = 'foobar' 4 | user = create(:user, password: password, agreement: true) 5 | user.confirm! 6 | visit '/' 7 | fill_in "Email", with: user.email 8 | fill_in "Password", with: password 9 | click_on 'Sign in' 10 | user 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /vendor/assets/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /vendor/assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /vendor/assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /vendor/assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /vendor/assets/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /vendor/assets/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /vendor/assets/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /vendor/assets/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /vendor/assets/fonts/summernote.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/fonts/summernote.eot -------------------------------------------------------------------------------- /vendor/assets/fonts/summernote.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/fonts/summernote.ttf -------------------------------------------------------------------------------- /vendor/assets/fonts/summernote.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/fonts/summernote.woff -------------------------------------------------------------------------------- /vendor/assets/javascripts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/javascripts/.gitkeep -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/assets/stylesheets/.gitkeep -------------------------------------------------------------------------------- /vendor/assets/stylesheets/ekko-lightbox.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lightbox for Bootstrap 3 by @ashleydw 3 | * https://github.com/ashleydw/lightbox 4 | * 5 | * License: https://github.com/ashleydw/lightbox/blob/master/LICENSE 6 | */.ekko-lightbox-container{position:relative}.ekko-lightbox-nav-overlay{position:absolute;top:0;left:0;z-index:100;width:100%;height:100%}.ekko-lightbox-nav-overlay a{z-index:100;display:block;width:49%;height:100%;padding-top:45%;font-size:30px;color:#fff;text-shadow:2px 2px 4px #000;opacity:0;filter:dropshadow(color=#000000,offx=2,offy=2);-webkit-transition:opacity .5s;-moz-transition:opacity .5s;-o-transition:opacity .5s;transition:opacity .5s}.ekko-lightbox-nav-overlay a:empty{width:49%}.ekko-lightbox a:hover{text-decoration:none;opacity:1}.ekko-lightbox .glyphicon-chevron-left{left:0;float:left;padding-left:15px;text-align:left}.ekko-lightbox .glyphicon-chevron-right{right:0;float:right;padding-right:15px;text-align:right}.ekko-lightbox .modal-footer{text-align:left} -------------------------------------------------------------------------------- /vendor/plugins/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperstudio/Annotation-Studio/fc48b6e8ad771f26fb1f5cc5574843f9ae36a16a/vendor/plugins/.gitkeep -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # gem 'rails', '3.1.0.rc5' 4 | gem 'rails', '>= 3.0.5' 5 | 6 | gem 'rspec' 7 | gem 'rspec-rails' 8 | 9 | gem 'cancan' 10 | gem 'acts-as-taggable-on', '~>2.1.0' 11 | 12 | gem 'sqlite3' 13 | gem 'pg' 14 | gem 'jeweler' 15 | 16 | group :test do 17 | gem 'factory_girl_rails' 18 | gem 'faker' 19 | end 20 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | 3 | require 'rspec/core' 4 | require 'rspec/core/rake_task' 5 | 6 | RSpec::Core::RakeTask.new(:spec) 7 | 8 | task :default => :spec 9 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/app/assets/stylesheets/user_set.css: -------------------------------------------------------------------------------- 1 | table#admin_console th { 2 | background-color: #eee; 3 | border-bottom: 1px solid black; 4 | } 5 | 6 | table#admin_console td.odd { 7 | margin: 0px; 8 | padding: 0px; 9 | padding-right: 15px; 10 | background-color: #eef; 11 | } 12 | 13 | table#admin_console td.current_groups { 14 | width: 130px; 15 | } 16 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/app/controllers/application_controller_extension.rb: -------------------------------------------------------------------------------- 1 | module Repertoire 2 | module Groups 3 | class ApplicationControllerExtension 4 | # https://github.com/ryanb/cancan/wiki/Exception-Handling 5 | #rescue_from CanCan::AccessDenied do |exception| 6 | # redirect_to root_url, :alert => exception.message 7 | #end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/app/controllers/user_sets_controller.rb: -------------------------------------------------------------------------------- 1 | class UserSetsController < ApplicationController 2 | load_and_authorize_resource # CanCan 3 | 4 | def index 5 | @users = UserSet.new 6 | end 7 | 8 | def edit 9 | @user = User.find(params[:id]) 10 | end 11 | 12 | # Right now this handles a set of users, not one individually. 13 | # It may make sense to break out the user_set to have its own 14 | # controller, but right now that is overkill. 15 | def update 16 | @users = UserSet.new 17 | @users.users_attributes(params[:users]) 18 | 19 | if @users.save 20 | flash[:notice] = 'Users were successfully updated.' 21 | render :index 22 | # WHY does redirecting revert the models to their previous state? 23 | # redirect_to user_sets_path 24 | else 25 | flash[:notice] = 'Users were not successfully updated.' 26 | redirect_to user_sets_path 27 | end 28 | end 29 | 30 | def destroy 31 | @user = User.find(params[:id]) 32 | @user.destroy 33 | redirect_to user_sets_path 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/app/helpers/groups_helper.rb: -------------------------------------------------------------------------------- 1 | module GroupsHelper 2 | def get_privacy_list 3 | get_list('rep_privacy') 4 | end 5 | 6 | def get_group_list 7 | get_list('rep_group') 8 | end 9 | 10 | def get_list(list_name) 11 | ActsAsTaggableOn::Tagging.find_all_by_context(list_name).collect {|tg| tg.tag }.uniq 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | # app/models/application_record.rb 2 | class ApplicationRecord < ActiveRecord::Base 3 | self.abstract_class = true 4 | end 5 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/app/models/assignment.rb: -------------------------------------------------------------------------------- 1 | class Assignment < ApplicationRecord 2 | belongs_to :user 3 | belongs_to :role 4 | end 5 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/app/models/role.rb: -------------------------------------------------------------------------------- 1 | class Role < ApplicationRecord 2 | has_many :assignments 3 | has_many :users, :through => :assignments 4 | 5 | validates_presence_of :name 6 | 7 | def Role.find_or_create_new(name) 8 | name = name.to_s if name.is_a?(Symbol) # Does this matter? 9 | Role.find_by_name(name) || Role.create!({:name => name}) 10 | end 11 | 12 | def role_to_sym 13 | self.name.underscore.to_sym 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/app/models/user_set.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Based on this idea: 3 | # http://stackoverflow.com/questions/972857/multiple-objects-in-a-rails-form 4 | # 5 | 6 | class UserSet 7 | include ActiveRecord::Validations 8 | attr_accessor :users 9 | 10 | validate :all_users_valid 11 | 12 | def all_users_valid 13 | @users.each do |user| 14 | errors.add user.errors unless user.valid? 15 | end 16 | end 17 | 18 | def initialize 19 | super 20 | @users = User.all 21 | # raise @users.detect {|u| u.id == 7}.roles.inspect 22 | end 23 | 24 | def save 25 | @users.all?(&:save) 26 | end 27 | 28 | # This is pretty inflexible now, should be set up 29 | # to handle user attributes more flexibly, so the administrative 30 | # page can be expanded? 31 | def users_attributes(params) 32 | params.each_key do |uid| 33 | user = @users.detect {|u| u.id == uid.to_i} 34 | user.set_roles = params[uid]['roles'] 35 | user.rep_group_list << params[uid]['rep_group_list'] unless params[uid]['rep_group_list'].empty? 36 | user.rep_group_list << params[uid]['rep_group_list_add'] unless params[uid]['rep_group_list_add'].empty? 37 | 38 | if params[uid]['rep_group_remove'] 39 | user.rep_group_list = user.rep_group_list - params[uid]['rep_group_remove'] 40 | end 41 | 42 | user.save # I have to save this? I guess so. 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/app/views/user_sets/edit.html.erb: -------------------------------------------------------------------------------- 1 | <%= @user.firstname %> <%= @user.lastname %> <% @user.roles.each do |r| %><%= r.name %><% end %> 2 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/init.rb: -------------------------------------------------------------------------------- 1 | require 'repertoire-groups' 2 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/lib/generators/repertoire/groups_migration_generator.rb: -------------------------------------------------------------------------------- 1 | require 'rails/generators/migration' 2 | 3 | module Repertoire 4 | class GroupsMigrationGenerator < Rails::Generators::Base 5 | include Rails::Generators::Migration 6 | 7 | source_root File.expand_path('../templates', __FILE__) 8 | 9 | desc "Generates migration for groups models" 10 | 11 | def self.next_migration_number(path) 12 | Time.now.utc.strftime("%Y%m%d%H%M%S") 13 | end 14 | 15 | def create_migration_file 16 | migration_template 'migration.rb', 'db/migrate/repertoire_groups_migration.rb' 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/lib/generators/repertoire/templates/migration.rb: -------------------------------------------------------------------------------- 1 | class RepertoireGroupsMigration < ActiveRecord::Migration 2 | def self.up 3 | create_table :roles, :force => true do |t| 4 | t.string :name 5 | t.string :description 6 | end 7 | 8 | create_table :assignments, :force => true do |t| 9 | t.integer :user_id 10 | t.integer :role_id 11 | t.timestamps 12 | end 13 | end 14 | 15 | def self.down 16 | drop_table :assignments 17 | drop_table :roles 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/lib/repertoire-groups.rb: -------------------------------------------------------------------------------- 1 | require 'active_record' 2 | require 'active_support/dependencies' 3 | 4 | require 'repertoire-groups/engine.rb' 5 | require 'repertoire-groups/acts_as_role_user.rb' 6 | require 'repertoire-groups/ability.rb' 7 | 8 | module Repertoire 9 | end 10 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/lib/repertoire-groups/engine.rb: -------------------------------------------------------------------------------- 1 | module Repertoire 2 | module Groups 3 | class Engine < Rails::Engine 4 | initializer 'application_controller_extension.controller' do |app| 5 | ActiveSupport.on_load(:action_controller) do 6 | # include Repertoire::Groups::ApplicationControllerExtension 7 | end 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/repertoire-groups.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | 5 | # PKG_FILES = FileList[ 6 | # '[a-zA-Z]*', 7 | # 'lib/**/*', 8 | # 'app/**/*', 9 | # 'spec/**/*' 10 | # ] 11 | 12 | # Provide a simple gemspec so you can easily use your 13 | # project in your rails apps through git. 14 | Gem::Specification.new do |s| 15 | s.name = "repertoire-groups" 16 | s.summary = "Insert RepertoireGroups summary." 17 | s.description = "Insert RepertoireGroups description." 18 | # s.files = PKG_FILES.to_a 19 | s.files = `git ls-files -z`.split("\x0") 20 | s.version = "0.0.1" 21 | s.authors = ["Dave Della Costa, Jamie Folsom"] 22 | end -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/spec/database.yml: -------------------------------------------------------------------------------- 1 | sqlite3: 2 | adapter: sqlite3 3 | database: repertoire_groups_test.sqlite3 4 | 5 | # MySQL ? 6 | 7 | postgresql: 8 | adapter: postgresql 9 | hostname: localhost 10 | username: postgres 11 | password: 12 | database: repertoire_groups_test 13 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/spec/factories.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | Factory.define :user do |user| 4 | user.firstname { Faker::Name.first_name } 5 | user.lastname { Faker::Name.last_name } 6 | user.email { Faker::Internet.email } 7 | user.password 'password' 8 | user.roles { [] } 9 | end 10 | 11 | Factory.define :test_model do |tm| 12 | tm.content "This is some test content!" 13 | end 14 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/spec/models.rb: -------------------------------------------------------------------------------- 1 | class User < ApplicationRecord 2 | attr_accessible :firstname, :lastname, :email, :password 3 | acts_as_role_user 4 | acts_as_taggable_on :rep_group 5 | end 6 | 7 | class TestModel < ApplicationRecord 8 | belongs_to :user 9 | attr_accessible :content, :user_id 10 | acts_as_taggable_on :rep_privacy, :rep_group 11 | end 12 | 13 | class Ability 14 | include CanCan::Ability 15 | include Repertoire::Groups::Ability 16 | 17 | def initialize(user) 18 | defaults_for user 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/spec/repertoire-groups/groups_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'factories' 3 | 4 | include GroupsHelper 5 | 6 | describe GroupsHelper do 7 | before(:each) do 8 | @tm = Factory.build(:test_model) 9 | @tm2 = Factory.build(:test_model) 10 | 11 | @tm.rep_privacy_list = ['private'] 12 | @tm2.rep_privacy_list = ['public'] 13 | @tm.rep_group_list = ['class1', 'class2', 'class3'] 14 | @tm2.rep_group_list = ['class3', 'class4', 'class5'] 15 | 16 | @tm.save 17 | @tm2.save 18 | end 19 | 20 | it "provides a list of unique privacy tags" do 21 | get_privacy_list.collect {|t| t.name}.should == ['private', 'public'] 22 | end 23 | 24 | it "provides a list of unique group tags" do 25 | get_group_list.collect {|t| t.name}.should == ['class1', 'class2', 'class3', 'class4', 'class5'] 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/spec/repertoire-groups/role_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'factories' 3 | 4 | describe Role do 5 | it "is invalid without required params" do 6 | @role = Role.new 7 | @role.should_not be_valid 8 | end 9 | 10 | it "is a valid given proper params" do 11 | @role = Role.new(:name => 'Guest User') 12 | @role.should be_valid 13 | end 14 | 15 | it "with a finder method, it creates a new role if it doesn't exist" do 16 | new_name_role = Role.find_or_create_new('New Role') 17 | new_name_role.should be_valid 18 | end 19 | 20 | it "with a finder method, it returns an existing role if it exists" do 21 | Role.create!({:name => 'admin'}) 22 | current_role = Role.find_or_create_new('admin') 23 | current_role.should be_valid 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/spec/repertoire-groups/user_set_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'factories' 3 | 4 | describe UserSet do 5 | before(:each) do 6 | @users = [] 7 | 10.times do 8 | @users << Factory.build(:user) 9 | end 10 | end 11 | 12 | describe "Authorizations" do 13 | it "prevents non-admins from viewing UserSets" do 14 | @non_admin = Factory.build(:user, :roles => [Role.find_or_create_new('student')]) 15 | ability = Ability.new(@non_admin) 16 | ability.should_not be_able_to(:manage, UserSet.new) 17 | end 18 | end 19 | 20 | describe "Saving Users" do 21 | # This is tested in Repertoire Groups too, but it was working there and not in the 22 | # app so I tested it here too to check and see what was up...although this succeeded too. 23 | # Turns out it was an issue with the incongruity between calling set_roles and 24 | # manipulating the roles array directly...will have to think about how to test next time. 25 | it "if more than one role is saved the user is not 'unapproved'" do 26 | @us = UserSet.new 27 | params = { @us.users[0].id => { 'rep_group_list' => [], 'rep_group_list_add' => [], 'roles' => ['admin', 'unapproved'] } } 28 | @us.users_attributes(params) 29 | @us.users[0].has_role?(:unapproved).should_not be(true) 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/spec/schema.rb: -------------------------------------------------------------------------------- 1 | ActiveRecord::Schema.define(:version => 0) do 2 | create_table :users, :force => true do |t| 3 | t.string :firstname 4 | t.string :lastname 5 | t.string :email 6 | t.string :password 7 | end 8 | 9 | create_table :roles, :force => true do |t| 10 | t.string :name 11 | t.string :description 12 | end 13 | 14 | create_table :assignments, :force => true do |t| 15 | t.integer :user_id 16 | t.integer :role_id 17 | t.timestamps 18 | end 19 | 20 | create_table :test_models, :force => true do |t| 21 | t.integer :user_id 22 | t.integer :id 23 | t.text :content 24 | t.timestamps 25 | end 26 | 27 | # Acts-As-Taggable-On Migration 28 | create_table :tags, :force => true do |t| 29 | t.string :name 30 | end 31 | 32 | create_table :taggings, :force => true do |t| 33 | t.references :tag 34 | 35 | # You should make sure that the column created is 36 | # long enough to store the required class names. 37 | t.references :taggable, :polymorphic => true 38 | t.references :tagger, :polymorphic => true 39 | 40 | t.string :context 41 | 42 | t.datetime :created_at 43 | end 44 | 45 | add_index :taggings, :tag_id 46 | add_index :taggings, [:taggable_id, :taggable_type, :context] 47 | # End Acts-As-Taggable-On Migration 48 | 49 | end 50 | -------------------------------------------------------------------------------- /vendor/repertoire-groups-0.0.1/spec/spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/spec_helper' 2 | --------------------------------------------------------------------------------