├── .classpath ├── .dockerignore ├── .gitignore ├── .gitmodules ├── .project ├── .travis.yml ├── CREDITS.TXT ├── Dockerfile ├── README.md ├── application.properties ├── catch-config.properties ├── docker-compose.yml ├── docs ├── admin-guide │ ├── configuration.md │ ├── deployment │ │ ├── aws-ebs.md │ │ ├── aws-ec2.md │ │ ├── digital-ocean.md │ │ └── docker.md │ ├── getting-started.md │ ├── getting-support.md │ ├── index.md │ ├── installation.md │ ├── manage-systems.md │ ├── manage-users.md │ ├── mysql.md │ ├── tomcat.md │ ├── ubuntu.md │ └── upgrade.md ├── developer-guide │ ├── getting-started.md │ └── index.md ├── img │ ├── create-system.png │ ├── debug-token.png │ ├── disabled-api-key.png │ ├── edit-system.png │ ├── generate-token-1.png │ ├── generate-token-2.png │ ├── generate-token.png │ ├── home.png │ ├── hub-architecture.png │ ├── list-systems.png │ ├── login.png │ ├── secret-key-cannot-be-null.png │ ├── show-system-api-key.png │ └── show-system.png ├── index.md └── user-guide │ ├── annotation.md │ ├── annotatorjs.md │ ├── api-errors.md │ ├── api.md │ ├── authentication.md │ ├── getting-started.md │ └── index.md ├── grails-app ├── conf │ ├── ApiLoggingFilters.groovy │ ├── ApplicationResources.groovy │ ├── AuthTokenFilters.groovy │ ├── BootStrap.groovy │ ├── BuildConfig.groovy │ ├── Config.groovy │ ├── DataSource.groovy │ ├── UrlMappings.groovy │ └── spring │ │ └── resources.groovy ├── controllers │ └── org │ │ └── mindinformatics │ │ └── ann │ │ └── catcha │ │ ├── ErrorController.groovy │ │ ├── MainController.groovy │ │ └── SecureController.groovy ├── domain │ └── .gitignore ├── i18n │ ├── messages.properties │ ├── messages_cs_CZ.properties │ ├── messages_da.properties │ ├── messages_de.properties │ ├── messages_es.properties │ ├── messages_fr.properties │ ├── messages_it.properties │ ├── messages_ja.properties │ ├── messages_nb.properties │ ├── messages_nl.properties │ ├── messages_pl.properties │ ├── messages_pt_BR.properties │ ├── messages_pt_PT.properties │ ├── messages_ru.properties │ ├── messages_sv.properties │ ├── messages_th.properties │ └── messages_zh_CN.properties ├── migrations │ ├── changelog-2014-02-20-1242.groovy │ ├── changelog-2014-02-20-1300.groovy │ ├── changelog-2015-06-03-1244.groovy │ ├── changelog-2015-06-03-1436.groovy │ ├── changelog-2016-03-13-2007.groovy │ ├── changelog-2016-03-13-2027.groovy │ ├── changelog-2016-03-13-2154.groovy │ ├── changelog-2016-03-14-0142.groovy │ ├── changelog.groovy │ ├── create-schema.groovy │ └── update-schema-feb-06-2014.groovy ├── services │ ├── .gitignore │ └── org │ │ └── annotationframework │ │ └── AuthTokenService.groovy ├── taglib │ └── .gitignore ├── utils │ └── .gitignore └── views │ ├── error.gsp │ ├── index.gsp │ ├── info.gsp │ ├── layouts │ └── main.gsp │ ├── public │ ├── _existing-systems.gsp │ ├── _homepage-content.gsp │ ├── _navigation.gsp │ ├── credits.gsp │ ├── home.gsp │ ├── node.gsp │ └── signup.gsp │ ├── secure │ ├── _navigation.gsp │ ├── _upload-banner.gsp │ ├── home.gsp │ └── upload.gsp │ └── shared │ ├── _banner.gsp │ ├── _content.gsp │ ├── _copyright.gsp │ ├── _credits-banner.gsp │ ├── _credits-team.gsp │ ├── _footer.gsp │ ├── _logo.gsp │ ├── _node-banner.gsp │ ├── _scripts.gsp │ ├── _signupTerms.gsp │ ├── _title-and-icon.gsp │ └── _wide.gsp ├── grailsw ├── grailsw.bat ├── mkdocs.yml ├── src ├── groovy │ └── .gitignore └── java │ └── .gitignore ├── test ├── functional │ └── org │ │ └── mindinformatics │ │ └── ann │ │ └── catcha │ │ └── AnnotatorApiTests.groovy ├── integration │ └── org │ │ └── mindinformatics │ │ └── ann │ │ └── framework │ │ └── module │ │ ├── converter │ │ └── ConversionServiceTests.groovy │ │ └── persistence │ │ └── RefreshAnnotationsTests.groovy └── unit │ └── org │ ├── annotationframework │ └── AuthTokenServiceTests.groovy │ └── mindinformatics │ └── ann │ └── catcha │ └── DateFormatTests.groovy ├── web-app ├── WEB-INF │ ├── applicationContext.xml │ ├── sitemesh.xml │ └── tld │ │ ├── c.tld │ │ ├── fmt.tld │ │ ├── grails.tld │ │ └── spring.tld ├── css │ ├── errors.css │ ├── main.css │ └── mobile.css ├── images │ ├── apple-touch-icon-retina.png │ ├── apple-touch-icon.png │ ├── favicon.ico │ ├── grails_logo.jpg │ ├── grails_logo.png │ ├── leftnav_btm.png │ ├── leftnav_midstretch.png │ ├── leftnav_top.png │ ├── logo.png │ ├── public │ │ ├── amarok_download.png │ │ ├── amarok_search.png │ │ ├── amarok_share.png │ │ ├── amarok_share.psd │ │ ├── amarok_share_green.png │ │ ├── amarok_share_red.png │ │ ├── amarok_validate.png │ │ ├── amarok_validate.psd │ │ ├── amarok_validate_green.png │ │ ├── amarok_validate_orange.png │ │ ├── amarok_validate_red.png │ │ ├── domeo-icon.png │ │ ├── highbrow-icon.png │ │ └── people │ │ │ └── paolo_ciccarese.png │ ├── shared │ │ ├── favicon.ico │ │ └── logo.png │ ├── skin │ │ ├── database_add.png │ │ ├── database_delete.png │ │ ├── database_edit.png │ │ ├── database_save.png │ │ ├── database_table.png │ │ ├── exclamation.png │ │ ├── house.png │ │ ├── information.png │ │ ├── shadow.jpg │ │ ├── sorted_asc.gif │ │ └── sorted_desc.gif │ ├── spinner.gif │ └── springsource.png ├── js │ └── application.js └── uploads │ └── users │ └── ff80818147b1aab00147b1aacdb2000c │ └── annotation-1a89fe40-34f8-4085-8b7d-3197a9eea282.json └── wrapper ├── grails-wrapper-runtime-2.2.5.jar ├── grails-wrapper.properties └── springloaded-core-1.1.3.jar /.dockerignore: -------------------------------------------------------------------------------- 1 | .data 2 | /target 3 | /build 4 | /out 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iws 2 | *.iml 3 | *.ids 4 | *.ipr 5 | *.db 6 | *Db.properties 7 | *Db.script 8 | .settings 9 | stacktrace.log 10 | /*.zip 11 | /plugin.xml 12 | /*.log 13 | /*DB.* 14 | /cobertura.ser 15 | .DS_Store 16 | /target/ 17 | /out/ 18 | /web-app/plugins 19 | /web-app/WEB-INF/classes 20 | /.link_to_grails_plugins/ 21 | /target-eclipse/ 22 | /projectFilesBackup/ 23 | .data 24 | .ideaDataSources/ 25 | .slcache/ 26 | dataSources/ 27 | site/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "plugins/AfShared"] 2 | path = plugins/AfShared 3 | url = https://github.com/annotationframework/AfShared.git 4 | [submodule "plugins/AfSecurity"] 5 | path = plugins/AfSecurity 6 | url = https://github.com/annotationframework/AfSecurity.git 7 | [submodule "plugins/AfPersistence"] 8 | path = plugins/AfPersistence 9 | url = https://github.com/annotationframework/AfPersistence.git 10 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Catch 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.common.project.facet.core.builder 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | 20 | org.grails.ide.eclipse.core.nature 21 | org.eclipse.jdt.groovy.core.groovyNature 22 | org.eclipse.jdt.core.javanature 23 | org.eclipse.wst.common.project.facet.core.nature 24 | 25 | 26 | 27 | .link_to_grails_plugins 28 | 2 29 | GRAILS_ROOT/2.2.1/projects/catch/plugins 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: groovy 2 | jdk: 3 | - openjdk7 4 | 5 | # To solve BufferOverflow on OpenJDK7 we setup short hostname (<64characters) 6 | # See: 7 | # - ISSUE-5227: https://github.com/travis-ci/travis-ci/issues/5227 8 | # - https://docs.travis-ci.com/user/hostname 9 | # - https://github.com/mockito/mockito/blob/master/.travis.yml 10 | addons: 11 | hosts: 12 | - catch-harvardx 13 | hostname: catch-harvardx 14 | 15 | before_install: 16 | # Install inline plugin dependencies 17 | - pwd 18 | - cd .. 19 | - mkdir annotationframework 20 | - cd annotationframework 21 | - git clone https://github.com/annotationframework/AfPersistence.git 22 | - git clone https://github.com/annotationframework/AfSecurity.git 23 | - git clone https://github.com/annotationframework/AfShared.git 24 | - cd ../catcha 25 | script: ./grailsw refresh-dependencies 26 | && ./grailsw "test-app unit:" 27 | && ./grailsw "test-app integration:" 28 | -------------------------------------------------------------------------------- /CREDITS.TXT: -------------------------------------------------------------------------------- 1 | amarok_download.png - GNU Lesser General Public License - http://www.iconlet.com/info/32619_amarok_download_64x64 2 | amarok_search.png - GNU Lesser General Public License- http://www.iconlet.com/info/32460_amarok_search_64x64 3 | groups.png - GNU General Public License - http://www.iconlet.com/info/72943_switchuser_32x32 4 | search.png - GNU Lesser General Public License - http://www.iconlet.com/info/80811_search_32x32 5 | computer.png - GNU General Public License - http://www.iconlet.com/info/49528_computer_32x32 6 | reload.png - GNU Lesser General Public License - http://www.iconlet.com/info/34642_reload_16x16 7 | computer_delete.png - Creative Commons Attribution 2.5 - http://www.iconlet.com/info/8330_computer_delete_16x16 8 | delete_group.png - GNU Lesser General Public License - http://www.iconlet.com/info/12547_delete_group_16x16 9 | xedit.png - GNU Lesser General Public License - http://www.iconlet.com/info/35177_xedit_22x22 10 | package_system.png - GNU Lesser General Public License - http://www.iconlet.com/info/10946_package_system_32x32 11 | warning16x16.png - GNU General Public License - http://www.iconlet.com/info/41902_messagebox_warning_16x16 -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:7-jdk 2 | 3 | ENV CATALINA_OPTS -Xms512m -Xmx512m -XX:MaxPermSize=256m 4 | ENV GRAILS_VERSION 2.2.5 5 | ENV GRAILS_HOME /opt/grails 6 | ENV PATH $GRAILS_HOME/bin:$PATH 7 | 8 | WORKDIR /opt 9 | 10 | RUN curl -s -L -o grails.zip https://github.com/grails/grails-core/releases/download/v${GRAILS_VERSION}/grails-${GRAILS_VERSION}.zip \ 11 | && unzip -q grails.zip \ 12 | && rm grails.zip \ 13 | && ln -s grails-${GRAILS_VERSION} grails 14 | 15 | WORKDIR /app 16 | 17 | EXPOSE 8080 18 | 19 | ADD . /app 20 | 21 | # AfPersistence/grails-app/conf/BuildConfig.groovy hard coded AfSecurity path. So we have to make a symbol link 22 | RUN ln -s plugins annotationframework \ 23 | && grails compile \ 24 | && sed -e 's/localhost:3306/db:3306/' -e 's/catch_test/catch/' Catch-config.properties > catch-config.properties 25 | 26 | VOLUME ['/app/web-app/uploads'] 27 | 28 | CMD ["grails", "run-app"] 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Stories in Ready](https://badge.waffle.io/annotationsatharvard/catcha.png?label=ready&title=Ready)](https://waffle.io/annotationsatharvard/catcha) 2 | [![Build Status](https://travis-ci.org/annotationsatharvard/catcha.svg?branch=master)](https://travis-ci.org/annotationsatharvard/catcha) 3 | [![Documentation Status](https://readthedocs.org/projects/catcha/badge/?version=latest)](http://catcha.readthedocs.io/en/latest/?badge=latest) 4 | [![Slack Status](http://slack.annotationhub.org/badge.svg)](http://slack.annotationhub.org) 5 | 6 | catcha 7 | ====== 8 | 9 | Catching Annotation (Catch-A) 10 | 11 | This software was created for the Harvard Library Labs project CATCH (https://osc.hul.harvard.edu/liblab/proj/catch) awarded to Phil Desenne, Martin Schreiner and Paolo Ciccarese 12 | 13 | The software was originally written by: 14 | * Dr. Paolo Ciccarese http://paolociccarese.info 15 | * Justin Miranda https://github.com/jmiranda 16 | 17 | You can find the core plugin dependencies at [https://github.com/annotationframework](https://github.com/annotationframework). 18 | 19 | # Getting Started 20 | 21 | ## Support 22 | Start a discussion on our [Slack](http://slack.annotationhub.org). Great place to ask questions, discuss feature requests, and report bugs. 23 | 24 | ## Implementer Installation 25 | * Use the Run With Docker installation instructions below. 26 | * Follow installation instructions on [catcha.readthedocs.io] (http://catcha.readthedocs.io/en/latest/admin-guide/installation/) 27 | 28 | ## Developer Installation 29 | 30 | ### Install dependencies 31 | * GVM - http://gvmtool.net/ 32 | * Grails 2.2.1+ 33 | * Tomcat 6+ 34 | * MySQL 5.5+ 35 | 36 | #### Install GVM 37 | See http://gvmtool.net/ 38 | ``` 39 | $ curl -s get.gvmtool.net | bash 40 | ``` 41 | 42 | #### Install Grails 43 | After downloading the source code check `catcha/Catch/application.properties` to find the required Grails version. 44 | ``` 45 | app.grails.version=2.2.1 46 | ``` 47 | 48 | To install the appropriate grails version: 49 | ``` 50 | $ gvm install grails 2.2.1 51 | ``` 52 | 53 | #### MySQL 54 | See http://dev.mysql.com/downloads/installer/. On Ubuntu 55 | ``` 56 | sudo apt-get install mysql-server 57 | ``` 58 | 59 | ### Build application from source 60 | 61 | #### Download application source code 62 | ``` 63 | $ git clone https://github.com/annotationsatharvard/catcha.git 64 | ``` 65 | 66 | #### Download plugin source code 67 | There are several plugins that are included as "local plugin" dependencies within the application's `BuildConfig.groovy`. It's important that the root directory of these plugins (`annotationframework`) is located at the same level as the `catcha` directory. 68 | ``` 69 | $ mkdir annotationframework 70 | $ cd annotationframework 71 | $ git clone https://github.com/annotationframework/AfPersistence.git 72 | $ git clone https://github.com/annotationframework/AfSecurity.git 73 | $ git clone https://github.com/annotationframework/AfShared.git 74 | ``` 75 | 76 | ##### Create database 77 | ``` 78 | mysql -u root -p -e 'create database catch default charset utf8;' 79 | ``` 80 | ##### Create database user 81 | ``` 82 | mysql -u root -p -e 'grant all on catch.* to "catch"@"localhost" identified by "";' 83 | ``` 84 | 85 | ##### Create external configuration file 86 | If you changed the database name, username, or password you need to edit an external configuration file. 87 | 88 | NOTE: I needed to rename the file (lowercase 'c') in order to get the application to read this file. 89 | ``` 90 | $ cd Catch 91 | $ mv Catch-config.properties catch-config.properties 92 | ``` 93 | 94 | Add the following properties to `catcha/Catch/catch-config.properties`. 95 | ``` 96 | # Database connection settings 97 | dataSource.url=jdbc:mysql://localhost:3306/catch?autoReconnect=true&zeroDateTimeBehavior=convertToNull&sessionVariables=storage_engine=InnoDB 98 | dataSource.username=catch 99 | dataSource.password= 100 | ``` 101 | 102 | NOTE: Do NOT change the database name as there is a bug I just discovered in the Liquibase changesets that hard-codes the schema name to "catch" when dealing with foreign key contstraints. 103 | 104 | ### Run application in development mode 105 | ``` 106 | $ grails run-app 107 | ``` 108 | 109 | 110 | ## Develop with Docker 111 | 112 | When developing with Docker, all the dependencies are included in docker images. No need to install anything on the host other than (docker)[https://docs.docker.com/engine/installation/] 113 | 114 | NOTE: This repo has submodules. If `--recursive` is not specified when cloning the repo, you need to run `git submodule update --init` to pull down the submodules. 115 | 116 | ### Update configruation 117 | 118 | Update the following line in `catch-config.properties`: 119 | 120 | ``` 121 | dataSource.url=jdbc:mysql://localhost:3306/catch_test?useUnicode=yes&characterEncoding=UTF-8&autoReconnect=true 122 | ``` 123 | To 124 | ``` 125 | dataSource.url=jdbc:mysql://db:3306/catch?useUnicode=yes&characterEncoding=UTF-8&autoReconnect=true 126 | ``` 127 | 128 | ### Start application 129 | 130 | ``` 131 | docker-compose up -d 132 | ``` 133 | 134 | Docker will download official MySQL image and build catcha image. Docker-compose will create a docker network and run both images. Once they are started, the application can be accessed at http://localhost:8080. 135 | 136 | Once the docker containers are running, you can make changes to the files on the host and they will be auto-reloaded. 137 | 138 | ### Check logs 139 | 140 | ``` 141 | docker logs -f catch_app_1 142 | ``` 143 | 144 | ### Stop application 145 | 146 | ``` 147 | docker-compose stop 148 | ``` 149 | 150 | ### Tear down application 151 | 152 | ``` 153 | docker-compose down 154 | ``` 155 | -------------------------------------------------------------------------------- /application.properties: -------------------------------------------------------------------------------- 1 | #Grails Metadata file 2 | #Tue Oct 07 18:47:39 EDT 2014 3 | app.grails.version=2.2.5 4 | app.name=catch 5 | app.version=0.6.0-alpha-3 6 | -------------------------------------------------------------------------------- /catch-config.properties: -------------------------------------------------------------------------------- 1 | 2 | af.shared.name=CATCH-A 3 | af.shared.title=CATCH-A, Annotations at Harvard 4 | 5 | af.shared.logo.title=CATCH 6 | af.shared.logo.subtitle=Annotation Hub 7 | 8 | af.shared.copyright.label=Annotations @ Harvard 9 | af.shared.copyright.link=http://www.annotations.harvard.edu/ 10 | 11 | af.security.initialize.user=true 12 | af.security.moderation.user.request=true 13 | 14 | af.node.organization=Massachusetts General Hospital 15 | af.node.administrator.name=Dr. Paolo Ciccarese 16 | af.node.administrator.email.to=paolo.ciccarese@gmail.com 17 | af.node.administrator.email.display=paolo dot ciccarese at gmail.com 18 | 19 | #af.node.base.url=http://purl.org/catcha/1/ 20 | af.node.base.url=http://localhost:8080/catch/ 21 | 22 | # Disabled these setting as they should probably go into ~/.grails/catch-config.properties instead 23 | #dataSource.url=jdbc:mysql://localhost:3306/catch?useUnicode=yes&characterEncoding=UTF-8&autoReconnect=true 24 | #dataSource.username=catch 25 | #dataSource.password=catch 26 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | db: 4 | image: mariadb:10.1 5 | volumes: 6 | - "./.data/db:/var/lib/mysql" 7 | restart: always 8 | environment: 9 | MYSQL_ROOT_PASSWORD: rootpass 10 | MYSQL_DATABASE: catch 11 | MYSQL_USER: catch 12 | MYSQL_PASSWORD: catch 13 | app: 14 | build: . 15 | image: compass/catcha:latest 16 | depends_on: 17 | - db 18 | volumes: 19 | - ".:/app" 20 | - "./.data/app:/app/web-app/uploads" 21 | - ".data/cache:/root/.grails/ivy-cache" 22 | ports: 23 | - "8080:8080" 24 | 25 | -------------------------------------------------------------------------------- /docs/admin-guide/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration -------------------------------------------------------------------------------- /docs/admin-guide/deployment/aws-ebs.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/admin-guide/deployment/aws-ebs.md -------------------------------------------------------------------------------- /docs/admin-guide/deployment/aws-ec2.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/admin-guide/deployment/aws-ec2.md -------------------------------------------------------------------------------- /docs/admin-guide/deployment/digital-ocean.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/admin-guide/deployment/digital-ocean.md -------------------------------------------------------------------------------- /docs/admin-guide/deployment/docker.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/admin-guide/deployment/docker.md -------------------------------------------------------------------------------- /docs/admin-guide/getting-started.md: -------------------------------------------------------------------------------- 1 | ## Assumptions 2 | * You have successfully deployed the CATCH-A web application to a cloud service of your choosing (AWS EC2, AWS EBS, DigitalOcean, RimuHosting, etc). 3 | * A developer who wants to access the CATCH-A API has requested an API key. 4 | 5 | ## Create an API Client 6 | Currently, there's no way for developers to request or manage their client API keys, so the owner of the API instance needs to manually create API keys for external developers. 7 | 8 | To create a new client API key you need to log into CATCH-A as an administrator. 9 | 10 | #### Navigate to admin console 11 | * Example URL if running the API locally: [http://localhost:8080/catch](http://localhost:8080/catch) 12 | 13 | #### Log in as an admin 14 | * Username: admin 15 | * Password: password 16 | 17 | ![Screenshot](/img/login.png) 18 | 19 | ### Administrative dashboard 20 | * Navigate your browser to the [CATCH-A Admin Dashboard](http://localhost:8080/catch/dashboard/index) by clicking the Administration Dashboard link at the top of the page. 21 | 22 | ![Screenshot](/img/home.png) 23 | 24 | ### List all existing systems 25 | * Click the List Systems link in the leftnav to view existing systems 26 | 27 | ![Screenshot](/img/list-systems.png) 28 | 29 | 30 | ### Create a new system 31 | * Click the Create System link in the leftnav 32 | * Enter a descriptive name (e.g."Justin's Demo Client API") 33 | * Enter a short code ("JUSTIN-DEMO"). 34 | * Enter the client URL (and the client developer's email address) in the description field so that we can contact the client developer in case of an issue. 35 | * Click the Save System button. 36 | 37 | ![Screenshot](/img/create-system.png) 38 | 39 | ### Distribute API key 40 | * Distribute the API and Secret keys from the Show System page to the developer. 41 | 42 | ![Screenshot](/img/show-system-api-key.png) 43 | 44 | -------------------------------------------------------------------------------- /docs/admin-guide/getting-support.md: -------------------------------------------------------------------------------- 1 | To get support with your CATCH API instance, please create a ticket in [GitHub issues](https://github.com/annotationsatharvard/catcha/issues) with very specific details about the problem you have encountered (including screenshots and steps to reproduce). 2 | -------------------------------------------------------------------------------- /docs/admin-guide/index.md: -------------------------------------------------------------------------------- 1 | # Overview -------------------------------------------------------------------------------- /docs/admin-guide/manage-systems.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/admin-guide/manage-systems.md -------------------------------------------------------------------------------- /docs/admin-guide/manage-users.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/admin-guide/manage-users.md -------------------------------------------------------------------------------- /docs/admin-guide/mysql.md: -------------------------------------------------------------------------------- 1 | ### To create a backup of the current database 2 | ``` 3 | $ mysqldump -u catch -p catch > catch-.sql 4 | ``` 5 | -------------------------------------------------------------------------------- /docs/admin-guide/tomcat.md: -------------------------------------------------------------------------------- 1 | ### To check if tomcat7 is currently running 2 | ``` 3 | $ sudo service tomcat7 status 4 | * Tomcat servlet engine is not running. 5 | 6 | ``` 7 | 8 | ### To start, stop, restart the tomcat7 service 9 | ``` 10 | $ sudo service tomcat7 start | stop | restart 11 | * Starting Tomcat servlet engine tomcat7 [ OK ] 12 | * Stopping Tomcat servlet engine tomcat7 [ OK ] 13 | ``` 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/admin-guide/ubuntu.md: -------------------------------------------------------------------------------- 1 | These are packages that we recommend you install on your server. 2 | 3 | ## Rolling log files 4 | 5 | ### Install logrotate 6 | ``` 7 | sudo apt-get install logrotate 8 | ``` 9 | 10 | ### Configure logrotate 11 | See [logrotate tutorial](https://www.digitalocean.com/community/tutorials/how-to-manage-log-files-with-logrotate-on-ubuntu-12-10) on Digital Ocean. 12 | 13 | ## Unattended upgrades 14 | 15 | ### Install unattended-upgrades 16 | ``` 17 | sudo apt-get install unattended-upgrades 18 | ``` 19 | 20 | ### Enabled unattended-upgrades 21 | ``` 22 | sudo dpkg-reconfigure -plow unattended-upgrades 23 | ``` 24 | For more details see documentation about [Automatic Security Updates](https://help.ubuntu.com/community/AutomaticSecurityUpdates). 25 | 26 | 27 | ``` 28 | Welcome to Ubuntu 12.04.5 LTS (GNU/Linux 3.2.0-83-virtual x86_64) 29 | 30 | * Documentation: https://help.ubuntu.com/ 31 | 32 | System information as of Thu May 21 20:01:31 UTC 2015 33 | 34 | System load: 0.0 Processes: 87 35 | Usage of /: 32.7% of 78.74GB Users logged in: 0 36 | Memory usage: 13% IP address for eth0: 172.31.40.181 37 | Swap usage: 0% 38 | 39 | Graph this data and manage this system at: 40 | https://landscape.canonical.com/ 41 | 42 | Get cloud support with Ubuntu Advantage Cloud Guest: 43 | http://www.ubuntu.com/business/services/cloud 44 | 45 | Use Juju to deploy your cloud instances and workloads: 46 | https://juju.ubuntu.com/#cloud-precise 47 | 48 | 6 packages can be updated. 49 | 0 updates are security updates. <========================= These are the packages to be updated 50 | 51 | New release '14.04.2 LTS' available. 52 | Run 'do-release-upgrade' to upgrade to it. 53 | 54 | *** /dev/xvda1 will be checked for errors at next reboot *** 55 | 56 | *** System restart required *** 57 | You have mail. 58 | Last login: Thu May 21 18:13:58 2015 from allscreens03.a.subnet.rcn.com 59 | ``` 60 | -------------------------------------------------------------------------------- /docs/admin-guide/upgrade.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Using the Command Line 4 | Upgrading the CATCH API from the command line is fairly straightforward if you've ever worked with Tomcat before. 5 | 6 | ### Backup WAR 7 | This is a precaution in case you need to rollback to the previous version after a failed deployment. 8 | ``` 9 | sudo cp /var/lib/tomcat7/webapps/catch.war 10 | 11 | ``` 12 | 13 | 14 | ### Backup database 15 | This is an extra precaution just in case there are database migrations that fail and you need to rollback to the previous version. 16 | ``` 17 | $ mysqldump -u catch -p catch > /catch---.sql 18 | ``` 19 | 20 | 21 | ### Stop Tomcat 22 | ``` 23 | $ sudo server tomcat7 stop 24 | ``` 25 | 26 | ### Undeploy the application 27 | ``` 28 | $ sudo rm -rf /var/lib/tomcat7/webapps/catch 29 | $ sudo rm -rf /var/lib/tomcat7/webapps/catch.war 30 | ``` 31 | 32 | ### Deploy the new application 33 | ``` 34 | $ sudo cp catch-.war /usr/lib/tomcat7/webapps/catch.war 35 | ``` 36 | 37 | ### Start tomcat 38 | ``` 39 | $ sudo service tomcat7 start 40 | ``` 41 | 42 | ### Tail catalina.out 43 | The reason you want to tail the log file is to ensure that all Liquibase database migration changesets go through. The log below shows that there were no database migrations for this version of the 44 | ``` 45 | $ tail -f /var/log/tomcat7/catalina.out 46 | Using configuration locations [file:./catch-config.properties, file:./catch-config.groovy, classpath:catch-config.properties, classpath:catch-config.groovy, file:/home/jmiranda/.grails/catch-config.properties, file:/home/jmiranda/.grails/catch-config.groovy] 47 | 48 | 2015-05-15 11:01:58,873 [localhost-startStop-1] INFO liquibase - Reading from `DATABASECHANGELOG` 49 | 2015-05-15 11:01:59,067 [localhost-startStop-1] WARN liquibase - modifyDataType will lose primary key/autoincrement/not null settings for mysql. Use and re-specify all configuration if this is the case 50 | 2015-05-15 11:01:59,067 [localhost-startStop-1] WARN liquibase - modifyDataType will lose primary key/autoincrement/not null settings for mysql. Use and re-specify all configuration if this is the case 51 | 2015-05-15 11:01:59,067 [localhost-startStop-1] WARN liquibase - modifyDataType will lose primary key/autoincrement/not null settings for mysql. Use and re-specify all configuration if this is the case 52 | 2015-05-15 11:01:59,067 [localhost-startStop-1] WARN liquibase - modifyDataType will lose primary key/autoincrement/not null settings for mysql. Use and re-specify all configuration if this is the case 53 | 2015-05-15 11:01:59,068 [localhost-startStop-1] WARN liquibase - modifyDataType will lose primary key/autoincrement/not null settings for mysql. Use and re-specify all configuration if this is the case 54 | 2015-05-15 11:01:59,068 [localhost-startStop-1] WARN liquibase - modifyDataType will lose primary key/autoincrement/not null settings for mysql. Use and re-specify all configuration if this is the case 55 | 2015-05-15 11:01:59,068 [localhost-startStop-1] WARN liquibase - modifyDataType will lose primary key/autoincrement/not null settings for mysql. Use and re-specify all configuration if this is the case 56 | 2015-05-15 11:01:59,069 [localhost-startStop-1] INFO databasemigration.MigrationRunner - No migrations to run for DataSource 'dataSource' 57 | ... 58 | INFO: Deployment of web application archive /var/lib/tomcat7/webapps/catch.war has finished in 88,304 ms 59 | May 21, 2015 1:51:35 PM org.apache.coyote.AbstractProtocol start 60 | INFO: Starting ProtocolHandler ["http-bio-8080"] 61 | May 21, 2015 1:51:35 PM org.apache.catalina.startup.Catalina start 62 | INFO: Server startup in 88663 ms 63 | ``` 64 | 65 | NOTE: Obviously, if you've changed the WAR filename to `ROOT.war` (see [Installation instructions](installation.md)) then you'll want to delete the `ROOT.war` and `ROOT` directory under `/usr/lib/tomcat7/webapps/`. 66 | 67 | 68 | ## Using Tomcat Manager 69 | You can also upgrade the application through the Tomcat Manager app. 70 | 71 | ### Undeploy the current version of the application 72 | 73 | ![Screenshot](/img/tomcat/undeploy-war.png) 74 | 75 | 76 | ### Deploy the latest version of the application 77 | 78 | ![Screenshot](/img/tomcat/deploy-war-1.png) 79 | 80 | ### Make sure the application has been deployed and is running 81 | 82 | ![Screenshot](/img/tomcat/deploy-war-2.png) 83 | 84 | ## Troubleshooting 85 | 86 | ### The request was rejected because its size (XXX) exceeds the configured maximum (52428800) 87 | 88 | #### Problem 89 | 90 | ![Screenshot](/img/tomcat/exceed-file-size-limit.png) 91 | 92 | #### Solution 93 | Edit **/usr/share/tomcat7-admin/manager/WEB-INF/web.xml** 94 | ``` 95 | 96 | HTMLManager 97 | org.apache.catalina.manager.HTMLManagerServlet 98 | 99 | debug 100 | 2 101 | 102 | 109 | 110 | 111 | 52428800 112 | 52428800 113 | 0 114 | 115 | 116 | ``` 117 | Increase the max-file-size and max-request-size from 50MB to 100MB: 118 | ``` 119 | 120 | 121 | 104857600 122 | 104857600 123 | 0 124 | 125 | ``` 126 | 127 | 128 | -------------------------------------------------------------------------------- /docs/developer-guide/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## Setting up your development environment 4 | 5 | ## Create database 6 | 7 | ## Getting the source code 8 | 9 | ## Building the source code 10 | 11 | ## Starting the application in development mode 12 | 13 | -------------------------------------------------------------------------------- /docs/developer-guide/index.md: -------------------------------------------------------------------------------- 1 | # Overview -------------------------------------------------------------------------------- /docs/img/create-system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/create-system.png -------------------------------------------------------------------------------- /docs/img/debug-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/debug-token.png -------------------------------------------------------------------------------- /docs/img/disabled-api-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/disabled-api-key.png -------------------------------------------------------------------------------- /docs/img/edit-system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/edit-system.png -------------------------------------------------------------------------------- /docs/img/generate-token-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/generate-token-1.png -------------------------------------------------------------------------------- /docs/img/generate-token-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/generate-token-2.png -------------------------------------------------------------------------------- /docs/img/generate-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/generate-token.png -------------------------------------------------------------------------------- /docs/img/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/home.png -------------------------------------------------------------------------------- /docs/img/hub-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/hub-architecture.png -------------------------------------------------------------------------------- /docs/img/list-systems.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/list-systems.png -------------------------------------------------------------------------------- /docs/img/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/login.png -------------------------------------------------------------------------------- /docs/img/secret-key-cannot-be-null.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/secret-key-cannot-be-null.png -------------------------------------------------------------------------------- /docs/img/show-system-api-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/show-system-api-key.png -------------------------------------------------------------------------------- /docs/img/show-system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/docs/img/show-system.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | CATCH-A is a cloud-based working prototype of the backend Annotation Hub (AH) database and 4 | Application Programing Interface (API) for the Common Annotation, Tagging, and Citation at 5 | Harvard (CATCH) project [https://github.com/annotationsatharvard/catcha](https://github.com/annotationsatharvard/catcha). 6 | The AH enables storing, searching, sharing and analyzing scholarly annotations, tags, including semantic tagging, 7 | produced on four digital media types: text, image, audio and video. The AH is designed to 8 | interoperate with third-party annotation multi-media tools to aggregate and associate contextualized 9 | annotation metadata with reference to persistent digital media in repositories, such as the Harvard 10 | Library DRS (see Figure 1). 11 | 12 | 17 | 18 | ![Screenshot](/img/hub-architecture.png) 19 |

Figure 1. Annotation Hub

20 | 21 | 22 | ## Details 23 | 24 | ### Storage API 25 | The AnnotatorJS Store API actions allow clients to perform CRUD operations (create, read, update, 26 | delete) for annotations they want to store in the CATCH backend. Storing the annotations in a 27 | remote backend allows clients to ignore the complexity of building their own backend. In addition, 28 | the CATCH API provides other services such as Security and Search which enables the clients to 29 | focus on making their applications more user-friendly and not on complex backend logic. The 30 | CATCH API also implements actions from the Harvard Annotation API Draft Spec (including 31 | archive and destroy). 32 | 33 | ### Search API 34 | The AnnotatorJS Search API is a basic search mechanism that allows clients to retrieve annotations 35 | by source, target, annotation text, and other attributes. The current Search API relies on a relational 36 | data model to pull out attributes that are available for searching. In other words, we store the JSON 37 | annotation document in a large text column and index on attributes that we want to expose to the 38 | search API. Therefore, we can only search on fields that we have indexed. In a future release, we 39 | will be moving to a document store which will allow us to provide a more flexible search API. 40 | 41 | ### Security (Authentication / Authorization) 42 | The CATCH API provides basic security using the JSON Web Token draft standard. The client is responsible for 43 | generating an auth token on every request. This is one of the more complicated pieces for clientside 44 | developers as it requires the developer to build their own token generator in the language of 45 | their choice. The auth token is basically a payload with authentication data (consumer public key, 46 | time-to-live, issued-at) signed with a secret shared between the client and server.   On every request 47 | made by the client, the server checks for an auth token and verifies that the token has not expired. 48 | This provides minimal security between the software, but obviously does not handle user 49 | authorization and whether a particular user should have access to an annotation. At the moment, 50 | the CATCH API does not restrict access to annotations -- all annotations are public. However, the 51 | Permissions spec for AnnotatorJS allows clients to provide filtering on the client-side. In the future, 52 | the CATCH API will improve on the authorization mechanism and only allow authenticated users 53 | with proper permission to access annotations from the API. 54 | 55 | ## Future Plans 56 | The next phase of the CATCH project contemplates the implementation of a document-oriented 57 | database designed for ease of development and scaling, coupled with a distributed restful search and 58 | analytics engine that is schema free. For this we are considering open source solutions such as 59 | [MongoDb](http://www.mongodb.org/) and [ElasticSearch](http://www.elasticsearch.org). On the 60 | client-side we will extend and refine the usability of the Annotation Grid Display to accommodate 61 | multiple tool-independent annotation scenarios. 62 | 63 | Furthermore, we will continue testing the implementations of the AH and Annotation Grid Display 64 | inside the edX platform and define APIs to connect the Library resources from the DRS inside the 65 | edX annotation modules. 66 | 67 | ## Attribution 68 | This software was created for the [Harvard Library Labs CATCH project](https://osc.hul.harvard.edu/liblab/proj/catch) awarded to Phil Desenne, Martin Schreiner and Paolo Ciccarese. 69 | 70 | The software was originally written by: 71 | 72 | * Dr. Paolo Ciccarese http://paolociccarese.info 73 | * Justin Miranda http://twitter.com/justinmiranda 74 | 75 | ## Project Team 76 | 77 | * Paolo Ciccarese - Lead Technical Architect and Data Model Design 78 | * Phil Desenne - Lead Application Design and Instructional Technology 79 | * Martin Schreiner - Library Integration and Quality Assurance 80 | * Justin Miranda - Back-end Database Development 81 | * Daniel Cebrian - Front-end UI Development 82 | * Mark Soper - Front-end UI Development 83 | * Lynn Sayers - Project Budget and Finances 84 | -------------------------------------------------------------------------------- /docs/user-guide/annotation.md: -------------------------------------------------------------------------------- 1 | ## Annotation Format 2 | According to the [annotatorjs documentation](http://docs.annotatorjs.org/en/v1.2.x/annotation-format.html) 3 | 4 | > An annotation is a JSON document that contains a number of fields describing the position and content of an annotation 5 | > within a specified document: 6 | ``` 7 | { 8 | "id": "39fc339cf058bd22176771b3e3187329", # unique id (added by backend) 9 | "annotator_schema_version": "v1.0", # schema version: default v1.0 10 | "created": "2011-05-24T18:52:08.036814", # created datetime in iso8601 format (added by backend) 11 | "updated": "2011-05-26T12:17:05.012544", # updated datetime in iso8601 format (added by backend) 12 | "text": "A note I wrote", # content of annotation 13 | "quote": "the text that was annotated", # the annotated text (added by frontend) 14 | "uri": "http://example.com", # URI of annotated document (added by frontend) 15 | "ranges": [ # list of ranges covered by annotation (usually only one entry) 16 | { 17 | "start": "/p[69]/span/span", # (relative) XPath to start element 18 | "end": "/p[70]/span/span", # (relative) XPath to end element 19 | "startOffset": 0, # character offset within start element 20 | "endOffset": 120 # character offset within end element 21 | } 22 | ], 23 | "user": "alice", # user id of annotation owner (can also be an object with an 'id' property) 24 | "consumer": "annotateit", # consumer key of backend 25 | "tags": [ "review", "error" ], # list of tags (from Tags plugin) 26 | "permissions": { # annotation permissions (from Permissions/AnnotateItPermissions plugin) 27 | "read": ["group:__world__"], 28 | "admin": [], 29 | "update": [], 30 | "delete": [] 31 | } 32 | } 33 | ``` -------------------------------------------------------------------------------- /docs/user-guide/api-errors.md: -------------------------------------------------------------------------------- 1 | ## Invalid token 2 | 3 | ### Request 4 | ``` 5 | curl -i -X GET \ 6 | -H "Content-Type: application/json" \ 7 | -H "x-annotator-auth-token:invalid-token" \ 8 | "http://localhost:8080/catch/annotator/search?limit=10" 9 | ``` 10 | ### Response 11 | ``` 12 | HTTP/1.1 401 Unauthorized 13 | Server: Apache-Coyote/1.1 14 | Content-Length: 0 15 | Date: Thu, 21 May 2015 19:51:53 GMT 16 | 17 | ``` 18 | 19 | ## Missing token 20 | 21 | ### Request 22 | ``` 23 | curl -i -X GET \ 24 | -H "Content-Type: application/json" \ 25 | -H "x-annotator-auth-token:" \ 26 | "http://localhost:8080/catch/annotator/search?limit=10" 27 | ``` 28 | ### Response 29 | ``` 30 | HTTP/1.1 401 Unauthorized 31 | Server: Apache-Coyote/1.1 32 | Content-Type: text/html;charset=utf-8 33 | Content-Length: 234 34 | Date: Thu, 21 May 2015 19:52:35 GMT 35 | 36 | You are not authorized to access annotations without a valid token. Please include an 'x-annotator-auth-token' request header. See AnnotatorJs documentation for more details (http://docs.annotatorjs.org/en/latest/authentication.html). 37 | ``` 38 | 39 | ## System API with key is currently disabled 40 | If you encounter this error, ask your system administrator to enable your API key. 41 | ![Screenshot](/img/disabled-api-key.png) 42 | 43 | ### Request 44 | ``` 45 | curl -i -X GET \ 46 | -H "Content-Type: application/json" \ 47 | -H "x-annotator-auth-token:eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHRcL3BsYWluIiwidHlwIjoiSldTIn0.eyJjb25zdW1lcktleSI6IjllYTJlZGUwLTQ2OTMtNGJlYy05MDk0LWIxZTNlN2E2YTM1NiIsImlzc3VlZEF0IjoiMjAxNS0wNS0wOFQwODoxMjoxOCswMDAwIiwidXNlcklkIjoiYWRtaW4iLCJqdGkiOiJiMjgxYzNmMy00YTg1LTQ3OWQtYWZlMS1mNTVmOTgyOGVmOWIiLCJ0dGwiOjg2NDAwLCJpYXQiOjE0MzExMTU5Mzh9.AduJJX_VijIEKUQ5WO_Ofu6tCURQZ67mf-_72LcJmU8" \ 48 | "http://localhost:8080/catch/annotator/search?limit=10" 49 | ``` 50 | ### Response 51 | ``` 52 | HTTP/1.1 401 Unauthorized 53 | Server: Apache-Coyote/1.1 54 | Content-Type: text/html;charset=utf-8 55 | Content-Length: 125 56 | Date: Thu, 21 May 2015 19:34:19 GMT 57 | 58 | You are not authorized to access annotations: System API with key 9ea2ede0-4693-4bec-9094-b1e3e7a6a356 is currently disabled. 59 | ``` 60 | 61 | ## The shared secret must not be null 62 | If this encounter this error, ask your system administrator to generate your secret key. 63 | 64 | ![Screenshot](/img/secret-key-cannot-be-null.png) 65 | 66 | ### Request 67 | ``` 68 | curl -i -X GET \ 69 | -H "Content-Type: application/json" \ 70 | -H "x-annotator-auth-token:eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHRcL3BsYWluIiwidHlwIjoiSldTIn0.eyJjb25zdW1lcktleSI6IjllYTJlZGUwLTQ2OTMtNGJlYy05MDk0LWIxZTNlN2E2YTM1NiIsImlzc3VlZEF0IjoiMjAxNS0wNS0wOFQwODoxMjoxOCswMDAwIiwidXNlcklkIjoiYWRtaW4iLCJqdGkiOiJiMjgxYzNmMy00YTg1LTQ3OWQtYWZlMS1mNTVmOTgyOGVmOWIiLCJ0dGwiOjg2NDAwLCJpYXQiOjE0MzExMTU5Mzh9.AduJJX_VijIEKUQ5WO_Ofu6tCURQZ67mf-_72LcJmU8" \ 71 | "http://localhost:8080/catch/annotator/search?limit=10" 72 | 73 | ``` 74 | 75 | ### Response 76 | ``` 77 | HTTP/1.1 401 Unauthorized 78 | Server: Apache-Coyote/1.1 79 | Content-Type: text/html;charset=utf-8 80 | Content-Length: 80 81 | Date: Thu, 21 May 2015 19:35:48 GMT 82 | 83 | You are not authorized to access annotations: The shared secret must not be null 84 | ``` 85 | 86 | -------------------------------------------------------------------------------- /docs/user-guide/api.md: -------------------------------------------------------------------------------- 1 | # API Docs 2 | 3 | ## Overview 4 | The initial version of the CATCH-A API supported the basic [Storage and Search API](http://docs.annotatorjs.org/en/v1.2.x/storage.html) specification provided by 5 | annotatorjs. The current version adds support for a few more 6 | features to the Storage and Search APIs and we continue to extend the API to support even more features. If you 7 | have any requests for new functionality please add an issue to our [GitHub Issue tracker](https://github.com/annotationsatharvard/catcha/issues). 8 | 9 | 28 | 29 | ## Search API 30 | ### Request 31 | ``` 32 | curl -i -X GET 33 | -H "Content-Type: application/json" 34 | -H "x-annotator-auth-token:eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHRcL3BsYWluIiwidHlwIjoiSldTIn0.eyJjb25zdW1lcktleSI6Ijc1MmRjOWM3LWRlOTYtNGU2OC05NzM5LTlmOTVlNWM2MTVhOSIsImlzc3VlZEF0IjoiMjAxNS0wNC0xMFQxMDoyNjozMS0wNDAwIiwidXNlcklkIjpudWxsLCJqdGkiOiI1Zjc4MTc2Yi02NThjLTRiMmMtYjFlNC04NmE5MmE3NjNlOTciLCJ0dGwiOm51bGwsImlhdCI6MTQyODY3NTk5MX0.O0KxIrXzxMWqagqvotTzEkpL2OZ_h3rkB5w9nmW0ufY" 35 | http://localhost:8080/catch/annotator/search 36 | ``` 37 | ### Response 38 | ``` 39 | ``` 40 | 41 | ### Request 42 | ``` 43 | curl -i -X GET \ 44 | -H "Content-Type: application/json" \ 45 | -H "x-annotator-auth-token:eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHRcL3BsYWluIiwidHlwIjoiSldTIn0.eyJjb25zdW1lcktleSI6ImVlYjIwZWMwLWI4ZGQtNDBhZS1iM2RlLTE0ODcwYWZmOTJjNiIsImlzc3VlZEF0IjoiMjAxNS0wNC0xMVQwMTo1MDo0OS0wNDAwIiwidXNlcklkIjoiam1pcmFuZGEiLCJqdGkiOiIxMWE0MTUzMi0xOWJiLTRmMTctYWY1Zi1jNzg3Y2E0YzhhNjAiLCJ0dGwiOjg2NDAwLCJpYXQiOjE0Mjg3NzQ2NDl9.naoxEc6QIRUuxUGZpLtmvgVfPsBkLISRGLohqBiyCjU"\ 46 | "http://localhost:8080/catch/annotator/search" 47 | ``` 48 | ### Response 49 | ``` 50 | ``` 51 | 52 | ### Request 53 | ``` 54 | curl -i -X GET \ 55 | -H "Content-Type: application/json" \ 56 | -H "x-annotator-auth-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MzA3NzExNjAsImQiOnsiaXNzdWVkQXQiOiIyMDE1LTA1LTA0VDIwOjI2OjAwLjA1MzA4OCswOjAwIiwiY29uc3VtZXJLZXkiOiJhZjE3ZmNiNi1hZTE2LTQyYjctOTdmNi1iMmQxYjJkNjYyMjYiLCJ1aWQiOiJ0ZXN0QG1pcmFkb3Iub3JnIiwidHRsIjoxNzI4MDB9LCJ2IjowfQ.fjNmf-PbC0YInfU0ddHPmMJ4P3ccciMLdOjvQ8E3r9A" \ 57 | "http://localhost:8080/catch/annotator/search?uri=1_Summer/BMo101/2013_Spring_2" 58 | ``` 59 | ### Response 60 | ``` 61 | 62 | ``` 63 | 64 | ### Request 65 | ``` 66 | curl -i -X GET \ 67 | -H "Content-Type: application/json" \ 68 | -H "x-annotator-auth-token:eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHRcL3BsYWluIiwidHlwIjoiSldTIn0.eyJjb25zdW1lcktleSI6IjllYTJlZGUwLTQ2OTMtNGJlYy05MDk0LWIxZTNlN2E2YTM1NiIsImlzc3VlZEF0IjoiMjAxNS0wNS0wOFQwNzowNToxMCswMDAwIiwidXNlcklkIjoiam1pcmFuZGEiLCJqdGkiOiI3ZmU0YWM5OS1kMDE2LTQ0YTgtOTNmZi0yNTQ5NDU0OTg5NjkiLCJ0dGwiOjg2NDAwLCJpYXQiOjE0MzExMTE5MTB9.sSPsSJkJPXTXmShdws2_8c-obeMWnFuaysZnFcAVMe4" \ 69 | "http://localhost:8080/catch/annotator/search?limit=10" 70 | ``` 71 | ### Response 72 | ``` 73 | ``` 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/user-guide/getting-started.md: -------------------------------------------------------------------------------- 1 | ## Request a System API key and Secret key 2 | Before you get started, you need to request an API key (and secret key) from the administrator of the CATCH-A API instance with which you want to connect. 3 | 4 | ![Screenshot](/img/show-system-api-key.png) 5 | 6 | ## What's next? 7 | 8 | ### Using LTI 9 | Once you have your API key and secret key, you can plug those values into your LTI tool (see LTI documentation for more information). The LTI tool will generate a token and make requests against the CATCH API. 10 | 11 | ### Using command line 12 | See [API Docs](api.md) for more information. 13 | 14 | ### Using annotatorjs client 15 | See [AnnotatorJs Docs](annotatorjs.md) for more information. 16 | 17 | -------------------------------------------------------------------------------- /docs/user-guide/index.md: -------------------------------------------------------------------------------- 1 | # Overview -------------------------------------------------------------------------------- /grails-app/conf/ApiLoggingFilters.groovy: -------------------------------------------------------------------------------- 1 | class ApiLoggingFilters { 2 | 3 | def filters = { 4 | all(controller:'api', action:'*') { 5 | before = { 6 | log.info controllerName + "." + actionName + ": " + params 7 | } 8 | after = { Map model -> 9 | 10 | } 11 | afterView = { Exception e -> 12 | 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /grails-app/conf/ApplicationResources.groovy: -------------------------------------------------------------------------------- 1 | modules = { 2 | application { 3 | resource url:'js/application.js' 4 | } 5 | } -------------------------------------------------------------------------------- /grails-app/conf/AuthTokenFilters.groovy: -------------------------------------------------------------------------------- 1 | import com.nimbusds.jose.JWSObject 2 | import org.mindinformatics.ann.framework.module.security.systems.SystemApi 3 | 4 | import java.text.ParseException 5 | 6 | class AuthTokenFilters { 7 | 8 | def authTokenService 9 | 10 | def filters = { 11 | 12 | 13 | annotator(controller: 'annotator', action: '*') { 14 | before = { 15 | 16 | // Always allow requests for token to pass through since the alternative 17 | // means that you would need to have a token to generate a token 18 | if (actionName == "token" || actionName == "index") { 19 | return true 20 | } 21 | 22 | def token = request.getHeader("x-annotator-auth-token") 23 | if (!token) { 24 | response.status = 401 25 | render ("You are not authorized to access annotations without a valid token. Please include an 'x-annotator-auth-token' request header. See AnnotatorJs documentation for more details (http://docs.annotatorjs.org/en/latest/authentication.html).") 26 | return false 27 | } 28 | else { 29 | try { 30 | return authTokenService.validateAuthToken(token, true) 31 | 32 | } catch (IllegalArgumentException e) { 33 | response.status = 401 34 | render ("You are not authorized to access annotations: " + e.message) 35 | return false 36 | } 37 | catch (ParseException e){ 38 | println("Error parsing JSON web token ${token}: " + e.message) 39 | log.error("Error parsing JSON web token ${token}: " + e.message, e) 40 | //throw new Exception("Error parsing JSON web token: " + e.message) 41 | response.status = 401 42 | render ("Error parsing JSON web token ${token}: " + e.message) 43 | return false 44 | } 45 | catch (NoSuchMethodError e) { 46 | println("No such method error while parsing JSON web token ${token}: " + e.message) 47 | log.error("No such method error while parsing JSON web token ${token}: " + e.message, e) 48 | response.status = 401 49 | return false 50 | } 51 | catch (RuntimeException e) { 52 | println("Fatal runtime error while parsing JSON web token ${token}: " + e.message) 53 | log.error("Fatal runtime error while parsing JSON web token ${token}: " + e.message, e) 54 | response.status = 401 55 | //render ("You are not authorized to access annotations without a valid token. Could not parse token " + token + " due to error: " + e.message + ".") 56 | return false 57 | } 58 | catch (Exception e) { 59 | println("An uncaught exception occurred while parsing JSON web token ${token}: " + e.message) 60 | log.error("An uncaught exception occurred while parsing JSON web token ${token}: " + e.message, e) 61 | return false 62 | } 63 | } 64 | return true 65 | } 66 | after = { Map model -> 67 | 68 | } 69 | afterView = { Exception e -> 70 | 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /grails-app/conf/BuildConfig.groovy: -------------------------------------------------------------------------------- 1 | grails.servlet.version = "3.0" // Change depending on target container compliance (2.5 or 3.0) 2 | grails.project.class.dir = "target/classes" 3 | grails.project.test.class.dir = "target/test-classes" 4 | grails.project.test.reports.dir = "target/test-reports" 5 | grails.project.target.level = 1.6 6 | grails.project.source.level = 1.6 7 | //grails.project.war.file = "target/${appName}-${appVersion}.war" 8 | 9 | // uncomment (and adjust settings) to fork the JVM to isolate classpaths 10 | //grails.project.fork = [ 11 | // run: [maxMemory:1024, minMemory:64, debug:false, maxPerm:256] 12 | //] 13 | 14 | grails.plugin.location.'af-shared' = 'plugins/AfShared' 15 | grails.plugin.location.'af-security' = 'plugins/AfSecurity' 16 | grails.plugin.location.'af-persistence' = 'plugins/AfPersistence' 17 | 18 | grails.project.dependency.resolution = { 19 | // inherit Grails' default dependencies 20 | inherits("global") { 21 | // specify dependency exclusions here; for example, uncomment this to disable ehcache: 22 | // excludes 'ehcache' 23 | } 24 | log "warn" // log level of Ivy resolver, either 'error', 'warn', 'info', 'debug' or 'verbose' 25 | checksums true // Whether to verify checksums on resolve 26 | legacyResolve false // whether to do a secondary resolve on plugin installation, not advised and here for backwards compatibility 27 | 28 | repositories { 29 | inherits true // Whether to inherit repository definitions from plugins 30 | 31 | grailsPlugins() 32 | grailsHome() 33 | grailsCentral() 34 | 35 | mavenLocal() 36 | mavenCentral() 37 | 38 | // uncomment these (or add new ones) to enable remote dependency resolution from public Maven repositories 39 | //mavenRepo "http://snapshots.repository.codehaus.org" 40 | //mavenRepo "http://repository.codehaus.org" 41 | //mavenRepo "http://download.java.net/maven/2/" 42 | //mavenRepo "http://repository.jboss.com/maven2/" 43 | mavenRepo 'http://repo.spring.io/milestone' 44 | mavenRepo "http://mavenrepo.fzi.de/semweb4j.org/repo/" 45 | mavenRepo "https://repository.jboss.org/nexus/content/repositories/thirdparty-releases" 46 | mavenRepo "https://repo.grails.org/grails/plugins" 47 | //mavenRepo "http://repo.aduna-software.org/maven2/releases/" 48 | } 49 | dependencies { 50 | // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg. 51 | runtime 'mysql:mysql-connector-java:5.1.32' 52 | 53 | compile ("org.semweb4j:rdf2go.api:4.8.3") { 54 | excludes 'slf4j-api' 55 | } 56 | compile ("org.semweb4j:rdf2go.impl.sesame:4.8.3") { 57 | excludes 'slf4j-api' 58 | //excludes "sesame-runtime-osgi" 59 | } 60 | 61 | compile ("com.nimbusds:nimbus-jose-jwt:2.20") 62 | 63 | compile "org.apache.marmotta:sesame-tools-rio-jsonld:3.0.0-incubating" 64 | 65 | compile ("org.apache.jena:jena-core:2.11.0") { 66 | excludes 'slf4j-api', 'xercesImpl' 67 | } 68 | compile ("org.apache.jena:jena-arq:2.9.3") 69 | 70 | 71 | compile("org.apache.httpcomponents:httpcore:4.4.1") 72 | runtime 'joda-time:joda-time:2.9.4' 73 | 74 | // Commented this out because this dependency should be brought in with the compile scope above. 75 | //runtime "org.semweb4j:rdf2go.api:4.8.2" 76 | //runtime "org.semweb4j:rdf2go.impl.sesame:4.8.2" 77 | 78 | //runtime "org.semweb4j:rdf2go.impl.base:4.6.2" 79 | //compile "org.openrdf:openrdf-sesame-onejar-osgi:2.1.2" 80 | //compile "org.openrdf.sesame:sesame-query:2.7.2" 81 | } 82 | 83 | plugins { 84 | runtime ":hibernate:$grailsVersion" 85 | runtime ":jquery:1.8.3" 86 | runtime ":resources:1.2.6" 87 | runtime ":cors:1.1.3" 88 | runtime ":httplogger:1.1" 89 | 90 | // Uncomment these (or add new ones) to enable additional resources capabilities 91 | //runtime ":zipped-resources:1.0" 92 | //runtime ":cached-resources:1.0" 93 | //runtime ":yui-minify-resources:0.1.5" 94 | 95 | build ":tomcat:$grailsVersion" 96 | runtime ":database-migration:1.3.8" 97 | 98 | compile ':cache:1.1.1' 99 | rumtime ":svn:1.0.2" 100 | 101 | //compile ":joda-time:1.4" 102 | //compile "org.grails.plugins:spring-security-facebook:0.11" 103 | 104 | //compile ":functional-test:1.2.7" 105 | compile ':spring-security-core:2.0-RC2' 106 | compile ":spring-security-openid:2.0-RC2" 107 | compile ":build-test-data:2.2.3" 108 | compile ":joda-time:1.4" 109 | compile ":jdbc-pool:7.0.47" 110 | 111 | // compile (":functional-test:1.2.7") { 112 | // excludes "commons-codec" 113 | // } 114 | 115 | // #21 Keep this here so commons-codec:1.3 does not get included 116 | compile (":functional-test:2.0.RC1") { 117 | excludes "commons-codec" 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /grails-app/conf/DataSource.groovy: -------------------------------------------------------------------------------- 1 | hibernate { 2 | cache.use_second_level_cache = true 3 | cache.use_query_cache = false 4 | cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory' 5 | } 6 | // environment specific settings 7 | environments { 8 | development { 9 | dataSource { 10 | pooled = true 11 | //dbCreate = "create-drop" 12 | driverClassName = "com.mysql.jdbc.Driver" 13 | dialect = org.hibernate.dialect.MySQL5InnoDBDialect 14 | url = "jdbc:mysql://localhost:3306/catch?useUnicode=yes&characterEncoding=UTF-8&autoReconnect=true" 15 | username = "catch" 16 | password = "catch" 17 | loggingSql = false 18 | } 19 | } 20 | test { 21 | dataSource { 22 | pooled = true 23 | driverClassName = "org.h2.Driver" 24 | username = "sa" 25 | password = "" 26 | dbCreate = "create-drop" 27 | url = "jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000" 28 | } 29 | } 30 | production { 31 | dataSource { 32 | //dbCreate = "create-drop" 33 | pooled = true 34 | driverClassName = "com.mysql.jdbc.Driver" 35 | dialect = org.hibernate.dialect.MySQL5InnoDBDialect 36 | url = "jdbc:mysql://localhost:3306/catch?useUnicode=yes&characterEncoding=UTF-8&autoReconnect=true" 37 | username = "catch" 38 | password = "catch" 39 | properties { 40 | maxActive = -1 41 | minEvictableIdleTimeMillis=1800000 42 | timeBetweenEvictionRunsMillis=1800000 43 | numTestsPerEvictionRun=3 44 | testOnBorrow=true 45 | testWhileIdle=true 46 | testOnReturn=true 47 | validationQuery="SELECT 1" 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /grails-app/conf/UrlMappings.groovy: -------------------------------------------------------------------------------- 1 | class UrlMappings { 2 | 3 | static mappings = { 4 | "/info" (view:'/info') 5 | 6 | "/$controller/$action?/$id?"{ 7 | constraints { 8 | // apply constraints here 9 | } 10 | } 11 | 12 | "/api/$action/$id?"{ 13 | controller = 'annotator' 14 | } 15 | 16 | "/login/auth" { 17 | controller = 'openId' 18 | action = 'auth' 19 | } 20 | "/login/openIdCreateAccount" { 21 | controller = 'openId' 22 | action = 'createAccount' 23 | } 24 | "/" { 25 | controller = 'main' 26 | action = 'index' 27 | } 28 | 29 | // Error URL Mappings 30 | "401"(controller: 'error', action: 'unauthorized') 31 | "403"(controller: 'error', action: 'forbidden') 32 | "404"(controller: 'error', action: 'notFound') 33 | "405"(controller: 'error', action: 'methodNotAllowed') 34 | "500"(controller: 'error', action: 'serverError') 35 | //"500"(view:'/error') 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /grails-app/conf/spring/resources.groovy: -------------------------------------------------------------------------------- 1 | import org.apache.tomcat.jdbc.pool.DataSource 2 | import org.codehaus.groovy.grails.commons.ConfigurationHolder 3 | import org.mindinformatics.ann.framework.module.persistence.services.InMemoryTripleStorePersistenceImpl 4 | import org.mindinformatics.ann.framework.module.security.AuthenticationApplicationListener 5 | 6 | // Place your Spring DSL code here 7 | beans = { 8 | //authenticationSuccessHandler(CustomAuthenticationSuccessHandler) 9 | applicationListener(AuthenticationApplicationListener) 10 | //userDetailsService(org.mindinformatics.ann.framework.module.security.CustomUserDetailsService) 11 | 12 | iTripleStorePersistence(InMemoryTripleStorePersistenceImpl) { bean -> 13 | bean.autowire = 'byName' 14 | } 15 | 16 | //annotatorToOpenAnnotationConverter (org.mindinformatics.ann.framework.module.converter.AnnotatorToOpenAnnotationConverter) { bean -> 17 | // 18 | //} 19 | annotationConverter org.mindinformatics.ann.framework.module.converter.AnnotationConverter 20 | conversionService (org.springframework.context.support.ConversionServiceFactoryBean) { bean -> 21 | // bean.autowire = 'byName' 22 | converters = [ annotationConverter ] 23 | } 24 | customPropertyEditorRegistrar(org.mindinformatics.ann.framework.module.propertyeditors.CustomPropertyEditorRegistrar) 25 | 26 | dataSource(DataSource) { 27 | // mandatory 28 | driverClassName = '${dataSource.driverClassName}' 29 | username = '${dataSource.username}' 30 | password = '${dataSource.password}' 31 | url = '${dataSource.url}' 32 | // optional 33 | initialSize=25 34 | minEvictableIdleTimeMillis=1800000 35 | timeBetweenEvictionRunsMillis=1800000 36 | numTestsPerEvictionRun=3 37 | testOnBorrow=true 38 | testWhileIdle=true 39 | testOnReturn=true 40 | validationQuery="SELECT 1" 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /grails-app/controllers/org/mindinformatics/ann/catcha/ErrorController.groovy: -------------------------------------------------------------------------------- 1 | package org.mindinformatics.ann.catcha 2 | 3 | import grails.converters.JSON 4 | 5 | class ErrorController { 6 | 7 | def badRequest() { 8 | render([error: [code: 400, message: "Bad request"]] as JSON) 9 | } 10 | 11 | def unauthorized() { 12 | render([error: [code: 401, message: "Unauthorized user"]] as JSON) 13 | } 14 | 15 | def forbidden() { 16 | render([error: [code: 403, message: "Forbidden"]] as JSON) 17 | } 18 | 19 | def notFound() { 20 | //def result = [success:false, message: "Page not found" ] 21 | //render result as GSON 22 | render([error: [code: 404, message: "Resource not found"]] as JSON) 23 | } 24 | 25 | def methodNotAllowed() { 26 | render([error: [code: 405, message: "Method not allowed", method: request.method]] as JSON) 27 | } 28 | 29 | def serverError() { 30 | log.warn("Uncaught exception: " + request?.exception?.message, request?.exception); 31 | withFormat { 32 | json { 33 | render([error: [code: 500, message: request?.exception?.message, exception: request?.exception?.cause?.class?.name]] as JSON) 34 | } 35 | html { 36 | render(view: "/error") 37 | } 38 | } 39 | } 40 | 41 | def serviceUnavailable() { 42 | render([error: [code: 503, message: "Service unavailable"]] as JSON) 43 | } 44 | 45 | 46 | } -------------------------------------------------------------------------------- /grails-app/controllers/org/mindinformatics/ann/catcha/MainController.groovy: -------------------------------------------------------------------------------- 1 | package org.mindinformatics.ann.catcha 2 | 3 | class MainController { 4 | 5 | def index = { 6 | render (view: "/public/home", model:['menuitem':'home']) 7 | } 8 | def signup = { 9 | render (view: "/public/signup", model:['menuitem':'signup']) 10 | } 11 | def node = { 12 | render (view: "/public/node", model:['menuitem':'node']) 13 | } 14 | def credits = { 15 | render (view: "/public/credits", model:['menuitem':'credits']) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /grails-app/controllers/org/mindinformatics/ann/catcha/SecureController.groovy: -------------------------------------------------------------------------------- 1 | package org.mindinformatics.ann.catcha 2 | 3 | class SecureController { 4 | 5 | def home = { 6 | render (view: "home") 7 | } 8 | 9 | def upload = { 10 | render (view: "upload") 11 | } 12 | 13 | def uploadAnnotationFile() { 14 | def f = request.getFile('myFile') 15 | if (f.empty) { 16 | flash.message = 'file cannot be empty' 17 | render(view: 'uploadForm') 18 | return 19 | } 20 | f.transferTo(new File('/some/local/dir/myfile.txt')) 21 | response.sendError(200, 'Done') 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /grails-app/domain/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/grails-app/domain/.gitignore -------------------------------------------------------------------------------- /grails-app/i18n/messages.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=Property [{0}] of class [{1}] with value [{2}] does not match the required pattern [{3}] 2 | default.invalid.url.message=Property [{0}] of class [{1}] with value [{2}] is not a valid URL 3 | default.invalid.creditCard.message=Property [{0}] of class [{1}] with value [{2}] is not a valid credit card number 4 | default.invalid.email.message=Property [{0}] of class [{1}] with value [{2}] is not a valid e-mail address 5 | default.invalid.range.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid range from [{3}] to [{4}] 6 | default.invalid.size.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}] 7 | default.invalid.max.message=Property [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}] 8 | default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}] 9 | default.invalid.max.size.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}] 10 | default.invalid.min.size.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{3}] 11 | default.invalid.validator.message=Property [{0}] of class [{1}] with value [{2}] does not pass custom validation 12 | default.not.inlist.message=Property [{0}] of class [{1}] with value [{2}] is not contained within the list [{3}] 13 | default.blank.message=Property [{0}] of class [{1}] cannot be blank 14 | default.not.equal.message=Property [{0}] of class [{1}] with value [{2}] cannot equal [{3}] 15 | default.null.message=Property [{0}] of class [{1}] cannot be null 16 | default.not.unique.message=Property [{0}] of class [{1}] with value [{2}] must be unique 17 | 18 | default.paginate.prev=Previous 19 | default.paginate.next=Next 20 | default.boolean.true=True 21 | default.boolean.false=False 22 | default.date.format=yyyy-MM-dd HH:mm:ss z 23 | default.number.format=0 24 | 25 | default.created.message={0} {1} created 26 | default.updated.message={0} {1} updated 27 | default.deleted.message={0} {1} deleted 28 | default.not.deleted.message={0} {1} could not be deleted 29 | default.not.found.message={0} not found with id {1} 30 | default.optimistic.locking.failure=Another user has updated this {0} while you were editing 31 | 32 | default.home.label=Home 33 | default.list.label={0} List 34 | default.add.label=Add {0} 35 | default.new.label=New {0} 36 | default.create.label=Create {0} 37 | default.show.label=Show {0} 38 | default.edit.label=Edit {0} 39 | 40 | default.button.create.label=Create 41 | default.button.edit.label=Edit 42 | default.button.update.label=Update 43 | default.button.delete.label=Delete 44 | default.button.delete.confirm.message=Are you sure? 45 | 46 | # Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) 47 | typeMismatch.java.net.URL=Property {0} must be a valid URL 48 | typeMismatch.java.net.URI=Property {0} must be a valid URI 49 | typeMismatch.java.util.Date=Property {0} must be a valid Date 50 | typeMismatch.java.lang.Double=Property {0} must be a valid number 51 | typeMismatch.java.lang.Integer=Property {0} must be a valid number 52 | typeMismatch.java.lang.Long=Property {0} must be a valid number 53 | typeMismatch.java.lang.Short=Property {0} must be a valid number 54 | typeMismatch.java.math.BigDecimal=Property {0} must be a valid number 55 | typeMismatch.java.math.BigInteger=Property {0} must be a valid number 56 | -------------------------------------------------------------------------------- /grails-app/i18n/messages_cs_CZ.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] neodpovídá požadovanému vzoru [{3}] 2 | default.invalid.url.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] není validní URL 3 | default.invalid.creditCard.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] není validní číslo kreditní karty 4 | default.invalid.email.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] není validní emailová adresa 5 | default.invalid.range.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] není v povoleném rozmezí od [{3}] do [{4}] 6 | default.invalid.size.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] není v povoleném rozmezí od [{3}] do [{4}] 7 | default.invalid.max.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] překračuje maximální povolenou hodnotu [{3}] 8 | default.invalid.min.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] je menší než minimální povolená hodnota [{3}] 9 | default.invalid.max.size.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] překračuje maximální velikost [{3}] 10 | default.invalid.min.size.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] je menší než minimální velikost [{3}] 11 | default.invalid.validator.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] neprošla validací 12 | default.not.inlist.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] není obsažena v seznamu [{3}] 13 | default.blank.message=Položka [{0}] třídy [{1}] nemůže být prázdná 14 | default.not.equal.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] nemůže být stejná jako [{3}] 15 | default.null.message=Položka [{0}] třídy [{1}] nemůže být prázdná 16 | default.not.unique.message=Položka [{0}] třídy [{1}] o hodnotě [{2}] musí být unikátní 17 | 18 | default.paginate.prev=Předcházející 19 | default.paginate.next=Následující 20 | default.boolean.true=Pravda 21 | default.boolean.false=Nepravda 22 | default.date.format=dd. MM. yyyy HH:mm:ss z 23 | default.number.format=0 24 | 25 | default.created.message={0} {1} vytvořeno 26 | default.updated.message={0} {1} aktualizováno 27 | default.deleted.message={0} {1} smazáno 28 | default.not.deleted.message={0} {1} nelze smazat 29 | default.not.found.message={0} nenalezen s id {1} 30 | default.optimistic.locking.failure=Jiný uživatel aktualizoval záznam {0}, právě když byl vámi editován 31 | 32 | default.home.label=Domů 33 | default.list.label={0} Seznam 34 | default.add.label=Přidat {0} 35 | default.new.label=Nový {0} 36 | default.create.label=Vytvořit {0} 37 | default.show.label=Ukázat {0} 38 | default.edit.label=Editovat {0} 39 | 40 | default.button.create.label=Vytvoř 41 | default.button.edit.label=Edituj 42 | default.button.update.label=Aktualizuj 43 | default.button.delete.label=Smaž 44 | default.button.delete.confirm.message=Jste si jistý? 45 | 46 | # Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) 47 | typeMismatch.java.net.URL=Položka {0} musí být validní URL 48 | typeMismatch.java.net.URI=Položka {0} musí být validní URI 49 | typeMismatch.java.util.Date=Položka {0} musí být validní datum 50 | typeMismatch.java.lang.Double=Položka {0} musí být validní desetinné číslo 51 | typeMismatch.java.lang.Integer=Položka {0} musí být validní číslo 52 | typeMismatch.java.lang.Long=Položka {0} musí být validní číslo 53 | typeMismatch.java.lang.Short=Položka {0} musí být validní číslo 54 | typeMismatch.java.math.BigDecimal=Položka {0} musí být validní číslo 55 | typeMismatch.java.math.BigInteger=Položka {0} musí být validní číslo -------------------------------------------------------------------------------- /grails-app/i18n/messages_da.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] overholder ikke mønsteret [{3}] 2 | default.invalid.url.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] er ikke en gyldig URL 3 | default.invalid.creditCard.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] er ikke et gyldigt kreditkortnummer 4 | default.invalid.email.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] er ikke en gyldig e-mail adresse 5 | default.invalid.range.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] ligger ikke inden for intervallet fra [{3}] til [{4}] 6 | default.invalid.size.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] ligger ikke inden for størrelsen fra [{3}] til [{4}] 7 | default.invalid.max.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] overstiger den maksimale værdi [{3}] 8 | default.invalid.min.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] er under den minimale værdi [{3}] 9 | default.invalid.max.size.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] overstiger den maksimale størrelse på [{3}] 10 | default.invalid.min.size.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] er under den minimale størrelse på [{3}] 11 | default.invalid.validator.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] overholder ikke den brugerdefinerede validering 12 | default.not.inlist.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] findes ikke i listen [{3}] 13 | default.blank.message=Feltet [{0}] i klassen [{1}] kan ikke være tom 14 | default.not.equal.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] må ikke være [{3}] 15 | default.null.message=Feltet [{0}] i klassen [{1}] kan ikke være null 16 | default.not.unique.message=Feltet [{0}] i klassen [{1}] som har værdien [{2}] skal være unik 17 | 18 | default.paginate.prev=Forrige 19 | default.paginate.next=Næste 20 | default.boolean.true=Sand 21 | default.boolean.false=Falsk 22 | default.date.format=yyyy-MM-dd HH:mm:ss z 23 | default.number.format=0 24 | 25 | default.created.message={0} {1} oprettet 26 | default.updated.message={0} {1} opdateret 27 | default.deleted.message={0} {1} slettet 28 | default.not.deleted.message={0} {1} kunne ikke slettes 29 | default.not.found.message={0} med id {1} er ikke fundet 30 | default.optimistic.locking.failure=En anden bruger har opdateret denne {0} imens du har lavet rettelser 31 | 32 | default.home.label=Hjem 33 | default.list.label={0} Liste 34 | default.add.label=Tilføj {0} 35 | default.new.label=Ny {0} 36 | default.create.label=Opret {0} 37 | default.show.label=Vis {0} 38 | default.edit.label=Ret {0} 39 | 40 | default.button.create.label=Opret 41 | default.button.edit.label=Ret 42 | default.button.update.label=Opdater 43 | default.button.delete.label=Slet 44 | default.button.delete.confirm.message=Er du sikker? 45 | 46 | # Databindingsfejl. Brug "typeMismatch.$className.$propertyName for at passe til en given klasse (f.eks typeMismatch.Book.author) 47 | typeMismatch.java.net.URL=Feltet {0} skal være en valid URL 48 | typeMismatch.java.net.URI=Feltet {0} skal være en valid URI 49 | typeMismatch.java.util.Date=Feltet {0} skal være en valid Dato 50 | typeMismatch.java.lang.Double=Feltet {0} skal være et valid tal 51 | typeMismatch.java.lang.Integer=Feltet {0} skal være et valid tal 52 | typeMismatch.java.lang.Long=Feltet {0} skal være et valid tal 53 | typeMismatch.java.lang.Short=Feltet {0} skal være et valid tal 54 | typeMismatch.java.math.BigDecimal=Feltet {0} skal være et valid tal 55 | typeMismatch.java.math.BigInteger=Feltet {0} skal være et valid tal 56 | 57 | -------------------------------------------------------------------------------- /grails-app/i18n/messages_de.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] entspricht nicht dem vorgegebenen Muster [{3}] 2 | default.invalid.url.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist keine gültige URL 3 | default.invalid.creditCard.message=Das Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist keine gültige Kreditkartennummer 4 | default.invalid.email.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist keine gültige E-Mail Adresse 5 | default.invalid.range.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist nicht im Wertebereich von [{3}] bis [{4}] 6 | default.invalid.size.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist nicht im Wertebereich von [{3}] bis [{4}] 7 | default.invalid.max.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist größer als der Höchstwert von [{3}] 8 | default.invalid.min.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist kleiner als der Mindestwert von [{3}] 9 | default.invalid.max.size.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] übersteigt den Höchstwert von [{3}] 10 | default.invalid.min.size.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] unterschreitet den Mindestwert von [{3}] 11 | default.invalid.validator.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist ungültig 12 | default.not.inlist.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist nicht in der Liste [{3}] enthalten. 13 | default.blank.message=Die Eigenschaft [{0}] des Typs [{1}] darf nicht leer sein 14 | default.not.equal.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] darf nicht gleich [{3}] sein 15 | default.null.message=Die Eigenschaft [{0}] des Typs [{1}] darf nicht null sein 16 | default.not.unique.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] darf nur einmal vorkommen 17 | 18 | default.paginate.prev=Vorherige 19 | default.paginate.next=Nächste 20 | default.boolean.true=Wahr 21 | default.boolean.false=Falsch 22 | default.date.format=dd.MM.yyyy HH:mm:ss z 23 | default.number.format=0 24 | 25 | default.created.message={0} {1} wurde angelegt 26 | default.updated.message={0} {1} wurde geändert 27 | default.deleted.message={0} {1} wurde gelöscht 28 | default.not.deleted.message={0} {1} konnte nicht gelöscht werden 29 | default.not.found.message={0} mit der id {1} wurde nicht gefunden 30 | default.optimistic.locking.failure=Ein anderer Benutzer hat das {0} Object geändert während Sie es bearbeitet haben 31 | 32 | default.home.label=Home 33 | default.list.label={0} Liste 34 | default.add.label={0} hinzufügen 35 | default.new.label={0} anlegen 36 | default.create.label={0} anlegen 37 | default.show.label={0} anzeigen 38 | default.edit.label={0} bearbeiten 39 | 40 | default.button.create.label=Anlegen 41 | default.button.edit.label=Bearbeiten 42 | default.button.update.label=Aktualisieren 43 | default.button.delete.label=Löschen 44 | default.button.delete.confirm.message=Sind Sie sicher? 45 | 46 | # Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) 47 | typeMismatch.java.net.URL=Die Eigenschaft {0} muss eine gültige URL sein 48 | typeMismatch.java.net.URI=Die Eigenschaft {0} muss eine gültige URI sein 49 | typeMismatch.java.util.Date=Die Eigenschaft {0} muss ein gültiges Datum sein 50 | typeMismatch.java.lang.Double=Die Eigenschaft {0} muss eine gültige Zahl sein 51 | typeMismatch.java.lang.Integer=Die Eigenschaft {0} muss eine gültige Zahl sein 52 | typeMismatch.java.lang.Long=Die Eigenschaft {0} muss eine gültige Zahl sein 53 | typeMismatch.java.lang.Short=Die Eigenschaft {0} muss eine gültige Zahl sein 54 | typeMismatch.java.math.BigDecimal=Die Eigenschaft {0} muss eine gültige Zahl sein 55 | typeMismatch.java.math.BigInteger=Die Eigenschaft {0} muss eine gültige Zahl sein -------------------------------------------------------------------------------- /grails-app/i18n/messages_es.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no corresponde al patrón [{3}] 2 | default.invalid.url.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no es una URL válida 3 | default.invalid.creditCard.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no es un número de tarjeta de crédito válida 4 | default.invalid.email.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no es una dirección de correo electrónico válida 5 | default.invalid.range.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no entra en el rango válido de [{3}] a [{4}] 6 | default.invalid.size.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no entra en el tamaño válido de [{3}] a [{4}] 7 | default.invalid.max.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] excede el valor máximo [{3}] 8 | default.invalid.min.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] es menos que el valor mínimo [{3}] 9 | default.invalid.max.size.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] excede el tamaño máximo de [{3}] 10 | default.invalid.min.size.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] es menor que el tamaño mínimo de [{3}] 11 | default.invalid.validator.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no es válido 12 | default.not.inlist.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no esta contenido dentro de la lista [{3}] 13 | default.blank.message=La propiedad [{0}] de la clase [{1}] no puede ser vacía 14 | default.not.equal.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no puede igualar a [{3}] 15 | default.null.message=La propiedad [{0}] de la clase [{1}] no puede ser nulo 16 | default.not.unique.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] debe ser única 17 | 18 | default.paginate.prev=Anterior 19 | default.paginate.next=Siguiente 20 | default.boolean.true=Verdadero 21 | default.boolean.false=Falso 22 | default.date.format=yyyy-MM-dd HH:mm:ss z 23 | default.number.format=0 24 | 25 | default.created.message={0} {1} creado 26 | default.updated.message={0} {1} actualizado 27 | default.deleted.message={0} {1} eliminado 28 | default.not.deleted.message={0} {1} no puede eliminarse 29 | default.not.found.message=No se encuentra {0} con id {1} 30 | default.optimistic.locking.failure=Mientras usted editaba, otro usuario ha actualizado su {0} 31 | 32 | default.home.label=Principal 33 | default.list.label={0} Lista 34 | default.add.label=Agregar {0} 35 | default.new.label=Nuevo {0} 36 | default.create.label=Crear {0} 37 | default.show.label=Mostrar {0} 38 | default.edit.label=Editar {0} 39 | 40 | default.button.create.label=Crear 41 | default.button.edit.label=Editar 42 | default.button.update.label=Actualizar 43 | default.button.delete.label=Eliminar 44 | default.button.delete.confirm.message=¿Está usted seguro? 45 | 46 | # Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) 47 | typeMismatch.java.net.URL=La propiedad {0} debe ser una URL válida 48 | typeMismatch.java.net.URI=La propiedad {0} debe ser una URI válida 49 | typeMismatch.java.util.Date=La propiedad {0} debe ser una fecha válida 50 | typeMismatch.java.lang.Double=La propiedad {0} debe ser un número válido 51 | typeMismatch.java.lang.Integer=La propiedad {0} debe ser un número válido 52 | typeMismatch.java.lang.Long=La propiedad {0} debe ser un número válido 53 | typeMismatch.java.lang.Short=La propiedad {0} debe ser un número válido 54 | typeMismatch.java.math.BigDecimal=La propiedad {0} debe ser un número válido 55 | typeMismatch.java.math.BigInteger=La propiedad {0} debe ser un número válido -------------------------------------------------------------------------------- /grails-app/i18n/messages_fr.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] ne correspond pas au pattern [{3}] 2 | default.invalid.url.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas une URL valide 3 | default.invalid.creditCard.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas un numéro de carte de crédit valide 4 | default.invalid.email.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas une adresse e-mail valide 5 | default.invalid.range.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas contenue dans l'intervalle [{3}] à [{4}] 6 | default.invalid.size.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas contenue dans l'intervalle [{3}] à [{4}] 7 | default.invalid.max.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] est supérieure à la valeur maximum [{3}] 8 | default.invalid.min.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] est inférieure à la valeur minimum [{3}] 9 | default.invalid.max.size.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] est supérieure à la valeur maximum [{3}] 10 | default.invalid.min.size.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] est inférieure à la valeur minimum [{3}] 11 | default.invalid.validator.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas valide 12 | default.not.inlist.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] ne fait pas partie de la liste [{3}] 13 | default.blank.message=La propriété [{0}] de la classe [{1}] ne peut pas être vide 14 | default.not.equal.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] ne peut pas être égale à [{3}] 15 | default.null.message=La propriété [{0}] de la classe [{1}] ne peut pas être nulle 16 | default.not.unique.message=La propriété [{0}] de la classe [{1}] avec la valeur [{2}] doit être unique 17 | 18 | default.paginate.prev=Précédent 19 | default.paginate.next=Suivant 20 | -------------------------------------------------------------------------------- /grails-app/i18n/messages_it.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non corrisponde al pattern [{3}] 2 | default.invalid.url.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non è un URL valido 3 | default.invalid.creditCard.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non è un numero di carta di credito valido 4 | default.invalid.email.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non è un indirizzo email valido 5 | default.invalid.range.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non rientra nell'intervallo valido da [{3}] a [{4}] 6 | default.invalid.size.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non rientra nell'intervallo di dimensioni valide da [{3}] a [{4}] 7 | default.invalid.max.message=La proprietà [{0}] della classe [{1}] con valore [{2}] è maggiore di [{3}] 8 | default.invalid.min.message=La proprietà [{0}] della classe [{1}] con valore [{2}] è minore di [{3}] 9 | default.invalid.max.size.message=La proprietà [{0}] della classe [{1}] con valore [{2}] è maggiore di [{3}] 10 | default.invalid.min.size.message=La proprietà [{0}] della classe [{1}] con valore [{2}] è minore di [{3}] 11 | default.invalid.validator.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non è valida 12 | default.not.inlist.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non è contenuta nella lista [{3}] 13 | default.blank.message=La proprietà [{0}] della classe [{1}] non può essere vuota 14 | default.not.equal.message=La proprietà [{0}] della classe [{1}] con valore [{2}] non può essere uguale a [{3}] 15 | default.null.message=La proprietà [{0}] della classe [{1}] non può essere null 16 | default.not.unique.message=La proprietà [{0}] della classe [{1}] con valore [{2}] deve essere unica 17 | 18 | default.paginate.prev=Precedente 19 | default.paginate.next=Successivo 20 | default.boolean.true=Vero 21 | default.boolean.false=Falso 22 | default.date.format=dd/MM/yyyy HH:mm:ss z 23 | default.number.format=0 24 | 25 | default.created.message={0} {1} creato 26 | default.updated.message={0} {1} aggiornato 27 | default.deleted.message={0} {1} eliminato 28 | default.not.deleted.message={0} {1} non può essere eliminato 29 | default.not.found.message={0} non trovato con id {1} 30 | default.optimistic.locking.failure=Un altro utente ha aggiornato questo {0} mentre si era in modifica 31 | 32 | default.home.label=Home 33 | default.list.label={0} Elenco 34 | default.add.label=Aggiungi {0} 35 | default.new.label=Nuovo {0} 36 | default.create.label=Crea {0} 37 | default.show.label=Mostra {0} 38 | default.edit.label=Modifica {0} 39 | 40 | default.button.create.label=Crea 41 | default.button.edit.label=Modifica 42 | default.button.update.label=Aggiorna 43 | default.button.delete.label=Elimina 44 | default.button.delete.confirm.message=Si è sicuri? 45 | 46 | # Data binding errors. Usa "typeMismatch.$className.$propertyName per la personalizzazione (es typeMismatch.Book.author) 47 | typeMismatch.java.net.URL=La proprietà {0} deve essere un URL valido 48 | typeMismatch.java.net.URI=La proprietà {0} deve essere un URI valido 49 | typeMismatch.java.util.Date=La proprietà {0} deve essere una data valida 50 | typeMismatch.java.lang.Double=La proprietà {0} deve essere un numero valido 51 | typeMismatch.java.lang.Integer=La proprietà {0} deve essere un numero valido 52 | typeMismatch.java.lang.Long=La proprietà {0} deve essere un numero valido 53 | typeMismatch.java.lang.Short=La proprietà {0} deve essere un numero valido 54 | typeMismatch.java.math.BigDecimal=La proprietà {0} deve essere un numero valido 55 | typeMismatch.java.math.BigInteger=La proprietà {0} deve essere un numero valido 56 | -------------------------------------------------------------------------------- /grails-app/i18n/messages_ja.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、[{3}]パターンと一致していません。 2 | default.invalid.url.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、有効なURLではありません。 3 | default.invalid.creditCard.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、有効なクレジットカード番号ではありません。 4 | default.invalid.email.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、有効なメールアドレスではありません。 5 | default.invalid.range.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、[{3}]から[{4}]範囲内を指定してください。 6 | default.invalid.size.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、[{3}]から[{4}]以内を指定してください。 7 | default.invalid.max.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、最大値[{3}]より大きいです。 8 | default.invalid.min.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、最小値[{3}]より小さいです。 9 | default.invalid.max.size.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、最大値[{3}]より大きいです。 10 | default.invalid.min.size.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、最小値[{3}]より小さいです。 11 | default.invalid.validator.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、カスタムバリデーションを通過できません。 12 | default.not.inlist.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、[{3}]リスト内に存在しません。 13 | default.blank.message=[{1}]クラスのプロパティ[{0}]の空白は許可されません。 14 | default.not.equal.message=クラス[{1}]プロパティ[{0}]の値[{2}]は、[{3}]と同等ではありません。 15 | default.null.message=[{1}]クラスのプロパティ[{0}]にnullは許可されません。 16 | default.not.unique.message=クラス[{1}]プロパティ[{0}]の値[{2}]は既に使用されています。 17 | 18 | default.paginate.prev=戻る 19 | default.paginate.next=次へ 20 | default.boolean.true=はい 21 | default.boolean.false=いいえ 22 | default.date.format=yyyy/MM/dd HH:mm:ss z 23 | default.number.format=0 24 | 25 | default.created.message={0}(id:{1})を作成しました。 26 | default.updated.message={0}(id:{1})を更新しました。 27 | default.deleted.message={0}(id:{1})を削除しました。 28 | default.not.deleted.message={0}(id:{1})は削除できませんでした。 29 | default.not.found.message={0}(id:{1})は見つかりませんでした。 30 | default.optimistic.locking.failure=この{0}は編集中に他のユーザによって先に更新されています。 31 | 32 | default.home.label=ホーム 33 | default.list.label={0}リスト 34 | default.add.label={0}を追加 35 | default.new.label={0}を新規作成 36 | default.create.label={0}を作成 37 | default.show.label={0}詳細 38 | default.edit.label={0}を編集 39 | 40 | default.button.create.label=作成 41 | default.button.edit.label=編集 42 | default.button.update.label=更新 43 | default.button.delete.label=削除 44 | default.button.delete.confirm.message=本当に削除してよろしいですか? 45 | 46 | # Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) 47 | typeMismatch.java.net.URL={0}は有効なURLでなければなりません。 48 | typeMismatch.java.net.URI={0}は有効なURIでなければなりません。 49 | typeMismatch.java.util.Date={0}は有効な日付でなければなりません。 50 | typeMismatch.java.lang.Double={0}は有効な数値でなければなりません。 51 | typeMismatch.java.lang.Integer={0}は有効な数値でなければなりません。 52 | typeMismatch.java.lang.Long={0}は有効な数値でなければなりません。 53 | typeMismatch.java.lang.Short={0}は有効な数値でなければなりません。 54 | typeMismatch.java.math.BigDecimal={0}は有効な数値でなければなりません。 55 | typeMismatch.java.math.BigInteger={0}は有効な数値でなければなりません。 56 | -------------------------------------------------------------------------------- /grails-app/i18n/messages_nb.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] overholder ikke mønsteret [{3}] 2 | default.invalid.url.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er ikke en gyldig URL 3 | default.invalid.creditCard.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er ikke et gyldig kredittkortnummer 4 | default.invalid.email.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er ikke en gyldig epostadresse 5 | default.invalid.range.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er ikke innenfor intervallet [{3}] til [{4}] 6 | default.invalid.size.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er ikke innenfor intervallet [{3}] til [{4}] 7 | default.invalid.max.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] overstiger maksimumsverdien på [{3}] 8 | default.invalid.min.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er under minimumsverdien på [{3}] 9 | default.invalid.max.size.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] overstiger maksimumslengden på [{3}] 10 | default.invalid.min.size.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] er kortere enn minimumslengden på [{3}] 11 | default.invalid.validator.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] overholder ikke den brukerdefinerte valideringen 12 | default.not.inlist.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] finnes ikke i listen [{3}] 13 | default.blank.message=Feltet [{0}] i klassen [{1}] kan ikke være tom 14 | default.not.equal.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] kan ikke være [{3}] 15 | default.null.message=Feltet [{0}] i klassen [{1}] kan ikke være null 16 | default.not.unique.message=Feltet [{0}] i klassen [{1}] med verdien [{2}] må være unik 17 | 18 | default.paginate.prev=Forrige 19 | default.paginate.next=Neste 20 | default.boolean.true=Ja 21 | default.boolean.false=Nei 22 | default.date.format=dd.MM.yyyy HH:mm:ss z 23 | default.number.format=0 24 | 25 | default.created.message={0} {1} opprettet 26 | default.updated.message={0} {1} oppdatert 27 | default.deleted.message={0} {1} slettet 28 | default.not.deleted.message={0} {1} kunne ikke slettes 29 | default.not.found.message={0} med id {1} ble ikke funnet 30 | default.optimistic.locking.failure=En annen bruker har oppdatert denne {0} mens du redigerte 31 | 32 | default.home.label=Hjem 33 | default.list.label={0}liste 34 | default.add.label=Legg til {0} 35 | default.new.label=Ny {0} 36 | default.create.label=Opprett {0} 37 | default.show.label=Vis {0} 38 | default.edit.label=Endre {0} 39 | 40 | default.button.create.label=Opprett 41 | default.button.edit.label=Endre 42 | default.button.update.label=Oppdater 43 | default.button.delete.label=Slett 44 | default.button.delete.confirm.message=Er du sikker? 45 | 46 | # Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) 47 | typeMismatch.java.net.URL=Feltet {0} må være en gyldig URL 48 | typeMismatch.java.net.URI=Feltet {0} må være en gyldig URI 49 | typeMismatch.java.util.Date=Feltet {0} må være en gyldig dato 50 | typeMismatch.java.lang.Double=Feltet {0} må være et gyldig tall 51 | typeMismatch.java.lang.Integer=Feltet {0} må være et gyldig heltall 52 | typeMismatch.java.lang.Long=Feltet {0} må være et gyldig heltall 53 | typeMismatch.java.lang.Short=Feltet {0} må være et gyldig heltall 54 | typeMismatch.java.math.BigDecimal=Feltet {0} må være et gyldig tall 55 | typeMismatch.java.math.BigInteger=Feltet {0} må være et gyldig heltall 56 | 57 | -------------------------------------------------------------------------------- /grails-app/i18n/messages_nl.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] komt niet overeen met het vereiste patroon [{3}] 2 | default.invalid.url.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is geen geldige URL 3 | default.invalid.creditCard.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is geen geldig credit card nummer 4 | default.invalid.email.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is geen geldig e-mailadres 5 | default.invalid.range.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] valt niet in de geldige waardenreeks van [{3}] tot [{4}] 6 | default.invalid.size.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] valt niet in de geldige grootte van [{3}] tot [{4}] 7 | default.invalid.max.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] overschrijdt de maximumwaarde [{3}] 8 | default.invalid.min.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is minder dan de minimumwaarde [{3}] 9 | default.invalid.max.size.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] overschrijdt de maximumgrootte van [{3}] 10 | default.invalid.min.size.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is minder dan minimumgrootte van [{3}] 11 | default.invalid.validator.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is niet geldig 12 | default.not.inlist.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] komt niet voor in de lijst [{3}] 13 | default.blank.message=Attribuut [{0}] van entiteit [{1}] mag niet leeg zijn 14 | default.not.equal.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] mag niet gelijk zijn aan [{3}] 15 | default.null.message=Attribuut [{0}] van entiteit [{1}] mag niet leeg zijn 16 | default.not.unique.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] moet uniek zijn 17 | 18 | default.paginate.prev=Vorige 19 | default.paginate.next=Volgende 20 | default.boolean.true=Ja 21 | default.boolean.false=Nee 22 | default.date.format=dd-MM-yyyy HH:mm:ss z 23 | default.number.format=0 24 | 25 | default.created.message={0} {1} ingevoerd 26 | default.updated.message={0} {1} gewijzigd 27 | default.deleted.message={0} {1} verwijderd 28 | default.not.deleted.message={0} {1} kon niet worden verwijderd 29 | default.not.found.message={0} met id {1} kon niet worden gevonden 30 | default.optimistic.locking.failure=Een andere gebruiker heeft deze {0} al gewijzigd 31 | 32 | default.home.label=Home 33 | default.list.label={0} Overzicht 34 | default.add.label=Toevoegen {0} 35 | default.new.label=Invoeren {0} 36 | default.create.label=Invoeren {0} 37 | default.show.label=Details {0} 38 | default.edit.label=Wijzigen {0} 39 | 40 | default.button.create.label=Invoeren 41 | default.button.edit.label=Wijzigen 42 | default.button.update.label=Opslaan 43 | default.button.delete.label=Verwijderen 44 | default.button.delete.confirm.message=Weet je het zeker? 45 | 46 | # Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) 47 | typeMismatch.java.net.URL=Attribuut {0} is geen geldige URL 48 | typeMismatch.java.net.URI=Attribuut {0} is geen geldige URI 49 | typeMismatch.java.util.Date=Attribuut {0} is geen geldige datum 50 | typeMismatch.java.lang.Double=Attribuut {0} is geen geldig nummer 51 | typeMismatch.java.lang.Integer=Attribuut {0} is geen geldig nummer 52 | typeMismatch.java.lang.Long=Attribuut {0} is geen geldig nummer 53 | typeMismatch.java.lang.Short=Attribuut {0} is geen geldig nummer 54 | typeMismatch.java.math.BigDecimal=Attribuut {0} is geen geldig nummer 55 | typeMismatch.java.math.BigInteger=Attribuut {0} is geen geldig nummer 56 | -------------------------------------------------------------------------------- /grails-app/i18n/messages_pl.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Translated by Matthias Hryniszak - padcom@gmail.com 3 | # 4 | 5 | default.doesnt.match.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie pasuje do wymaganego wzorca [{3}] 6 | default.invalid.url.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] jest niepoprawnym adresem URL 7 | default.invalid.creditCard.message=Właściwość [{0}] klasy [{1}] with value [{2}] nie jest poprawnym numerem karty kredytowej 8 | default.invalid.email.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie jest poprawnym adresem e-mail 9 | default.invalid.range.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie zawiera się zakładanym zakresie od [{3}] do [{4}] 10 | default.invalid.size.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie zawiera się w zakładanym zakresie rozmiarów od [{3}] do [{4}] 11 | default.invalid.max.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] przekracza maksymalną wartość [{3}] 12 | default.invalid.min.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] jest mniejsza niż minimalna wartość [{3}] 13 | default.invalid.max.size.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] przekracza maksymalny rozmiar [{3}] 14 | default.invalid.min.size.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] jest mniejsza niż minimalny rozmiar [{3}] 15 | default.invalid.validator.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie spełnia założonych niestandardowych warunków 16 | default.not.inlist.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie zawiera się w liście [{3}] 17 | default.blank.message=Właściwość [{0}] klasy [{1}] nie może być pusta 18 | default.not.equal.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] nie może równać się [{3}] 19 | default.null.message=Właściwość [{0}] klasy [{1}] nie może być null 20 | default.not.unique.message=Właściwość [{0}] klasy [{1}] o wartości [{2}] musi być unikalna 21 | 22 | default.paginate.prev=Poprzedni 23 | default.paginate.next=Następny 24 | default.boolean.true=Prawda 25 | default.boolean.false=Fałsz 26 | default.date.format=yyyy-MM-dd HH:mm:ss z 27 | default.number.format=0 28 | 29 | default.created.message=Utworzono {0} {1} 30 | default.updated.message=Zaktualizowano {0} {1} 31 | default.deleted.message=Usunięto {0} {1} 32 | default.not.deleted.message={0} {1} nie mógł zostać usunięty 33 | default.not.found.message=Nie znaleziono {0} o id {1} 34 | default.optimistic.locking.failure=Inny użytkownik zaktualizował ten obiekt {0} w trakcie twoich zmian 35 | 36 | default.home.label=Strona domowa 37 | default.list.label=Lista {0} 38 | default.add.label=Dodaj {0} 39 | default.new.label=Utwórz {0} 40 | default.create.label=Utwórz {0} 41 | default.show.label=Pokaż {0} 42 | default.edit.label=Edytuj {0} 43 | 44 | default.button.create.label=Utwórz 45 | default.button.edit.label=Edytuj 46 | default.button.update.label=Zaktualizuj 47 | default.button.delete.label=Usuń 48 | default.button.delete.confirm.message=Czy jesteś pewien? 49 | 50 | # Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) 51 | typeMismatch.java.net.URL=Właściwość {0} musi być poprawnym adresem URL 52 | typeMismatch.java.net.URI=Właściwość {0} musi być poprawnym adresem URI 53 | typeMismatch.java.util.Date=Właściwość {0} musi być poprawną datą 54 | typeMismatch.java.lang.Double=Właściwość {0} musi być poprawnyą liczbą 55 | typeMismatch.java.lang.Integer=Właściwość {0} musi być poprawnyą liczbą 56 | typeMismatch.java.lang.Long=Właściwość {0} musi być poprawnyą liczbą 57 | typeMismatch.java.lang.Short=Właściwość {0} musi być poprawnyą liczbą 58 | typeMismatch.java.math.BigDecimal=Właściwość {0} musi być poprawnyą liczbą 59 | typeMismatch.java.math.BigInteger=Właściwość {0} musi być poprawnyą liczbą 60 | -------------------------------------------------------------------------------- /grails-app/i18n/messages_pt_BR.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Translated by Lucas Teixeira - lucastex@gmail.com 3 | # 4 | 5 | default.doesnt.match.message=O campo [{0}] da classe [{1}] com o valor [{2}] não atende ao padrão definido [{3}] 6 | default.invalid.url.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é uma URL válida 7 | default.invalid.creditCard.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é um número válido de cartão de crédito 8 | default.invalid.email.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é um endereço de email válido. 9 | default.invalid.range.message=O campo [{0}] da classe [{1}] com o valor [{2}] não está entre a faixa de valores válida de [{3}] até [{4}] 10 | default.invalid.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] não está na faixa de tamanho válida de [{3}] até [{4}] 11 | default.invalid.max.message=O campo [{0}] da classe [{1}] com o valor [{2}] ultrapass o valor máximo [{3}] 12 | default.invalid.min.message=O campo [{0}] da classe [{1}] com o valor [{2}] não atinge o valor mínimo [{3}] 13 | default.invalid.max.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] ultrapassa o tamanho máximo de [{3}] 14 | default.invalid.min.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] não atinge o tamanho mínimo de [{3}] 15 | default.invalid.validator.message=O campo [{0}] da classe [{1}] com o valor [{2}] não passou na validação 16 | default.not.inlist.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é um valor dentre os permitidos na lista [{3}] 17 | default.blank.message=O campo [{0}] da classe [{1}] não pode ficar em branco 18 | default.not.equal.message=O campo [{0}] da classe [{1}] com o valor [{2}] não pode ser igual a [{3}] 19 | default.null.message=O campo [{0}] da classe [{1}] não pode ser vazia 20 | default.not.unique.message=O campo [{0}] da classe [{1}] com o valor [{2}] deve ser único 21 | 22 | default.paginate.prev=Anterior 23 | default.paginate.next=Próximo 24 | default.boolean.true=Sim 25 | default.boolean.false=Não 26 | default.date.format=dd/MM/yyyy HH:mm:ss z 27 | default.number.format=0 28 | 29 | default.created.message={0} {1} criado 30 | default.updated.message={0} {1} atualizado 31 | default.deleted.message={0} {1} removido 32 | default.not.deleted.message={0} {1} não pode ser removido 33 | default.not.found.message={0} não foi encontrado com id {1} 34 | default.optimistic.locking.failure=Outro usuário atualizou este [{0}] enquanto você tentou salvá-lo 35 | 36 | default.home.label=Principal 37 | default.list.label={0} Listagem 38 | default.add.label=Adicionar {0} 39 | default.new.label=Novo {0} 40 | default.create.label=Criar {0} 41 | default.show.label=Ver {0} 42 | default.edit.label=Editar {0} 43 | 44 | default.button.create.label=Criar 45 | default.button.edit.label=Editar 46 | default.button.update.label=Alterar 47 | default.button.delete.label=Remover 48 | default.button.delete.confirm.message=Tem certeza? 49 | 50 | # Mensagens de erro em atribuição de valores. Use "typeMismatch.$className.$propertyName" para customizar (eg typeMismatch.Book.author) 51 | typeMismatch.java.net.URL=O campo {0} deve ser uma URL válida. 52 | typeMismatch.java.net.URI=O campo {0} deve ser uma URI válida. 53 | typeMismatch.java.util.Date=O campo {0} deve ser uma data válida 54 | typeMismatch.java.lang.Double=O campo {0} deve ser um número válido. 55 | typeMismatch.java.lang.Integer=O campo {0} deve ser um número válido. 56 | typeMismatch.java.lang.Long=O campo {0} deve ser um número válido. 57 | typeMismatch.java.lang.Short=O campo {0} deve ser um número válido. 58 | typeMismatch.java.math.BigDecimal=O campo {0} deve ser um número válido. 59 | typeMismatch.java.math.BigInteger=O campo {0} deve ser um número válido. -------------------------------------------------------------------------------- /grails-app/i18n/messages_pt_PT.properties: -------------------------------------------------------------------------------- 1 | # 2 | # translation by miguel.ping@gmail.com, based on pt_BR translation by Lucas Teixeira - lucastex@gmail.com 3 | # 4 | 5 | default.doesnt.match.message=O campo [{0}] da classe [{1}] com o valor [{2}] não corresponde ao padrão definido [{3}] 6 | default.invalid.url.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é um URL válido 7 | default.invalid.creditCard.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é um número válido de cartão de crédito 8 | default.invalid.email.message=O campo [{0}] da classe [{1}] com o valor [{2}] não é um endereço de email válido. 9 | default.invalid.range.message=O campo [{0}] da classe [{1}] com o valor [{2}] não está dentro dos limites de valores válidos de [{3}] a [{4}] 10 | default.invalid.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] está fora dos limites de tamanho válido de [{3}] a [{4}] 11 | default.invalid.max.message=O campo [{0}] da classe [{1}] com o valor [{2}] ultrapassa o valor máximo [{3}] 12 | default.invalid.min.message=O campo [{0}] da classe [{1}] com o valor [{2}] não atinge o valor mínimo [{3}] 13 | default.invalid.max.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] ultrapassa o tamanho máximo de [{3}] 14 | default.invalid.min.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] não atinge o tamanho mínimo de [{3}] 15 | default.invalid.validator.message=O campo [{0}] da classe [{1}] com o valor [{2}] não passou na validação 16 | default.not.inlist.message=O campo [{0}] da classe [{1}] com o valor [{2}] não se encontra nos valores permitidos da lista [{3}] 17 | default.blank.message=O campo [{0}] da classe [{1}] não pode ser vazio 18 | default.not.equal.message=O campo [{0}] da classe [{1}] com o valor [{2}] não pode ser igual a [{3}] 19 | default.null.message=O campo [{0}] da classe [{1}] não pode ser vazio 20 | default.not.unique.message=O campo [{0}] da classe [{1}] com o valor [{2}] deve ser único 21 | 22 | default.paginate.prev=Anterior 23 | default.paginate.next=Próximo 24 | 25 | # Mensagens de erro em atribuição de valores. Use "typeMismatch.$className.$propertyName" para personalizar(eg typeMismatch.Book.author) 26 | typeMismatch.java.net.URL=O campo {0} deve ser um URL válido. 27 | typeMismatch.java.net.URI=O campo {0} deve ser um URI válido. 28 | typeMismatch.java.util.Date=O campo {0} deve ser uma data válida 29 | typeMismatch.java.lang.Double=O campo {0} deve ser um número válido. 30 | typeMismatch.java.lang.Integer=O campo {0} deve ser um número válido. 31 | typeMismatch.java.lang.Long=O campo {0} deve ser um número valido. 32 | typeMismatch.java.lang.Short=O campo {0} deve ser um número válido. 33 | typeMismatch.java.math.BigDecimal=O campo {0} deve ser um número válido. 34 | typeMismatch.java.math.BigInteger=O campo {0} deve ser um número válido. 35 | -------------------------------------------------------------------------------- /grails-app/i18n/messages_ru.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=Значение [{2}] поля [{0}] класса [{1}] не соответствует образцу [{3}] 2 | default.invalid.url.message=Значение [{2}] поля [{0}] класса [{1}] не является допустимым URL-адресом 3 | default.invalid.creditCard.message=Значение [{2}] поля [{0}] класса [{1}] не является допустимым номером кредитной карты 4 | default.invalid.email.message=Значение [{2}] поля [{0}] класса [{1}] не является допустимым e-mail адресом 5 | default.invalid.range.message=Значение [{2}] поля [{0}] класса [{1}] не попадает в допустимый интервал от [{3}] до [{4}] 6 | default.invalid.size.message=Размер поля [{0}] класса [{1}] (значение: [{2}]) не попадает в допустимый интервал от [{3}] до [{4}] 7 | default.invalid.max.message=Значение [{2}] поля [{0}] класса [{1}] больше чем максимально допустимое значение [{3}] 8 | default.invalid.min.message=Значение [{2}] поля [{0}] класса [{1}] меньше чем минимально допустимое значение [{3}] 9 | default.invalid.max.size.message=Размер поля [{0}] класса [{1}] (значение: [{2}]) больше чем максимально допустимый размер [{3}] 10 | default.invalid.min.size.message=Размер поля [{0}] класса [{1}] (значение: [{2}]) меньше чем минимально допустимый размер [{3}] 11 | default.invalid.validator.message=Значение [{2}] поля [{0}] класса [{1}] не допустимо 12 | default.not.inlist.message=Значение [{2}] поля [{0}] класса [{1}] не попадает в список допустимых значений [{3}] 13 | default.blank.message=Поле [{0}] класса [{1}] не может быть пустым 14 | default.not.equal.message=Значение [{2}] поля [{0}] класса [{1}] не может быть равно [{3}] 15 | default.null.message=Поле [{0}] класса [{1}] не может иметь значение null 16 | default.not.unique.message=Значение [{2}] поля [{0}] класса [{1}] должно быть уникальным 17 | 18 | default.paginate.prev=Предыдушая страница 19 | default.paginate.next=Следующая страница 20 | 21 | # Ошибки при присвоении данных. Для точной настройки для полей классов используйте 22 | # формат "typeMismatch.$className.$propertyName" (например, typeMismatch.Book.author) 23 | typeMismatch.java.net.URL=Значение поля {0} не является допустимым URL 24 | typeMismatch.java.net.URI=Значение поля {0} не является допустимым URI 25 | typeMismatch.java.util.Date=Значение поля {0} не является допустимой датой 26 | typeMismatch.java.lang.Double=Значение поля {0} не является допустимым числом 27 | typeMismatch.java.lang.Integer=Значение поля {0} не является допустимым числом 28 | typeMismatch.java.lang.Long=Значение поля {0} не является допустимым числом 29 | typeMismatch.java.lang.Short=Значение поля {0} не является допустимым числом 30 | typeMismatch.java.math.BigDecimal=Значение поля {0} не является допустимым числом 31 | typeMismatch.java.math.BigInteger=Значение поля {0} не является допустимым числом 32 | -------------------------------------------------------------------------------- /grails-app/i18n/messages_sv.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=Attributet [{0}] för klassen [{1}] med värde [{2}] matchar inte mot uttrycket [{3}] 2 | default.invalid.url.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är inte en giltig URL 3 | default.invalid.creditCard.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är inte ett giltigt kreditkortsnummer 4 | default.invalid.email.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är inte en giltig e-postadress 5 | default.invalid.range.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är inte inom intervallet [{3}] till [{4}] 6 | default.invalid.size.message=Attributet [{0}] för klassen [{1}] med värde [{2}] har en storlek som inte är inom [{3}] till [{4}] 7 | default.invalid.max.message=Attributet [{0}] för klassen [{1}] med värde [{2}] överskrider maxvärdet [{3}] 8 | default.invalid.min.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är mindre än minimivärdet [{3}] 9 | default.invalid.max.size.message=Attributet [{0}] för klassen [{1}] med värde [{2}] överskrider maxstorleken [{3}] 10 | default.invalid.min.size.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är mindre än minimistorleken [{3}] 11 | default.invalid.validator.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är inte giltigt enligt anpassad regel 12 | default.not.inlist.message=Attributet [{0}] för klassen [{1}] med värde [{2}] är inte giltigt, måste vara ett av [{3}] 13 | default.blank.message=Attributet [{0}] för klassen [{1}] får inte vara tomt 14 | default.not.equal.message=Attributet [{0}] för klassen [{1}] med värde [{2}] får inte vara lika med [{3}] 15 | default.null.message=Attributet [{0}] för klassen [{1}] får inte vara tomt 16 | default.not.unique.message=Attributet [{0}] för klassen [{1}] med värde [{2}] måste vara unikt 17 | 18 | default.paginate.prev=Föregående 19 | default.paginate.next=Nästa 20 | default.boolean.true=Sant 21 | default.boolean.false=Falskt 22 | default.date.format=yyyy-MM-dd HH:mm:ss z 23 | default.number.format=0 24 | 25 | default.created.message={0} {1} skapades 26 | default.updated.message={0} {1} uppdaterades 27 | default.deleted.message={0} {1} borttagen 28 | default.not.deleted.message={0} {1} kunde inte tas bort 29 | default.not.found.message={0} med id {1} kunde inte hittas 30 | default.optimistic.locking.failure=En annan användare har uppdaterat det här {0} objektet medan du redigerade det 31 | 32 | default.home.label=Hem 33 | default.list.label= {0} - Lista 34 | default.add.label=Lägg till {0} 35 | default.new.label=Skapa {0} 36 | default.create.label=Skapa {0} 37 | default.show.label=Visa {0} 38 | default.edit.label=Ändra {0} 39 | 40 | default.button.create.label=Skapa 41 | default.button.edit.label=Ändra 42 | default.button.update.label=Uppdatera 43 | default.button.delete.label=Ta bort 44 | default.button.delete.confirm.message=Är du säker? 45 | 46 | # Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) 47 | typeMismatch.java.net.URL=Värdet för {0} måste vara en giltig URL 48 | typeMismatch.java.net.URI=Värdet för {0} måste vara en giltig URI 49 | typeMismatch.java.util.Date=Värdet {0} måste vara ett giltigt datum 50 | typeMismatch.java.lang.Double=Värdet {0} måste vara ett giltigt nummer 51 | typeMismatch.java.lang.Integer=Värdet {0} måste vara ett giltigt heltal 52 | typeMismatch.java.lang.Long=Värdet {0} måste vara ett giltigt heltal 53 | typeMismatch.java.lang.Short=Värdet {0} måste vara ett giltigt heltal 54 | typeMismatch.java.math.BigDecimal=Värdet {0} måste vara ett giltigt nummer 55 | typeMismatch.java.math.BigInteger=Värdet {0} måste vara ett giltigt heltal -------------------------------------------------------------------------------- /grails-app/i18n/messages_th.properties: -------------------------------------------------------------------------------- 1 | default.doesnt.match.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ถูกต้องตามรูปแบบที่กำหนดไว้ใน [{3}] 2 | default.invalid.url.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ถูกต้องตามรูปแบบ URL 3 | default.invalid.creditCard.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ถูกต้องตามรูปแบบหมายเลขบัตรเครดิต 4 | default.invalid.email.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ถูกต้องตามรูปแบบอีเมล์ 5 | default.invalid.range.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ได้มีค่าที่ถูกต้องในช่วงจาก [{3}] ถึง [{4}] 6 | default.invalid.size.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ได้มีขนาดที่ถูกต้องในช่วงจาก [{3}] ถึง [{4}] 7 | default.invalid.max.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] มีค่าเกิดกว่าค่ามากสุด [{3}] 8 | default.invalid.min.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] มีค่าน้อยกว่าค่าต่ำสุด [{3}] 9 | default.invalid.max.size.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] มีขนาดเกินกว่าขนาดมากสุดของ [{3}] 10 | default.invalid.min.size.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] มีขนาดต่ำกว่าขนาดต่ำสุดของ [{3}] 11 | default.invalid.validator.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ผ่านการทวนสอบค่าที่ตั้งขึ้น 12 | default.not.inlist.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ได้อยู่ในรายการต่อไปนี้ [{3}] 13 | default.blank.message=คุณสมบัติ [{0}] ของคลาส [{1}] ไม่สามารถเป็นค่าว่างได้ 14 | default.not.equal.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่สามารถเท่ากับ [{3}] ได้ 15 | default.null.message=คุณสมบัติ [{0}] ของคลาส [{1}] ไม่สามารถเป็น null ได้ 16 | default.not.unique.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] จะต้องไม่ซ้ำ (unique) 17 | 18 | default.paginate.prev=ก่อนหน้า 19 | default.paginate.next=ถัดไป 20 | default.boolean.true=จริง 21 | default.boolean.false=เท็จ 22 | default.date.format=dd-MM-yyyy HH:mm:ss z 23 | default.number.format=0 24 | 25 | default.created.message=สร้าง {0} {1} เรียบร้อยแล้ว 26 | default.updated.message=ปรับปรุง {0} {1} เรียบร้อยแล้ว 27 | default.deleted.message=ลบ {0} {1} เรียบร้อยแล้ว 28 | default.not.deleted.message=ไม่สามารถลบ {0} {1} 29 | default.not.found.message=ไม่พบ {0} ด้วย id {1} นี้ 30 | default.optimistic.locking.failure=มีผู้ใช้ท่านอื่นปรับปรุง {0} ขณะที่คุณกำลังแก้ไขข้อมูลอยู่ 31 | 32 | default.home.label=หน้าแรก 33 | default.list.label=รายการ {0} 34 | default.add.label=เพิ่ม {0} 35 | default.new.label=สร้าง {0} ใหม่ 36 | default.create.label=สร้าง {0} 37 | default.show.label=แสดง {0} 38 | default.edit.label=แก้ไข {0} 39 | 40 | default.button.create.label=สร้าง 41 | default.button.edit.label=แก้ไข 42 | default.button.update.label=ปรับปรุง 43 | default.button.delete.label=ลบ 44 | default.button.delete.confirm.message=คุณแน่ใจหรือไม่ ? 45 | 46 | # Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) 47 | typeMismatch.java.net.URL=คุณสมบัติ '{0}' จะต้องเป็นค่า URL ที่ถูกต้อง 48 | typeMismatch.java.net.URI=คุณสมบัติ '{0}' จะต้องเป็นค่า URI ที่ถูกต้อง 49 | typeMismatch.java.util.Date=คุณสมบัติ '{0}' จะต้องมีค่าเป็นวันที่ 50 | typeMismatch.java.lang.Double=คุณสมบัติ '{0}' จะต้องมีค่าเป็นจำนวนประเภท Double 51 | typeMismatch.java.lang.Integer=คุณสมบัติ '{0}' จะต้องมีค่าเป็นจำนวนประเภท Integer 52 | typeMismatch.java.lang.Long=คุณสมบัติ '{0}' จะต้องมีค่าเป็นจำนวนประเภท Long 53 | typeMismatch.java.lang.Short=คุณสมบัติ '{0}' จะต้องมีค่าเป็นจำนวนประเภท Short 54 | typeMismatch.java.math.BigDecimal=คุณสมบัติ '{0}' จะต้องมีค่าเป็นจำนวนประเภท BigDecimal 55 | typeMismatch.java.math.BigInteger=คุณสมบัติ '{0}' จะต้องมีค่าเป็นจำนวนประเภท BigInteger 56 | -------------------------------------------------------------------------------- /grails-app/i18n/messages_zh_CN.properties: -------------------------------------------------------------------------------- 1 | default.blank.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u4E0D\u80FD\u4E3A\u7A7A 2 | default.doesnt.match.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0E\u5B9A\u4E49\u7684\u6A21\u5F0F [{3}]\u4E0D\u5339\u914D 3 | default.invalid.creditCard.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684\u4FE1\u7528\u5361\u53F7 4 | default.invalid.email.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u662F\u4E00\u4E2A\u5408\u6CD5\u7684\u7535\u5B50\u90AE\u4EF6\u5730\u5740 5 | default.invalid.max.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u6BD4\u6700\u5927\u503C [{3}]\u8FD8\u5927 6 | default.invalid.max.size.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u7684\u5927\u5C0F\u6BD4\u6700\u5927\u503C [{3}]\u8FD8\u5927 7 | default.invalid.min.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u6BD4\u6700\u5C0F\u503C [{3}]\u8FD8\u5C0F 8 | default.invalid.min.size.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u7684\u5927\u5C0F\u6BD4\u6700\u5C0F\u503C [{3}]\u8FD8\u5C0F 9 | default.invalid.range.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u5728\u5408\u6CD5\u7684\u8303\u56F4\u5185( [{3}] \uFF5E [{4}] ) 10 | default.invalid.size.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u7684\u5927\u5C0F\u4E0D\u5728\u5408\u6CD5\u7684\u8303\u56F4\u5185( [{3}] \uFF5E [{4}] ) 11 | default.invalid.url.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u662F\u4E00\u4E2A\u5408\u6CD5\u7684URL 12 | default.invalid.validator.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u672A\u80FD\u901A\u8FC7\u81EA\u5B9A\u4E49\u7684\u9A8C\u8BC1 13 | default.not.equal.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0E[{3}]\u4E0D\u76F8\u7B49 14 | default.not.inlist.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u5728\u5217\u8868\u7684\u53D6\u503C\u8303\u56F4\u5185 15 | default.not.unique.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u5FC5\u987B\u662F\u552F\u4E00\u7684 16 | default.null.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u4E0D\u80FD\u4E3Anull 17 | default.paginate.next=\u4E0B\u9875 18 | default.paginate.prev=\u4E0A\u9875 19 | -------------------------------------------------------------------------------- /grails-app/migrations/changelog-2014-02-20-1242.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "jmiranda (generated)", id: "1424455190494-1") { 4 | addColumn(tableName: "system_api") { 5 | column(name: "secret_key", type: "varchar(255)") 6 | } 7 | } 8 | 9 | changeSet(author: "jmiranda (generated)", id: "1424455190494-2") { 10 | grailsChange { 11 | change { 12 | sql.execute("UPDATE system_api SET secret_key = apikey WHERE secret_key IS NULL") 13 | confirm "Successfully set secret key for existing API systems." 14 | } 15 | } 16 | 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /grails-app/migrations/changelog-2014-02-20-1300.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "jmiranda (generated)", id: "1424455279294-2") { 4 | modifyDataType(columnName: "json", newDataType: "text", tableName: "annotation") 5 | } 6 | 7 | changeSet(author: "jmiranda (generated)", id: "1424455279294-3") { 8 | addNotNullConstraint(columnDataType: "text", columnName: "json", tableName: "annotation") 9 | } 10 | 11 | changeSet(author: "jmiranda (generated)", id: "1424455279294-4") { 12 | modifyDataType(columnName: "quote", newDataType: "text", tableName: "annotation") 13 | } 14 | 15 | changeSet(author: "jmiranda (generated)", id: "1424455279294-5") { 16 | modifyDataType(columnName: "text", newDataType: "text", tableName: "annotation") 17 | } 18 | 19 | changeSet(author: "jmiranda (generated)", id: "1424455279294-6") { 20 | modifyDataType(columnName: "uri", newDataType: "varchar(2048)", tableName: "annotation") 21 | } 22 | 23 | changeSet(author: "jmiranda (generated)", id: "1424455279294-7") { 24 | addNotNullConstraint(columnDataType: "varchar(2048)", columnName: "uri", tableName: "annotation") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /grails-app/migrations/changelog-2015-06-03-1244.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "jmiranda (generated)", id: "1433349892335-1") { 4 | modifyDataType(columnName: "json", newDataType: "text", tableName: "annotation") 5 | } 6 | 7 | changeSet(author: "jmiranda (generated)", id: "1433349892335-2") { 8 | modifyDataType(columnName: "quote", newDataType: "text", tableName: "annotation") 9 | } 10 | 11 | changeSet(author: "jmiranda (generated)", id: "1433349892335-3") { 12 | modifyDataType(columnName: "text", newDataType: "text", tableName: "annotation") 13 | } 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /grails-app/migrations/changelog-2015-06-03-1436.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "jmiranda (generated)", id: "1433356780261-1") { 4 | addColumn(tableName: "annotation") { 5 | column(name: "collection_id", type: "varchar(255)") 6 | } 7 | } 8 | 9 | changeSet(author: "jmiranda (generated)", id: "1433356780261-2") { 10 | addColumn(tableName: "annotation") { 11 | column(name: "context_id", type: "varchar(255)") 12 | } 13 | } 14 | 15 | changeSet(author: "jmiranda (generated)", id: "1433356780261-3") { 16 | validCheckSum '3:4480a9efb9e64b70af3604da4486a6cb' 17 | createIndex(indexName: "annotation_source_idx", tableName: "annotation") { 18 | column(name: "source(255)") 19 | } 20 | } 21 | 22 | changeSet(author: "jmiranda (generated)", id: "1433356780261-4") { 23 | validCheckSum '3:244fe5c7e0bff85f8b214d43566a40bb' 24 | createIndex(indexName: "annotation_uri_idx", tableName: "annotation") { 25 | column(name: "uri(255)") 26 | } 27 | } 28 | 29 | 30 | changeSet(author: "jmiranda (generated)", id: "1433356780261-5") { 31 | createIndex(indexName: "annotation_user_idx", tableName: "annotation") { 32 | column(name: "userid") 33 | column(name: "username") 34 | } 35 | } 36 | 37 | changeSet(author: "jmiranda (generated)", id: "1433356780261-6") { 38 | createIndex(indexName: "annotation_media_idx", tableName: "annotation") { 39 | column(name: "media") 40 | } 41 | } 42 | 43 | changeSet(author: "jmiranda (generated)", id: "1433356780261-7") { 44 | createIndex(indexName: "annotation_context_idx", tableName: "annotation") { 45 | column(name: "collection_id") 46 | column(name: "context_id") 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /grails-app/migrations/changelog-2016-03-13-2007.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "jmiranda (generated)", id: "1457917690694-1") { 4 | validCheckSum "3:39c19021bd3b9bac7fa720cb69bc39e4" 5 | addNotNullConstraint(columnDataType: "text", columnName: "json", tableName: "annotation") 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /grails-app/migrations/changelog-2016-03-13-2027.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "jmiranda (generated)", id: "1457918899928-1") { 4 | createTable(tableName: "annotation_permission") { 5 | column(autoIncrement: "true", name: "id", type: "bigint") { 6 | constraints(nullable: "false", primaryKey: "true", primaryKeyName: "annotation_pePK") 7 | } 8 | 9 | column(name: "version", type: "bigint") { 10 | constraints(nullable: "false") 11 | } 12 | 13 | column(name: "annotation_id", type: "bigint") { 14 | constraints(nullable: "false") 15 | } 16 | 17 | column(name: "permission", type: "varchar(255)") { 18 | constraints(nullable: "false") 19 | } 20 | 21 | column(name: "user_id", type: "bigint") 22 | } 23 | } 24 | 25 | changeSet(author: "jmiranda (generated)", id: "1457918899928-2") { 26 | createTable(tableName: "annotation_user") { 27 | column(autoIncrement: "true", name: "id", type: "bigint") { 28 | constraints(nullable: "false", primaryKey: "true", primaryKeyName: "annotation_usPK") 29 | } 30 | 31 | column(name: "version", type: "bigint") { 32 | constraints(nullable: "false") 33 | } 34 | 35 | column(name: "email", type: "varchar(255)") { 36 | constraints(nullable: "false") 37 | } 38 | 39 | column(name: "user_id", type: "varchar(255)") { 40 | constraints(nullable: "false") 41 | } 42 | 43 | column(name: "username", type: "varchar(255)") { 44 | constraints(nullable: "false") 45 | } 46 | } 47 | } 48 | 49 | changeSet(author: "jmiranda (generated)", id: "1457918899928-3") { 50 | createIndex(indexName: "FK23C0ACDF28835BA1", tableName: "annotation_permission") { 51 | column(name: "annotation_id") 52 | } 53 | } 54 | 55 | changeSet(author: "jmiranda (generated)", id: "1457918899928-4") { 56 | createIndex(indexName: "FK23C0ACDF3B26FA70", tableName: "annotation_permission") { 57 | column(name: "user_id") 58 | } 59 | } 60 | 61 | changeSet(author: "jmiranda (generated)", id: "1457918899928-6") { 62 | addForeignKeyConstraint(baseColumnNames: "annotation_id", baseTableName: "annotation_permission", constraintName: "FK23C0ACDF28835BA1", deferrable: "false", initiallyDeferred: "false", referencedColumnNames: "id", referencedTableName: "annotation", referencesUniqueColumn: "false") 63 | } 64 | 65 | changeSet(author: "jmiranda (generated)", id: "1457918899928-7") { 66 | addForeignKeyConstraint(baseColumnNames: "user_id", baseTableName: "annotation_permission", constraintName: "FK23C0ACDF3B26FA70", deferrable: "false", initiallyDeferred: "false", referencedColumnNames: "id", referencedTableName: "annotation_user", referencesUniqueColumn: "false") 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /grails-app/migrations/changelog-2016-03-13-2154.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "jmiranda (generated)", id: "1457924249816-1") { 4 | dropForeignKeyConstraint(baseTableName: "annotation", constraintName: "FKA34FEB2F575B432E") 5 | } 6 | 7 | changeSet(author: "jmiranda (generated)", id: "1457924249816-2") { 8 | modifyDataType(columnName: "owner_id", newDataType: "bigint", tableName: "annotation") 9 | } 10 | 11 | changeSet(author: "jmiranda (generated)", id: "1457924249816-3") { 12 | addForeignKeyConstraint(baseColumnNames: "owner_id", baseTableName: "annotation", constraintName: "FKA34FEB2FA70DAA88", deferrable: "false", initiallyDeferred: "false", referencedColumnNames: "id", referencedTableName: "annotation_user", referencesUniqueColumn: "false") 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /grails-app/migrations/changelog-2016-03-14-0142.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "jmiranda (generated)", id: "1457937795254-1") { 4 | dropNotNullConstraint(columnDataType: "varchar(255)", columnName: "email", tableName: "annotation_user") 5 | } 6 | 7 | changeSet(author: "jmiranda (generated)", id: "1457937795254-2") { 8 | dropNotNullConstraint(columnDataType: "varchar(255)", columnName: "user_id", tableName: "annotation_user") 9 | } 10 | 11 | changeSet(author: "jmiranda (generated)", id: "1457937795254-3") { 12 | dropNotNullConstraint(columnDataType: "varchar(255)", columnName: "username", tableName: "annotation_user") 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /grails-app/migrations/changelog.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | include file: 'create-schema.groovy' 3 | 4 | 5 | include file: 'update-schema-feb-06-2014.groovy' 6 | 7 | include file: 'changelog-2014-02-20-1242.groovy' 8 | 9 | include file: 'changelog-2014-02-20-1300.groovy' 10 | 11 | include file: 'changelog-2015-06-03-1244.groovy' 12 | 13 | include file: 'changelog-2015-06-03-1436.groovy' 14 | 15 | include file: 'changelog-2016-03-13-2007.groovy' 16 | 17 | include file: 'changelog-2016-03-13-2027.groovy' 18 | 19 | include file: 'changelog-2016-03-13-2154.groovy' 20 | 21 | include file: 'changelog-2016-03-14-0142.groovy' 22 | } 23 | -------------------------------------------------------------------------------- /grails-app/migrations/update-schema-feb-06-2014.groovy: -------------------------------------------------------------------------------- 1 | databaseChangeLog = { 2 | 3 | changeSet(author: "jmiranda (generated)", id: "1391669329771-1") { 4 | createTable(tableName: "annotation_tags") { 5 | column(name: "annotation_id", type: "bigint") { 6 | constraints(nullable: "false") 7 | } 8 | 9 | column(name: "tag_id", type: "bigint") { 10 | constraints(nullable: "false") 11 | } 12 | } 13 | } 14 | 15 | changeSet(author: "jmiranda (generated)", id: "1391669329771-2") { 16 | modifyDataType(columnName: "json", newDataType: "text", tableName: "annotation") 17 | } 18 | 19 | changeSet(author: "jmiranda (generated)", id: "1391669329771-3") { 20 | modifyDataType(columnName: "quote", newDataType: "text", tableName: "annotation") 21 | } 22 | 23 | changeSet(author: "jmiranda (generated)", id: "1391669329771-4") { 24 | modifyDataType(columnName: "text", newDataType: "text", tableName: "annotation") 25 | } 26 | 27 | changeSet(author: "jmiranda (generated)", id: "1391669329771-5") { 28 | modifyDataType(columnName: "uri", newDataType: "text", tableName: "annotation") 29 | } 30 | 31 | changeSet(author: "jmiranda (generated)", id: "1391669329771-6") { 32 | addPrimaryKey(columnNames: "annotation_id, tag_id", tableName: "annotation_tags") 33 | } 34 | 35 | changeSet(author: "jmiranda (generated)", id: "1391669329771-7") { 36 | validCheckSum '3:ac5a6caf2c4be46d7bd830c40a2e38c9' 37 | dropForeignKeyConstraint(baseTableName: "tag", constraintName: "FK1BF9A28835BA1") 38 | } 39 | 40 | changeSet(author: "jmiranda (generated)", id: "1391669329771-10") { 41 | createIndex(indexName: "FK6E8FA72928835BA1", tableName: "annotation_tags") { 42 | column(name: "annotation_id") 43 | } 44 | } 45 | 46 | changeSet(author: "jmiranda (generated)", id: "1391669329771-11") { 47 | createIndex(indexName: "FK6E8FA729C33ED913", tableName: "annotation_tags") { 48 | column(name: "tag_id") 49 | } 50 | } 51 | 52 | changeSet(author: "jmiranda (generated)", id: "1391669329771-12") { 53 | dropColumn(columnName: "annotation_id", tableName: "tag") 54 | } 55 | 56 | changeSet(author: "jmiranda (generated)", id: "1391669329771-8") { 57 | addForeignKeyConstraint(baseColumnNames: "annotation_id", baseTableName: "annotation_tags", constraintName: "FK6E8FA72928835BA1", deferrable: "false", initiallyDeferred: "false", referencedColumnNames: "id", referencedTableName: "annotation", referencesUniqueColumn: "false") 58 | } 59 | 60 | changeSet(author: "jmiranda (generated)", id: "1391669329771-9") { 61 | addForeignKeyConstraint(baseColumnNames: "tag_id", baseTableName: "annotation_tags", constraintName: "FK6E8FA729C33ED913", deferrable: "false", initiallyDeferred: "false", referencedColumnNames: "id", referencedTableName: "tag", referencesUniqueColumn: "false") 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /grails-app/services/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/grails-app/services/.gitignore -------------------------------------------------------------------------------- /grails-app/taglib/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/grails-app/taglib/.gitignore -------------------------------------------------------------------------------- /grails-app/utils/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/grails-app/utils/.gitignore -------------------------------------------------------------------------------- /grails-app/views/error.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <g:if env="development">Grails Runtime Exception</g:if><g:else>Error</g:else> 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
    14 |
  • An error has occurred
  • 15 |
16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /grails-app/views/index.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Welcome to Grails 6 | 82 | 83 | 84 | 85 | 105 |
106 |

Welcome to Grails

107 |

Congratulations, you have successfully started your first Grails application! At the moment 108 | this is the default page, feel free to modify it to either redirect to a controller or display whatever 109 | content you may choose. Below is a list of controllers that are currently deployed in this application, 110 | click on each to execute its default action:

111 | 112 | 120 |
121 | 122 | 123 | -------------------------------------------------------------------------------- /grails-app/views/info.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <g:meta name="app.name"/> - powered by Annotation Framework 6 | 82 | 83 | 84 |
85 | 105 |
106 |

- powered by Annotation Framework

107 |

You are running the powered by Annotation Framework. 108 |
109 | 110 |
111 | 112 |

120 | 121 | 131 | 132 |

About

133 |
134 | project is 135 | part of the Annotation Framework.
136 | The Application has been originally coded by Dr. Paolo Ciccarese.
137 | The code is available on GitHub. 138 |
139 |
140 | 141 | 142 | -------------------------------------------------------------------------------- /grails-app/views/layouts/main.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | <g:layoutTitle default="Grails"/> 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /grails-app/views/public/_existing-systems.gsp: -------------------------------------------------------------------------------- 1 |

Systems connected to CATCH-A

2 |
    3 |
  • 4 |

    Domeo Toolkit Highbrow - 5 | It is an experimental "genome browser" for literary texts. It is an html5-based visualization tool that plots the density of scholarly references or other annotations (such as pattern matches results or arbitrary scores) from multiple sources onto literary works. Highbrow provides a quick, high level overview of the areas of the text that are of most interest to different commentators or match certain patterns, and shows increasingly detailed information about these regions as the user zooms in. 6 |

    Continue Reading »

    7 |
  • 8 |
  • 9 |

    Domeo Toolkit Domeo - 10 | It is an extensible web application enabling users to visually and efficiently create and share ontology-based stand-off annotation on HTML or XML document targets. The tool supports manual, fully automated, and semi-automated annotation with complete provenance records, as well as personal or community annotation with access authorization and control.

    11 |

    Continue Reading »

    12 |
  • 13 | <%-- 14 |
  • 15 |

    Library Cloud - Coming soon

    16 |

    Continue Reading »

    17 |
  • 18 | --%> 19 |
-------------------------------------------------------------------------------- /grails-app/views/public/_homepage-content.gsp: -------------------------------------------------------------------------------- 1 |
2 |

About CATCH-A

3 |

Common Annotation,Tagging and Citation (CATC) API is a unified public open API that will enable storing, searching, discovering, sharing and analyzing scholarly annotations produced on four digital media types - text, image, audio and video - across existing pedagogical and research tools at Harvard.

4 |
-------------------------------------------------------------------------------- /grails-app/views/public/_navigation.gsp: -------------------------------------------------------------------------------- 1 |
2 | 24 |
-------------------------------------------------------------------------------- /grails-app/views/public/credits.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Credits :: ${grailsApplication.config.af.shared.title} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /grails-app/views/public/home.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Home :: ${grailsApplication.config.af.shared.title} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /grails-app/views/public/node.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Node Info :: ${grailsApplication.config.af.shared.title} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /grails-app/views/public/signup.gsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Sign up :: ${grailsApplication.config.af.shared.title} 10 | 11 | 12 | 13 |
14 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /grails-app/views/secure/_navigation.gsp: -------------------------------------------------------------------------------- 1 |
2 | 47 |
48 | 49 | <%-- 50 |
  • Open ID
  • 51 |
  • Open ID
  • 52 | --%> -------------------------------------------------------------------------------- /grails-app/views/secure/_upload-banner.gsp: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 | 5 | 6 | 8 | 14 | 16 | 22 | 24 | 30 | 31 | 32 | 33 | 42 | 46 | 47 | 48 | 54 | 55 | 60 | 61 |
    7 | 9 |
    10 |

    Upload

    11 |

    Accepted formats: json.
    Max file size 2Mb.

    12 |
    13 |
    15 | 17 |
    18 |

    Validate

    19 |

    Against the Open Annotation model.

    20 |
    21 |
    23 | 25 |
    26 |

    Save

    27 |

    Save your annotation in the hub.

    28 |
    29 |
    34 |
    35 |
    36 |
    37 |
    38 |
    39 |
     
    40 |
    41 |
    43 |
     
    44 |
    45 |
    49 |
    50 | 51 |
    52 |
    53 |
      56 | 59 |
    62 |
    63 | 64 |
    65 |
    -------------------------------------------------------------------------------- /grails-app/views/secure/home.gsp: -------------------------------------------------------------------------------- 1 | 2 | <%@ page import="org.mindinformatics.ann.framework.module.security.users.User" %> 3 | <%@ page import="org.mindinformatics.ann.framework.module.security.users.UserRole" %> 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Home :: ${grailsApplication.config.af.shared.title} 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /grails-app/views/secure/upload.gsp: -------------------------------------------------------------------------------- 1 | 2 | <%@ page import="org.mindinformatics.ann.framework.module.security.users.User" %> 3 | <%@ page import="org.mindinformatics.ann.framework.module.security.users.UserRole" %> 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Upload :: ${grailsApplication.config.af.shared.title} 12 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /grails-app/views/shared/_banner.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 43 |
    -------------------------------------------------------------------------------- /grails-app/views/shared/_content.gsp: -------------------------------------------------------------------------------- 1 | 2 |
    3 |
    4 |
    5 |
    6 |
    7 |
    8 | 9 |
    10 |
    11 | 12 |
    13 |
    14 |
    15 |
    16 |
    17 |
    18 |
    -------------------------------------------------------------------------------- /grails-app/views/shared/_copyright.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 36 |
    -------------------------------------------------------------------------------- /grails-app/views/shared/_credits-banner.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 34 |
    -------------------------------------------------------------------------------- /grails-app/views/shared/_credits-team.gsp: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 | 5 |
    6 |

    ${grailsApplication.config.af.shared.logo.title} Team

    7 | 8 | 9 | 12 | 22 | 23 |
    10 | 11 | 13 |

    Paolo Ciccarese, PhD

    14 |

    Dr. Paolo Ciccarese is the architect and principal developer of CATCH. 15 | Paolo is assistant in neuroscience at Mass General Hospital and 16 | Instructor in Neurology at Harvard Medical School. 17 | Paolo is interested in enabling personal and community-driven knowledge acquisition, curation and sharing. 18 | Paolo has been working on scientific discourse representation in Alzheimer's Disease research and he is 19 | currently exploring the use of Annotation of digital resources for supporting the knowledge creation process in both scholarly and research settings. 20 | Paolo is the author of Annotation Ontology (AO) and is currently co-chair of the W3C Open Annotation Community Group.

    21 |
    24 |
    25 | 26 |
    27 |
    28 |
    -------------------------------------------------------------------------------- /grails-app/views/shared/_footer.gsp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /grails-app/views/shared/_logo.gsp: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /grails-app/views/shared/_node-banner.gsp: -------------------------------------------------------------------------------- 1 |
    2 | 58 |
    -------------------------------------------------------------------------------- /grails-app/views/shared/_scripts.gsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | --%> 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /grails-app/views/shared/_signupTerms.gsp: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |

    ${grailsApplication.config.af.shared.name} :: Terms and Conditions

    5 |

    This is a W3C compliant free website template from OS Templates. This template is distributed using a Website Template Licence.

    6 |

    You can use and modify the template for both personal and commercial use. You must keep all copyright information and credit links in the template and associated files. For more CSS templates visit Free Website Templates.

    7 |
      8 |
    • Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    • 9 |
    • Etiam vel sapien et est adipiscing commodo.
    • 10 |
    • Duis pharetra eleifend sapien, id faucibus dolor rutrum et.
    • 11 |
    • Donec et dui dolor, in lacinia leo.
    • 12 |
    • Mauris posuere tellus ac purus adipiscing dapibus.
    • 13 |
    14 |

    Vestibulumaccumsan egestibulum eu justo convallis augue estas aenean elit intesque sed. Facilispede estibulum nulla orna nisl velit elit ac aliquat non tincidunt. Namjusto cras urna urnaretra lor urna neque sed quis orci nulla. Laoremut vitae doloreet condimentumst phasellentes dolor ut a ipsum id consectetus. Inpede cumst vitae ris tellentesque fring intesquet nibh fames nulla curabitudin.

    15 |
      16 |
    1. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    2. 17 |
    3. Etiam vel sapien et est adipiscing commodo.
    4. 18 |
    5. Duis pharetra eleifend sapien, id faucibus dolor rutrum et.
    6. 19 |
    7. Donec et dui dolor, in lacinia leo.
    8. 20 |
    9. Mauris posuere tellus ac purus adipiscing dapibus.
    10. 21 |
    22 |
    23 |
    24 |
    -------------------------------------------------------------------------------- /grails-app/views/shared/_title-and-icon.gsp: -------------------------------------------------------------------------------- 1 | 2 | <g:layoutTitle default="Domeo Framework Toolkit"/> 3 | -------------------------------------------------------------------------------- /grails-app/views/shared/_wide.gsp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: CATCH-A 2 | site_description: 3 | site_author: Justin Miranda 4 | theme: readthedocs 5 | repo_url: https://github.com/annotationsatharvard/catcha 6 | include_search: true 7 | #use_absolute_urls: true 8 | use_directory_urls: true 9 | copyright: Copyright © 2015, CATCH-A 10 | google_analytics: ['UA-61763038-2', 'CATCH-A'] 11 | markdown_extensions: [toc, tables, fenced_code] 12 | pages: 13 | - ['index.md', 'Introduction'] 14 | 15 | # About 16 | #- ['about/license.md', 'About', 'License'] 17 | #- ['about/release-notes.md', 'About', 'Release Notes'] 18 | #- ['about/changelog.md', 'About', 'Change Log'] 19 | #- ['about/contributing.md', 'About', 'Contributing'] 20 | 21 | # Admin Guide 22 | #- ['admin-guide/index.md', 'Admin Guide', 'Overview'] 23 | - ['admin-guide/installation.md', 'Admin Guide', 'Installation'] 24 | - ['admin-guide/getting-started.md', 'Admin Guide', 'Getting Started'] 25 | #- ['admin-guide/configuration.md', 'Admin Guide', 'Configuration'] 26 | - ['admin-guide/upgrade.md', 'Admin Guide', 'Upgrading'] 27 | - ['admin-guide/getting-support.md', 'Admin Guide', 'Getting Support'] 28 | 29 | # HOWTO Guide 30 | - ['admin-guide/mysql.md', 'HOWTO Guide', 'MySQL HOWTO'] 31 | - ['admin-guide/tomcat.md', 'HOWTO Guide', 'Tomcat HOWTO'] 32 | - ['admin-guide/ubuntu.md', 'HOWTO Guide', 'Ubuntu HOWTO'] 33 | 34 | # Deployment Guide 35 | #- ['admin-guide/deployment/aws-ec2.md', 'Deployment Guide', 'AWS Elastic Compute Cloud'] 36 | #- ['admin-guide/deployment/aws-ebs.md', 'Deployment Guide', 'AWS Elastic Beanstalk'] 37 | #- ['admin-guide/deployment/digital-ocean.md', 'Deployment Guide', 'Digital Ocean'] 38 | #- ['admin-guide/deployment/docker.md', 'Deployment Guide', 'Docker'] 39 | 40 | 41 | # User Guide 42 | #- ['user-guide/index.md', 'User Guide', 'Overview'] 43 | - ['user-guide/getting-started.md', 'User Guide', 'Getting Started'] 44 | - ['user-guide/api.md', 'User Guide', 'API Docs'] 45 | - ['user-guide/api-errors.md', 'User Guide', 'API Error Handling'] 46 | - ['user-guide/authentication.md', 'User Guide', 'Authentication'] 47 | - ['user-guide/annotatorjs.md', 'User Guide', 'AnnotatorJs'] 48 | 49 | # Developer Guide 50 | #- ['developer-guide/index.md', 'Developer Guide', 'Overview'] 51 | - ['developer-guide/getting-started.md', 'Developer Guide', 'Getting Started'] 52 | 53 | # Deployment Guide 54 | 55 | # Configuration 56 | #- ['configuration.md', 'Configuration', 'Configuration'] 57 | 58 | # Installation Guide 59 | #- ['installation/ubuntu.md', 'Installation', 'Ubuntu'] 60 | #- ['installation/mac.md', 'Installation', 'Mac OS X'] 61 | #- ['installation/windows.md', 'Installation', 'Windows'] 62 | 63 | # HowTo 64 | # Continuous Integration 65 | 66 | # Releases: 67 | #- ['release-notes.md', 'Releases', 'Release Notes'] 68 | -------------------------------------------------------------------------------- /src/groovy/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/src/groovy/.gitignore -------------------------------------------------------------------------------- /src/java/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/src/java/.gitignore -------------------------------------------------------------------------------- /test/functional/org/mindinformatics/ann/catcha/AnnotatorApiTests.groovy: -------------------------------------------------------------------------------- 1 | package org.mindinformatics.ann.catcha 2 | 3 | //import com.grailsrocks.functionaltest.APITestCase 4 | //import com.grailsrocks.functionaltest.BrowserTestCase 5 | import functionaltestplugin.FunctionalTestCase 6 | import grails.converters.JSON 7 | 8 | class AnnotatorApiTests extends FunctionalTestCase { 9 | 10 | def validToken = 'eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHRcL3BsYWluIiwidHlwIjoiSldTIn0.eyJjb25zdW1lcktleSI6IjBjYmZhMzcwLWI3M2MtNGUzYS1hZTQ2LTU4MmRmMjg0YjdjMyIsImlzc3VlZEF0IjoiMjAxNC0wOC0yOFQwMzoyNToyOC0wNDAwIiwidXNlcklkIjoiam1pcmFuZGEiLCJqdGkiOiI5ZWVkNjdhZC04ZmExLTRiYTItOWExOS1jOGY3YTBhZDUzNTAiLCJ0dGwiOjg2NDAwLCJpYXQiOjE0MDkyNTM5Mjh9.LOoRN_xJeV4QEL22puG3eA65wX5qsTHmb_a7RKnmJEA' 11 | 12 | void testGenerateToken() { 13 | get('/annotator/token') { 14 | headers['x-annotator-auth-token'] = validToken 15 | //headers['Content-Type'] = 'application/json' 16 | } 17 | assertStatus 200 18 | println "RESPONSE: " + page 19 | //assertContentType("application/json") 20 | //def json = JSON.parse(page.inputStream.text) 21 | //println "RESPONSE: " + json 22 | //assert json.data.connection != null 23 | //assert json.data.connection.id == 2 24 | } 25 | 26 | void testCreateAnnotation() { 27 | post('/annotator/create') { 28 | headers['x-annotator-auth-token'] = validToken 29 | headers['Content-Type'] = 'application/json' 30 | body { 31 | """ 32 | {"tags":["longs"],"citation":"Wu, Jingzi, 1701-1754. The Scholars. [Translated by Yang Hsien-yi and Gladys Yang. Author's port. and illus. by Cheng Shih-fa] Peking, Foreign Languages Press, 1957. Pages 49-51","text":"","created":"2014-06-29T07:25:07.498Z","updated":"2014-06-29T07:25:07.498Z","quote":"Xia","ranges":[{"endOffset":346,"start":"/textannotation[1]/p[10]","end":"/textannotation[1]/p[10]","startOffset":343}],"permissions":{"update":["micazorla@yahoo.es"],"admin":["micazorla@yahoo.es"],"delete":["micazorla@yahoo.es"],"read":[]},"parent":"0","uri":"https://courses.edx.org/courses/HarvardX/SW12.6x/2T2014/courseware/f9ec9c0c7bb8498d814684358b6e8b0f/0134825cf0f34fd68516ff4018d3ead4/1","media":"text","user":{"id":"micazorla@yahoo.es","name":"Mila1969"}} 33 | """ 34 | } 35 | } 36 | } 37 | 38 | 39 | void testReadAnnotation() { 40 | get('/annotator/read/1') { 41 | headers['x-annotator-auth-token'] = validToken 42 | headers['Content-Type'] = 'application/json' 43 | } 44 | assertStatus 200 45 | assertContentType("application/json") 46 | def json = JSON.parse(page.inputStream.text) 47 | println "RESPONSE: " + json 48 | //assert json.data.connection != null 49 | //assert json.data.connection.id == 2 50 | } 51 | 52 | void testUpdateAnnotation() { 53 | post('/annotator/update/1') { 54 | headers['x-annotator-auth-token'] = validToken 55 | headers['Content-Type'] = 'application/json' 56 | body { 57 | """ 58 | {"id":1, "tags":["longs"],"citation":"Wu, Jingzi, 1701-1754. The Scholars. [Translated by Yang Hsien-yi and Gladys Yang. Author's port. and illus. by Cheng Shih-fa] Peking, Foreign Languages Press, 1957. Pages 49-51","text":"","created":"2014-06-29T07:25:07.498Z","updated":"2014-06-29T07:25:07.498Z","quote":"Xia","ranges":[{"endOffset":346,"start":"/textannotation[1]/p[10]","end":"/textannotation[1]/p[10]","startOffset":343}],"permissions":{"update":["micazorla@yahoo.es"],"admin":["micazorla@yahoo.es"],"delete":["micazorla@yahoo.es"],"read":[]},"parent":"0","uri":"https://courses.edx.org/courses/HarvardX/SW12.6x/2T2014/courseware/f9ec9c0c7bb8498d814684358b6e8b0f/0134825cf0f34fd68516ff4018d3ead4/1","media":"text","user":{"id":"micazorla@yahoo.es","name":"Mila1969"}} 59 | """ 60 | } 61 | } 62 | } 63 | 64 | void testUpdateAnnotationWithoutId() { 65 | post('/annotator/update/1') { 66 | headers['x-annotator-auth-token'] = validToken 67 | headers['Content-Type'] = 'application/json' 68 | body { 69 | """ 70 | {"tags":["longs"],"citation":"Wu, Jingzi, 1701-1754. The Scholars. [Translated by Yang Hsien-yi and Gladys Yang. Author's port. and illus. by Cheng Shih-fa] Peking, Foreign Languages Press, 1957. Pages 49-51","text":"","created":"2014-06-29T07:25:07.498Z","updated":"2014-06-29T07:25:07.498Z","quote":"Xia","ranges":[{"endOffset":346,"start":"/textannotation[1]/p[10]","end":"/textannotation[1]/p[10]","startOffset":343}],"permissions":{"update":["micazorla@yahoo.es"],"admin":["micazorla@yahoo.es"],"delete":["micazorla@yahoo.es"],"read":[]},"parent":"0","uri":"https://courses.edx.org/courses/HarvardX/SW12.6x/2T2014/courseware/f9ec9c0c7bb8498d814684358b6e8b0f/0134825cf0f34fd68516ff4018d3ead4/1","media":"text","user":{"id":"micazorla@yahoo.es","name":"Mila1969"}} 71 | """ 72 | } 73 | } 74 | } 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /test/integration/org/mindinformatics/ann/framework/module/converter/ConversionServiceTests.groovy: -------------------------------------------------------------------------------- 1 | package org.mindinformatics.ann.framework.module.converter 2 | 3 | import org.joda.time.format.DateTimeFormatter 4 | import org.joda.time.format.ISODateTimeFormat 5 | import org.junit.After 6 | import org.junit.Before 7 | import org.junit.Test 8 | import org.mindinformatics.ann.framework.module.converter.AnnotationConverter; 9 | import org.mindinformatics.ann.framework.module.persistence.Annotation 10 | 11 | import java.text.SimpleDateFormat 12 | 13 | import static org.junit.Assert.assertEquals 14 | import static org.junit.Assert.fail 15 | 16 | /** 17 | * 18 | */ 19 | class ConversionServiceTests { 20 | 21 | def conversionService 22 | 23 | @Before 24 | void setUp() { 25 | // Setup logic here 26 | } 27 | 28 | @After 29 | void tearDown() { 30 | // Tear down logic here 31 | } 32 | 33 | @Test 34 | void converter_shouldReturnAnnotationClone() { 35 | def annotation = new Annotation(id: 1, uri: "this-uri", json: "{'id':1, 'uri':'this-uri'}") 36 | def converter = new AnnotationConverter() 37 | def annotationConverted = converter.convert(annotation) 38 | assertEquals annotation.id, annotationConverted.id 39 | } 40 | 41 | @Test 42 | void conversionService_shouldReturnAnnotationClone() { 43 | def annotation = new Annotation(id: 1, uri: "this-uri", json: "{'id':1, 'uri':'this-uri'}") 44 | def converter = new AnnotationConverter() 45 | def annotationConverted = conversionService.convert(annotation, Annotation.class) 46 | assertEquals annotationConverted.id, annotation.id 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /test/integration/org/mindinformatics/ann/framework/module/persistence/RefreshAnnotationsTests.groovy: -------------------------------------------------------------------------------- 1 | package org.mindinformatics.ann.framework.module.persistence 2 | 3 | import grails.converters.JSON 4 | import org.junit.After 5 | import org.junit.Before 6 | import org.junit.Ignore 7 | import org.junit.Test 8 | 9 | import javax.script.ScriptEngine 10 | import javax.script.ScriptEngineManager 11 | 12 | //@TestFor(AnnotatorService) 13 | //@Mock([Annotation,Tag]) 14 | class RefreshAnnotationsTests extends GroovyTestCase { 15 | 16 | def annotatorService 17 | 18 | @Before 19 | void setUp() { 20 | 21 | } 22 | 23 | @After 24 | void tearDown() { 25 | // Tear down logic here 26 | } 27 | 28 | 29 | @Test 30 | void testRefreshAnnotations() { 31 | annotatorService.refreshAnnotations([max:1000]) 32 | annotatorService.refreshAnnotations([max:2000]) 33 | annotatorService.refreshAnnotations([max:5000]) 34 | annotatorService.refreshAnnotations([max:10000]) 35 | annotatorService.refreshAnnotations([max:30000]) 36 | } 37 | 38 | 39 | @Ignore 40 | void testSomething() { 41 | println "Testing something" 42 | 43 | /* 44 | def annotations = Annotation.list() 45 | assert annotations != null 46 | assert annotations.size() == 1 47 | annotations.each { 48 | println new URL(it.uri).getText() 49 | } 50 | */ 51 | 52 | // def localPath = "edx.html" 53 | // def remoteUrl = "https://courses.edx.org/courses/HarvardX/AI12.2x/2013_SOND/courseware/fe939c73594e454da10d734884e54db2/016f704dd546408998ab2c2545878d89/" 54 | // def user = "jcm62%40columbia.edu" 55 | // def passwd = "password" 56 | // new File(localPath).withOutputStream { out -> 57 | // def url = new URL(remoteUrl).openConnection() 58 | // def remoteAuth = "Basic " + "${user}:${passwd}".getBytes().encodeBase64().toString() 59 | // url.setRequestProperty("Authorization", remoteAuth); 60 | // out << url.getInputStream() 61 | // } 62 | 63 | def remoteUrl = "https://courses.edx.org/courses/HarvardX/AI12.2x/2013_SOND/courseware/fe939c73594e454da10d734884e54db2/016f704dd546408998ab2c2545878d89/" 64 | remoteUrl += ";sessionid=9acd66a84226f27f0c8ec4aee026e836" 65 | //def authString = "jcm62%40columbia.edu:password".getBytes().encodeBase64().toString() 66 | 67 | def conn = remoteUrl.toURL().openConnection() 68 | //conn.setRequestProperty( "Authorization", "Basic ${authString}" ) 69 | if( conn.responseCode == 200 ) { 70 | def feed = conn.content.text 71 | println feed 72 | // Work with the xml document 73 | 74 | } else { 75 | println "Something bad happened." 76 | println "${conn.responseCode}: ${conn.responseMessage}" 77 | } 78 | 79 | } 80 | 81 | 82 | @Ignore 83 | void testMe() { 84 | 85 | ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript"); 86 | println "hello world (" + engine.toString() + ")"; 87 | 88 | } 89 | 90 | @Ignore 91 | void testSomethingElse() { 92 | def annotations = Annotation.list([max: 10, sort: "dateCreated", order: "desc"]) 93 | println annotations.size() 94 | 95 | def dir = '/home/jmiranda/Desktop/poetry/:2' 96 | def map = [1:[],2:[],3:[]] 97 | def list = [] 98 | new File(dir).eachFileRecurse{ list<< it } 99 | list.each { 100 | if (it.isFile()) { 101 | println "* " + it.absolutePath 102 | def index = (it.absolutePath - dir).substring(2,3) 103 | println " >> " + index 104 | try { 105 | String content = new File(it.absolutePath).text 106 | if (content) { 107 | def rootNode = new XmlSlurper().parseText(content) 108 | println rootNode 109 | 110 | def fileList = map[index] 111 | if (!fileList) { 112 | fileList = [] 113 | } 114 | fileList << content 115 | map[index] = fileList 116 | } 117 | } catch (RuntimeException e) { 118 | e.printStackTrace() 119 | } catch (Exception e) { 120 | e.printStackTrace() 121 | } 122 | } 123 | } 124 | def found = [:] 125 | annotations.each { annotation -> 126 | //"ranges":[{"endOffset":60,"start":"/annotatable[1]/p[8]/font[1]","end":"/annotatable[1]/p[9]/font[1]","startOffset":0}] 127 | //println annotation.json 128 | def jsonObject = JSON.parse(annotation.json) 129 | def start = jsonObject.ranges.start 130 | def end = jsonObject.ranges.end 131 | def startOffset = jsonObject.ranges.startOffset 132 | def endOffset = jsonObject.ranges.endOffset 133 | 134 | println "Ranges:" + start + ":" + end + ":" + endOffset + ":" + startOffset 135 | 136 | //println "annotation: " + annotation.id + " " + annotation.uri 137 | map.each {k,v-> 138 | //println "key " + k 139 | v.each { contents -> 140 | //println "v: " + contents.size() 141 | if (annotation.quote) { 142 | //println "check for quote " + annotation.quote 143 | if (contents.indexOf(annotation.quote)) { 144 | //println "Found one! " + k + " " + k.class 145 | if (!found[k]) { 146 | found[k] = 0 147 | } 148 | found[k]++ 149 | } 150 | } 151 | 152 | } 153 | 154 | } 155 | } 156 | println found 157 | 158 | 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /test/unit/org/annotationframework/AuthTokenServiceTests.groovy: -------------------------------------------------------------------------------- 1 | package org.annotationframework 2 | 3 | import grails.buildtestdata.mixin.Build 4 | import grails.test.mixin.* 5 | import org.junit.* 6 | import org.mindinformatics.ann.framework.module.security.systems.SystemApi 7 | 8 | /** 9 | * See the API for {@link grails.test.mixin.services.ServiceUnitTestMixin} for usage instructions 10 | */ 11 | @TestFor(AuthTokenService) 12 | @Build([SystemApi]) 13 | @Mock([SystemApi]) 14 | class AuthTokenServiceTests { 15 | 16 | 17 | @Test 18 | void generateToken_shouldGenerateAndVerifyToken() { 19 | SystemApi.build(name:"openannotation", apikey: "0cbfa370-b73c-4e3a-ae46-582df284b7c3", secretKey: "{shared key}", enabled:true) 20 | def actualToken = service.generateAuthToken("0cbfa370-b73c-4e3a-ae46-582df284b7c3", "jmiranda", new Date(), 86400) 21 | assertTrue service.validateAuthToken(actualToken) 22 | } 23 | 24 | @Test 25 | void validateAuthToken() { 26 | //assertTrue service.validateAuthToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEyMzQ1Njc4OTAsIm5hbWUiOiJKb2huIERvZSIsImFkbWluIjp0cnVlfQ.eoaDVGTClRdfxUZXiPs3f8FmJDkDE_VCQFXqKxpLsts") 27 | SystemApi.build(apikey: "0cbfa370-b73c-4e3a-ae46-582df284b7c3", secretKey: "{shared key}", enabled:true) 28 | assertTrue service.validateAuthToken("eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHRcL3BsYWluIiwidHlwIjoiSldTIn0.eyJjb25zdW1lcktleSI6IjBjYmZhMzcwLWI3M2MtNGUzYS1hZTQ2LTU4MmRmMjg0YjdjMyIsImlzc3VlZEF0IjoiMjAxNC0wOC0yOFQwMzoyNToyOC0wNDAwIiwidXNlcklkIjoiam1pcmFuZGEiLCJqdGkiOiI5ZWVkNjdhZC04ZmExLTRiYTItOWExOS1jOGY3YTBhZDUzNTAiLCJ0dGwiOjg2NDAwLCJpYXQiOjE0MDkyNTM5Mjh9.LOoRN_xJeV4QEL22puG3eA65wX5qsTHmb_a7RKnmJEA", false) 29 | } 30 | 31 | @Test 32 | void generateAuthToken() { 33 | SystemApi.build(apikey: "consumer-key", secretKey: "super-secret-key-shh" , enabled: true) 34 | String authToken = service.generateAuthToken("consumer-key", "user-id", new Date(), 86400) 35 | println "authToken: " + authToken 36 | assertTrue service.validateAuthToken(authToken) 37 | } 38 | 39 | @Test 40 | void generateAuthToken_defaultSecretKey() { 41 | SystemApi.build(apikey: "consumer-key", secretKey: "consumer-key", enabled: true ) 42 | String authToken = service.generateAuthToken("consumer-key", "user-id", new Date(), 86400) 43 | println "authToken: " + authToken 44 | assertTrue service.validateAuthToken(authToken) 45 | } 46 | 47 | @Test 48 | void generateAuthToken_emptySecretKey() { 49 | SystemApi.build(apikey: "consumer-key", secretKey: "", enabled: true ) 50 | shouldFail(IllegalArgumentException) { 51 | service.generateAuthToken("consumer-key", "user-id", new Date(), 86400) 52 | } 53 | } 54 | 55 | @Test 56 | void generateAuthToken_nullSecretKey() { 57 | SystemApi.build(apikey: "consumer-key", secretKey: null, enabled: true) 58 | shouldFail(IllegalArgumentException) { 59 | service.generateAuthToken("consumer-key", "user-id", new Date(), 86400) 60 | } 61 | } 62 | 63 | @Test 64 | void generateAuthToken_shouldFailWithExpiryError() { 65 | SystemApi.build(apikey: "consumer-key", secretKey: "super-secret-key-shh", enabled: true ) 66 | String authToken = service.generateAuthToken("consumer-key", "user-id", new Date()-2, 86400) 67 | println "authToken: " + authToken 68 | def message = shouldFail(IllegalArgumentException) { 69 | service.validateAuthToken(authToken) 70 | } 71 | println message 72 | assert message.startsWith("Token expired on ") 73 | } 74 | 75 | @Test 76 | void generateAuthToken_shouldFailWithIssuedAtError() { 77 | SystemApi.build(apikey: "consumer-key", secretKey: "super-secret-key-shh", enabled: true) 78 | String authToken = service.generateAuthToken("consumer-key", "user-id", new Date()+1, 400) 79 | println "authToken: " + authToken 80 | def message = shouldFail(IllegalArgumentException) { 81 | service.validateAuthToken(authToken) 82 | } 83 | println message 84 | assert message.startsWith("Token is not valid yet") 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /test/unit/org/mindinformatics/ann/catcha/DateFormatTests.groovy: -------------------------------------------------------------------------------- 1 | package org.mindinformatics.ann.catcha 2 | 3 | import org.joda.time.format.DateTimeFormatter 4 | import org.joda.time.format.ISODateTimeFormat 5 | import org.junit.After 6 | import org.junit.Before 7 | import org.junit.Test 8 | import org.mindinformatics.ann.framework.module.converter.AnnotationConverter 9 | import org.mindinformatics.ann.framework.module.persistence.Annotation 10 | 11 | import java.text.SimpleDateFormat 12 | 13 | import static org.junit.Assert.assertEquals 14 | 15 | /** 16 | * 17 | */ 18 | class DateFormatTests { 19 | 20 | def conversionService 21 | 22 | @Before 23 | void setUp() { 24 | // Setup logic here 25 | } 26 | 27 | @After 28 | void tearDown() { 29 | // Tear down logic here 30 | } 31 | 32 | 33 | @Test 34 | void testJavaDateFormat() { 35 | def stringDate = "2013-08-23T02:24:15.427+00:00" 36 | def isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S") 37 | def javaDate = isoFormat.parse(stringDate) 38 | println javaDate; 39 | 40 | } 41 | 42 | @Test 43 | void testJodaDateFormat() { 44 | def stringDate = "2013-08-23T02:24:15.427+00:00" 45 | DateTimeFormatter fmt = ISODateTimeFormat.dateTime().withOffsetParsed(); 46 | def jodaDate = fmt.parseDateTime(stringDate) 47 | println jodaDate 48 | 49 | 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /web-app/WEB-INF/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | Grails application factory bean 9 | 10 | 11 | 12 | 13 | 14 | A bean that manages Grails plugins 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | utf-8 31 | 32 | 33 | -------------------------------------------------------------------------------- /web-app/WEB-INF/sitemesh.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /web-app/css/errors.css: -------------------------------------------------------------------------------- 1 | h1, h2 { 2 | margin: 10px 25px 5px; 3 | } 4 | 5 | h2 { 6 | font-size: 1.1em; 7 | } 8 | 9 | .filename { 10 | font-style: italic; 11 | } 12 | 13 | .exceptionMessage { 14 | margin: 10px; 15 | border: 1px solid #000; 16 | padding: 5px; 17 | background-color: #E9E9E9; 18 | } 19 | 20 | .stack, 21 | .snippet { 22 | margin: 0 25px 10px; 23 | } 24 | 25 | .stack, 26 | .snippet { 27 | border: 1px solid #ccc; 28 | -mox-box-shadow: 0 0 2px rgba(0,0,0,0.2); 29 | -webkit-box-shadow: 0 0 2px rgba(0,0,0,0.2); 30 | box-shadow: 0 0 2px rgba(0,0,0,0.2); 31 | } 32 | 33 | /* error details */ 34 | .error-details { 35 | border-top: 1px solid #FFAAAA; 36 | -mox-box-shadow: 0 0 2px rgba(0,0,0,0.2); 37 | -webkit-box-shadow: 0 0 2px rgba(0,0,0,0.2); 38 | box-shadow: 0 0 2px rgba(0,0,0,0.2); 39 | border-bottom: 1px solid #FFAAAA; 40 | -mox-box-shadow: 0 0 2px rgba(0,0,0,0.2); 41 | -webkit-box-shadow: 0 0 2px rgba(0,0,0,0.2); 42 | box-shadow: 0 0 2px rgba(0,0,0,0.2); 43 | background-color:#FFF3F3; 44 | line-height: 1.5; 45 | overflow: hidden; 46 | padding: 5px; 47 | padding-left:25px; 48 | } 49 | 50 | .error-details dt { 51 | clear: left; 52 | float: left; 53 | font-weight: bold; 54 | margin-right: 5px; 55 | } 56 | 57 | .error-details dt:after { 58 | content: ":"; 59 | } 60 | 61 | .error-details dd { 62 | display: block; 63 | } 64 | 65 | /* stack trace */ 66 | .stack { 67 | padding: 5px; 68 | overflow: auto; 69 | height: 150px; 70 | } 71 | 72 | /* code snippet */ 73 | .snippet { 74 | background-color: #fff; 75 | font-family: monospace; 76 | } 77 | 78 | .snippet .line { 79 | display: block; 80 | } 81 | 82 | .snippet .lineNumber { 83 | background-color: #ddd; 84 | color: #999; 85 | display: inline-block; 86 | margin-right: 5px; 87 | padding: 0 3px; 88 | text-align: right; 89 | width: 3em; 90 | } 91 | 92 | .snippet .error { 93 | background-color: #fff3f3; 94 | font-weight: bold; 95 | } 96 | 97 | .snippet .error .lineNumber { 98 | background-color: #faa; 99 | color: #333; 100 | font-weight: bold; 101 | } 102 | 103 | .snippet .line:first-child .lineNumber { 104 | padding-top: 5px; 105 | } 106 | 107 | .snippet .line:last-child .lineNumber { 108 | padding-bottom: 5px; 109 | } -------------------------------------------------------------------------------- /web-app/css/mobile.css: -------------------------------------------------------------------------------- 1 | /* Styles for mobile devices */ 2 | 3 | @media screen and (max-width: 480px) { 4 | .nav { 5 | padding: 0.5em; 6 | } 7 | 8 | .nav li { 9 | margin: 0 0.5em 0 0; 10 | padding: 0.25em; 11 | } 12 | 13 | /* Hide individual steps in pagination, just have next & previous */ 14 | .pagination .step, .pagination .currentStep { 15 | display: none; 16 | } 17 | 18 | .pagination .prevLink { 19 | float: left; 20 | } 21 | 22 | .pagination .nextLink { 23 | float: right; 24 | } 25 | 26 | /* pagination needs to wrap around floated buttons */ 27 | .pagination { 28 | overflow: hidden; 29 | } 30 | 31 | /* slightly smaller margin around content body */ 32 | fieldset, 33 | .property-list { 34 | padding: 0.3em 1em 1em; 35 | } 36 | 37 | input, textarea { 38 | width: 100%; 39 | -moz-box-sizing: border-box; 40 | -webkit-box-sizing: border-box; 41 | -ms-box-sizing: border-box; 42 | box-sizing: border-box; 43 | } 44 | 45 | select, input[type=checkbox], input[type=radio], input[type=submit], input[type=button], input[type=reset] { 46 | width: auto; 47 | } 48 | 49 | /* hide all but the first column of list tables */ 50 | .scaffold-list td:not(:first-child), 51 | .scaffold-list th:not(:first-child) { 52 | display: none; 53 | } 54 | 55 | .scaffold-list thead th { 56 | text-align: center; 57 | } 58 | 59 | /* stack form elements */ 60 | .fieldcontain { 61 | margin-top: 0.6em; 62 | } 63 | 64 | .fieldcontain label, 65 | .fieldcontain .property-label, 66 | .fieldcontain .property-value { 67 | display: block; 68 | float: none; 69 | margin: 0 0 0.25em 0; 70 | text-align: left; 71 | width: auto; 72 | } 73 | 74 | .errors ul, 75 | .message p { 76 | margin: 0.5em; 77 | } 78 | 79 | .error ul { 80 | margin-left: 0; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /web-app/images/apple-touch-icon-retina.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/apple-touch-icon-retina.png -------------------------------------------------------------------------------- /web-app/images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/apple-touch-icon.png -------------------------------------------------------------------------------- /web-app/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/favicon.ico -------------------------------------------------------------------------------- /web-app/images/grails_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/grails_logo.jpg -------------------------------------------------------------------------------- /web-app/images/grails_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/grails_logo.png -------------------------------------------------------------------------------- /web-app/images/leftnav_btm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/leftnav_btm.png -------------------------------------------------------------------------------- /web-app/images/leftnav_midstretch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/leftnav_midstretch.png -------------------------------------------------------------------------------- /web-app/images/leftnav_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/leftnav_top.png -------------------------------------------------------------------------------- /web-app/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/logo.png -------------------------------------------------------------------------------- /web-app/images/public/amarok_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/amarok_download.png -------------------------------------------------------------------------------- /web-app/images/public/amarok_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/amarok_search.png -------------------------------------------------------------------------------- /web-app/images/public/amarok_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/amarok_share.png -------------------------------------------------------------------------------- /web-app/images/public/amarok_share.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/amarok_share.psd -------------------------------------------------------------------------------- /web-app/images/public/amarok_share_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/amarok_share_green.png -------------------------------------------------------------------------------- /web-app/images/public/amarok_share_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/amarok_share_red.png -------------------------------------------------------------------------------- /web-app/images/public/amarok_validate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/amarok_validate.png -------------------------------------------------------------------------------- /web-app/images/public/amarok_validate.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/amarok_validate.psd -------------------------------------------------------------------------------- /web-app/images/public/amarok_validate_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/amarok_validate_green.png -------------------------------------------------------------------------------- /web-app/images/public/amarok_validate_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/amarok_validate_orange.png -------------------------------------------------------------------------------- /web-app/images/public/amarok_validate_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/amarok_validate_red.png -------------------------------------------------------------------------------- /web-app/images/public/domeo-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/domeo-icon.png -------------------------------------------------------------------------------- /web-app/images/public/highbrow-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/highbrow-icon.png -------------------------------------------------------------------------------- /web-app/images/public/people/paolo_ciccarese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/public/people/paolo_ciccarese.png -------------------------------------------------------------------------------- /web-app/images/shared/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/shared/favicon.ico -------------------------------------------------------------------------------- /web-app/images/shared/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/shared/logo.png -------------------------------------------------------------------------------- /web-app/images/skin/database_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/skin/database_add.png -------------------------------------------------------------------------------- /web-app/images/skin/database_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/skin/database_delete.png -------------------------------------------------------------------------------- /web-app/images/skin/database_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/skin/database_edit.png -------------------------------------------------------------------------------- /web-app/images/skin/database_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/skin/database_save.png -------------------------------------------------------------------------------- /web-app/images/skin/database_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/skin/database_table.png -------------------------------------------------------------------------------- /web-app/images/skin/exclamation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/skin/exclamation.png -------------------------------------------------------------------------------- /web-app/images/skin/house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/skin/house.png -------------------------------------------------------------------------------- /web-app/images/skin/information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/skin/information.png -------------------------------------------------------------------------------- /web-app/images/skin/shadow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/skin/shadow.jpg -------------------------------------------------------------------------------- /web-app/images/skin/sorted_asc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/skin/sorted_asc.gif -------------------------------------------------------------------------------- /web-app/images/skin/sorted_desc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/skin/sorted_desc.gif -------------------------------------------------------------------------------- /web-app/images/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/spinner.gif -------------------------------------------------------------------------------- /web-app/images/springsource.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/web-app/images/springsource.png -------------------------------------------------------------------------------- /web-app/js/application.js: -------------------------------------------------------------------------------- 1 | if (typeof jQuery !== 'undefined') { 2 | (function($) { 3 | $('#spinner').ajaxStart(function() { 4 | $(this).fadeIn(); 5 | }).ajaxStop(function() { 6 | $(this).fadeOut(); 7 | }); 8 | })(jQuery); 9 | } 10 | -------------------------------------------------------------------------------- /web-app/uploads/users/ff80818147b1aab00147b1aacdb2000c/annotation-1a89fe40-34f8-4085-8b7d-3197a9eea282.json: -------------------------------------------------------------------------------- 1 | {"tags":[],"text":"

    annotation<\/p>","ranges":[],"uri":"http://catool.localhost/ova/index.php?r=ova/index","id":8,"geolocation":{"altitude":null,"longitude":-77.061244,"latitude":38.9171597,"accuracy":24},"created":"2013-10-18T02:30:34.0+0000","updated":"2013-10-18T15:55:56.919Z","quote":"","target":{"container":"vid1","src":"http://video-js.zencoder.com/oceans-clip.mp4","ext":".mp4"},"permissions":{"update":[],"admin":[],"delete":[],"read":[]},"user":{"id":3,"name":"dani"},"rangeTime":{"start":0.562899,"end":5.217549},"media":"video"} 2 | 3 | -------------------------------------------------------------------------------- /wrapper/grails-wrapper-runtime-2.2.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/wrapper/grails-wrapper-runtime-2.2.5.jar -------------------------------------------------------------------------------- /wrapper/grails-wrapper.properties: -------------------------------------------------------------------------------- 1 | wrapper.dist.url=http://dist.springframework.org.s3.amazonaws.com/release/GRAILS/ 2 | -------------------------------------------------------------------------------- /wrapper/springloaded-core-1.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/annotationsatharvard/catcha/7632c32b9026672d3257b58082410b46187e8e3c/wrapper/springloaded-core-1.1.3.jar --------------------------------------------------------------------------------