diff --git a/.github/workflows/codecov-report.yml b/.github/workflows/codecov-report.yml index 20ec118028..53a11c68cd 100644 --- a/.github/workflows/codecov-report.yml +++ b/.github/workflows/codecov-report.yml @@ -1,6 +1,98 @@ -- name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v3 - with: - fail_ci_if_error: false - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} +name: CodCov, Run Backend and Frontend Tests + +on: + push: + branches: + - '**' + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + # Set up Java for backend tests + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '8' + + # Set up Node.js for frontend tests + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '16' + + # Install dependencies for backend + - name: Install backend dependencies + run: | + #cd src/test + mvn clean install + mkdir -p src/surefire-reports + mkdir -p frontend/coverage + + # Run backend tests with coverage + - name: Run backend tests + run: mvn test -e + working-directory: ./ + continue-on-error: true + + # Install dependencies for frontend + - name: Install frontend dependencies + run: | + cd frontend + npm install + + # Run frontend tests with coverage + - name: Run frontend tests + run: npm run test --coverage + working-directory: frontend + continue-on-error: true + + # Upload test results and coverage + - name: Upload coverage results + uses: actions/upload-artifact@v3 + with: + name: test-results + path: | + target/surefire-reports + frontend/coverage + + # List coverage files + - name: Verify coverage files + run: | + echo "Checking backend coverage files..." + ls -l target/site/jacoco/ || echo "No backend coverage files found" + echo "Checking frontend coverage files..." + ls -l frontend/coverage/ || echo "No frontend coverage files found" + + + # Upload to Codecov + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} # Add Codecov token as a secret in GitHub + files: | + target/site/jacoco/jacoco.xml + frontend/coverage/lcov.info + flags: backend,frontend + name: codecov-coverage-report + fail_ci_if_error: false # Does not block merge if there’s an error + + - name: List files + run: | + #cd src/test + ls -l target/surefire-reports + ls -l frontend/coverage + + + # Display test coverage in the summary (optional) + - name: Display test coverage summary + run: | + echo "Backend Test Results:" + cat target/surefire-reports/*.txt || true + echo "Frontend Test Coverage Summary:" + cat frontend/coverage/*.* || true diff --git a/devops/deploy/.dockerfiles/tomcat/commonConfiguration.properties b/devops/deploy/.dockerfiles/tomcat/commonConfiguration.properties index 1a336a9487..acf0992ef1 100644 --- a/devops/deploy/.dockerfiles/tomcat/commonConfiguration.properties +++ b/devops/deploy/.dockerfiles/tomcat/commonConfiguration.properties @@ -25,12 +25,6 @@ #file system folder in which marked individual data will be stored (e.g. data files) #markedIndividualDirectoryLocation=individuals -# default behaviors for Project object -loggedOutDefaultDesired = true -defaultProjectOrganizationParameter = IndoCet -defaultProjName = Indocet Opportunistic Sightings -defaultProjId = IndoCetOppS- - #file system folder in which adoption data will be stored (e.g. photos) #adoptionLocation=adoptions @@ -56,8 +50,8 @@ allowAdoptions = false #email addresses and parameters sendEmailNotifications=true -autoEmailAddress=info@wildbook.org -newSubmissionEmail=donotreply@wildbook.org +autoEmailAddress=info@wildme.org +newSubmissionEmail=donotreply@wildme.org mailHost=localhost removeEmailString=Do you want to REMOVE your email address from this database? Click the link below to remove it. You will no longer receive updates on your encounters. diff --git a/devops/development/.dockerfiles/tomcat/commonConfiguration.properties b/devops/development/.dockerfiles/tomcat/commonConfiguration.properties index 4a37384b95..6e6e1a13f8 100644 --- a/devops/development/.dockerfiles/tomcat/commonConfiguration.properties +++ b/devops/development/.dockerfiles/tomcat/commonConfiguration.properties @@ -25,12 +25,6 @@ #file system folder in which marked individual data will be stored (e.g. data files) #markedIndividualDirectoryLocation=individuals -# default behaviors for Project object -loggedOutDefaultDesired = true -defaultProjectOrganizationParameter = IndoCet -defaultProjName = Indocet Opportunistic Sightings -defaultProjId = IndoCetOppS- - #file system folder in which adoption data will be stored (e.g. photos) #adoptionLocation=adoptions diff --git a/eslint.config.mjs b/eslint.config.mjs index 4129a6b0c8..3de883b5a2 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -8,20 +8,24 @@ export default [ pluginJs.configs.recommended, pluginReactConfig, { - files: ["**/*.{js,mjs,cjs,jsx}"], + files: ["**/*.{js,mjs,cjs,jsx}"], plugins: { - "react-hooks": reactHooks, + "react-hooks": reactHooks, }, languageOptions: { - globals: globals.browser, + globals: { + ...globals.browser, + process: "readonly", + }, parser: babelParser, + }, settings: { react: { version: "detect" } - }, - + }, + rules: { "semi": 2, "react/prop-types": 0, @@ -54,19 +58,19 @@ export default [ "no-param-reassign": 0, "no-mixed-operators": 0, "no-else-return": 0, - + }, }, { files: ['frontend/babel.config.js', 'frontend/jest.config.js', 'babel.config.js'], // Specify the config files languageOptions: { globals: { - require: "readonly", + require: "readonly", module: "readonly", - __dirname: "readonly", + __dirname: "readonly", process: "readonly", }, - }, + }, }, { files: ["**/__tests__/**/*.{js,jsx}", "**/*.test.{js,jsx}"], diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4c940481dd..4a01c9476f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,20 +8,28 @@ "name": "frontend", "version": "0.1.0", "dependencies": { + "@flowjs/flow.js": "^2.14.1", "@testing-library/user-event": "^13.5.0", + "antd": "^5.21.5", "autoprefixer": "^10.4.18", "axios": "^1.7.4", "bootstrap": "^5.3.2", "copy-webpack-plugin": "^12.0.2", + "exif-js": "^2.3.0", + "flow.js": "^0.2.6", "google-map-react": "^2.2.1", "js-cookie": "^3.0.5", "lodash-es": "^4.17.21", + "mobx": "6.13.3", + "mobx-react-lite": "^4.0.7", + "moment": "^2.30.1", "postcss-cli": "^11.0.0", "rc-slider": "^10.6.2", "react": "^18.2.0", "react-bootstrap": "^2.10.1", "react-burger-menu": "^3.0.9", "react-data-table-component": "^7.6.2", + "react-datetime": "^3.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.52.1", "react-intl": "^6.6.2", @@ -54,7 +62,7 @@ "@testing-library/react": "^16.0.1", "bootstrap-icons": "^1.11.3", "css-loader": "^6.10.0", - "date-fns": "^3.6.0", + "date-fns": "^4.1.0", "eslint": "^8.57.0", "eslint-plugin-react": "^7.35.0", "globals": "^15.9.0", @@ -111,6 +119,121 @@ "node": ">=6.0.0" } }, + "node_modules/@ant-design/colors": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.1.0.tgz", + "integrity": "sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^3.6.1" + } + }, + "node_modules/@ant-design/cssinjs": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.21.1.tgz", + "integrity": "sha512-tyWnlK+XH7Bumd0byfbCiZNK43HEubMoCcu9VxwsAwiHdHTgWa+tMN0/yvxa+e8EzuFP1WdUNNPclRpVtD33lg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "@emotion/hash": "^0.8.0", + "@emotion/unitless": "^0.7.5", + "classnames": "^2.3.1", + "csstype": "^3.1.3", + "rc-util": "^5.35.0", + "stylis": "^4.3.3" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/cssinjs-utils": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs-utils/-/cssinjs-utils-1.1.1.tgz", + "integrity": "sha512-2HAiyGGGnM0es40SxdszeQAU5iWp41wBIInq+ONTCKjlSKOrzQfnw4JDtB8IBmqE6tQaEKwmzTP2LGdt5DSwYQ==", + "license": "MIT", + "dependencies": { + "@ant-design/cssinjs": "^1.21.0", + "@babel/runtime": "^7.23.2", + "rc-util": "^5.38.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@ant-design/cssinjs/node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "license": "MIT" + }, + "node_modules/@ant-design/cssinjs/node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", + "license": "MIT" + }, + "node_modules/@ant-design/cssinjs/node_modules/stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==", + "license": "MIT" + }, + "node_modules/@ant-design/fast-color": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-2.0.6.tgz", + "integrity": "sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7" + }, + "engines": { + "node": ">=8.x" + } + }, + "node_modules/@ant-design/icons": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.5.1.tgz", + "integrity": "sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==", + "license": "MIT", + "dependencies": { + "@ant-design/colors": "^7.0.0", + "@ant-design/icons-svg": "^4.4.0", + "@babel/runtime": "^7.24.8", + "classnames": "^2.2.6", + "rc-util": "^5.31.1" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/icons-svg": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz", + "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==", + "license": "MIT" + }, + "node_modules/@ant-design/react-slick": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.1.2.tgz", + "integrity": "sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.4", + "classnames": "^2.2.5", + "json2mq": "^0.2.0", + "resize-observer-polyfill": "^1.5.1", + "throttle-debounce": "^5.0.0" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", @@ -2037,9 +2160,10 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", - "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.9.tgz", + "integrity": "sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==", + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2376,6 +2500,15 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -2454,11 +2587,6 @@ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" }, - "node_modules/@emotion/cache/node_modules/@emotion/weak-memoize": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", - "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" - }, "node_modules/@emotion/cache/node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", @@ -2483,17 +2611,18 @@ "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" }, "node_modules/@emotion/react": { - "version": "11.11.4", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", - "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "version": "11.13.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", + "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.3", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" }, "peerDependencies": { @@ -2506,14 +2635,15 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.1.tgz", - "integrity": "sha512-dEPNKzBPU+vFPGa+z3axPRn8XVDetYORmDC0wAiej+TNcOZE70ZMJa0X7JdeoM6q/nWTMZeLpN/fTnD9o8MQBA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz", + "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==", + "license": "MIT", "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/unitless": "^0.10.0", - "@emotion/utils": "^1.4.0", + "@emotion/utils": "^1.4.1", "csstype": "^3.0.2" } }, @@ -2546,14 +2676,16 @@ } }, "node_modules/@emotion/utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", - "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz", + "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==", + "license": "MIT" }, "node_modules/@emotion/weak-memoize": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", - "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", @@ -2667,9 +2799,15 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz", - "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==" + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", + "license": "MIT" + }, + "node_modules/@flowjs/flow.js": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/@flowjs/flow.js/-/flow.js-2.14.1.tgz", + "integrity": "sha512-99DWlPnksOOS8uHfo+bhSjvs8d2MfLTB/22JBDC2ONwz/OCdP+gL/iiM4puMSTE2wH4A2/+J0eMc7pKwusXunw==" }, "node_modules/@formatjs/ecma402-abstract": { "version": "1.18.2", @@ -3744,6 +3882,155 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@rc-component/async-validator": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz", + "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.4" + }, + "engines": { + "node": ">=14.x" + } + }, + "node_modules/@rc-component/color-picker": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-2.0.1.tgz", + "integrity": "sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==", + "license": "MIT", + "dependencies": { + "@ant-design/fast-color": "^2.0.6", + "@babel/runtime": "^7.23.6", + "classnames": "^2.2.6", + "rc-util": "^5.38.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/context": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz", + "integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/mini-decimal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz", + "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0" + }, + "engines": { + "node": ">=8.x" + } + }, + "node_modules/@rc-component/mutate-observer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz", + "integrity": "sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/portal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz", + "integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/qrcode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rc-component/qrcode/-/qrcode-1.0.0.tgz", + "integrity": "sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/tour": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.15.1.tgz", + "integrity": "sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0", + "@rc-component/portal": "^1.0.0-9", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/trigger": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.2.3.tgz", + "integrity": "sha512-X1oFIpKoXAMXNDYCviOmTfuNuYxE4h5laBsyCqVAVMjNHxoF3/uiyA7XdegK1XbCvBbCZ6P6byWrEoDRpKL8+A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2", + "@rc-component/portal": "^1.1.0", + "classnames": "^2.3.2", + "rc-motion": "^2.0.0", + "rc-resize-observer": "^1.3.1", + "rc-util": "^5.38.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/@react-aria/ssr": { "version": "3.9.2", "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.2.tgz", @@ -4593,9 +4880,10 @@ "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", + "license": "MIT" }, "node_modules/@types/q": { "version": "1.5.8", @@ -5364,6 +5652,89 @@ "node": ">=4" } }, + "node_modules/antd": { + "version": "5.21.5", + "resolved": "https://registry.npmjs.org/antd/-/antd-5.21.5.tgz", + "integrity": "sha512-g/c8VkdruKDCVA6di9Ow1fG6dLtYJ1IOraPo7vXaY7DoQ56A3HExaFaH0fBEwTYKC0ICeftC4iA5eAjrF6/b9w==", + "license": "MIT", + "dependencies": { + "@ant-design/colors": "^7.1.0", + "@ant-design/cssinjs": "^1.21.1", + "@ant-design/cssinjs-utils": "^1.1.1", + "@ant-design/icons": "^5.5.1", + "@ant-design/react-slick": "~1.1.2", + "@babel/runtime": "^7.25.6", + "@ctrl/tinycolor": "^3.6.1", + "@rc-component/color-picker": "~2.0.1", + "@rc-component/mutate-observer": "^1.1.0", + "@rc-component/qrcode": "~1.0.0", + "@rc-component/tour": "~1.15.1", + "@rc-component/trigger": "^2.2.3", + "classnames": "^2.5.1", + "copy-to-clipboard": "^3.3.3", + "dayjs": "^1.11.11", + "rc-cascader": "~3.28.2", + "rc-checkbox": "~3.3.0", + "rc-collapse": "~3.8.0", + "rc-dialog": "~9.6.0", + "rc-drawer": "~7.2.0", + "rc-dropdown": "~4.2.0", + "rc-field-form": "~2.4.0", + "rc-image": "~7.11.0", + "rc-input": "~1.6.3", + "rc-input-number": "~9.2.0", + "rc-mentions": "~2.16.1", + "rc-menu": "~9.15.1", + "rc-motion": "^2.9.3", + "rc-notification": "~5.6.2", + "rc-pagination": "~4.3.0", + "rc-picker": "~4.6.15", + "rc-progress": "~4.0.0", + "rc-rate": "~2.13.0", + "rc-resize-observer": "^1.4.0", + "rc-segmented": "~2.5.0", + "rc-select": "~14.15.2", + "rc-slider": "~11.1.7", + "rc-steps": "~6.0.1", + "rc-switch": "~4.1.0", + "rc-table": "~7.47.5", + "rc-tabs": "~15.3.0", + "rc-textarea": "~1.8.2", + "rc-tooltip": "~6.2.1", + "rc-tree": "~5.9.0", + "rc-tree-select": "~5.23.0", + "rc-upload": "~4.8.1", + "rc-util": "^5.43.0", + "scroll-into-view-if-needed": "^3.1.0", + "throttle-debounce": "^5.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ant-design" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/antd/node_modules/rc-slider": { + "version": "11.1.7", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-11.1.7.tgz", + "integrity": "sha512-ytYbZei81TX7otdC0QvoYD72XSlxvTihNth5OeZ6PMXyEDq/vHdWFulQmfDGyXK1NwKwSlKgpvINOa88uT5g2A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.36.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -5441,6 +5812,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-tree-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz", + "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==", + "license": "MIT" + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -6705,6 +7082,12 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz", + "integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==", + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -6760,6 +7143,15 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "license": "MIT", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, "node_modules/copy-webpack-plugin": { "version": "12.0.2", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz", @@ -7436,15 +7828,22 @@ } }, "node_modules/date-fns": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", - "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", - "dev": true, + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "devOptional": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/kossnocorp" } }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", @@ -8902,6 +9301,12 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/exif-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/exif-js/-/exif-js-2.3.0.tgz", + "integrity": "sha512-1Og9pAzG2FZRVlaavH8bB8BTeHcjMdJhKmeQITkX+uLRCD0xPtKAdZ2clZmQdJ56p9adXtJ8+jwrGp/4505lYg==", + "license": "MIT" + }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -9228,6 +9633,11 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" }, + "node_modules/flow.js": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/flow.js/-/flow.js-0.2.6.tgz", + "integrity": "sha512-KvXsCPNj3uIOnXu07qXiqsxjqEveAe5nAM8W3ULTEDPynoMZlWvMyKZdH8pOh5oCFy7uXtgWnZQZOzgoH9Epdw==" + }, "node_modules/follow-redirects": { "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", @@ -13085,6 +13495,15 @@ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" }, + "node_modules/json2mq": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", + "license": "MIT", + "dependencies": { + "string-convert": "^0.2.0" + } + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -13626,6 +14045,48 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mobx": { + "version": "6.13.3", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.13.3.tgz", + "integrity": "sha512-YtAS+ZMbdpbHYUU4ESht3na8KiX11KuMT1yOiKtbKlQ0GZkHDYPKyEw/Tdp7h7aHyLrTWj2TBaSNJ6bCr638iQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + } + }, + "node_modules/mobx-react-lite": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-4.0.7.tgz", + "integrity": "sha512-RjwdseshK9Mg8On5tyJZHtGD+J78ZnCnRaxeQDSiciKVQDUbfZcXhmld0VMxAwvcTnPEHZySGGewm467Fcpreg==", + "dependencies": { + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.9.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/mrmime": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", @@ -15998,6 +16459,401 @@ "node": ">=0.10.0" } }, + "node_modules/rc-cascader": { + "version": "3.28.2", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.28.2.tgz", + "integrity": "sha512-8f+JgM83iLTvjgdkgU7GfI4qY8icXOBP0cGZjOdx2iJAkEe8ucobxDQAVE69UD/c3ehCxZlcgEHeD5hFmypbUw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "array-tree-filter": "^2.1.0", + "classnames": "^2.3.1", + "rc-select": "~14.15.0", + "rc-tree": "~5.9.0", + "rc-util": "^5.37.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-checkbox": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.3.0.tgz", + "integrity": "sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.25.2" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-collapse": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.8.0.tgz", + "integrity": "sha512-YVBkssrKPBG09TGfcWWGj8zJBYD9G3XuTy89t5iUmSXrIXEAnO1M+qjUxRW6b4Qi0+wNWG6MHJF/+US+nmIlzA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.3.4", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-dialog": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.6.0.tgz", + "integrity": "sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/portal": "^1.0.0-8", + "classnames": "^2.2.6", + "rc-motion": "^2.3.0", + "rc-util": "^5.21.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-drawer": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.2.0.tgz", + "integrity": "sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@rc-component/portal": "^1.1.1", + "classnames": "^2.2.6", + "rc-motion": "^2.6.1", + "rc-util": "^5.38.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-dropdown": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.2.0.tgz", + "integrity": "sha512-odM8Ove+gSh0zU27DUj5cG1gNKg7mLWBYzB5E4nNLrLwBmYEgYP43vHKDGOVZcJSVElQBI0+jTQgjnq0NfLjng==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.11.0", + "react-dom": ">=16.11.0" + } + }, + "node_modules/rc-field-form": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.4.0.tgz", + "integrity": "sha512-XZ/lF9iqf9HXApIHQHqzJK5v2w4mkUMsVqAzOyWVzoiwwXEavY6Tpuw7HavgzIoD+huVff4JghSGcgEfX6eycg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0", + "@rc-component/async-validator": "^5.0.3", + "rc-util": "^5.32.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-image": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.11.0.tgz", + "integrity": "sha512-aZkTEZXqeqfPZtnSdNUnKQA0N/3MbgR7nUnZ+/4MfSFWPFHZau4p5r5ShaI0KPEMnNjv4kijSCFq/9wtJpwykw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.2", + "@rc-component/portal": "^1.0.2", + "classnames": "^2.2.6", + "rc-dialog": "~9.6.0", + "rc-motion": "^2.6.2", + "rc-util": "^5.34.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-input": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.6.3.tgz", + "integrity": "sha512-wI4NzuqBS8vvKr8cljsvnTUqItMfG1QbJoxovCgL+DX4eVUcHIjVwharwevIxyy7H/jbLryh+K7ysnJr23aWIA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.18.1" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/rc-input-number": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.2.0.tgz", + "integrity": "sha512-5XZFhBCV5f9UQ62AZ2hFbEY8iZT/dm23Q1kAg0H8EvOgD3UDbYYJAayoVIkM3lQaCqYAW5gV0yV3vjw1XtzWHg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/mini-decimal": "^1.0.1", + "classnames": "^2.2.5", + "rc-input": "~1.6.0", + "rc-util": "^5.40.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-mentions": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.16.1.tgz", + "integrity": "sha512-GnhSTGP9Mtv6pqFFGQze44LlrtWOjHNrUUAcsdo9DnNAhN4pwVPEWy4z+2jpjkiGlJ3VoXdvMHcNDQdfI9fEaw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.22.5", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-input": "~1.6.0", + "rc-menu": "~9.15.1", + "rc-textarea": "~1.8.0", + "rc-util": "^5.34.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-menu": { + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.15.1.tgz", + "integrity": "sha512-UKporqU6LPfHnpPmtP6hdEK4iO5Q+b7BRv/uRpxdIyDGplZy9jwUjsnpev5bs3PQKB0H0n34WAPDfjAfn3kAPA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.0.0", + "classnames": "2.x", + "rc-motion": "^2.4.3", + "rc-overflow": "^1.3.1", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-motion": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.3.tgz", + "integrity": "sha512-rkW47ABVkic7WEB0EKJqzySpvDqwl60/tdkY7hWP7dYnh5pm0SzJpo54oW3TDUGXV5wfxXFmMkxrzRRbotQ0+w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.43.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-notification": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.2.tgz", + "integrity": "sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.9.0", + "rc-util": "^5.20.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-overflow": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.3.2.tgz", + "integrity": "sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.37.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-pagination": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-4.3.0.tgz", + "integrity": "sha512-UubEWA0ShnroQ1tDa291Fzw6kj0iOeF26IsUObxYTpimgj4/qPCWVFl18RLZE+0Up1IZg0IK4pMn6nB3mjvB7g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-picker": { + "version": "4.6.15", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.6.15.tgz", + "integrity": "sha512-OWZ1yrMie+KN2uEUfYCfS4b2Vu6RC1FWwNI0s+qypsc3wRt7g+peuZKVIzXCTaJwyyZruo80+akPg2+GmyiJjw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.1", + "rc-overflow": "^1.3.2", + "rc-resize-observer": "^1.4.0", + "rc-util": "^5.43.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "date-fns": ">= 2.x", + "dayjs": ">= 1.x", + "luxon": ">= 3.x", + "moment": ">= 2.x", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + }, + "peerDependenciesMeta": { + "date-fns": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + } + } + }, + "node_modules/rc-progress": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-4.0.0.tgz", + "integrity": "sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-util": "^5.16.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-rate": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.0.tgz", + "integrity": "sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.0.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-resize-observer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz", + "integrity": "sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.7", + "classnames": "^2.2.1", + "rc-util": "^5.38.0", + "resize-observer-polyfill": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-segmented": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.5.0.tgz", + "integrity": "sha512-B28Fe3J9iUFOhFJET3RoXAPFJ2u47QvLSYcZWC4tFYNGPEjug5LAxEasZlA/PpAxhdOPqGWsGbSj7ftneukJnw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-motion": "^2.4.4", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/rc-select": { + "version": "14.15.2", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.15.2.tgz", + "integrity": "sha512-oNoXlaFmpqXYcQDzcPVLrEqS2J9c+/+oJuGrlXeVVX/gVgrbHa5YcyiRUXRydFjyuA7GP3elRuLF7Y3Tfwltlw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.1.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-overflow": "^1.3.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, "node_modules/rc-slider": { "version": "10.6.2", "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-10.6.2.tgz", @@ -16015,6 +16871,166 @@ "react-dom": ">=16.9.0" } }, + "node_modules/rc-steps": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-6.0.1.tgz", + "integrity": "sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.16.7", + "classnames": "^2.2.3", + "rc-util": "^5.16.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-switch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz", + "integrity": "sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0", + "classnames": "^2.2.1", + "rc-util": "^5.30.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-table": { + "version": "7.47.5", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.47.5.tgz", + "integrity": "sha512-fzq+V9j/atbPIcvs3emuclaEoXulwQpIiJA6/7ey52j8+9cJ4P8DGmp4YzfUVDrb3qhgedcVeD6eRgUrokwVEQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/context": "^1.4.0", + "classnames": "^2.2.5", + "rc-resize-observer": "^1.1.0", + "rc-util": "^5.41.0", + "rc-virtual-list": "^3.14.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tabs": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.3.0.tgz", + "integrity": "sha512-lzE18r+zppT/jZWOAWS6ntdkDUKHOLJzqMi5UAij1LeKwOaQaupupAoI9Srn73GRzVpmGznkECMRrzkRusC40A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.2", + "classnames": "2.x", + "rc-dropdown": "~4.2.0", + "rc-menu": "~9.15.1", + "rc-motion": "^2.6.2", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.34.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-textarea": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.8.2.tgz", + "integrity": "sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-input": "~1.6.0", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tooltip": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.2.1.tgz", + "integrity": "sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.2", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.3.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tree": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.9.0.tgz", + "integrity": "sha512-CPrgOvm9d/9E+izTONKSngNzQdIEjMox2PBufWjS1wf7vxtvmCWzK1SlpHbRY6IaBfJIeZ+88RkcIevf729cRg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.1" + }, + "engines": { + "node": ">=10.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-tree-select": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.23.0.tgz", + "integrity": "sha512-aQGi2tFSRw1WbXv0UVXPzHm09E0cSvUVZMLxQtMv3rnZZpNmdRXWrnd9QkLNlVH31F+X5rgghmdSFF3yZW0N9A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-select": "~14.15.0", + "rc-tree": "~5.9.0", + "rc-util": "^5.16.1" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-upload": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.8.1.tgz", + "integrity": "sha512-toEAhwl4hjLAI1u8/CgKWt30BR06ulPa4iGQSMvSXoHzO88gPCslxqV/mnn4gJU7PDoltGIC9Eh+wkeudqgHyw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "classnames": "^2.2.5", + "rc-util": "^5.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/rc-util": { "version": "5.43.0", "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.43.0.tgz", @@ -16033,10 +17049,29 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, + "node_modules/rc-virtual-list": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.15.0.tgz", + "integrity": "sha512-dF2YQztqrU3ijAeWOqscTshCEr7vpimzSqAVjO1AyAmaqcHulaXpnGR0ptK5PXfxTUy48VkJOiglMIxlkYGs0w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.0", + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.36.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { "loose-envify": "^1.1.0" }, @@ -16166,6 +17201,19 @@ } } }, + "node_modules/react-datetime": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-datetime/-/react-datetime-3.2.0.tgz", + "integrity": "sha512-w5XdeNIGzBht9CadaZIJhKUhEcDTgH0XokKxGPCxeeJRYL7B3HIKA8CM6Q0xej2JFJt0n5d+zi3maMwaY3262A==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.5.7" + }, + "peerDependencies": { + "moment": "^2.16.0", + "react": "^16.5.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -16284,15 +17332,15 @@ } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.3.1" } }, "node_modules/react-error-overlay": { @@ -16766,6 +17814,12 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -17124,9 +18178,9 @@ } }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dependencies": { "loose-envify": "^1.1.0" } @@ -17148,6 +18202,15 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", + "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -17731,6 +18794,12 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-convert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==", + "license": "MIT" + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -18468,6 +19537,15 @@ "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==" }, + "node_modules/throttle-debounce": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz", + "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==", + "license": "MIT", + "engines": { + "node": ">=12.22" + } + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -18502,6 +19580,12 @@ "node": ">=8.0" } }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", + "license": "MIT" + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -18959,6 +20043,14 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -20281,6 +21373,92 @@ "@jridgewell/trace-mapping": "^0.3.9" } }, + "@ant-design/colors": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.1.0.tgz", + "integrity": "sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==", + "requires": { + "@ctrl/tinycolor": "^3.6.1" + } + }, + "@ant-design/cssinjs": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.21.1.tgz", + "integrity": "sha512-tyWnlK+XH7Bumd0byfbCiZNK43HEubMoCcu9VxwsAwiHdHTgWa+tMN0/yvxa+e8EzuFP1WdUNNPclRpVtD33lg==", + "requires": { + "@babel/runtime": "^7.11.1", + "@emotion/hash": "^0.8.0", + "@emotion/unitless": "^0.7.5", + "classnames": "^2.3.1", + "csstype": "^3.1.3", + "rc-util": "^5.35.0", + "stylis": "^4.3.3" + }, + "dependencies": { + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==" + } + } + }, + "@ant-design/cssinjs-utils": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs-utils/-/cssinjs-utils-1.1.1.tgz", + "integrity": "sha512-2HAiyGGGnM0es40SxdszeQAU5iWp41wBIInq+ONTCKjlSKOrzQfnw4JDtB8IBmqE6tQaEKwmzTP2LGdt5DSwYQ==", + "requires": { + "@ant-design/cssinjs": "^1.21.0", + "@babel/runtime": "^7.23.2", + "rc-util": "^5.38.0" + } + }, + "@ant-design/fast-color": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-2.0.6.tgz", + "integrity": "sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==", + "requires": { + "@babel/runtime": "^7.24.7" + } + }, + "@ant-design/icons": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.5.1.tgz", + "integrity": "sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==", + "requires": { + "@ant-design/colors": "^7.0.0", + "@ant-design/icons-svg": "^4.4.0", + "@babel/runtime": "^7.24.8", + "classnames": "^2.2.6", + "rc-util": "^5.31.1" + } + }, + "@ant-design/icons-svg": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz", + "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==" + }, + "@ant-design/react-slick": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.1.2.tgz", + "integrity": "sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==", + "requires": { + "@babel/runtime": "^7.10.4", + "classnames": "^2.2.5", + "json2mq": "^0.2.0", + "resize-observer-polyfill": "^1.5.1", + "throttle-debounce": "^5.0.0" + } + }, "@babel/code-frame": { "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", @@ -21550,9 +22728,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "@babel/runtime": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", - "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.9.tgz", + "integrity": "sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==", "requires": { "regenerator-runtime": "^0.14.0" } @@ -21732,6 +22910,11 @@ "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", "requires": {} }, + "@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==" + }, "@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -21800,11 +22983,6 @@ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" }, - "@emotion/weak-memoize": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", - "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" - }, "stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", @@ -21831,29 +23009,29 @@ "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" }, "@emotion/react": { - "version": "11.11.4", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", - "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "version": "11.13.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", + "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", "requires": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.3", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" } }, "@emotion/serialize": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.1.tgz", - "integrity": "sha512-dEPNKzBPU+vFPGa+z3axPRn8XVDetYORmDC0wAiej+TNcOZE70ZMJa0X7JdeoM6q/nWTMZeLpN/fTnD9o8MQBA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz", + "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==", "requires": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/unitless": "^0.10.0", - "@emotion/utils": "^1.4.0", + "@emotion/utils": "^1.4.1", "csstype": "^3.0.2" }, "dependencies": { @@ -21886,14 +23064,14 @@ "requires": {} }, "@emotion/utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", - "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz", + "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==" }, "@emotion/weak-memoize": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", - "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" }, "@eslint-community/eslint-utils": { "version": "4.4.0", @@ -21976,9 +23154,14 @@ } }, "@floating-ui/utils": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz", - "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==" + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" + }, + "@flowjs/flow.js": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/@flowjs/flow.js/-/flow.js-2.14.1.tgz", + "integrity": "sha512-99DWlPnksOOS8uHfo+bhSjvs8d2MfLTB/22JBDC2ONwz/OCdP+gL/iiM4puMSTE2wH4A2/+J0eMc7pKwusXunw==" }, "@formatjs/ecma402-abstract": { "version": "1.18.2", @@ -22764,6 +23947,97 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" }, + "@rc-component/async-validator": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz", + "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==", + "requires": { + "@babel/runtime": "^7.24.4" + } + }, + "@rc-component/color-picker": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-2.0.1.tgz", + "integrity": "sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==", + "requires": { + "@ant-design/fast-color": "^2.0.6", + "@babel/runtime": "^7.23.6", + "classnames": "^2.2.6", + "rc-util": "^5.38.1" + } + }, + "@rc-component/context": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz", + "integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==", + "requires": { + "@babel/runtime": "^7.10.1", + "rc-util": "^5.27.0" + } + }, + "@rc-component/mini-decimal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz", + "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==", + "requires": { + "@babel/runtime": "^7.18.0" + } + }, + "@rc-component/mutate-observer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz", + "integrity": "sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==", + "requires": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + } + }, + "@rc-component/portal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz", + "integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==", + "requires": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + } + }, + "@rc-component/qrcode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rc-component/qrcode/-/qrcode-1.0.0.tgz", + "integrity": "sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==", + "requires": { + "@babel/runtime": "^7.24.7", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + } + }, + "@rc-component/tour": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.15.1.tgz", + "integrity": "sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==", + "requires": { + "@babel/runtime": "^7.18.0", + "@rc-component/portal": "^1.0.0-9", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + } + }, + "@rc-component/trigger": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.2.3.tgz", + "integrity": "sha512-X1oFIpKoXAMXNDYCviOmTfuNuYxE4h5laBsyCqVAVMjNHxoF3/uiyA7XdegK1XbCvBbCZ6P6byWrEoDRpKL8+A==", + "requires": { + "@babel/runtime": "^7.23.2", + "@rc-component/portal": "^1.1.0", + "classnames": "^2.3.2", + "rc-motion": "^2.0.0", + "rc-resize-observer": "^1.3.1", + "rc-util": "^5.38.0" + } + }, "@react-aria/ssr": { "version": "3.9.2", "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.2.tgz", @@ -23393,9 +24667,9 @@ "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" }, "@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" }, "@types/q": { "version": "1.5.8", @@ -23971,6 +25245,74 @@ "color-convert": "^1.9.0" } }, + "antd": { + "version": "5.21.5", + "resolved": "https://registry.npmjs.org/antd/-/antd-5.21.5.tgz", + "integrity": "sha512-g/c8VkdruKDCVA6di9Ow1fG6dLtYJ1IOraPo7vXaY7DoQ56A3HExaFaH0fBEwTYKC0ICeftC4iA5eAjrF6/b9w==", + "requires": { + "@ant-design/colors": "^7.1.0", + "@ant-design/cssinjs": "^1.21.1", + "@ant-design/cssinjs-utils": "^1.1.1", + "@ant-design/icons": "^5.5.1", + "@ant-design/react-slick": "~1.1.2", + "@babel/runtime": "^7.25.6", + "@ctrl/tinycolor": "^3.6.1", + "@rc-component/color-picker": "~2.0.1", + "@rc-component/mutate-observer": "^1.1.0", + "@rc-component/qrcode": "~1.0.0", + "@rc-component/tour": "~1.15.1", + "@rc-component/trigger": "^2.2.3", + "classnames": "^2.5.1", + "copy-to-clipboard": "^3.3.3", + "dayjs": "^1.11.11", + "rc-cascader": "~3.28.2", + "rc-checkbox": "~3.3.0", + "rc-collapse": "~3.8.0", + "rc-dialog": "~9.6.0", + "rc-drawer": "~7.2.0", + "rc-dropdown": "~4.2.0", + "rc-field-form": "~2.4.0", + "rc-image": "~7.11.0", + "rc-input": "~1.6.3", + "rc-input-number": "~9.2.0", + "rc-mentions": "~2.16.1", + "rc-menu": "~9.15.1", + "rc-motion": "^2.9.3", + "rc-notification": "~5.6.2", + "rc-pagination": "~4.3.0", + "rc-picker": "~4.6.15", + "rc-progress": "~4.0.0", + "rc-rate": "~2.13.0", + "rc-resize-observer": "^1.4.0", + "rc-segmented": "~2.5.0", + "rc-select": "~14.15.2", + "rc-slider": "~11.1.7", + "rc-steps": "~6.0.1", + "rc-switch": "~4.1.0", + "rc-table": "~7.47.5", + "rc-tabs": "~15.3.0", + "rc-textarea": "~1.8.2", + "rc-tooltip": "~6.2.1", + "rc-tree": "~5.9.0", + "rc-tree-select": "~5.23.0", + "rc-upload": "~4.8.1", + "rc-util": "^5.43.0", + "scroll-into-view-if-needed": "^3.1.0", + "throttle-debounce": "^5.0.2" + }, + "dependencies": { + "rc-slider": { + "version": "11.1.7", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-11.1.7.tgz", + "integrity": "sha512-ytYbZei81TX7otdC0QvoYD72XSlxvTihNth5OeZ6PMXyEDq/vHdWFulQmfDGyXK1NwKwSlKgpvINOa88uT5g2A==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.36.0" + } + } + } + }, "any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -24033,6 +25375,11 @@ "is-string": "^1.0.7" } }, + "array-tree-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz", + "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==" + }, "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -24958,6 +26305,11 @@ } } }, + "compute-scroll-into-view": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz", + "integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -25001,6 +26353,14 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "requires": { + "toggle-selection": "^1.0.6" + } + }, "copy-webpack-plugin": { "version": "12.0.2", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz", @@ -25443,10 +26803,15 @@ } }, "date-fns": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", - "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "devOptional": true + }, + "dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" }, "debounce": { "version": "1.2.1", @@ -26521,6 +27886,11 @@ "strip-final-newline": "^2.0.0" } }, + "exif-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/exif-js/-/exif-js-2.3.0.tgz", + "integrity": "sha512-1Og9pAzG2FZRVlaavH8bB8BTeHcjMdJhKmeQITkX+uLRCD0xPtKAdZ2clZmQdJ56p9adXtJ8+jwrGp/4505lYg==" + }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -26791,6 +28161,11 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" }, + "flow.js": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/flow.js/-/flow.js-0.2.6.tgz", + "integrity": "sha512-KvXsCPNj3uIOnXu07qXiqsxjqEveAe5nAM8W3ULTEDPynoMZlWvMyKZdH8pOh5oCFy7uXtgWnZQZOzgoH9Epdw==" + }, "follow-redirects": { "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", @@ -29505,6 +30880,14 @@ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" }, + "json2mq": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", + "requires": { + "string-convert": "^0.2.0" + } + }, "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -29914,6 +31297,24 @@ "minimist": "^1.2.6" } }, + "mobx": { + "version": "6.13.3", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.13.3.tgz", + "integrity": "sha512-YtAS+ZMbdpbHYUU4ESht3na8KiX11KuMT1yOiKtbKlQ0GZkHDYPKyEw/Tdp7h7aHyLrTWj2TBaSNJ6bCr638iQ==" + }, + "mobx-react-lite": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-4.0.7.tgz", + "integrity": "sha512-RjwdseshK9Mg8On5tyJZHtGD+J78ZnCnRaxeQDSiciKVQDUbfZcXhmld0VMxAwvcTnPEHZySGGewm467Fcpreg==", + "requires": { + "use-sync-external-store": "^1.2.0" + } + }, + "moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" + }, "mrmime": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", @@ -31400,6 +32801,258 @@ } } }, + "rc-cascader": { + "version": "3.28.2", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.28.2.tgz", + "integrity": "sha512-8f+JgM83iLTvjgdkgU7GfI4qY8icXOBP0cGZjOdx2iJAkEe8ucobxDQAVE69UD/c3ehCxZlcgEHeD5hFmypbUw==", + "requires": { + "@babel/runtime": "^7.12.5", + "array-tree-filter": "^2.1.0", + "classnames": "^2.3.1", + "rc-select": "~14.15.0", + "rc-tree": "~5.9.0", + "rc-util": "^5.37.0" + } + }, + "rc-checkbox": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.3.0.tgz", + "integrity": "sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.25.2" + } + }, + "rc-collapse": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.8.0.tgz", + "integrity": "sha512-YVBkssrKPBG09TGfcWWGj8zJBYD9G3XuTy89t5iUmSXrIXEAnO1M+qjUxRW6b4Qi0+wNWG6MHJF/+US+nmIlzA==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.3.4", + "rc-util": "^5.27.0" + } + }, + "rc-dialog": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.6.0.tgz", + "integrity": "sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg==", + "requires": { + "@babel/runtime": "^7.10.1", + "@rc-component/portal": "^1.0.0-8", + "classnames": "^2.2.6", + "rc-motion": "^2.3.0", + "rc-util": "^5.21.0" + } + }, + "rc-drawer": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.2.0.tgz", + "integrity": "sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==", + "requires": { + "@babel/runtime": "^7.23.9", + "@rc-component/portal": "^1.1.1", + "classnames": "^2.2.6", + "rc-motion": "^2.6.1", + "rc-util": "^5.38.1" + } + }, + "rc-dropdown": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.2.0.tgz", + "integrity": "sha512-odM8Ove+gSh0zU27DUj5cG1gNKg7mLWBYzB5E4nNLrLwBmYEgYP43vHKDGOVZcJSVElQBI0+jTQgjnq0NfLjng==", + "requires": { + "@babel/runtime": "^7.18.3", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-util": "^5.17.0" + } + }, + "rc-field-form": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.4.0.tgz", + "integrity": "sha512-XZ/lF9iqf9HXApIHQHqzJK5v2w4mkUMsVqAzOyWVzoiwwXEavY6Tpuw7HavgzIoD+huVff4JghSGcgEfX6eycg==", + "requires": { + "@babel/runtime": "^7.18.0", + "@rc-component/async-validator": "^5.0.3", + "rc-util": "^5.32.2" + } + }, + "rc-image": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.11.0.tgz", + "integrity": "sha512-aZkTEZXqeqfPZtnSdNUnKQA0N/3MbgR7nUnZ+/4MfSFWPFHZau4p5r5ShaI0KPEMnNjv4kijSCFq/9wtJpwykw==", + "requires": { + "@babel/runtime": "^7.11.2", + "@rc-component/portal": "^1.0.2", + "classnames": "^2.2.6", + "rc-dialog": "~9.6.0", + "rc-motion": "^2.6.2", + "rc-util": "^5.34.1" + } + }, + "rc-input": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.6.3.tgz", + "integrity": "sha512-wI4NzuqBS8vvKr8cljsvnTUqItMfG1QbJoxovCgL+DX4eVUcHIjVwharwevIxyy7H/jbLryh+K7ysnJr23aWIA==", + "requires": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.18.1" + } + }, + "rc-input-number": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.2.0.tgz", + "integrity": "sha512-5XZFhBCV5f9UQ62AZ2hFbEY8iZT/dm23Q1kAg0H8EvOgD3UDbYYJAayoVIkM3lQaCqYAW5gV0yV3vjw1XtzWHg==", + "requires": { + "@babel/runtime": "^7.10.1", + "@rc-component/mini-decimal": "^1.0.1", + "classnames": "^2.2.5", + "rc-input": "~1.6.0", + "rc-util": "^5.40.1" + } + }, + "rc-mentions": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.16.1.tgz", + "integrity": "sha512-GnhSTGP9Mtv6pqFFGQze44LlrtWOjHNrUUAcsdo9DnNAhN4pwVPEWy4z+2jpjkiGlJ3VoXdvMHcNDQdfI9fEaw==", + "requires": { + "@babel/runtime": "^7.22.5", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-input": "~1.6.0", + "rc-menu": "~9.15.1", + "rc-textarea": "~1.8.0", + "rc-util": "^5.34.1" + } + }, + "rc-menu": { + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.15.1.tgz", + "integrity": "sha512-UKporqU6LPfHnpPmtP6hdEK4iO5Q+b7BRv/uRpxdIyDGplZy9jwUjsnpev5bs3PQKB0H0n34WAPDfjAfn3kAPA==", + "requires": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.0.0", + "classnames": "2.x", + "rc-motion": "^2.4.3", + "rc-overflow": "^1.3.1", + "rc-util": "^5.27.0" + } + }, + "rc-motion": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.3.tgz", + "integrity": "sha512-rkW47ABVkic7WEB0EKJqzySpvDqwl60/tdkY7hWP7dYnh5pm0SzJpo54oW3TDUGXV5wfxXFmMkxrzRRbotQ0+w==", + "requires": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.43.0" + } + }, + "rc-notification": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.2.tgz", + "integrity": "sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.9.0", + "rc-util": "^5.20.1" + } + }, + "rc-overflow": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.3.2.tgz", + "integrity": "sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==", + "requires": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.37.0" + } + }, + "rc-pagination": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-4.3.0.tgz", + "integrity": "sha512-UubEWA0ShnroQ1tDa291Fzw6kj0iOeF26IsUObxYTpimgj4/qPCWVFl18RLZE+0Up1IZg0IK4pMn6nB3mjvB7g==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + } + }, + "rc-picker": { + "version": "4.6.15", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.6.15.tgz", + "integrity": "sha512-OWZ1yrMie+KN2uEUfYCfS4b2Vu6RC1FWwNI0s+qypsc3wRt7g+peuZKVIzXCTaJwyyZruo80+akPg2+GmyiJjw==", + "requires": { + "@babel/runtime": "^7.24.7", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.1", + "rc-overflow": "^1.3.2", + "rc-resize-observer": "^1.4.0", + "rc-util": "^5.43.0" + } + }, + "rc-progress": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-4.0.0.tgz", + "integrity": "sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-util": "^5.16.1" + } + }, + "rc-rate": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.0.tgz", + "integrity": "sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.0.1" + } + }, + "rc-resize-observer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz", + "integrity": "sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==", + "requires": { + "@babel/runtime": "^7.20.7", + "classnames": "^2.2.1", + "rc-util": "^5.38.0", + "resize-observer-polyfill": "^1.5.1" + } + }, + "rc-segmented": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.5.0.tgz", + "integrity": "sha512-B28Fe3J9iUFOhFJET3RoXAPFJ2u47QvLSYcZWC4tFYNGPEjug5LAxEasZlA/PpAxhdOPqGWsGbSj7ftneukJnw==", + "requires": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-motion": "^2.4.4", + "rc-util": "^5.17.0" + } + }, + "rc-select": { + "version": "14.15.2", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.15.2.tgz", + "integrity": "sha512-oNoXlaFmpqXYcQDzcPVLrEqS2J9c+/+oJuGrlXeVVX/gVgrbHa5YcyiRUXRydFjyuA7GP3elRuLF7Y3Tfwltlw==", + "requires": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.1.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-overflow": "^1.3.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.2" + } + }, "rc-slider": { "version": "10.6.2", "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-10.6.2.tgz", @@ -31410,6 +33063,109 @@ "rc-util": "^5.36.0" } }, + "rc-steps": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-6.0.1.tgz", + "integrity": "sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==", + "requires": { + "@babel/runtime": "^7.16.7", + "classnames": "^2.2.3", + "rc-util": "^5.16.1" + } + }, + "rc-switch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz", + "integrity": "sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==", + "requires": { + "@babel/runtime": "^7.21.0", + "classnames": "^2.2.1", + "rc-util": "^5.30.0" + } + }, + "rc-table": { + "version": "7.47.5", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.47.5.tgz", + "integrity": "sha512-fzq+V9j/atbPIcvs3emuclaEoXulwQpIiJA6/7ey52j8+9cJ4P8DGmp4YzfUVDrb3qhgedcVeD6eRgUrokwVEQ==", + "requires": { + "@babel/runtime": "^7.10.1", + "@rc-component/context": "^1.4.0", + "classnames": "^2.2.5", + "rc-resize-observer": "^1.1.0", + "rc-util": "^5.41.0", + "rc-virtual-list": "^3.14.2" + } + }, + "rc-tabs": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.3.0.tgz", + "integrity": "sha512-lzE18r+zppT/jZWOAWS6ntdkDUKHOLJzqMi5UAij1LeKwOaQaupupAoI9Srn73GRzVpmGznkECMRrzkRusC40A==", + "requires": { + "@babel/runtime": "^7.11.2", + "classnames": "2.x", + "rc-dropdown": "~4.2.0", + "rc-menu": "~9.15.1", + "rc-motion": "^2.6.2", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.34.1" + } + }, + "rc-textarea": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.8.2.tgz", + "integrity": "sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-input": "~1.6.0", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.27.0" + } + }, + "rc-tooltip": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.2.1.tgz", + "integrity": "sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==", + "requires": { + "@babel/runtime": "^7.11.2", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.3.1" + } + }, + "rc-tree": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.9.0.tgz", + "integrity": "sha512-CPrgOvm9d/9E+izTONKSngNzQdIEjMox2PBufWjS1wf7vxtvmCWzK1SlpHbRY6IaBfJIeZ+88RkcIevf729cRg==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.1" + } + }, + "rc-tree-select": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.23.0.tgz", + "integrity": "sha512-aQGi2tFSRw1WbXv0UVXPzHm09E0cSvUVZMLxQtMv3rnZZpNmdRXWrnd9QkLNlVH31F+X5rgghmdSFF3yZW0N9A==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-select": "~14.15.0", + "rc-tree": "~5.9.0", + "rc-util": "^5.16.1" + } + }, + "rc-upload": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.8.1.tgz", + "integrity": "sha512-toEAhwl4hjLAI1u8/CgKWt30BR06ulPa4iGQSMvSXoHzO88gPCslxqV/mnn4gJU7PDoltGIC9Eh+wkeudqgHyw==", + "requires": { + "@babel/runtime": "^7.18.3", + "classnames": "^2.2.5", + "rc-util": "^5.2.0" + } + }, "rc-util": { "version": "5.43.0", "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.43.0.tgz", @@ -31426,10 +33182,21 @@ } } }, + "rc-virtual-list": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.15.0.tgz", + "integrity": "sha512-dF2YQztqrU3ijAeWOqscTshCEr7vpimzSqAVjO1AyAmaqcHulaXpnGR0ptK5PXfxTUy48VkJOiglMIxlkYGs0w==", + "requires": { + "@babel/runtime": "^7.20.0", + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.36.0" + } + }, "react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "requires": { "loose-envify": "^1.1.0" } @@ -31519,6 +33286,14 @@ "deepmerge": "^4.3.1" } }, + "react-datetime": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-datetime/-/react-datetime-3.2.0.tgz", + "integrity": "sha512-w5XdeNIGzBht9CadaZIJhKUhEcDTgH0XokKxGPCxeeJRYL7B3HIKA8CM6Q0xej2JFJt0n5d+zi3maMwaY3262A==", + "requires": { + "prop-types": "^15.5.7" + } + }, "react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -31606,12 +33381,12 @@ } }, "react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "requires": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.2" } }, "react-error-overlay": { @@ -31958,6 +33733,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, "resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -32171,9 +33951,9 @@ } }, "scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "requires": { "loose-envify": "^1.1.0" } @@ -32188,6 +33968,14 @@ "ajv-keywords": "^3.5.2" } }, + "scroll-into-view-if-needed": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", + "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", + "requires": { + "compute-scroll-into-view": "^3.0.2" + } + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -32659,6 +34447,11 @@ "safe-buffer": "~5.2.0" } }, + "string-convert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==" + }, "string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -33192,6 +34985,11 @@ "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==" }, + "throttle-debounce": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz", + "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==" + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -33220,6 +35018,11 @@ "is-number": "^7.0.0" } }, + "toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -33549,6 +35352,12 @@ "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", "requires": {} }, + "use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index d4a365b9e4..3befd3ea34 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,20 +3,28 @@ "version": "0.1.0", "private": true, "dependencies": { + "@flowjs/flow.js": "^2.14.1", "@testing-library/user-event": "^13.5.0", + "antd": "^5.21.5", "autoprefixer": "^10.4.18", "axios": "^1.7.4", "bootstrap": "^5.3.2", "copy-webpack-plugin": "^12.0.2", + "exif-js": "^2.3.0", + "flow.js": "^0.2.6", "google-map-react": "^2.2.1", "js-cookie": "^3.0.5", "lodash-es": "^4.17.21", + "mobx": "6.13.3", + "mobx-react-lite": "^4.0.7", + "moment": "^2.30.1", "postcss-cli": "^11.0.0", "rc-slider": "^10.6.2", "react": "^18.2.0", "react-bootstrap": "^2.10.1", "react-burger-menu": "^3.0.9", "react-data-table-component": "^7.6.2", + "react-datetime": "^3.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.52.1", "react-intl": "^6.6.2", @@ -74,7 +82,7 @@ "@testing-library/react": "^16.0.1", "bootstrap-icons": "^1.11.3", "css-loader": "^6.10.0", - "date-fns": "^3.6.0", + "date-fns": "^4.1.0", "eslint": "^8.57.0", "eslint-plugin-react": "^7.35.0", "globals": "^15.9.0", @@ -92,5 +100,10 @@ "webpack-bundle-analyzer": "^4.10.1", "webpack-cli": "^5.1.4", "webpack-dev-server": "^4.15.1" + }, + "jest":{ + "collectCoverage": true, + "coverageReporters": ["lcov", "text"], + "coverageDirectory": "./coverage" } } diff --git a/frontend/public/images/List_of_Logs_Image.png b/frontend/public/images/List_of_Logs_Image.png new file mode 100644 index 0000000000..93d5c57e49 Binary files /dev/null and b/frontend/public/images/List_of_Logs_Image.png differ diff --git a/frontend/public/images/report_an_encounter.png b/frontend/public/images/report_an_encounter.png new file mode 100644 index 0000000000..295ef283d4 Binary files /dev/null and b/frontend/public/images/report_an_encounter.png differ diff --git a/frontend/public/index.html b/frontend/public/index.html index 3827c6bb5d..cb02504d84 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -13,6 +13,8 @@ --> + + " + FlowFilePath); - + // System.out.println("FlowFilePath ---> " + FlowFilePath); FlowInfoStorage storage = FlowInfoStorage.getInstance(); +/* System.out.println("FlowChunkSize: " + FlowChunkSize); System.out.println("FlowTotalSize: " + FlowTotalSize); System.out.println("FlowIdentifier: " + FlowIdentifier); System.out.println("FlowFilename: " + FlowFilename); System.out.println("FlowRelativePath: " + FlowRelativePath); System.out.println("FlowFilePath: " + FlowFilePath); + */ // hacky, but gets us userFilename request.getSession().setAttribute("userFilename:" + FlowFilename, FlowRelativePath); @@ -289,4 +325,10 @@ private FlowInfo getFlowInfo(List parts, HttpServletRequest request) } return info; } + + // a simple wrapper, in case we want to change the logic here + private boolean accessAllowed(HttpServletRequest request) { + // note: this will return true for logged-in user (indifferent to captcha) + return ReCAPTCHA.sessionIsHuman(request); + } } diff --git a/src/main/java/org/ecocean/servlet/IndividualAddComment.java b/src/main/java/org/ecocean/servlet/IndividualAddComment.java index 1bf474aef1..cbccbd6f47 100644 --- a/src/main/java/org/ecocean/servlet/IndividualAddComment.java +++ b/src/main/java/org/ecocean/servlet/IndividualAddComment.java @@ -34,6 +34,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) response.setContentType("text/html"); PrintWriter out = response.getWriter(); boolean locked = false; + String newComment = ""; myShepherd.beginDBTransaction(); if ((request.getParameter("individual") != null) && @@ -43,9 +44,10 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) "individual")); if (ServletUtilities.isUserAuthorizedForIndividual(commentMe, request)) { try { - commentMe.addComments("

" + request.getParameter("user") + " on " + + newComment = ("

" + request.getParameter("user") + " on " + (new java.util.Date()).toString() + "
" + request.getParameter("comments") + "

"); + commentMe.addComments(newComment); } catch (Exception le) { locked = true; le.printStackTrace(); @@ -57,6 +59,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) response.setStatus(HttpServletResponse.SC_OK); out.println( "Success: I have successfully added your comments."); + out.println(newComment); // out.println("

Return to " + request.getParameter("individual") + // "

\n"); diff --git a/src/main/java/org/ecocean/servlet/ReCAPTCHA.java b/src/main/java/org/ecocean/servlet/ReCAPTCHA.java index 6741d6eea4..b8df95ef69 100644 --- a/src/main/java/org/ecocean/servlet/ReCAPTCHA.java +++ b/src/main/java/org/ecocean/servlet/ReCAPTCHA.java @@ -4,6 +4,8 @@ import java.io.PrintWriter; import java.net.URL; import java.util.Properties; +import java.util.Map; +import java.util.HashMap; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -12,10 +14,16 @@ import org.ecocean.*; import org.json.JSONObject; -/* some ReCAPTCHA-related stuff .... note that this has some useful public utility functions, as well as is a servlet which can do standalone - verification */ +/* + captcha-related functionality + TODO: this should be eventually renamed captcha-agnostically, but for now code is being left in for ReCAPTCHA + backwards compatibility. + + note that this has some useful public utility functions, as well as is a servlet which can do standalone + verification +*/ public class ReCAPTCHA extends HttpServlet { - private final static String ATTRIBUTE_PASSED = "reCAPTCHA-passed"; + private final static String ATTRIBUTE_PASSED = "captcha-passed"; public void init(ServletConfig config) throws ServletException { @@ -33,7 +41,12 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) response.setHeader("Access-Control-Allow-Origin", "*"); // allow us stuff from localhost response.setContentType("application/json"); PrintWriter out = response.getWriter(); - out.println(jsonResults(request, request.getParameter("recaptchaValue"))); + String procaptchaValue = request.getParameter("procaptchaValue"); + if (procaptchaValue != null) { + out.println(jsonResultsProcaptcha(request, procaptchaValue)); + } else { + out.println(jsonResults(request, request.getParameter("recaptchaValue"))); + } out.close(); } @@ -43,7 +56,16 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) response.setContentType("application/json"); JSONObject j = ServletUtilities.jsonFromHttpServletRequest(request); PrintWriter out = response.getWriter(); - out.println((j == null) ? null : jsonResults(request, j.optString("recaptchaValue", null))); + String procaptchaValue = null; + if (j != null) procaptchaValue = j.optString("procaptchaValue", null); + boolean useEnterprise = (j != null) && j.optBoolean("useEnterprise", false); + if (procaptchaValue != null) { + out.println(jsonResultsProcaptcha(request, procaptchaValue)); + } else if (useEnterprise) { + out.println(jsonResultsEnterprise(request, j.optString("recaptchaToken", null))); + } else { + out.println((j == null) ? null : jsonResults(request, j.optString("recaptchaValue", null))); + } out.close(); } @@ -55,7 +77,7 @@ private String jsonResults(HttpServletRequest request, String recaptchaValue) { return rtn.toString(); } boolean valid = captchaIsValid(ServletUtilities.getContext(request), recaptchaValue, - request.getRemoteAddr()); + ServletUtilities.getRemoteHost(request)); request.getSession().setAttribute(ATTRIBUTE_PASSED, valid); rtn.put("valid", valid); rtn.put("success", true); @@ -95,7 +117,7 @@ public static String captchaWidget(HttpServletRequest request, String params, // note: catcha can only be tested once.... see sessionIsHuman() below for sustained verification public static boolean captchaIsValid(HttpServletRequest request) { return captchaIsValid(ServletUtilities.getContext(request), - request.getParameter("g-recaptcha-response"), request.getRemoteAddr()); + request.getParameter("g-recaptcha-response"), ServletUtilities.getRemoteHost(request)); } public static boolean captchaIsValid(String context, String uresp, String remoteIP) { @@ -140,6 +162,127 @@ public static boolean captchaIsValid(String context, String uresp, String remote return valid; } + public static boolean captchaIsValidEnterprise(String context, String token, String remoteIP) { + String EXPECTED_ACTION = "VALIDATE"; + if (context == null) context = "context0"; + Properties recaptchaProps = ShepherdProperties.getProperties("recaptcha.properties", "", + context); + if (recaptchaProps == null) { + System.out.println("WARNING: no recaptcha.properties for captchaIsValid(); failing"); + return false; + } + String siteKey = recaptchaProps.getProperty("enterpriseSiteKey"); + String apiKey = recaptchaProps.getProperty("enterpriseApiKey"); + if ((siteKey == null) || (apiKey == null)) { + System.out.println("WARNING: could not determine keys for captchaIsValid(); failing"); + return false; + } + if (token == null) { + System.out.println("WARNING: recaptcha token is null in captchaIsValid(); failing"); + return false; + } + JSONObject cdata = new JSONObject(); + JSONObject cevent = new JSONObject(); + cevent.put("token", token); + cevent.put("userIpAddress", remoteIP); + cevent.put("siteKey", siteKey); + cevent.put("expectedAction", EXPECTED_ACTION); + cdata.put("event", cevent); + JSONObject gresp = null; + try { + gresp = RestClient.postJSON(new URL("https://recaptchaenterprise.googleapis.com/v1/projects/wildme-dev/assessments?key=" + apiKey), cdata, null); + } catch (Exception ex) { + System.out.println( + "WARNING: exception calling captcha api in captchaIsValid(); failing: " + + ex.toString()); + return false; + } + if (gresp == null) { // would this ever happen? + System.out.println( + "WARNING: null return from captcha api in captchaIsValid(); failing"); + return false; + } + System.out.println("INFO: captchaIsValid() api call returned: " + gresp.toString()); + JSONObject riskAnalysis = gresp.optJSONObject("riskAnalysis"); + JSONObject tokenProperties = gresp.optJSONObject("tokenProperties"); + JSONObject event = gresp.optJSONObject("event"); + System.out.println(" > riskAnalysis " + riskAnalysis); + System.out.println(" > tokenProperties " + tokenProperties); + System.out.println(" > event " + event); + if ((riskAnalysis == null) || (tokenProperties == null) || (event == null)) return false; + if (riskAnalysis.optDouble("score", 0.0) < 0.5) return false; + return true; + } + + public static boolean captchaIsValidProcaptcha(String context, String token) { + if (context == null) context = "context0"; + Properties captchaProps = ShepherdProperties.getProperties("captcha.properties", "", context); + if (captchaProps == null) { + System.out.println("WARNING: no captcha.properties for captchaIsValid(); failing"); + return false; + } + String secretKey = captchaProps.getProperty("procaptchaSecretKey"); + //String siteKey = captchaProps.getProperty("procaptchaSiteKey"); + if (secretKey == null) { + System.out.println("WARNING: could not determine secretKey for captchaIsValid(); failing"); + return false; + } + if (token == null) { + System.out.println("WARNING: captcha token is null in captchaIsValid(); failing"); + return false; + } + JSONObject cdata = new JSONObject(); + cdata.put("token", token); + cdata.put("secret", secretKey); + JSONObject resp = null; + Map headers = new HashMap(); + headers.put("User-Agent", "Wildbook/wildme.org"); // :( we need this or we get a 403 from their api + try { + resp = RestClient.postJSON(new URL("https://api.prosopo.io/siteverify"), cdata, headers); + } catch (Exception ex) { + System.out.println( + "WARNING: exception calling captcha api in captchaIsValid(); failing: " + + ex.toString()); + return false; + } + if (resp == null) { // would this ever happen? + System.out.println( + "WARNING: null return from captcha api in captchaIsValid(); failing"); + return false; + } + System.out.println("INFO: captchaIsValid() api call returned: " + resp.toString()); + return "ok".equals(resp.optString("status")) && resp.optBoolean("verified", false); + } + + private String jsonResultsEnterprise(HttpServletRequest request, String recaptchaToken) { + JSONObject rtn = new JSONObject("{\"success\": false}"); + + if ((request == null) || (recaptchaToken == null)) { + rtn.put("error", "recaptchaToken not set (or bad request)"); + return rtn.toString(); + } + boolean valid = captchaIsValidEnterprise(ServletUtilities.getContext(request), recaptchaToken, + ServletUtilities.getRemoteHost(request)); + request.getSession().setAttribute(ATTRIBUTE_PASSED, valid); + rtn.put("valid", valid); + rtn.put("success", true); + return rtn.toString(); + } + + private String jsonResultsProcaptcha(HttpServletRequest request, String value) { + JSONObject rtn = new JSONObject("{\"success\": false}"); + + if ((request == null) || (value == null)) { + rtn.put("error", "value not set (or bad request)"); + return rtn.toString(); + } + boolean valid = captchaIsValidProcaptcha(ServletUtilities.getContext(request), value); + request.getSession().setAttribute(ATTRIBUTE_PASSED, valid); + rtn.put("valid", valid); + rtn.put("success", true); + return rtn.toString(); + } + /* this does best guess at "are we human"? based on one of two things: 1. is the user logged in? if so: YES 2. if not, did they previously pass ReCAPTCHA (based on session attribute)? diff --git a/src/main/java/org/ecocean/servlet/ServletUtilities.java b/src/main/java/org/ecocean/servlet/ServletUtilities.java index a57fb3fe25..9d6f46af6d 100644 --- a/src/main/java/org/ecocean/servlet/ServletUtilities.java +++ b/src/main/java/org/ecocean/servlet/ServletUtilities.java @@ -1108,8 +1108,7 @@ public static void importJsp(String filename, HttpServletRequest request, request.getRequestDispatcher(filename).include(request, response); } - // used to determine if we want to apply a custom UI style, e.g. for IndoCet or - // the New England Aquarium to a web page + // used to determine if we want to apply a custom UI style, e.g. the New England Aquarium to a web page public static boolean useCustomStyle(HttpServletRequest request, String orgName) { // check url for "organization=____" arg String organization = request.getParameter("organization"); diff --git a/src/main/java/org/ecocean/servlet/export/EncounterAnnotationExportExcelFile.java b/src/main/java/org/ecocean/servlet/export/EncounterAnnotationExportExcelFile.java index 665653284f..da365c077d 100644 --- a/src/main/java/org/ecocean/servlet/export/EncounterAnnotationExportExcelFile.java +++ b/src/main/java/org/ecocean/servlet/export/EncounterAnnotationExportExcelFile.java @@ -204,12 +204,14 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) annViewpoint, columns); aanViewpointK.setMaNum(maNum); } + // individual names and summaries + MultiValueExportColumn.addNameColumns(numNameCols, columns); ExportColumn markedIndividualSex = new ExportColumn(MarkedIndividual.class, - "Encounter.sex", markedIndividualSexName, columns); + "IndividualSummary.sex", markedIndividualSexName, columns); ExportColumn markedIndividuallifeStage = new ExportColumn(MarkedIndividual.class, - "Encounter.lifeStage", markedIndividualLifeStageName, columns); + "IndividualSummary.lifeStage", markedIndividualLifeStageName, columns); - MultiValueExportColumn.addNameColumns(numNameCols, columns); + // encounter information newEasyColumn("Encounter.genus", columns); newEasyColumn("Encounter.specificEpithet", columns); newEasyColumn("Encounter.verbatimLocality", columns); @@ -222,6 +224,8 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) newEasyColumn("Encounter.day", columns); newEasyColumn("Encounter.hour", columns); newEasyColumn("Encounter.minutes", columns); + newEasyColumn("Encounter.sex", columns); + newEasyColumn("Encounter.lifeStage", columns); newEasyColumn("Encounter.occurrenceRemarks", columns); ExportColumn OccurrenceComments = new ExportColumn(Occurrence.class, "Occurrence.comments", occurrenceComments, columns); diff --git a/src/main/java/org/ecocean/servlet/export/EncounterSearchExportShapefile.java b/src/main/java/org/ecocean/servlet/export/EncounterSearchExportShapefile.java index 929fa5cb18..8cc2365e6b 100644 --- a/src/main/java/org/ecocean/servlet/export/EncounterSearchExportShapefile.java +++ b/src/main/java/org/ecocean/servlet/export/EncounterSearchExportShapefile.java @@ -89,7 +89,8 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) ("the_geom:Point:srid=4326," + // <- the geometry attribute: Point type "Date:java.util.Date," + // <- a String attribute "Encounter:String," + // a number attribute - "Individual:String," + // a number attribute + "Individual:String," + // a string attribute + "Name:String," + // a number attribute "Sex:String," + // a number attribute "Haplotype:String," + // a number attribute "URL:String," + // a number attribute @@ -140,6 +141,8 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) featureBuilder.set("Encounter", enc.getCatalogNumber()); featureBuilder.set("Individual", ServletUtilities.handleNullString(enc.getIndividualID())); + featureBuilder.set("Name", + ServletUtilities.handleNullString(enc.getDisplayName())); if (enc.getSex() != null) { featureBuilder.set("Sex", enc.getSex()); } diff --git a/src/main/java/org/ecocean/servlet/importer/IndocetStandardImport.java b/src/main/java/org/ecocean/servlet/importer/IndocetStandardImport.java deleted file mode 100644 index 82ac7252f9..0000000000 --- a/src/main/java/org/ecocean/servlet/importer/IndocetStandardImport.java +++ /dev/null @@ -1,1040 +0,0 @@ -package org.ecocean.servlet.importer; - -import java.io.*; -import java.io.File; -import java.util.*; -import org.ecocean.*; -import org.ecocean.genetics.*; -import org.ecocean.media.*; -import org.ecocean.servlet.*; -import org.ecocean.tag.SatelliteTag; - -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.ss.usermodel.WorkbookFactory; -import org.joda.time.DateTime; - -import org.json.JSONObject; - -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; - -/// DEPRECATED!!! This importer is not compatible with the new naming scheme and must be updated - -public class IndocetStandardImport extends HttpServlet { - // variables shared by any single import instance - Shepherd myShepherd; - Map colIndexMap = new HashMap(); - Set unusedColumns; - Set missingColumns; // columns we look for but don't find - List missingPhotos = new ArrayList(); - List foundPhotos = new ArrayList(); - int numFolderRows = 0; - boolean committing = false; - PrintWriter out; - // verbose variable can be switched on/off throughout the import for debugging - boolean verbose = false; - String photoDirectory; - - private AssetStore astore; - - // just for lazy loading a var used on each row - Integer numMediaAssets; - - public void init(ServletConfig config) - throws ServletException { - super.init(config); - } - - public void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - doPost(request, response); - } - - public void doPost(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { - String context = "context0"; - - context = ServletUtilities.getContext(request); - myShepherd = new Shepherd(context); - out = response.getWriter(); - astore = getAssetStore(myShepherd); - - // photoDirectory = "/data/oman_import/photos/"; - // String filename = "/data/oman_import/ASWN_secondExport.xlsx"; - photoDirectory = "/data/indocet/"; - String filename = "/data/indocet/indocet_blended.xlsx"; - if (request.getParameter("filename") != null) filename = request.getParameter("filename"); - File dataFile = new File(filename); - boolean dataFound = dataFile.exists(); - - missingColumns = new HashSet(); - missingPhotos = new ArrayList(); - foundPhotos = new ArrayList(); - numFolderRows = 0; - - committing = (request.getParameter("commit") != null && - !request.getParameter("commit").toLowerCase().equals("false")); // false by default - - out.println("

File Overview:

"); - out.println("
    "); - out.println("
  • Filename: " + filename + "
  • "); - out.println("
  • File found = " + dataFound + "
  • "); - - Workbook wb = null; - try { - wb = WorkbookFactory.create(dataFile); - } catch (org.apache.poi.openxml4j.exceptions.InvalidFormatException invalidFormat) { - out.println("InvalidFormatException on input file " + filename + - ". Only excel files supported."); - return; - } - Sheet sheet = wb.getSheetAt(0); - int numSheets = wb.getNumberOfSheets(); - out.println("
  • Num Sheets = " + numSheets + "
  • "); - int physicalNumberOfRows = sheet.getPhysicalNumberOfRows(); - out.println("
  • Num Rows = " + physicalNumberOfRows + "
  • "); - int rows = sheet.getPhysicalNumberOfRows(); // No of rows - Row firstRow = sheet.getRow(0); - // below line is important for on-screen logging - initColIndexVariables(firstRow); - int cols = firstRow.getPhysicalNumberOfCells(); // No of columns - int lastColNum = firstRow.getLastCellNum(); - - out.println("
  • Num Cols = " + cols + "
  • "); - out.println("
  • Last col num = " + lastColNum + "
  • "); - out.println("
  • committing = " + committing + "
  • "); - out.println("
"); - out.println("

Column headings:

    "); - out.println("
  • number columns = " + colIndexMap.size() + "
  • "); - for (String heading : colIndexMap.keySet()) - out.println("
  • " + colIndexMap.get(heading) + ": " + heading + "
  • "); - out.println("
"); - - int printPeriod = 100; - if (committing) myShepherd.beginDBTransaction(); - out.println("

Beginning row loop:

"); - out.println("
    "); - // one encounter per-row. We keep these running. - Occurrence occ = null; - int maxRows = 50000; - int offset = 0; - for (int i = 1 + offset; i < rows && i < (maxRows + offset); i++) { - MarkedIndividual mark = null; - verbose = ((i % printPeriod) == 0); - try { - if (committing) myShepherd.beginDBTransaction(); - Row row = sheet.getRow(i); - if (isRowEmpty(row)) continue; - // here's the central logic - ArrayList annotations = loadAnnotations(row); - Encounter enc = loadEncounter(row, annotations); - occ = loadOccurrence(row, occ, enc); - mark = loadIndividual(row, enc); - if (committing) { - for (Annotation ann : annotations) { - try { - MediaAsset ma = ann.getMediaAsset(); - if (ma != null) { - myShepherd.storeNewAnnotation(ann); - ma.setMetadata(); - ma.updateStandardChildren(myShepherd); - } - } catch (Exception e) { - System.out.println("EXCEPTION on annot/ma persisting!"); - e.printStackTrace(); - } - } - myShepherd.storeNewEncounter(enc, enc.getCatalogNumber()); - if (!myShepherd.isOccurrence(occ)) myShepherd.storeNewOccurrence(occ); - if (!myShepherd.isMarkedIndividual(mark)) - myShepherd.storeNewMarkedIndividual(mark); - myShepherd.commitDBTransaction(); - } - if (verbose) { - out.println("
  • Parsed row (" + i + ")
      " + "
    • Enc " + - getEncounterDisplayString(enc) + "
    • " + "
    • individual " + mark + - "
    • " + "
    • occurrence " + occ + "
    • " + "
    • dateInMillis " + - enc.getDateInMilliseconds() + "
    • " + "
    • sex " + enc.getSex() + - "
    • " + "
    • lifeStage " + enc.getLifeStage() + "
    • " + "
  • "); - } - } catch (Exception e) { - out.println("Encountered an error while importing the file."); - e.printStackTrace(out); - myShepherd.rollbackDBTransaction(); - } - } - out.println("
"); - - out.println("

UNUSED Column headings (" + unusedColumns.size() + "):

    "); - for (String heading : unusedColumns) { - out.println("
  • " + heading + "
  • "); - } - out.println("
"); - - List usedColumns = new ArrayList(); - for (String colName : colIndexMap.keySet()) { - if (!unusedColumns.contains(colName)) usedColumns.add(colName); - } - out.println("

USED Column headings (" + usedColumns.size() + "):

    "); - for (String heading : usedColumns) { - out.println("
  • " + heading + "
  • "); - } - out.println("
"); - - out.println("

Missing photos(" + missingPhotos.size() + "):

    "); - for (String photo : missingPhotos) { - out.println("
  • " + photo + "
  • "); - } - out.println("
"); - - out.println("

Found photos(" + foundPhotos.size() + "):

    "); - for (String photo : foundPhotos) { - out.println("
  • " + photo + "
  • "); - } - out.println("
"); - - out.println("

" + numFolderRows + " Folder Rows

"); - - out.println("

Import completed successfully

"); - // fs.close(); - } - - public Taxonomy loadTaxonomy0(Row row) { - String sciName = getString(row, "Taxonomy.scientificName"); - - if (sciName == null) return null; - Taxonomy taxy = myShepherd.getOrCreateTaxonomy(sciName); - String commonName = getString(row, "Taxonomy.commonName"); - if (commonName != null) taxy.addCommonName(commonName); - return taxy; - } - - public Taxonomy loadTaxonomy1(Row row) { - String sciName = getString(row, "Occurrence.taxonomy1"); - - if (sciName == null) return null; - return myShepherd.getOrCreateTaxonomy(sciName); - } - - public static boolean validLatLon(Double lat, Double lon) { - return ((lat != null) && (lon != null) && ((lat != 0.0) && (lon != 0.0))); - } - - public Occurrence loadOccurrence(Row row, Occurrence oldOcc, Encounter enc) { - Occurrence occ = getCurrentOccurrence(oldOcc, row); - // would love to have a more concise way to write following couplets, c'est la vie - Double seaSurfaceTemp = getDouble(row, "Occurrence.seaSurfaceTemperature"); - - if (seaSurfaceTemp != null) occ.setSeaSurfaceTemp(seaSurfaceTemp); - Integer individualCount = getInteger(row, "Occurrence.individualCount"); - if (individualCount != null) occ.setIndividualCount(individualCount); - Double decimalLatitiude = getDouble(row, "Encounter.decimalLatitiude"); - if (decimalLatitiude != null) occ.setDecimalLatitude(decimalLatitiude); - Double decimalLatitude = getDouble(row, "Encounter.decimalLatitude"); - Double decimalLongitude = getDouble(row, "Encounter.decimalLongitude"); - if (validLatLon(decimalLatitude, decimalLongitude)) { - occ.setDecimalLatitude(decimalLatitude); - occ.setDecimalLongitude(decimalLongitude); - } - String fieldStudySite = getString(row, "Occurrence.fieldStudySite"); - if (fieldStudySite != null) occ.setFieldStudySite(fieldStudySite); - String groupComposition = getString(row, "Occurrence.groupComposition"); - if (groupComposition != null) occ.setGroupComposition(groupComposition); - String fieldSurveyCode = getString(row, "Survey.id"); - if (fieldSurveyCode == null) fieldSurveyCode = getString(row, "Occurrence.fieldSurveyCode"); - if (fieldSurveyCode != null) occ.setFieldSurveyCode(fieldSurveyCode); - String sightingPlatform = getString(row, "Survey.vessel"); - if (sightingPlatform == null) sightingPlatform = getString(row, "Platform Designation"); - if (sightingPlatform != null) occ.setSightingPlatform(sightingPlatform); - String surveyComments = getString(row, "Survey.comments"); - if (surveyComments != null) occ.addComments(surveyComments); - Integer numAdults = getInteger(row, "Occurrence.numAdults"); - if (numAdults != null) occ.setNumAdults(numAdults); - Integer minGroupSize = getInteger(row, "Occurrence.minGroupSizeEstimate"); - if (minGroupSize != null) occ.setMinGroupSizeEstimate(minGroupSize); - Integer maxGroupSize = getInteger(row, "Occurrence.maxGroupSizeEstimate"); - if (maxGroupSize != null) occ.setMaxGroupSizeEstimate(maxGroupSize); - Double bestGroupSize = getDouble(row, "Occurrence.bestGroupSizeEstimate"); - if (bestGroupSize != null) occ.setBestGroupSizeEstimate(bestGroupSize); - Integer numCalves = getInteger(row, "Occurrence.numCalves"); - if (numCalves != null) occ.setNumCalves(numCalves); - Integer numJuveniles = getInteger(row, "Occurrence.numJuveniles"); - if (numJuveniles != null) occ.setNumJuveniles(numJuveniles); - Double bearing = getDouble(row, "Occurrence.bearing"); - if (bearing != null) occ.setBearing(bearing); - Double distance = getDouble(row, "Occurrence.distance"); - if (distance != null) occ.setDistance(distance); - Double swellHeight = getDouble(row, "Occurrence.swellHeight"); - if (swellHeight != null) occ.setSwellHeight(swellHeight); - String seaState = getString(row, "Occurrence.seaState"); - if (seaState != null) occ.setSeaState(seaState); - Double visibilityIndex = getDouble(row, "Occurrence.visibilityIndex"); - if (visibilityIndex != null) occ.setVisibilityIndex(visibilityIndex); - Double transectBearing = getDouble(row, "Occurrence.transectBearing"); - if (transectBearing != null) occ.setTransectBearing(transectBearing); - String transectName = getString(row, "Occurrence.transectName"); - if (transectName != null) occ.setTransectName(transectName); - String initialCue = getString(row, "Occurrence.initialCue"); - String humanActivity = getString(row, "Occurrence.humanActivityNearby"); - if (humanActivity != null) occ.setHumanActivityNearby(humanActivity); - Double effortCode = getDouble(row, "Occurrence.effortCode"); - if (effortCode != null) occ.setEffortCode(effortCode); - Taxonomy taxy = loadTaxonomy0(row); - if (taxy != null) occ.addTaxonomy(taxy); - Taxonomy taxy1 = loadTaxonomy1(row); - if (taxy1 != null) occ.addTaxonomy(taxy1); - String surveyTrackVessel = getString(row, "SurveyTrack.vesselID"); - if (surveyTrackVessel != null) occ.setSightingPlatform(surveyTrackVessel); - Long millis = getLong(row, "Encounter.dateInMilliseconds"); - if (millis == null) millis = getLong(row, "Occurrence.dateInMilliseconds"); - if (millis == null) millis = getLong(row, "Occurrence.millis"); - if (millis != null) occ.setDateTimeLong(millis); - if (enc != null) { - occ.addEncounter(enc); - // overwrite=false on following fromEncs methods - occ.setLatLonFromEncs(false); - occ.setSubmitterIDFromEncs(false); - } - return occ; - } - - public Encounter loadEncounter(Row row, ArrayList annotations) { - Encounter enc = new Encounter(annotations); - - // since we need access to the encounter ID - String encID = Util.generateUUID(); - - enc.setEncounterNumber(encID); - - // Time - Integer year = getInteger(row, "Encounter.year"); - if (year == null) year = getInteger(row, "Occurrence.year"); - if (year != null) enc.setYear(year); - Integer month = getInteger(row, "Encounter.month"); - if (month == null) month = getInteger(row, "Occurrence.month"); - if (month != null) enc.setMonth(month); - Integer day = getInteger(row, "Encounter.day"); - if (day == null) day = getInteger(row, "Occurrence.day"); - if (day != null) enc.setDay(day); - Integer hour = getInteger(row, "Encounter.hour"); - if (hour == null) hour = getInteger(row, "Occurrence.hour"); - if (hour != null) enc.setHour(hour); - String minutes = getIntAsString(row, "Encounter.minutes"); - if (minutes == null) minutes = getIntAsString(row, "Occurrence.minutes"); - if (minutes != null) enc.setMinutes(minutes); - // setting milliseconds last means that (if provided) the exif/millis data will always take precedence - // if we set it before, enc.setMinutes & others would reset millis - Long millis = getLong(row, "Encounter.dateInMilliseconds"); - if (millis == null) millis = getLong(row, "Occurrence.dateInMilliseconds"); - if (millis == null) millis = getLong(row, "Occurrence.millis"); - boolean hasTimeCategories = (year != null || month != null || day != null || hour != null || - minutes != null); - if (millis != null) { - if (hasTimeCategories) enc.setDateInMillisOnly(millis); // does not overwrite day/month/etc - else enc.setDateInMilliseconds(millis); - } - // Location - Double latitude = getDouble(row, "Encounter.latitude"); - if (latitude == null) latitude = getDouble(row, "Encounter.decimalLatitude"); - if (latitude == null) latitude = getDouble(row, "Occurrence.decimalLatitude"); - Double longitude = getDouble(row, "Encounter.longitude"); - if (longitude == null) longitude = getDouble(row, "Encounter.decimalLongitude"); - if (longitude == null) longitude = getDouble(row, "Occurrence.decimalLongitude"); - if (validLatLon(latitude, longitude)) { - enc.setDecimalLatitude(latitude); - enc.setDecimalLongitude(longitude); - } - String locationID = getString(row, "Encounter.locationID"); - if (locationID != null) enc.setLocationID(locationID); - String country = getString(row, "Encounter.country"); - if (country != null) enc.setCountry(country); - // String fields - String otherCatalogNumbers = getStringOrInt(row, "Encounter.otherCatalogNumbers"); - if (otherCatalogNumbers != null) enc.setOtherCatalogNumbers(otherCatalogNumbers); - String sex = getString(row, "Encounter.sex"); - if (sex != null) enc.setSex(sex); - String genus = getString(row, "Encounter.genus"); - if (genus != null) enc.setGenus(genus); - String specificEpithet = getString(row, "Encounter.specificEpithet"); - if (specificEpithet != null) enc.setSpecificEpithet(specificEpithet); - String submitterOrganization = getString(row, "Encounter.submitterOrganization"); - if (submitterOrganization != null) enc.setSubmitterOrganization(submitterOrganization); - String submitterName = getString(row, "Encounter.submitterName"); - if (submitterName != null) enc.setSubmitterName(submitterName); - Integer patterningCode = getInteger(row, "Encounter.patterningCode"); - if (patterningCode != null) enc.setFlukeType(patterningCode); - String occurrenceRemarks = getString(row, "Encounter.occurrenceRemarks"); - if (occurrenceRemarks != null) enc.setOccurrenceRemarks(occurrenceRemarks); - String occurrenceID = getString(row, "Encounter.occurrenceID"); - if (occurrenceID == null) occurrenceID = getString(row, "Occurrence.occurrenceID"); - if (occurrenceID != null) enc.setOccurrenceID(occurrenceID); - String submitterID = getString(row, "Encounter.submitterID"); - if (submitterID != null) enc.setSubmitterID(submitterID); - String behavior = getString(row, "Encounter.behavior"); - if (behavior != null) enc.setBehavior(behavior); - String individualID = getIndividualID(row); - // DEPRECATED - // if (individualID!=null) enc.setIndividualID(individualID); - String lifeStage = getString(row, "Encounter.lifeStage"); - if (lifeStage != null) enc.setLifeStage(lifeStage); - String groupRole = getString(row, "Encounter.groupRole"); - if (groupRole != null) enc.setGroupRole(groupRole); - String researcherComments = getString(row, "Encounter.researcherComments"); - if (researcherComments != null) enc.addComments(researcherComments); - String verbatimLocality = getString(row, "Encounter.verbatimLocality"); - if (verbatimLocality != null) enc.setVerbatimLocality(verbatimLocality); - String nickname = getString(row, "MarkedIndividual.nickname"); - if (nickname == null) nickname = getString(row, "MarkedIndividual.nickName"); - if (nickname != null) enc.setAlternateID(nickname); - String alternateID = getString(row, "Encounter.alternateID"); - if (alternateID != null) enc.setAlternateID(alternateID); - Double length = getDouble(row, "Encounter.measurement.length"); - if (length != null) { - Measurement lengthMeas = new Measurement(encID, "length", length, "m", ""); - if (committing) enc.setMeasurement(lengthMeas, myShepherd); - } - Double weight = getDouble(row, "Encounter.measurement.weight"); - if (weight != null) { - Measurement weightMeas = new Measurement(encID, "weight", weight, "kg", ""); - if (committing) enc.setMeasurement(weightMeas, myShepherd); - } - Double depth = getDouble(row, "Encounter.depth"); - if (depth != null) enc.setDepth(depth); - String scar = getIntAsString(row, "Encounter.distinguishingScar"); - if (scar != null) enc.setDistinguishingScar(scar); - // SAMPLES - TissueSample sample = null; - String tissueSampleID = getStringOrInt(row, "TissueSample.sampleID"); - // we need to make sure we have a sampleID whenever we have a microsat marker - if (tissueSampleID == null) - tissueSampleID = getStringOrInt(row, "MicrosatelliteMarkersAnalysis.analysisID"); - // same for sex analysis - if (tissueSampleID == null) - tissueSampleID = getStringOrInt(row, "SexAnalysis.processingLabTaskID"); - if (tissueSampleID != null) { - sample = myShepherd.getTissueSample(tissueSampleID, encID); - if (sample == null) sample = new TissueSample(enc.getCatalogNumber(), tissueSampleID); - } - String markerAnalysisID = getStringOrInt(row, "MicrosatelliteMarkersAnalysis.analysisID"); - // we need to add uniqueness to the parsed string bc it's a primary key - // but adding full encID is too long of a string. - if (markerAnalysisID != null) - markerAnalysisID = markerAnalysisID + "-enc-" + encID.substring(0, - Math.min(8, encID.length())); - if (markerAnalysisID != null && !myShepherd.isGeneticAnalysis(markerAnalysisID)) { - markerAnalysisID = markerAnalysisID.replaceAll("_", "-"); - MicrosatelliteMarkersAnalysis microMark = myShepherd.getMicrosatelliteMarkersAnalysis( - markerAnalysisID); - if (microMark == null) { - microMark = new MicrosatelliteMarkersAnalysis(markerAnalysisID, tissueSampleID, - encID); - if (sample != null) sample.addGeneticAnalysis(microMark); - } // if microMark was grabbed from Shepherd correctly there is no further data to store. - } - String sexAnalID = getStringOrInt(row, "SexAnalysis.processingLabTaskID"); - String sexAnalSex = getString(row, "SexAnalysis.sex"); - if (sexAnalID != null) { - // we need to add uniqueness to the parsed string bc it's a primary key - // but adding full encID is too long of a string. - sexAnalID = sexAnalID + "-enc-" + encID.substring(0, Math.min(8, encID.length())); - sexAnalID = sexAnalID.replaceAll("_", "-"); - } - if (sexAnalID != null && sexAnalSex != null && !myShepherd.isGeneticAnalysis(sexAnalID)) { - SexAnalysis sexAnal = myShepherd.getSexAnalysis(sexAnalID); - if (sexAnal == null) { - sexAnal = new SexAnalysis(sexAnalID, sexAnalSex, encID, tissueSampleID); - if (sample != null) sample.addGeneticAnalysis(sexAnal); - } else sexAnal.setSex(sexAnalSex); - } - if (sample != null) enc.addTissueSample(sample); - // END SAMPLES - - String satelliteTag = getString(row, "SatelliteTag.serialNumber"); - if (satelliteTag != null) { - SatelliteTag tag = new SatelliteTag("", satelliteTag, ""); // note the empty fields. sat tags are weird. - enc.setSatelliteTag(tag); - } - String caudalType = getIntAsString(row, "Type caudale Mn"); - if (caudalType != null) { - enc.setDynamicProperty("caudal type", caudalType); - } - enc.setState("approved"); - return enc; - } - - public Set getColumnFieldsForClass(String className) { - Set fieldNames = new HashSet(); - - try { - for (String columnHeader : colIndexMap.keySet()) { - if (columnHeader.contains(className + ".")) { - fieldNames.add(columnHeader.split(className + ".")[1]); // for Encounter.date returns date - } - } - } catch (Exception e) {} - return fieldNames; - } - - public ArrayList loadAnnotations(Row row) { - if (isFolderRow(row)) return loadAnnotationsFolderRow(row); - ArrayList annots = new ArrayList(); - for (int i = 0; i < getNumMediaAssets(); i++) { - MediaAsset ma = getMediaAsset(row, i); - if (ma == null) continue; - String species = getSpeciesString(row); - Annotation ann = new Annotation(species, ma); - ann.setIsExemplar(true); - annots.add(ann); - // if (ma!=null && ma.localPath()!=null) foundPhotos.add(ma.localPath().toString()); - } - if (annots.size() > 0) { - for (int i = 0; i < annots.size(); i++) { - String maName = "Encounter.mediaAsset" + i; - String localPath = getString(row, maName); - if (localPath != null) foundPhotos.add(photoDirectory + localPath); - } - } - return annots; - } - - // for when the provided image filename is actually a folder of images - private ArrayList loadAnnotationsFolderRow(Row row) { - ArrayList annots = new ArrayList(); - String localPath = getString(row, "Encounter.mediaAsset0"); - - if (localPath == null) return annots; - localPath = localPath.substring(0, localPath.length() - 1); // removes trailing asterisk - localPath = fixGlobiceFullPath(localPath) + "/"; -// localPath = localPath.replace(" ","\\ "); - String fullPath = photoDirectory + localPath; - // Globice fix! - // now fix spaces - File photoDir = new File(fullPath); - if (!photoDir.exists() || !photoDir.isDirectory() || photoDir.listFiles() == null) { - boolean itExists = photoDir.exists(); - boolean isDirectory = (itExists) && photoDir.isDirectory(); - boolean hasFiles = isDirectory && photoDir.listFiles() != null; - System.out.println( - "StandardImport ERROR: loadAnnotationsFolderRow called on non-directory (or empty?) path " - + fullPath); - System.out.println("\t\titExists: " + itExists); - System.out.println("\t\tisDirectory: " + isDirectory); - System.out.println("\t\thasFiles: " + hasFiles); - missingPhotos.add(localPath); - return annots; - } - // if there are keywords we apply to all photos in encounter - String keyword0 = getString(row, "Encounter.keyword00"); - Keyword key0 = (keyword0 == null) ? null : myShepherd.getOrCreateKeyword(keyword0); - String keyword1 = getString(row, "Encounter.keyword01"); - Keyword key1 = (keyword1 == null) ? null : myShepherd.getOrCreateKeyword(keyword1); - String species = getSpeciesString(row); - for (File f : photoDir.listFiles()) { - MediaAsset ma = null; - try { - JSONObject assetParams = astore.createParameters(f); - System.out.println("\t\thave assetParams"); - assetParams.put("_localDirect", f.toString()); - System.out.println("\t\tabout to create mediaAsset"); - ma = astore.copyIn(f, assetParams); - } catch (Exception e) { - System.out.println("IOException creating MediaAsset for file " + f.getPath()); - missingPhotos.add(f.getPath()); - continue; // skips the rest of loop for this file - } - if (ma == null) continue; - if (key0 != null) ma.addKeyword(key0); - if (key1 != null) ma.addKeyword(key1); - Annotation ann = new Annotation(species, ma); - ann.setIsExemplar(true); - annots.add(ann); - } - if (annots.size() > 0) foundPhotos.add(fullPath); - return annots; - } - - // capitolizes the final directory in path - private String fixGlobiceFullPath(String path) { - String fixed = capitolizeLastFilepart(path); - - fixed = removeExtraGlobiceString(fixed); - return fixed; - } - - private String removeExtraGlobiceString(String path) { - // we somehow got an extra instance of the word "globice" in the path string, right before a 1 - return (path.replace("Globice1", "1")); - } - - private String capitolizeLastFilepart(String path) { - String[] parts = path.split("/"); - String lastPart = parts[parts.length - 1]; - String firstPart = path.substring(0, path.indexOf(lastPart)); - - return firstPart + lastPart.toUpperCase(); - } - - // most rows have a single image, but some have an image folder - private boolean isFolderRow(Row row) { - String path = getString(row, "Encounter.mediaAsset0"); - - if (path == null) return false; - boolean ans = path.endsWith("*"); - if (ans) numFolderRows++; - return ans; - } - - public String getSpeciesString(Row row) { - String genus = getString(row, "Encounter.genus"); - String species = getString(row, "Encounter.species"); - String total = genus + " " + species; - - if (total == null || total.equals(" ")) total = "unknown"; - return total; - } - - public String getIndividualID(Row row) { - String indID = getString(row, "Encounter.individualID"); - - if (indID == null) indID = getString(row, "MarkedIndividual.individualID"); - // Cetamada uses single letter names like A - if (indID != null && indID.length() == 1) return "Cetamada-" + indID; - return indID; - } - - public MediaAsset getMediaAsset(Row row, int i) { - String localPath = getString(row, "Encounter.mediaAsset" + i); - - if (localPath == null) return null; - localPath = Util.windowsFileStringToLinux(localPath); - String fullPath = photoDirectory + localPath; - String resolvedPath = resolveHumanEnteredFilename(fullPath); - if (resolvedPath == null) { - missingPhotos.add(fullPath); - return null; - } - File f = new File(resolvedPath); - - // create MediaAsset and return it - JSONObject assetParams = astore.createParameters(f); - assetParams.put("_localDirect", f.toString()); - MediaAsset ma = null; - try { - ma = astore.copyIn(f, assetParams); - } catch (java.io.IOException ioEx) { - System.out.println("IOException creating MediaAsset for file " + fullPath); - missingPhotos.add(fullPath); - } - // keywording - - ArrayList kws = getKeywordsForAsset(row, i); - ma.setKeywords(kws); - - return ma; - } - - private ArrayList getKeywordsForAsset(Row row, int n) { - ArrayList ans = new ArrayList(); - int maxAssets = getNumAssets(row); - int maxKeywords = 2; - int stopAtKeyword = (maxAssets == (n + 1)) ? maxKeywords : n; // - - // we have up to two keywords per row. - for (int i = n; i < stopAtKeyword; i++) { - String kwColName = "Encounter.keyword0" + i; - String kwName = getString(row, kwColName); - if (kwName == null) continue; - Keyword kw = myShepherd.getOrCreateKeyword(kwName); - if (kw != null) ans.add(kw); - } - return ans; - } - - private int getNumAssets(Row row) { - int n = 0; - - while (getString(row, "Encounter.mediaAsset" + n) != null) { n++; } - return n; - } - - // Checks common human errors in inputing filenames - // and returns the most similar filename that actually exists on the server - // returns null if it cannot find a good string - private String resolveHumanEnteredFilename(String fullPath) { - if (Util.fileExists(fullPath)) return fullPath; - String candidatePath = uppercaseJpg(fullPath); - if (Util.fileExists(candidatePath)) return candidatePath; - String candidatePath2 = uppercaseBeforeJpg(candidatePath); - if (Util.fileExists(candidatePath2)) return candidatePath2; - candidatePath = lowercaseJpg(fullPath); - if (Util.fileExists(candidatePath)) return candidatePath; - candidatePath = fixSpaceBeforeJpg(candidatePath); - if (Util.fileExists(candidatePath)) return candidatePath; - candidatePath = fixSpaceBeforeDotJpg(candidatePath); - if (Util.fileExists(candidatePath)) return candidatePath; - candidatePath = removeSpaceDashSpaceBeforeDot(candidatePath); - if (Util.fileExists(candidatePath)) return candidatePath; - return null; - } - - private String uppercaseBeforeJpg(String filename) { - // uppercases the section between final slash and .jpg - if (filename == null) return null; - int indexOfDotJpg = filename.indexOf(".jpg"); - if (indexOfDotJpg == -1) indexOfDotJpg = filename.indexOf(".JPG"); - int indexOfLastSlash = filename.lastIndexOf("/"); - if (indexOfDotJpg == -1 || indexOfLastSlash == -1) return filename; - String beforePart = filename.substring(0, indexOfLastSlash + 1); - String capitolizedPart = filename.substring(indexOfLastSlash + 1, - indexOfDotJpg).toUpperCase(); - String afterPart = filename.substring(indexOfDotJpg); - - return (beforePart + capitolizedPart + afterPart); - } - - private String lowercaseJpg(String filename) { - if (filename == null) return null; - return (filename.replace(".JPG", ".jpg")); - } - - private String uppercaseJpg(String filename) { - if (filename == null) return null; - return (filename.replace(".jpg", ".JPG")); - } - - private String fixSpaceBeforeJpg(String filename) { - if (filename == null) return null; - return (filename.replace(" jpg", ".jpg")); - } - - private String fixSpaceBeforeDotJpg(String filename) { - if (filename == null) return null; - return (filename.replace(" .jpg", ".jpg")); - } - - private String removeTailingSpace(String filename) { - if (filename == null) return null; - return (filename.replace(" .jpg", ".jpg")); - } - - private String removeSpaceDashSpaceBeforeDot(String filename) { - if (filename == null) return null; - return (filename.replace(" - .", ".")); - } - - private int getNumMediaAssets() { - if (numMediaAssets == null) setNumMediaAssets(); - return numMediaAssets.intValue(); - } - - private void setNumMediaAssets() { - int numAssets = 0; - - for (String col : colIndexMap.keySet()) { - if (col.indexOf("mediaAsset") > -1) numAssets++; - } - numMediaAssets = numAssets; - } - - public MarkedIndividual loadIndividual(Row row, Encounter enc) { - boolean newIndividual = false; - String individualID = getIndividualID(row); - - if (individualID == null) return null; - MarkedIndividual mark = myShepherd.getMarkedIndividualQuiet(individualID); - if (mark == null) { // new individual - mark = new MarkedIndividual(individualID, enc); - newIndividual = true; - } - if (mark == null) { - System.out.println( - "StandardImport WARNING: weird behavior. Just made an individual but it's still null."); - return mark; - } - if (!newIndividual) mark.addEncounterNoCommit(enc); - String alternateID = getString(row, "Encounter.alternateID"); - if (alternateID != null) mark.setAlternateID(alternateID); - String nickname = getString(row, "MarkedIndividual.nickname"); - if (nickname == null) nickname = getString(row, "MarkedIndividual.nickName"); - if (nickname != null) mark.setNickName(nickname); - return mark; - } - - // check if oldOcc is the same occurrence as the occurrence on this row - // if so, return oldOcc. If not, return parseOccurrence(row) - public Occurrence getCurrentOccurrence(Occurrence oldOcc, Row row) { - String occID = getOccurrenceID(row); - - if (oldOcc != null && oldOcc.getOccurrenceID() != null && - oldOcc.getOccurrenceID().equals(occID)) return oldOcc; - Occurrence occ = myShepherd.getOrCreateOccurrence(occID); - - return occ; - // if (isOccurrenceOnRow(oldOcc, row)) return oldOcc; - // return parseOccurrence(row); - } - - private void initColIndexVariables(Row firstRow) { - colIndexMap = makeColIndexMap(firstRow); - unusedColumns = new HashSet(); - // have to manually copy-in like this because keySet returns a POINTER (!!!) - for (String colName : colIndexMap.keySet()) { - unusedColumns.add(colName); - } - } - - // Returns a map from each column header to the integer col number - public static Map makeColIndexMap(Row firstRow) { - Map colMap = new HashMap(); - - for (int i = 0; i < firstRow.getLastCellNum(); i++) { - String colName = getString(firstRow, i); - colMap.put(colName, i); - } - return colMap; - } - - public String getOccurrenceID(Row row) { - return (getString(row, "Occurrence.occurrenceID")); - } - - public boolean isOccurrenceOnRow(Occurrence occ, Row row) { - return (occ != null && !occ.getOccurrenceID().equals(getOccurrenceID(row))); - } - -//// following 'get' functions swallow errors - public static Integer getInteger(Row row, int i) { - try { - double val = row.getCell(i).getNumericCellValue(); - return new Integer((int)val); - } catch (Exception e) { - // case for when we have a weird String-Double, which looks like a double in the excel sheet, yet is cast as a String, AND has a leading - // apostrophe in its stored value that prevents us from parsing it as a number. - try { - String str = getString(row, i); - if (str == null) return null; - try { - Integer ans = Integer.parseInt(str); - return ans; - } catch (Exception badParse) { - str = str.substring(1); - Integer ans2 = Integer.parseInt(str); - System.out.println(" getInteger SUBSTRINGED and got ans " + ans2); - return ans2; - } - } catch (Exception ex) {} - } - return null; - } - - public static Long getLong(Row row, int i) { - try { - double val = row.getCell(i).getNumericCellValue(); - return new Long((long)val); - } catch (Exception e) { - try { - String str = getString(row, i); - if (str == null) return null; - try { - Long ans = Long.parseLong(str); - return ans; - } catch (Exception badParse) { - str = str.substring(1); - Long ans2 = Long.parseLong(str); - System.out.println(" getLong SUBSTRINGED and got ans " + ans2); - return ans2; - } - } catch (Exception ex) {} - } - return null; - } - - public static Double getDouble(Row row, int i) { - try { - double val = row.getCell(i).getNumericCellValue(); - return new Double(val); - } catch (Exception e) { - // case for when we have a weird String-Double, which looks like a double in the excel sheet, yet is cast as a String, AND has a leading - // apostrophe in its stored value that prevents us from parsing it as a number. - try { - String str = getString(row, i); - if (str == null) return null; - System.out.println("EXCEL getDouble string conversion case reached with string " + - str); - try { - Double ans = Double.parseDouble(str); - System.out.println(" getDouble string conversion got ans " + ans); - return ans; - } catch (Exception badParse) { - str = str.substring(1); - Double ans2 = Double.parseDouble(str); - System.out.println(" getDouble SUBSTRINGED and got ans " + ans2); - return ans2; - } - } catch (Exception ex) {} - } - return null; - } - - public static String getString(Row row, int i) { - try { - String str = row.getCell(i).getStringCellValue(); - if (str.equals("")) return null; - return str; - } catch (Exception e) {} - return null; - } - - public static Boolean getBooleanFromString(Row row, int i) { - try { - String boolStr = getString(row, i).trim().toLowerCase(); - if (boolStr == null || boolStr.equals("")) return null; - else if (boolStr.equals("yes")) return new Boolean(true); - else if (boolStr.equals("no")) return new Boolean(false); - } catch (Exception e) {} - return null; - } - - public static Date getDate(Row row, int i) { - try { - Date date = row.getCell(i).getDateCellValue(); - return date; - } catch (Exception e) {} - return null; - } - - public static DateTime getDateTime(Row row, int i) { - Date date = getDate(row, i); - - if (date == null) return null; - return new DateTime(date); - } - - // Below methods are *not* static and work from column names rather than column numbers - // IMPORTANT: ONLY WORKS IF colIndexMap HAS BEEN INITIALIZED - public String getString(Row row, String colName) { - if (!colIndexMap.containsKey(colName)) { - if (verbose) missingColumns.add(colName); - return null; - } - String ans = getString(row, colIndexMap.get(colName)); - if (ans != null && unusedColumns != null) unusedColumns.remove(colName); - return ans; - } - - public String getIntAsString(Row row, String colName) { - Integer i = getInteger(row, colName); - - if (i == null) return null; - return i.toString(); - } - - public String getStringOrInt(Row row, String colName) { - if (!colIndexMap.containsKey(colName)) { - if (verbose) missingColumns.add(colName); - return null; - } - String ans = getStringOrInt(row, colIndexMap.get(colName)); - if (ans != null && unusedColumns != null) unusedColumns.remove(colName); - return ans; - } - - public static String getStringOrInt(Row row, int i) { - String ans = getString(row, i); - - if (ans == null) { - Integer inty = getInteger(row, i); - if (inty != null) ans = inty.toString(); - } - return ans; - } - - public Integer getInteger(Row row, String colName) { - if (!colIndexMap.containsKey(colName)) { - if (verbose) missingColumns.add(colName); - return null; - } - Integer ans = getInteger(row, colIndexMap.get(colName)); - if (ans != null && unusedColumns != null) unusedColumns.remove(colName); - return ans; - } - - public Long getLong(Row row, String colName) { - if (!colIndexMap.containsKey(colName)) { - if (verbose) missingColumns.add(colName); - return null; - } - Long ans = getLong(row, colIndexMap.get(colName)); - if (ans != null && unusedColumns != null) unusedColumns.remove(colName); - return ans; - } - - public Double getDouble(Row row, String colName) { - if (!colIndexMap.containsKey(colName)) { - if (verbose) missingColumns.add(colName); - return null; - } - Double ans = getDouble(row, colIndexMap.get(colName)); - if (ans != null && unusedColumns != null) unusedColumns.remove(colName); - return ans; - } - - public Date getDate(Row row, String colName) { - if (!colIndexMap.containsKey(colName)) { - if (verbose) missingColumns.add(colName); - return null; - } - Date ans = getDate(row, colIndexMap.get(colName)); - if (ans != null && unusedColumns != null) unusedColumns.remove(colName); - return ans; - } - - public DateTime getDateTime(Row row, String colName) { - if (!colIndexMap.containsKey(colName)) { - if (verbose) missingColumns.add(colName); - return null; - } - DateTime ans = getDateTime(row, colIndexMap.get(colName)); - if (ans != null && unusedColumns != null) unusedColumns.remove(colName); - return ans; - } - - // Apache POI, shame on you for making me write this. Shame! Shame! Shame! SHAME! - // (as if I actually wrote this. thanks stackoverflow!) - public static boolean isRowEmpty(Row row) { - for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) { - Cell cell = row.getCell(c); - if (cell != null && cell.getCellType() != Cell.CELL_TYPE_BLANK) - return false; - } - return true; - } - - // This would be cool to put in Encounter or something. - // tho I'm not immediately sure how we'd get the url context, or determine if we want to include /encounters/ or not - public static String getEncounterURL(Encounter enc) { - if (enc == null || enc.getCatalogNumber() == null) return null; - return "/encounters/encounter.jsp?number=" + enc.getCatalogNumber(); - } - - // gives us a nice link if we're - public String getEncounterDisplayString(Encounter enc) { - if (enc == null) return null; - if (committing) { - return "" + enc.getCatalogNumber() + ""; - } - return enc.getCatalogNumber(); - } - - private AssetStore getAssetStore(Shepherd myShepherd) { - // return AssetStore.getDefault(myShepherd); - return AssetStore.get(myShepherd, 5); - - } -} diff --git a/src/main/java/org/ecocean/servlet/importer/StandardImport.java b/src/main/java/org/ecocean/servlet/importer/StandardImport.java index b5136f811c..c33bb2fa3e 100644 --- a/src/main/java/org/ecocean/servlet/importer/StandardImport.java +++ b/src/main/java/org/ecocean/servlet/importer/StandardImport.java @@ -912,7 +912,8 @@ public Encounter loadEncounter(Row row, ArrayList annotations, Strin List configuredSpecies = CommonConfiguration.getIndexedPropertyValues( "genusSpecies", myShepherd.getContext()); if (configuredSpecies != null && configuredSpecies.size() > 0 && - configuredSpecies.toString().replaceAll("_"," ").indexOf(enc.getTaxonomyString()) < 0) { + configuredSpecies.toString().replaceAll("_", + " ").indexOf(enc.getTaxonomyString()) < 0) { // if bad values feedback.logParseError(getColIndexFromColName("Encounter.genus", colIndexMap), genus, row, "UNSUPPORTED VALUE: " + genus); @@ -2529,27 +2530,12 @@ public String getStringNoLog(Row row, int i) { // returns file so you can use .getName() or .lastModified() etc public static File importXlsFile(String rootDir, HttpServletRequest request) { File dir = new File(rootDir, "import"); - File f = null; + File f = new File(dir, "WildbookStandardFormat.xlsx"); - if (ServletUtilities.useCustomStyle(request, "IndoCet")) { - f = new File(dir, "WildbookStandardFormat_IndoCet.xlsx"); - } else { - f = new File(dir, "WildbookStandardFormat.xlsx"); - } if (f != null && f.isFile()) { return f; } else { System.out.println("ERROR: importXlsFile() rootDir=" + rootDir + ";f is: " + f); return null; } - /* - try { - for (final File f : dir.listFiles()) { - if (f.isFile() && f.getName().matches("WildbookStandardFormat.*\\.xlsx")) return f; - } - } catch (Exception ex) { - System.out.println("ERROR: importXlsFile() rootDir=" + rootDir + " threw " + ex.toString()); - return null; - } - */ } // cannot put this inside CellFeedback bc java inner classes are not allowed static methods or vars (this is stupid). diff --git a/src/main/resources/bundles/captcha.properties b/src/main/resources/bundles/captcha.properties new file mode 100644 index 0000000000..0a4e6e154d --- /dev/null +++ b/src/main/resources/bundles/captcha.properties @@ -0,0 +1,3 @@ +procaptchaSiteKey=CHANGEME +procaptchaSecretKey=CHANGEME + diff --git a/src/main/resources/bundles/codexMigration.properties b/src/main/resources/bundles/codexMigration.properties deleted file mode 100644 index 4722850ea5..0000000000 --- a/src/main/resources/bundles/codexMigration.properties +++ /dev/null @@ -1,3 +0,0 @@ -codexDbUrl=jdbc:postgresql://localhost:5432/codex -codexDbUsername=example -codexDbPassword=example diff --git a/src/main/resources/bundles/commonConfiguration.properties b/src/main/resources/bundles/commonConfiguration.properties index 3ac1285131..a6edbf880c 100755 --- a/src/main/resources/bundles/commonConfiguration.properties +++ b/src/main/resources/bundles/commonConfiguration.properties @@ -6,12 +6,6 @@ #file system folder in which marked individual data will be stored (e.g. data files) #markedIndividualDirectoryLocation=individuals -# default behaviors for Project object -loggedOutDefaultDesired = true -defaultProjectOrganizationParameter = IndoCet -defaultProjName = Indocet Opportunistic Sightings -defaultProjId = IndoCetOppS- - dataDirectoryName = wildbook_data_dir #URL to the graphic to be displayed at the top of every page through header.jsp @@ -31,8 +25,8 @@ GlobalUniqueIdentifierPrefix=MyGroup:MyStudy: #email addresses and parameters sendEmailNotifications=true -autoEmailAddress=info@wildbook.org -newSubmissionEmail=donotreply@wildbook.org +autoEmailAddress=info@wildme.org +newSubmissionEmail=donotreply@wildme.org mailHost=localhost removeEmailString=Do you want to REMOVE your email address from this database? Click the link below to remove it. You will no longer receive updates on your encounters. @@ -111,6 +105,9 @@ showEXIF = true #show taxonomy showTaxonomy = true +# show option for "classic" submit page in UI +showClassicSubmit = true + #for multi-species libraries, fill out the genus and species for each supported animal type, starting with genusSpecies0 genusSpecies0 = Balaenoptera acutorostrata diff --git a/src/main/resources/bundles/de/header.properties b/src/main/resources/bundles/de/header.properties index c358aa6a3e..c4926bac94 100755 --- a/src/main/resources/bundles/de/header.properties +++ b/src/main/resources/bundles/de/header.properties @@ -7,6 +7,7 @@ learn = Lernen intro = Einf\u00FChrung participate = Teilnehmen report = Eine Begegnung melden +reportClassic = Eine Begegnung melden (Klassisch) individuals = Einzelpersonen viewAll = Alle anzeigen encounters = Begegnungen diff --git a/src/main/resources/bundles/en/header.properties b/src/main/resources/bundles/en/header.properties index d91055d021..37c7ac7ad9 100755 --- a/src/main/resources/bundles/en/header.properties +++ b/src/main/resources/bundles/en/header.properties @@ -7,6 +7,7 @@ learn = Learn intro = Introduction participate = Participate report = Report an encounter +reportClassic = Report an encounter (Classic) individuals = Individuals viewAll = View All encounters = Encounters diff --git a/src/main/resources/bundles/en/indocet/encounter.properties b/src/main/resources/bundles/en/indocet/encounter.properties deleted file mode 100644 index 6b98527b08..0000000000 --- a/src/main/resources/bundles/en/indocet/encounter.properties +++ /dev/null @@ -1 +0,0 @@ -title = IndoCet Encounter \ No newline at end of file diff --git a/src/main/resources/bundles/es/header.properties b/src/main/resources/bundles/es/header.properties index 4d073a4056..2434443002 100755 --- a/src/main/resources/bundles/es/header.properties +++ b/src/main/resources/bundles/es/header.properties @@ -7,6 +7,7 @@ learn = Aprender intro = Introducci\u00f3n participate = Participar report = Informar un encuentro +reportClassic = Informar un encuentro (Cl\u00e1sico) individuals = Individuos viewAll = Ver todos encounters = Encuentros diff --git a/src/main/resources/bundles/fr/header.properties b/src/main/resources/bundles/fr/header.properties index 56990dfdd1..a6c54ed594 100644 --- a/src/main/resources/bundles/fr/header.properties +++ b/src/main/resources/bundles/fr/header.properties @@ -7,6 +7,7 @@ learn = Apprendre intro = Introduction participate = Participer report = Signaler une rencontre +reportClassic = Signaler une rencontre (Classique) individuals = Individus viewAll = Tout voir encounters = Rencontres diff --git a/src/main/resources/bundles/indocet.properties b/src/main/resources/bundles/indocet.properties deleted file mode 100644 index e1c77ecc96..0000000000 --- a/src/main/resources/bundles/indocet.properties +++ /dev/null @@ -1,136 +0,0 @@ -# These are all the fields that IndoCet has defined, which should appear ANYWHERE they are used on the site. - -behavior0 = Feeding -behavior1 = Traveling -behavior2 = Milling -behavior3 = Resting -behavior4 = Socializing -behavior5 = Probable Feeding -behavior6 = Mating -behavior7 = Undetermined - -country0 = Comoros -country1 = France-Mayotte -country2 = France-Reunion -country3 = France-Scattered Islands -country4 = Kenya -country5 = Madagascar -country6 = Mauritius-Mauritius -country7 = Mauritius-Rodrigues -country8 = Mozambique -country9 = Seychelles -country10 = Somalia -country11 = South Africa -country12 = Tanzania - -locationID0 = Nosy Be -locationID1 = Nosy Iranja -locationID2 = Nosy Mitsio -locationID3 = Antongil Bay -locationID4 = Sainte Marie -locationID5 = Fort Dauphin -locationID6 = Anakao -locationID7 = Ifaty -locationID8 = Mahajanga -locationID9 = Reunion -locationID10 = Mayotte -locationID11 = La Perouse -locationID12 = Glorieuses -locationID13 = Juan de Nova -locationID14 = Bassas da India -locationID15 = Europa -locationID16 = Tromelin -locationID17 = Mauritius -locationID18 = Rodrigues -locationID19 = Grande Comore -locationID20 = Moheli -locationID21 = Anjouan - -groupComposition0 = MotherCalf -groupComposition1 = MotherCalfEscort -groupComposition2 = MotherCalfMultipleEscort -groupComposition3 = CompetitiveGroup -groupComposition4 = Pair -groupComposition5 = Singleton -groupComposition6 = Singer -groupComposition7 = Non-Competitive -groupComposition8 = AdultsOnly -groupComposition9 = MixedAgeClasses - -groupBehavior0 = Feeding -groupBehavior1 = Traveling -groupBehavior2 = Milling -groupBehavior3 = Resting -groupBehavior4 = Socializing -groupBehavior5 = Probable Feeding -groupBehavior6 = Undetermined -groupBehavior7 = Mating - -initialCue0 = Blow -initialCue1 = Breach -initialCue2 = DorsalFin -initialCue3 = BodyPart -initialCue4 = FlukeUp -initialCue5 = Acoustic -initialCue6 = Splash -initialCue7 = Birds -initialCue8 = Boats - -seaState0 = 1 -seaState1 = 2 -seaState2 = 3 -seaState3 = 4 -seaState4 = 5 - -visibilityIndex0 = 0 -visibilityIndex1 = 1 -visibilityIndex2 = 2 -visibilityIndex3 = 3 -visibilityIndex4 = 4 -visibilityIndex5 = 5 - -groupRole0 = NuclearAnimal -groupRole1 = PrincipleEscort -groupRole2 = Challenger -groupRole3 = SecondaryEscort -groupRole4 = Mother -groupRole5 = Escort -groupRole6 = Singer -groupRole7 = Undetermined - -lifeStage0 = Adult -lifeStage1 = Juvenile -lifeStage2 = Calf - - -# Labeled keywords: -kwLabel0 = feature -kwLabel1 = flukeType -kwLabel2 = quality -kwLabel3 = distinctiveness - -feature0 = Fluke -feature1 = Right Dorsal Fin -feature2 = Left Dorsal Fin -feature3 = Right Blaze -feature4 = Right Chevron -feature5 = Left Chevron - -flukeType0 = 1 -flukeType1 = 2 -flukeType2 = 3 -flukeType3 = 4 -flukeType4 = 5 - -quality0 = 0 -quality1 = 1 -quality2 = 2 -quality3 = 3 -quality4 = 4 - -distinctiveness0 = 0 -distinctiveness1 = 1 -distinctiveness2 = 2 -distinctiveness3 = 3 -distinctiveness4 = 4 - diff --git a/src/main/resources/bundles/it/header.properties b/src/main/resources/bundles/it/header.properties index ea68d08359..aaa2b4f714 100644 --- a/src/main/resources/bundles/it/header.properties +++ b/src/main/resources/bundles/it/header.properties @@ -7,6 +7,7 @@ learn = scopri intro = introduzione participate = Partecipa report = Segnala un incontro +reportClassic = Segnala un incontro (Classico) individuals = Gli esemplari viewAll = Guarda tutto encounters = Incontri diff --git a/src/main/resources/bundles/locationID.json b/src/main/resources/bundles/locationID.json index 76dd0792b0..ab0025dcd3 100644 --- a/src/main/resources/bundles/locationID.json +++ b/src/main/resources/bundles/locationID.json @@ -109,6 +109,6 @@ "long": 8.880677 }, "locationID": [] - }, + } ] } \ No newline at end of file diff --git a/src/main/resources/emails/en/passwordReset.html b/src/main/resources/emails/en/passwordReset.html index 2f6456d9fa..b2923680ec 100755 --- a/src/main/resources/emails/en/passwordReset.html +++ b/src/main/resources/emails/en/passwordReset.html @@ -474,7 +474,7 @@
Wildbook.org + href="http://www.wildme.org/">wildme.org diff --git a/src/main/resources/servletResponseTemplate.htm b/src/main/resources/servletResponseTemplate.htm index 0c415d4d75..1c4a6f9cab 100755 --- a/src/main/resources/servletResponseTemplate.htm +++ b/src/main/resources/servletResponseTemplate.htm @@ -66,7 +66,7 @@ @@ -147,9 +147,9 @@
  • My Accounts
  • User Management
  • Library Administration
  • -
  • Logs
  • +
  • Logs
  • Photo Keywords
  • -
  • Software Documentation
  • +
  • Software Documentation
  • Data Integrity
  • Bulk Import Logs
  • diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 7a5914bdbd..ebf945b3be 100755 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -457,7 +457,6 @@ /UpdateStandard = authc, roles[researcher] /WebImport = authc, roles[researcher] /import/upload = authc, roles[researcher] - /ResumableUpload = authc, roles[researcher] /upload = authc, roles[researcher] @@ -548,6 +547,23 @@ /api/v3/home + + ApiBaseObject + org.ecocean.api.BaseObject + + + ApiBaseObject + /api/v3/encounters/* + + + ApiBaseObject + /api/v3/individuals/* + + + ApiBaseObject + /api/v3/occurrences/* + + ApiProjects @@ -991,6 +1007,12 @@ org.ecocean.servlet.BatchUpload + + BatchUpload + /BatchUpload/* + + --> + ReCAPTCHA org.ecocean.servlet.ReCAPTCHA @@ -1000,12 +1022,6 @@ /ReCAPTCHA - - BatchUpload - /BatchUpload/* - - --> - IAGateway /ia diff --git a/src/main/webapp/appadmin/codexMigrator.jsp b/src/main/webapp/appadmin/codexMigrator.jsp deleted file mode 100644 index 71dfb3b174..0000000000 --- a/src/main/webapp/appadmin/codexMigrator.jsp +++ /dev/null @@ -1,1125 +0,0 @@ -<%@ page contentType="text/html; charset=utf-8" language="java" -import="org.ecocean.*, -org.ecocean.tag.MetalTag, -org.ecocean.social.*, -org.ecocean.servlet.ServletUtilities, -org.ecocean.social.Relationship, -org.joda.time.DateTime, -java.io.IOException, -javax.servlet.jsp.JspWriter, -javax.servlet.http.HttpServletRequest, -java.nio.file.Files, -java.sql.Timestamp, -java.sql.*, -java.io.File, -java.util.ArrayList, -java.util.List, -java.util.Map, -java.util.HashMap, -java.util.Collection, -java.util.Set, -java.util.HashSet, -java.util.Properties, -java.util.TimeZone, -javax.jdo.Query, -org.json.JSONObject, -org.json.JSONArray, -org.ecocean.media.* - " -%> - -<%! - -private static String TMP_DIR = "/tmp/migrate"; - -private static Encounter encounterFromPending(JSONObject edata) { - Encounter enc = null; - return enc; -} - -private static boolean stringEmpty(String str) { - return ((str == null) || str.equals("")); -} - -private static void cfOccurrence(Shepherd myShepherd, Occurrence occ, Map cfMap) { - for (String key : cfMap.keySet()) { - String value = cfMap.get(key); - if (stringEmpty(value)) continue; - String label = key.replaceAll(" ", "_"); -System.out.println(">>>>>> " + label + " => " + value + " on " + occ); - occ.addComments("

    " + key + ": " + value + "

    "); - if (occ.getNumberEncounters() < 1) continue; - LabeledKeyword kw = myShepherd.getOrCreateLabeledKeyword(label, value, false); - for (Encounter enc : occ.getEncounters()) { - for (MediaAsset ma : enc.getMedia()) { - ma.addKeyword(kw); -System.out.println(">>>>>> ++++++ " + kw + " on " + ma); - } - } - } -} - -private static String cleanJsonString(String json) { - if (json == null) return null; - json = json.replaceAll("\\\\", ""); - json = json.substring(1, json.length() - 1); - return json; -} - -private static JSONObject cleanJSONObject(String data) { - String clean = cleanJsonString(data); - if (clean == null) return null; - try { - return new JSONObject(clean); - } catch (Exception ex) {} - return null; -} - -private static JSONArray cleanJSONArray(String data) { - String clean = cleanJsonString(data); - if (clean == null) return null; - try { - return new JSONArray(clean); - } catch (Exception ex) {} - return null; -} - -private static Object siteSetting(String key, Connection conn) throws SQLException, IOException { - Statement st = conn.createStatement(); - ResultSet res = st.executeQuery("SELECT * FROM site_setting WHERE key='" + key + "'"); - if (!res.next()) return null; - String data = cleanJsonString(res.getString("data")); - if (data == null) return null; - try { - return new JSONObject(data); - } catch (Exception ex) {} - try { - return new JSONArray(data); - } catch (Exception ex) {} - return data; -} - -private static JSONObject cfDefinitions(String cls, Connection conn) throws SQLException, IOException { - Statement st = conn.createStatement(); - ResultSet res = st.executeQuery("SELECT data FROM site_setting WHERE key='site.custom.customFields." + cls + "'"); - if (!res.next()) return null; - JSONObject j = cleanJSONObject(res.getString("data")); - if (j == null) return null; - JSONArray darr = j.optJSONArray("definitions"); - if (darr == null) return null; - JSONObject rtn = new JSONObject(); - for (int i = 0 ; i < darr.length() ; i++) { - JSONObject defn = darr.optJSONObject(i); - if (defn == null) continue; - String id = defn.optString("id", null); - if (id == null) continue; - rtn.put(id, defn); - } - return rtn; -} - -private static String cfString(JSONObject cfData, String key) { - if (cfData == null) return null; - String value = cfData.optString(key, null); - if ("".equals(value)) return null; - return value; -} - -private static Integer cfInteger(JSONObject cfData, String key) { - if (cfData == null) return null; - if (!cfData.has(key)) return null; - if (cfData.isNull(key)) return null; - try { - return cfData.getInt(key); - } catch (Exception ex) {} - return null; -} - -private static Map relationshipMeta(Connection conn) throws SQLException, IOException { - Object ss = siteSetting("relationship_type_roles", conn); - Map rtn = new HashMap(); - if (ss == null) return rtn; - JSONObject rel = (JSONObject)ss; - for (String key : (Set)rel.keySet()) { - JSONObject data = rel.optJSONObject(key); - if (data == null) continue; - String label = data.optString("label", null); - if (label != null) rtn.put(key, label); - JSONArray roles = data.optJSONArray("roles"); - if (roles == null) continue; - for (int i = 0 ; i < roles.length() ; i++) { - JSONObject role = roles.optJSONObject(i); - if (role == null) continue; - String rid = role.optString("guid", null); - String rlabel = role.optString("label", null); - if ((rid != null) && (rlabel != null)) rtn.put(rid, rlabel); - } - } - return rtn; -} - -private static Map socialGroupMeta(Connection conn) throws SQLException, IOException { - Object ss = siteSetting("social_group_roles", conn); - Map rtn = new HashMap(); - if (ss == null) return rtn; - JSONArray sgArr = (JSONArray)ss; - for (int i = 0 ; i < sgArr.length() ; i++) { - JSONObject sg = sgArr.optJSONObject(i); - if (sg == null) continue; - String guid = sg.optString("guid", null); - String label = sg.optString("label", null); - if ((guid == null) || (label == null)) continue; - rtn.put(guid, label); - } - return rtn; -} - -private static Map taxonomyMap(Connection conn) throws SQLException, IOException { - Object ss = siteSetting("site.species", conn); - Map rtn = new HashMap(); - if (ss == null) return rtn; - JSONArray arr = (JSONArray)ss; - for (int i = 0 ; i < arr.length() ; i++) { - JSONObject tx = arr.getJSONObject(i); - rtn.put(tx.optString("id", "_FAIL"), tx.optString("scientificName", "_FAIL")); - } - return rtn; -} - -private static JSONObject locationJson(Connection conn) throws SQLException, IOException { - Object ss = siteSetting("site.custom.regions", conn); - if (ss == null) return null; - try { - return (JSONObject)ss; - } catch (Exception ex) {} - return null; -} - -private static Map locationMap(Connection conn) throws SQLException, IOException { - Map map = new HashMap(); - return locationMap(locationJson(conn), map); -} - -private static Map locationMap(JSONObject data, Map map) { - if (data == null) return map; - String id = data.optString("id", null); - String name = data.optString("name", id); - if (id != null) map.put(id, name); - JSONArray sub = data.optJSONArray("locationID"); - if (sub != null) for (int i = 0 ; i < sub.length() ; i++) { - JSONObject subObj = sub.optJSONObject(i); - if (subObj == null) continue; - locationMap(subObj, map); - } - return map; -} - - -private static int batchMax() { - return 00; -} - -private static void migrateUsers(JspWriter out, Shepherd myShepherd, Connection conn) throws SQLException, IOException { - out.println("

    Users

      "); - Statement st = conn.createStatement(); - ResultSet res = st.executeQuery("SELECT * FROM \"user\""); - int ct = 0; - while (res.next()) { - String guid = res.getString("guid"); - int staticRoles = res.getInt("static_roles"); - out.println("
    1. " + guid + ": "); - Set roles = new HashSet(); - if ((staticRoles & 0x04000) > 0) { - roles.add("admin"); - roles.add("orgAdmin"); - roles.add("researcher"); - roles.add("rest"); - roles.add("machinelearning"); - } - if ((staticRoles & 0x80000) > 0) roles.add("orgAdmin"); - //if ((staticRoles & 0x10000) > 0) exporter == "N/A" - if ((staticRoles & 0x20000) > 0) roles.add("researcher"); - if ((staticRoles & 0x40000) > 0) { - roles.add("rest"); - roles.add("machinelearning"); - } - User user = myShepherd.getUserByUUID(guid); - if (user != null) { - out.println("user exists; skipping"); - } else { - user = new User(guid); - String username = res.getString("email"); - user.setUsername(username); - user.setAffiliation(res.getString("affiliation")); - // location seems to often have value in codex - user.setUserURL(res.getString("website")); - user.setEmailAddress(res.getString("email")); - user.setFullName(res.getString("full_name")); - myShepherd.getPM().makePersistent(user); - - for (String roleName : roles) { - Role role = new Role(); - role.setRolename(roleName); - role.setUsername(username); - role.setContext("context0"); - myShepherd.getPM().makePersistent(role); - } - - // TODO: Organizations - - String msg = "created user [" + ct + "] [" + String.join(",", roles) + "] " + user; - out.println("" + msg + ""); - System.out.println(msg); - } - out.println("
    2. "); - ct++; - } - out.println("
    "); -} - - -private static void migrateMediaAssets(JspWriter out, Shepherd myShepherd, Connection conn, HttpServletRequest request, File assetGroupDir) throws SQLException, IOException { - out.println("

    MediaAssets

      "); - Statement st = conn.createStatement(); - ResultSet res = st.executeQuery("SELECT * FROM asset ORDER BY git_store_guid, guid"); - AssetStore targetStore = AssetStore.getDefault(myShepherd); - List maIds = new ArrayList(); - int ct = 0; - - while (res.next()) { - ct++; - if (ct > batchMax()) break; - String guid = res.getString("guid"); - out.println("
    1. " + guid + ": "); - MediaAsset ma = MediaAssetFactory.loadByUuid(guid, myShepherd); - if (ma != null) { - ct--; - out.println("asset exists; skipping"); - } else { - String ext = "unknown"; - String mimeType = res.getString("mime_type"); - if ((mimeType != null) && mimeType.contains("/")) ext = mimeType.split("\\/")[1]; - if ("jpeg".equals(ext)) ext = "jpg"; - String assetGroupGuid = res.getString("git_store_guid"); - File sourceFile = new File(assetGroupDir, assetGroupGuid + "/_assets/" + guid + "." + ext); - String userFilename = res.getString("path"); - if (stringEmpty(userFilename)) userFilename = guid + "." + ext; - //out.println(sourceFile.toString()); - if (!sourceFile.exists()) { - out.println("" + sourceFile + " does not exist"); - if (ext.equals("unknown")) continue; - break; - } - File tmpFile = new File(TMP_DIR, guid + "." + ext); - Files.copy(sourceFile.toPath(), tmpFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); - String grouping = Util.hashDirectories(assetGroupGuid, File.separator); - JSONObject params = targetStore.createParameters(tmpFile, grouping); - params.put("userFilename", userFilename); - params.put("_codexMigration", System.currentTimeMillis()); - ma = targetStore.create(params); - try { - ma.copyIn(sourceFile); - } catch (Exception ex) { - out.println("failed to copyIn " + sourceFile + " => " + ex.toString() + ""); - break; - } - ma.setUUID(guid); - // TODO: revision from codex? - ma.setAcmId(res.getString("content_guid")); - ma.updateMetadata(); - ma.addLabel("_original"); - ma.setAccessControl(request); - MediaAssetFactory.save(ma, myShepherd); - maIds.add(ma.getId()); - String msg = "created [" + ct + "] " + ma; - out.println("" + msg + ""); - System.out.println(msg); - } - out.println("
    2. "); - } - myShepherd.commitDBTransaction(); // necessary for backgrounding - myShepherd.beginDBTransaction(); - MediaAsset.updateStandardChildrenBackground(ServletUtilities.getContext(request), maIds); - out.println("
    "); -} - - -private static void migrateAnnotations(JspWriter out, Shepherd myShepherd, Connection conn) throws SQLException, IOException { - out.println("

    Annotations

      "); - Statement st = conn.createStatement(); - ResultSet res = st.executeQuery("SELECT * FROM annotation ORDER BY guid"); - FeatureType.initAll(myShepherd); - int ct = 0; - - while (res.next()) { - ct++; - if (ct > batchMax()) break; - String guid = res.getString("guid"); - Annotation ann = myShepherd.getAnnotation(guid); - if (ann != null) { - ct--; - out.println("
    1. " + guid + ": annotation exists; skipping"); - } else { - String maId = res.getString("asset_guid"); - MediaAsset ma = MediaAssetFactory.loadByUuid(maId, myShepherd); - if (ma == null) { - //out.println("" + guid + ": failed due to missing MediaAsset id=" + maId + ""); - //System.out.println(guid + " failed due to missing MediaAsset id=" + maId); - ct--; - continue; - } - out.println("
    2. " + guid + ": "); - JSONObject bounds = cleanJSONObject(res.getString("bounds")); - if (bounds == null) bounds = new JSONObject(); - Feature feat = null; - JSONArray rect = bounds.optJSONArray("rect"); - if (rect != null) { - JSONObject params = new JSONObject(); - params.put("theta", bounds.optDouble("theta", 0d)); - params.put("x", rect.optInt(0, 0)); - params.put("y", rect.optInt(1, 0)); - params.put("width", rect.optInt(2, 0)); - params.put("height", rect.optInt(3, 0)); - feat = new Feature("org.ecocean.boundingBox", params); - } else { - System.out.println("%%% failed on bbox for bounds=" + bounds); - feat = new Feature(); - } - ma.addFeature(feat); - // 99.9% sure species doesnt matter any more, so setting as null - ann = new Annotation(null, feat, res.getString("ia_class")); - ann.setId(guid); - // TODO: id status? - ann.setAcmId(res.getString("content_guid")); - ann.setViewpoint(res.getString("viewpoint")); - ann.setMatchAgainst(true); - myShepherd.getPM().makePersistent(ann); - - String msg = "created annot [" + ct + "] " + ann; - out.println("" + msg + ""); - System.out.println(msg); - } - out.println("
    3. "); - } - out.println("
    "); -} - -private static void migrateEncounters(JspWriter out, Shepherd myShepherd, Connection conn) throws SQLException, IOException { - out.println("

    Encounters

      "); - Map txmap = taxonomyMap(conn); - Statement st = conn.createStatement(); - Statement st2 = conn.createStatement(); - ResultSet res = st.executeQuery("SELECT encounter.*, complex_date_time.datetime, complex_date_time.timezone, complex_date_time.specificity FROM encounter JOIN complex_date_time ON (time_guid = complex_date_time.guid) ORDER BY guid"); - int ct = 0; - - while (res.next()) { - ct++; - if (ct > batchMax()) break; - String guid = res.getString("guid"); - out.println("
    1. " + guid + ": "); - Encounter enc = myShepherd.getEncounter(guid); - if (enc != null) { - ct--; - out.println("encounter exists; skipping"); - } else { - enc = new Encounter(); - enc.setId(guid); - Timestamp ts = res.getTimestamp("created"); - if (ts != null) enc.setDWCDateAdded(ts.toString()); - ts = res.getTimestamp("updated"); - if (ts != null) enc.setDWCDateLastModified(ts.toString()); - String txguid = res.getString("taxonomy_guid"); - if (txguid != null) enc.setTaxonomyFromString(txmap.get(txguid)); - User owner = myShepherd.getUserByUUID(res.getString("owner_guid")); - if (owner != null) { - enc.addSubmitter(owner); - enc.setSubmitterID(owner.getUsername()); - } - Double d = res.getDouble("decimal_latitude"); - if (res.wasNull()) d = null; - enc.setDecimalLatitude(d); - d = res.getDouble("decimal_longitude"); - if (res.wasNull()) d = null; - enc.setDecimalLongitude(d); - enc.setSex(res.getString("sex")); - enc.setVerbatimLocality(res.getString("verbatim_locality")); - enc.setLocationID(res.getString("location_guid")); - - // date/time madness - ts = res.getTimestamp("datetime"); -System.out.println("TIME: ts=" + ts); - String tz = res.getString("timezone"); - if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone(tz)); - String spec = res.getString("specificity"); - Timestamp adjusted = ts; - enc.setYear(adjusted.getYear() + 1900); - if (!"year".equals(spec)) { - enc.setMonth(adjusted.getMonth() + 1); - if (!"month".equals(spec)) { - enc.setDay(adjusted.getDate()); - if (!"day".equals(spec)) { - enc.setHour(adjusted.getHours()); - enc.setMinutes(Integer.toString(adjusted.getMinutes())); // ygbkm - } - } - } - - // custom fields, oof - // these need to be hard-coded per migration - JSONObject cfData = cleanJSONObject(res.getString("custom_fields")); - String lifeStage = cfString(cfData, "344792fc-7910-45cd-867b-cb9c927677e1"); - String livingStatus = cfString(cfData, "b9eb55f4-ebc6-47b7-9991-9339084c8639"); - String occRemarks = cfString(cfData, "0d9a3764-f872-4320-ba03-bde268ce1513"); - String researcherComments = cfString(cfData, "b230a670-ee2e-44c4-89a1-6b1dffe2cda3"); - String unidentIndiv = cfString(cfData, "0f48fdc5-6a5e-4a01-aeff-2f1bebf4864d"); - enc.setLifeStage(lifeStage); - enc.setLivingStatus(livingStatus); - enc.setOccurrenceRemarks(occRemarks); - enc.addComments(researcherComments); - if (unidentIndiv != null) enc.setDynamicProperty("unidentified_individual", unidentIndiv); - - myShepherd.storeNewEncounter(enc, guid); - - String msg = "created encounter [" + ct + "] " + enc; - out.println("" + msg + ""); - System.out.println(msg); - } - out.println("
    2. "); - } - out.println("
    "); - - // annotation joins after - ct = 0; - res = st.executeQuery("SELECT guid, encounter_guid FROM annotation ORDER BY encounter_guid, guid"); - while (res.next()) { - String annGuid = res.getString("guid"); - String encGuid = res.getString("encounter_guid"); - Encounter enc = myShepherd.getEncounter(encGuid); - Annotation ann = myShepherd.getAnnotation(annGuid); - if ((enc == null) || (ann == null)) { - System.out.println("migrateEncounters: cannot join due to null; enc=" + enc + "; ann=" + ann); - continue; - } - ct++; - enc.addAnnotation(ann); - } - out.println("

    joined " + ct + " enc/ann pairs

    "); -} - - -private static void migrateOccurrences(JspWriter out, Shepherd myShepherd, Connection conn) throws SQLException, IOException { - out.println("

    Occurrences

      "); - Statement st = conn.createStatement(); - Statement st2 = conn.createStatement(); - ResultSet res = st.executeQuery("SELECT sighting.*, complex_date_time.datetime, complex_date_time.timezone, complex_date_time.specificity FROM sighting JOIN complex_date_time ON (time_guid = complex_date_time.guid) ORDER BY guid"); - int ct = 0; - - while (res.next()) { - ct++; - if (ct > batchMax()) break; - String guid = res.getString("guid"); - out.println("
    1. " + guid + ": "); - Occurrence occ = myShepherd.getOccurrence(guid); - if (occ != null) { - ct--; - out.println("occurrence exists; skipping"); - } else { - occ = new Occurrence(); - occ.setId(guid); - Timestamp ts = res.getTimestamp("created"); - if (ts != null) occ.setDateTimeCreated(ts.toString()); - ts = res.getTimestamp("updated"); - if (ts != null) occ.setDWCDateLastModified(ts.toString()); - - Double d = res.getDouble("decimal_latitude"); - if (res.wasNull()) d = null; - occ.setDecimalLatitude(d); - d = res.getDouble("decimal_longitude"); - if (res.wasNull()) d = null; - occ.setDecimalLongitude(d); - occ.setComments(res.getString("comments")); - //occ.setVerbatimLocality(res.getString("verbatim_locality")); - //occ.setLocationID(res.getString("location_guid")); - - // date/time madness - ts = res.getTimestamp("datetime"); - String tz = res.getString("timezone"); - if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone(tz)); - //String spec = res.getString("specificity"); - // we only store a long for this on occurrences - if (ts != null) occ.setDateTimeLong(ts.getTime()); - - // custom fields, oof - // these need to be hard-coded per migration - JSONObject cfData = cleanJSONObject(res.getString("custom_fields")); - Map cfMap = new HashMap(); - cfMap.put("Seen in Artificial Nest", cfString(cfData, "34a8f03e-d282-4fef-b1ed-9eeebaaa887e")); - cfMap.put("Observation Type", cfString(cfData, "736d8b8f-7abb-404f-9da8-0c1507185baa")); - cfMap.put("Seen with Unknown Seal", cfString(cfData, "e9a00eab-7ea6-4777-afb3-79d95ebfbf4f")); - cfMap.put("Photography Type", cfString(cfData, "cf7ed66f-e6c1-4cb1-aadf-0f141ca22316")); - cfMap.put("Sighting Origin", cfString(cfData, "15b4525a-47e9-4673-ae42-f99ea55f810c")); - cfMap.put("Seen with Unknown Pup", cfString(cfData, "d0f2cc9e-0845-4608-8754-3d1f70eec699")); - String photogName = cfString(cfData, "305b50df-7f21-4d8d-aeb6-45ab1869f5ba"); - String photogEmail = cfString(cfData, "ecc6f017-057c-4821-b07a-f82cd60aa31d"); - - // we have to link encounters here due to customField needs :( - // this makes the joining code below kinda redundant but leaving it to catch stuff that missed - ResultSet res2 = st2.executeQuery("SELECT guid FROM encounter WHERE sighting_guid='" + guid + "' ORDER BY guid"); - while (res2.next()) { - Encounter enc = myShepherd.getEncounter(res2.getString("guid")); - if (enc == null) continue; - occ.addEncounter(enc); - enc.setOccurrenceID(occ.getId()); - if (!stringEmpty(photogName)) enc.setPhotographerName(photogName); - if (!stringEmpty(photogEmail)) enc.setPhotographerEmail(photogEmail); - } - - // now we can do this, since it needs encs - cfOccurrence(myShepherd, occ, cfMap); - - myShepherd.storeNewOccurrence(occ); - - String msg = "created occurrence [" + ct + "] " + occ; - out.println("" + msg + ""); - System.out.println(msg); - } - out.println("
    2. "); - } - out.println("
    "); - - ct = 0; - res = st.executeQuery("SELECT guid, sighting_guid FROM encounter ORDER BY sighting_guid"); - while (res.next()) { - String encGuid = res.getString("guid"); - String occGuid = res.getString("sighting_guid"); - Encounter enc = myShepherd.getEncounter(encGuid); - Occurrence occ = myShepherd.getOccurrence(occGuid); - if ((enc == null) || (occ == null)) { - System.out.println("migrateOccurrences: cannot join due to null; enc=" + enc + "; occ=" + occ); - continue; - } - if (occ.addEncounter(enc)) { - enc.setOccurrenceID(occ.getId()); - ct++; - } - } - out.println("

    joined " + ct + " occ/enc pairs

    "); - -} - -private static void migrateMarkedIndividuals(JspWriter out, Shepherd myShepherd, Connection conn) throws SQLException, IOException { - out.println("

    MarkedIndividuals

      "); - Map txmap = taxonomyMap(conn); - Statement st = conn.createStatement(); - Statement st2 = conn.createStatement(); - ResultSet res = st.executeQuery("SELECT * FROM individual ORDER BY guid"); - int ct = 0; - - while (res.next()) { - ct++; - if (ct > batchMax()) break; - String guid = res.getString("guid"); - out.println("
    1. " + guid + ": "); - MarkedIndividual indiv = myShepherd.getMarkedIndividual(guid); - if (indiv != null) { - ct--; - out.println("indiv exists; skipping"); - } else { - indiv = new MarkedIndividual(); - indiv.setId(guid); - Timestamp ts = res.getTimestamp("created"); - if (ts != null) indiv.setDateTimeCreated(ts.toString()); - //ts = res.getTimestamp("updated"); - //if (ts != null) occ.setDWCDateLastModified(ts.toString()); - String txguid = res.getString("taxonomy_guid"); - if (txguid != null) indiv.setTaxonomyString(txmap.get(txguid)); - ts = res.getTimestamp("time_of_birth"); - if (ts != null) indiv.setTimeOfBirth(ts.getTime()); - ts = res.getTimestamp("time_of_death"); - if (ts != null) indiv.setTimeOfDeath(ts.getTime()); - indiv.setSex(res.getString("sex")); - indiv.setComments(res.getString("comments")); - - ResultSet res2 = st2.executeQuery("SELECT * FROM name WHERE individual_guid='" + guid + "'"); - while (res2.next()) { - String nameContext = res2.getString("context"); - String nameValue = res2.getString("value"); - if ("FirstName".equals(nameContext)) { - indiv.addName(nameValue); - } else { - indiv.addName(nameContext, nameValue); - } - } - - // same note as occurrences on needing encs attached first :( - res2 = st2.executeQuery("SELECT guid FROM encounter WHERE individual_guid='" + guid + "' ORDER BY guid"); - while (res2.next()) { - Encounter enc = myShepherd.getEncounter(res2.getString("guid")); - if (enc == null) continue; - if (!enc.hasMarkedIndividual(indiv)) { - enc.setIndividual(indiv); - } - } - - // custom fields, oof - // these need to be hard-coded per migration - JSONObject cfData = cleanJSONObject(res.getString("custom_fields")); - - String dateOfBirth = cfString(cfData, "87d08929-2133-4053-911a-8740f7fa8dd5"); - if (!stringEmpty(dateOfBirth)) try { - indiv.setTimeOfBirth(Util.getVersionFromModified(dateOfBirth)); - } catch (Exception ex) {} - String dateOfDeath = cfString(cfData, "ed537aa9-5d68-45e5-9236-f701d95a8bdd"); - if (!stringEmpty(dateOfDeath)) try { - indiv.setTimeOfDeath(Util.getVersionFromModified(dateOfDeath)); - } catch (Exception ex) {} - String notes = cfString(cfData, "8ac7286d-3290-41d3-8497-17b3f7aa5184"); - if (!stringEmpty(notes)) indiv.addComments(notes); - - // these require more complex stuff - String withPup = cfString(cfData, "6428357e-8965-45f6-8f53-d17df08c4316"); - String lifeStatus = cfString(cfData, "854a9755-1909-464b-b024-7608045309a7"); - String flipperTag = cfString(cfData, "7bb54bb8-f148-47b5-91b3-286b8851e461"); - String entanglement = cfString(cfData, "e9ecaaac-54c9-4c94-bf2e-0989f467c1d1"); - - if (!stringEmpty(withPup)) { - indiv.addComments("

      With Pup: " + withPup + "

      "); - for (Encounter enc : indiv.getEncounters()) { -System.out.println(">>>>> ??? " + withPup + " on " + enc); - enc.setDynamicProperty("with_pup", withPup); - } - } - if (!stringEmpty(flipperTag)) { - indiv.addComments("

      Flipper Tag: " + flipperTag + "

      "); - MetalTag tag = new MetalTag(flipperTag, "flipper"); - for (Encounter enc : indiv.getEncounters()) { -System.out.println(">>>>> ??? " + tag + " on " + enc); - enc.addMetalTag(tag); - } - } - if (!stringEmpty(lifeStatus)) { - indiv.addComments("

      Life Status: " + lifeStatus + "

      "); - Encounter[] recent = indiv.getDateSortedEncounters(true, 1); - if ((recent != null) && (recent.length > 0)) recent[0].setLifeStage(lifeStatus); -System.out.println(">>>>> ??? " + lifeStatus + " on " + indiv); - } - if (!stringEmpty(entanglement)) { - indiv.addComments("

      Entanglement: " + entanglement + "

      "); - LabeledKeyword kw = myShepherd.getOrCreateLabeledKeyword("Entanglement", entanglement, false); - for (Encounter enc : indiv.getEncounters()) { - for (MediaAsset ma : enc.getMedia()) { -System.out.println(">>>>> ??? " + kw + " on " + enc); - ma.addKeyword(kw); - } - } - } - - myShepherd.storeNewMarkedIndividual(indiv); - - String msg = "created indiv [" + ct + "] " + indiv; - out.println("" + msg + ""); - System.out.println(msg); - } - out.println("
    2. "); - } - out.println("
    "); - - ct = 0; - res = st.executeQuery("SELECT guid, individual_guid FROM encounter WHERE individual_guid IS NOT NULL ORDER BY individual_guid"); - while (res.next()) { - String encGuid = res.getString("guid"); - String indivGuid = res.getString("individual_guid"); - Encounter enc = myShepherd.getEncounter(encGuid); - MarkedIndividual indiv = myShepherd.getMarkedIndividual(indivGuid); - if ((enc == null) || (indiv == null)) { - System.out.println("migrateMarkedIndividuals: cannot join due to null; enc=" + enc + "; indiv=" + indiv); - continue; - } - ct++; - enc.setIndividual(indiv); - } - out.println("

    joined " + ct + " enc/indiv pairs

    "); - -} - - -private static void migrateKeywords(JspWriter out, Shepherd myShepherd, Connection conn) throws SQLException, IOException { - out.println("

    Keywords

      "); - Statement st = conn.createStatement(); - ResultSet res = st.executeQuery("SELECT keyword.guid, value, STRING_AGG(annotation_guid::text, ',') AS annot_guids FROM keyword JOIN annotation_keywords ON (keyword.guid = keyword_guid) GROUP BY keyword.guid"); - int ct = 0; - - while (res.next()) { - ct++; - String guid = res.getString("guid"); - String value = res.getString("value"); - if (stringEmpty(value)) continue; - String annIdList = res.getString("annot_guids"); - if (stringEmpty(annIdList)) continue; - String[] annIds = annIdList.split(","); - if (annIds.length < 1) continue; - Keyword kw = myShepherd.getOrCreateKeyword(value); - out.println("
    1. " + guid + " " + kw + ":
        "); - for (String annId : annIds) { - Annotation ann = myShepherd.getAnnotation(annId); - if (ann == null) { - out.println("
      • cannot load Annot " + annId + "
      • "); - continue; - } - MediaAsset ma = ann.getMediaAsset(); - if (ma == null) { - out.println("
      • cannot load MediaAsset on " + ann + "
      • "); - continue; - } - if (ma.hasKeyword(kw)) { - out.println("
      • " + ma + " already has " + kw + "
      • "); - continue; - } - ma.addKeyword(kw); - out.println("
      • Added " + kw + " to " + ma + "
      • "); - } - out.println("
    2. "); - } - out.println("
    "); -} - -private static void migrateRelationships(JspWriter out, Shepherd myShepherd, Connection conn) throws SQLException, IOException { - out.println("

    Relationships

      "); - Map relMeta = relationshipMeta(conn); - Statement st = conn.createStatement(); - Statement st2 = conn.createStatement(); - ResultSet res = st.executeQuery("SELECT * FROM relationship"); - int ct = 0; - - while (res.next()) { - ct++; - String guid = res.getString("guid"); - String typeGuid = res.getString("type_guid"); - out.println("
    1. " + guid + " [" + typeGuid + "]: "); - String typeLabel = relMeta.get(typeGuid); - if (typeLabel == null) { - out.println("unknown label
    2. "); - continue; - } - out.println(" typeLabel=" + typeLabel); - ResultSet res2 = st2.executeQuery("SELECT * FROM relationship_individual_member WHERE relationship_guid='" + guid + "'"); - List indivs = new ArrayList(); - List roles = new ArrayList(); - out.println("
        "); - while (res2.next()) { - String indivGuid = res2.getString("individual_guid"); - String roleGuid = res2.getString("individual_role_guid"); - MarkedIndividual indiv = myShepherd.getMarkedIndividual(indivGuid); - String roleLabel = relMeta.get(roleGuid); - if ((indiv == null) || (roleLabel == null)) { - out.println("
      • failed on indivGuid=" + indivGuid + ", roleGuid=" + roleGuid + "[" + roleLabel + "]
      • "); - } else { - out.println("
      • " + roleGuid + "[" + roleLabel + "] on " + indiv + "
      • "); - indivs.add(indiv); - roles.add(roleLabel); - } - } - out.println("
      "); - if (indivs.size() != 2) { - out.println("invalid indivs.size=" + indivs.size() + ""); - continue; - } - - Relationship rel = myShepherd.getRelationship(typeLabel, indivs.get(0).getId(), indivs.get(1).getId(), roles.get(0), roles.get(1)); - if (rel != null) { - out.println("rel already exists: " + rel + ""); - continue; - } - rel = new Relationship(typeLabel, indivs.get(0), indivs.get(1)); - myShepherd.getPM().makePersistent(rel); - myShepherd.commitDBTransaction(); - myShepherd.beginDBTransaction(); - rel.setMarkedIndividualRole1(roles.get(0)); - rel.setMarkedIndividualRole2(roles.get(1)); - out.println("created " + rel + " on " + indivs.get(0) + " and " + indivs.get(1) + ""); - out.println(""); - } - out.println("
    "); -} - -private static void migrateSocialGroups(JspWriter out, Shepherd myShepherd, Connection conn) throws SQLException, IOException { - out.println("

    SocialGroups

      "); - Map sgMeta = socialGroupMeta(conn); - Statement st = conn.createStatement(); - ResultSet res = st.executeQuery("SELECT group_guid, name, individual_guid, roles FROM social_group_individual_membership JOIN social_group ON (group_guid=social_group.guid);"); - int ct = 0; - - Map units = new HashMap(); - while (res.next()) { - ct++; - String suName = res.getString("name"); - SocialUnit su = units.get(suName); - if (su == null) su = myShepherd.getSocialUnit(suName); - if (su == null) su = new SocialUnit(suName); - units.put(suName, su); - out.println("
    1. " + su + ": "); - - String indivID = res.getString("individual_guid"); - MarkedIndividual indiv = myShepherd.getMarkedIndividual(indivID); - if (indiv == null) { - out.println("failed to load indivID=" + indivID + "
    2. "); - continue; - } - out.println("[" + indiv + "]; "); - // even tho the code before will import multiple roles per individual, we are - // going to bail on there already *existing* one meaning this has been done - // ymmv ??? - Membership exists = su.getMembershipForMarkedIndividual(indiv); - if (exists != null) { - out.println("a membership exists for " + indiv + "; skipping"); - continue; - } - myShepherd.getPM().makePersistent(su); - - JSONArray rolesArr = cleanJSONArray(res.getString("roles")); - if ((rolesArr == null) || (rolesArr.length() == 0)) { - // guess we make it a null role and add it??? - Membership membership = new Membership(indiv); - membership.setRole(null); - myShepherd.getPM().makePersistent(membership); - su.addMember(membership); - out.println("[null role]"); - } else { - for (int i = 0 ; i < rolesArr.length() ; i++) { - String role = rolesArr.optString(i, null); - if (role == null) continue; - String roleName = sgMeta.get(role); - if (roleName == null) { - out.println("[failed to find roleName for role=" + role + "; skipping]"); - continue; - } - Membership membership = new Membership(indiv); - membership.setRole(roleName); - myShepherd.getPM().makePersistent(membership); - su.addMember(membership); - out.println("[role=" + role + "; roleName=" + roleName + "]"); - } - } - - out.println(""); - } - out.println("
    "); -} - -private static void migratePendingSightings(JspWriter out, Shepherd myShepherd, Connection conn, HttpServletRequest request) throws SQLException, IOException { - out.println("

    PendingSightings

      "); - Statement st = conn.createStatement(); - ResultSet res = st.executeQuery("SELECT * FROM asset_group_sighting WHERE stage != 'processed' ORDER BY guid"); - int ct = 0; - - while (res.next()) { - ct++; - String guid = res.getString("guid"); - out.println("
    1. " + guid + ": "); - Occurrence occ = myShepherd.getOccurrence(guid); - if (occ != null) { - ct--; - out.println("occurrence exists; skipping"); - } else { - JSONObject config = cleanJSONObject(res.getString("config")); - if (config == null) { - out.println("null config; failing
    2. "); - continue; - } - out.println("" + config.toString(4) + ""); - - JSONObject sdata = config.optJSONObject("sighting"); - if (sdata == null) { - out.println("null sighitng data in config; failing"); - continue; - } - JSONArray earr = sdata.optJSONArray("encounters"); - if ((earr == null) || (earr.length() < 1)) { - out.println("null or empty encounters array in config; failing"); - continue; - } - - occ = new Occurrence(); - occ.setId(guid); - // TODO: something with asset_group_guid ? - - occ.setEncounters(new ArrayList()); //grrr - for (int i = 0 ; i < earr.length() ; i++) { - Encounter enc = encounterFromPending(earr.optJSONObject(i)); - if (enc == null) { - out.println("failed to create enc " + i + ""); - continue; - } - occ.addEncounter(enc); - enc.setOccurrenceID(occ.getId()); - } - - Timestamp ts = res.getTimestamp("created"); - if (ts != null) occ.setDateTimeCreated(ts.toString()); - ts = res.getTimestamp("updated"); - if (ts != null) occ.setDWCDateLastModified(ts.toString()); - - Double d = null; - if (sdata.has("decimal_latitude") && !sdata.isNull("decimal_latitude")) d = sdata.getDouble("decimal_latitude"); - occ.setDecimalLatitude(d); - d = null; - if (sdata.has("decimal_longitude") && !sdata.isNull("decimal_longitude")) d = sdata.getDouble("decimal_longitude"); - occ.setDecimalLongitude(d); - occ.setComments(sdata.optString("comments", null)); - //occ.setVerbatimLocality(res.getString("verbatim_locality")); - //occ.setLocationID(res.getString("location_guid")); - - // date/time madness - String time = sdata.optString("time", null); - if (time == null) { - out.println("null time config; failing"); - continue; - } - //String spec = res.getString("specificity"); n/a - // we only store a long for this on occurrences - occ.setDateTimeLong(new DateTime(time).getMillis()); - - // custom fields, oof - // these need to be hard-coded per migration - JSONObject cfData = sdata.optJSONObject("customFields"); - Map cfMap = new HashMap(); - cfMap.put("Seen in Artificial Nest", cfString(cfData, "34a8f03e-d282-4fef-b1ed-9eeebaaa887e")); - cfMap.put("Observation Type", cfString(cfData, "736d8b8f-7abb-404f-9da8-0c1507185baa")); - cfMap.put("Seen with Unknown Seal", cfString(cfData, "e9a00eab-7ea6-4777-afb3-79d95ebfbf4f")); - cfMap.put("Photography Type", cfString(cfData, "cf7ed66f-e6c1-4cb1-aadf-0f141ca22316")); - cfMap.put("Sighting Origin", cfString(cfData, "15b4525a-47e9-4673-ae42-f99ea55f810c")); - cfMap.put("Seen with Unknown Pup", cfString(cfData, "d0f2cc9e-0845-4608-8754-3d1f70eec699")); - String photogName = cfString(cfData, "305b50df-7f21-4d8d-aeb6-45ab1869f5ba"); - String photogEmail = cfString(cfData, "ecc6f017-057c-4821-b07a-f82cd60aa31d"); - - if (occ.getNumberEncounters() > 0) for (Encounter enc : occ.getEncounters()) { - if (!stringEmpty(photogName)) enc.setPhotographerName(photogName); - if (!stringEmpty(photogEmail)) enc.setPhotographerEmail(photogEmail); - try { - out.println("" + enc.uiJson(request).toString(4) + "
      "); - } catch (Exception ex) {} - } - - // now we can do this, since it needs encs - cfOccurrence(myShepherd, occ, cfMap); - -/* - myShepherd.storeNewOccurrence(occ); - - String msg = "created occurrence [" + ct + "] " + occ; - out.println("" + msg + ""); - System.out.println(msg); -*/ - - - out.println("" + occ.getJSONSummary().toString(4) + ""); - } - - out.println(""); - } - out.println("
    "); -} - - -private static void fixAutogenNames(JspWriter out, Shepherd myShepherd, Connection conn) throws SQLException, IOException { - Object ss = siteSetting("autogenerated_names", conn); - if (ss == null) return; - JSONObject autogenMeta = (JSONObject)ss; - - out.println("

    Autogenerated Names

      "); - //Statement st = conn.createStatement(); - Query query = myShepherd.getPM().newQuery("SELECT FROM org.ecocean.MultiValue WHERE valuesAsString.matches('.*autogen-.*')"); - Collection c = (Collection)(query.execute()); - List all = new ArrayList(c); - query.closeAll(); - for (MultiValue mv : all) { - JSONObject val = mv.getValues(); - Map replace = new HashMap(); - for (String key : (Set)val.keySet()) { - if (key.startsWith("autogen-")) { - JSONArray names = val.optJSONArray(key); - if ((names == null) || (names.length() < 1)) continue; - String suffix = names.optString(0, null); - if (suffix == null) continue; - String txId = key.substring(8); - JSONObject meta = autogenMeta.optJSONObject(txId); - if (meta == null) continue; - String prefix = meta.optString("prefix", null); - if (prefix == null) continue; - replace.put(key, prefix + "-" + suffix); - } - } - for (String kill : replace.keySet()) { - val.remove(kill); - JSONArray newNames = new JSONArray(); - newNames.put(replace.get(kill)); - val.put("autogenerated", newNames); - } - out.println("
    1. " + val + "
    2. "); - mv.setValues(val); - myShepherd.getPM().makePersistent(mv); - } - out.println("
    "); -} - -%> - - -<% - -File tmp = new File(TMP_DIR); -if (!tmp.exists()) tmp.mkdir(); - -String context = ServletUtilities.getContext(request); -Shepherd myShepherd = new Shepherd(context); -myShepherd.beginDBTransaction(); - -Properties props = ShepherdProperties.getProperties("codexMigration.properties", "", context); -String dbUrl = props.getProperty("codexDbUrl", context); -String dbUsername = props.getProperty("codexDbUsername", context); -String dbPassword = props.getProperty("codexDbPassword", context); - -// this is under data-dir -String assetGroupDir = props.getProperty("assetGroupDir", context); -File dataDir = CommonConfiguration.getDataDirectory(getServletContext(), context); - - -Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword); - -JSONObject locJson = locationJson(conn); -// hard-coded file path, but life is rough -if (locJson != null) Util.writeToFile(locJson.toString(4), "/usr/local/tomcat/webapps/wildbook_data_dir/WEB-INF/classes/bundles/locationID.json"); - - -/* -migrateUsers(out, myShepherd, conn); - -migrateMediaAssets(out, myShepherd, conn, request, new File(dataDir, assetGroupDir)); - -migrateAnnotations(out, myShepherd, conn); - -migrateEncounters(out, myShepherd, conn); - -migrateOccurrences(out, myShepherd, conn); - -migrateMarkedIndividuals(out, myShepherd, conn); - -migrateKeywords(out, myShepherd, conn); - -migrateRelationships(out, myShepherd, conn); - -fixAutogenNames(out, myShepherd, conn); - -migrateSocialGroups(out, myShepherd, conn); -*/ - -migratePendingSightings(out, myShepherd, conn, request); - - -myShepherd.commitDBTransaction(); -myShepherd.closeDBTransaction(); - -%> - - - diff --git a/src/main/webapp/appadmin/locationIDTester.jsp b/src/main/webapp/appadmin/locationIDTester.jsp index 596b998115..0c837bcf6d 100644 --- a/src/main/webapp/appadmin/locationIDTester.jsp +++ b/src/main/webapp/appadmin/locationIDTester.jsp @@ -51,25 +51,6 @@ myShepherd.setAction("locationIDTester.jsp");

    -

    Override Indocet tests

    -

    <%=LocationID.getLocationIDStructure("indocet").toString() %>

    - -

    The name for locationID 1 is:

    <%=LocationID.getNameForLocationID("Moheli","indocet") %>

    - -

    The name for locationID 6 is:

    <%=LocationID.getNameForLocationID("Moheli","indocet") %>

    - -

    -

    -<%=LocationID.getHTMLSelector(true,(String)null,"indocet","id","name","class")%> -
    -

    - -

    Single select and selected: -

    -<%=LocationID.getHTMLSelector(false, "Ifaty","indocet","id","name","class")%> -
    -

    -

    Get hierarchy for ID

    <% diff --git a/src/main/webapp/cust/indocet/overwrite.css b/src/main/webapp/cust/indocet/overwrite.css index 181d22e7ea..40b3227493 100644 --- a/src/main/webapp/cust/indocet/overwrite.css +++ b/src/main/webapp/cust/indocet/overwrite.css @@ -13,13 +13,6 @@ body { background-position: center; } -.navbar-brand.indocet { - display: inline !important; /* display: none by default; */ - background: url(indocet-logo-white.png) no-repeat; - background-position: center; - background-size: 76%; /* custom value that looks nice next to flukebook logo */ -} - .nav-bar-wrapper { background-color: #075366; } @@ -195,9 +188,6 @@ h1, h2, .brand-primary, div #markedIndividualHeader { color } -/* -Link code copied from indocet's website -*/ a:hover, .entry-meta span a:hover, .comments-link a:hover, body.coldisplay2 #front-columns a:active { color: #ffb200; } diff --git a/src/main/webapp/encounters/encounter.jsp b/src/main/webapp/encounters/encounter.jsp index 908023393b..63392d0f3b 100755 --- a/src/main/webapp/encounters/encounter.jsp +++ b/src/main/webapp/encounters/encounter.jsp @@ -175,9 +175,7 @@ URLCodec urlCodec = new URLCodec(); //let's load encounters.properties //Properties encprops = new Properties(); //encprops.load(getClass().getResourceAsStream("/bundles/" + langCode + "/encounter.properties")); - - //Properties encprops = ShepherdProperties.getProperties("encounter.properties", langCode, context, "indocet"); - + pageContext.setAttribute("num", num); diff --git a/src/main/webapp/encounters/manualAnnotation.jsp b/src/main/webapp/encounters/manualAnnotation.jsp index cf6b44daf0..8aa055749b 100644 --- a/src/main/webapp/encounters/manualAnnotation.jsp +++ b/src/main/webapp/encounters/manualAnnotation.jsp @@ -16,6 +16,7 @@ java.io.UnsupportedEncodingException, org.ecocean.identity.IBEISIA, java.util.ArrayList, + java.util.Collections, org.apache.commons.collections4.CollectionUtils " %> @@ -198,9 +199,11 @@ try{ final String noViewpoint = "----------"; vlist += ""; final Set results = new LinkedHashSet<>(Annotation.getAllValidViewpoints()); - Iterator it = results.iterator(); + List sortedResults = new ArrayList<>(results); + Collections.sort(sortedResults); + Iterator it = sortedResults.iterator(); while (it.hasNext()) { - String v = (String)it.next(); + String v = it.next(); if (!Util.stringExists(v)) continue; vlist += "" + v + ""; } diff --git a/src/main/webapp/header.jsp b/src/main/webapp/header.jsp index 1e8ac3b1cf..0ccad495e4 100755 --- a/src/main/webapp/header.jsp +++ b/src/main/webapp/header.jsp @@ -101,7 +101,7 @@ if(request.getUserPrincipal()!=null){ } } catch(Exception e){ - System.out.println("Exception on indocetCheck in header.jsp:"); + System.out.println("Exception in header.jsp:"); e.printStackTrace(); myShepherd.closeDBTransaction(); } @@ -159,7 +159,7 @@ if(request.getUserPrincipal()!=null){ - + @@ -436,7 +436,10 @@ if(request.getUserPrincipal()!=null){