diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..f864af29ee --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +/GAE +/Config +/Dashboard/.sass-cache +/Dashboard/tmp +/.git +/scripts +/tests \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6a96128083..1387fc6544 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ GAE/war/WEB-INF/lib/geronimo*.jar GAE/war/WEB-INF/lib/jdo2-api*.jar GAE/war/WEB-INF/lib/jsr107*.jar GAE/war/WEB-INF/lib/libservice.jar +GAE/target # APK paths WFPMapping/device/debugcert @@ -84,3 +85,5 @@ dwsync.xml out/ .idea/ *.iml +rake.log +lein.log \ No newline at end of file diff --git a/Dashboard/Assetfile b/Dashboard/Assetfile index 7d67e569df..6a41bbe52a 100644 --- a/Dashboard/Assetfile +++ b/Dashboard/Assetfile @@ -48,7 +48,7 @@ class CSSMinFilter < Filter end end -output '../GAE/war/admin' +output '../GAE/target/akvo-flow/admin' input 'app' do match 'css/main.scss' do @@ -126,7 +126,7 @@ input 'app' do end -output '../GAE/war/vendorjs' +output '../GAE/target/akvo-flow/vendorjs' input 'app' do match "js/vendor/**/*.js" do concat do |input| diff --git a/Dashboard/AssetfilePublic b/Dashboard/AssetfilePublic index 4f468b5b6c..e1b795e489 100755 --- a/Dashboard/AssetfilePublic +++ b/Dashboard/AssetfilePublic @@ -48,7 +48,7 @@ class CSSMinFilter < Filter end end -output '../GAE/war/publicmap' +output '../GAE/target/akvo-flow/publicmap' input 'app' do match 'css/main.scss' do diff --git a/Dashboard/Rakefile b/Dashboard/Rakefile index 695945ce7d..c3ad15a904 100755 --- a/Dashboard/Rakefile +++ b/Dashboard/Rakefile @@ -30,3 +30,7 @@ task :watch do system "bundle exec guard start" end +desc "Watch for changes in the background" +task :watchbg do + system "bundle exec guard start --no-interactions" +end diff --git a/Dashboard/app/cljs/cp-html.sh b/Dashboard/app/cljs/cp-html.sh index c87a55fe1f..f18342fa44 100755 --- a/Dashboard/app/cljs/cp-html.sh +++ b/Dashboard/app/cljs/cp-html.sh @@ -1,6 +1,6 @@ #!/bin/bash -OUT_ROOT=../../../GAE/war/admin/frames/ +OUT_ROOT=../../../GAE/target/akvo-flow/admin/frames/ mkdir -p ${OUT_ROOT} diff --git a/Dashboard/app/cljs/project.clj b/Dashboard/app/cljs/project.clj index 7a9b161a72..7de56381ac 100644 --- a/Dashboard/app/cljs/project.clj +++ b/Dashboard/app/cljs/project.clj @@ -14,9 +14,9 @@ :source-paths ["src"] - :clean-targets ^{:protect false} ["../../../GAE/war/admin/frames/users.html" - "../../../GAE/war/admin/frames/users.js" - "../../../GAE/war/admin/frames/out/"] + :clean-targets ^{:protect false} ["../../../GAE/target/akvo-flow/admin/frames/users.html" + "../../../GAE/target/akvo-flow/admin/frames/users.js" + "../../../GAE/target/akvo-flow/admin/frames/out/"] :aliases {"copyhtml" ["shell" "./cp-html.sh"] "copyhtml-production" ["shell" "./cp-html.sh" "--production"] @@ -34,8 +34,8 @@ :source-paths ["src"] :compiler { :main org.akvo.flow.dashboard.users.core - :output-to "../../../GAE/war/admin/frames/users.js" - :output-dir "../../../GAE/war/admin/frames/out" + :output-to "../../../GAE/target/akvo-flow/admin/frames/users.js" + :output-dir "../../../GAE/target/akvo-flow/admin/frames/out" :asset-path "out" :optimizations :none :source-map true}} @@ -43,5 +43,5 @@ :source-paths ["src"] :compiler { :main org.akvo.flow.dashboard.users.core - :output-to "../../../GAE/war/admin/frames/users.js" + :output-to "../../../GAE/target/akvo-flow/admin/frames/users.js" :optimizations :advanced}}]}) diff --git a/Dashboard/app/css/main.scss b/Dashboard/app/css/main.scss index 062ee9ad6c..3156fd7a95 100644 --- a/Dashboard/app/css/main.scss +++ b/Dashboard/app/css/main.scss @@ -3322,7 +3322,10 @@ table.dataTable.notificationTable thead tr th a:visited { } .reportTools { - padding-left: 0.5%; + position: relative; + >div { + position: relative; + } } div.chooseSurveyData { @@ -3767,7 +3770,7 @@ footer.bottomPage nav.footItems { clear: both; background: rgba($akvoBlack, 0.05); border-top: thin solid rgba($akvoBlack, 0.05); - /* + /* border-bottom: thin solid rgba($akvoBlack, 0.05); */ padding: 5px 0 7px 0; ul { @@ -4406,248 +4409,6 @@ table.surveyDetails { } } -/* Uploader: Drag & Drop */ - -.resumable-error { - font-style: italic; -} - -.resumable-drop { - padding: 3em; - text-align: center; - color: rgb(32, 32, 36); - background-color: white; - background-color: rgba(44, 42, 116, 0.1); - border: thin solid rgb(171, 170, 200); - border-radius: 0.25em; - margin: 1.5em auto 1.5em; - z-index: 9999; -} - -.resumable-drop u { - font-weight: bold; - cursor: pointer; -} - -.resumable-drop input { - cursor: pointer; -} - -.resumable-dragover { - padding: 30px; - color: #555; - background-color: #ddd; - border: 1px solid #999; -} - -/* Uploader: Progress bar */ - -.resumable-progress { - margin: 0 0 0.5em 0; - width: 100%; - display: none; -} - -.progress-container { - height: 10px; - background: rgb(234, 185, 45); - background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VhYjkyZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNjNzk4MTAiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(234, 185, 45, 1)), color-stop(100%, rgba(199, 152, 16, 1))); - background: -webkit-linear-gradient(top, rgba(234, 185, 45, 1) 0%, rgba(199, 152, 16, 1) 100%); - background: -webkit-gradient(linear, left top, left bottom, from(rgba(234, 185, 45, 1)), to(rgba(199, 152, 16, 1))); - background: linear-gradient(to bottom, rgba(234, 185, 45, 1) 0%, rgba(199, 152, 16, 1) 100%); - position: relative; - -o-border-radius: 0.5em; - border-radius: 0.5em; -} - -.progress-bar { - height: 10px; - left: -1px; - background: rgb(191, 210, 85); - /* Old browsers */ - /* IE9 SVG, needs conditional override of 'filter' to 'none' */ - background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2JmZDI1NSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iIzhlYjkyYSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjUxJSIgc3RvcC1jb2xvcj0iIzcyYWEwMCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiM5ZWNiMmQiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); - /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(191, 210, 85, 1)), color-stop(50%, rgba(142, 185, 42, 1)), color-stop(51%, rgba(114, 170, 0, 1)), color-stop(100%, rgba(158, 203, 45, 1))); - /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, rgba(191, 210, 85, 1) 0%, rgba(142, 185, 42, 1) 50%, rgba(114, 170, 0, 1) 51%, rgba(158, 203, 45, 1) 100%); - /* Chrome10+,Safari5.1+ */ - /* Opera 11.10+ */ - /* IE10+ */ - background: -webkit-gradient(linear, left top, left bottom, from(rgba(191, 210, 85, 1)), color-stop(50%, rgba(142, 185, 42, 1)), color-stop(51%, rgba(114, 170, 0, 1)), to(rgba(158, 203, 45, 1))); - background: linear-gradient(to bottom, rgba(191, 210, 85, 1) 0%, rgba(142, 185, 42, 1) 50%, rgba(114, 170, 0, 1) 51%, rgba(158, 203, 45, 1) 100%); - width: 0; - border-right: 1px solid white; - -o-border-radius: 0.5em; - border-radius: 0.5em; -} - -.progress-text { - line-height: 9px; - padding-left: 10px; -} - -.progress-pause { - padding: 0 0 0 7px; -} - -.progress-resume-link { - display: none; -} - -.is-paused .progress-resume-link { - display: inline; -} - -.is-paused .progress-pause-link { - display: none; -} - -.is-complete .progress-pause { - display: none; -} - -/* Uploader: List of items being uploaded */ - -.resumable-list { - display: table; - overflow: auto; - display: none; - margin: 0 auto; - padding: 0.25em; - color: rgb(180, 180, 180); -} - -.resumable-list li { - margin: 0 0 1px 0; - padding: 15px 0.25em; - background: rgb(245, 245, 245); - border-bottom: 1px solid rgba($akvoBlack, 0.1); -} - -.resumable-file-name { - color: rgb(44, 42, 116); - margin-left: 5px; - margin-right: 15px; -} - -.unsupportedFile { - display: inline; - width: 15px; - height: 15px; -} -.uploadComplete { - display:inline; - width:15px; - height:15px; -} - -.uploadStatus { - float: right -} - -.resumable-file-progress { - color: rgb(44, 42, 116); - font-weight: bold; -} - -.uploader-item { - width: 148px; - height: 90px; - background-color: #666; - position: relative; - border: 2px solid black; - float: left; - margin: 0 6px 6px 0; -} - -.uploader-item-thumbnail { - width: 100%; - height: 100%; - position: absolute; - top: 0; - left: 0; -} - -.uploader-item img.uploader-item-thumbnail { - opacity: 0; -} - -.uploader-item-creating-thumbnail { - padding: 0 5px; - color: white; -} - -.uploader-item-title { - position: absolute; - line-height: 11px; - padding: 3px 50px 3px 5px; - bottom: 0; - left: 0; - right: 0; - color: white; - background-color: rgba(0, 0, 0, 0.6); - min-height: 27px; -} - -.uploader-item-status { - position: absolute; - bottom: 3px; - right: 3px; -} - -/* Uploader: Hover & Active status */ - -.uploader-item:hover, -.is-active .uploader-item { - border-color: #4a873c; - cursor: pointer; -} - -.uploader-item:hover .uploader-item-title, -.is-active .uploader-item .uploader-item-title { - background-color: rgba(74, 135, 60, 0.8); -} - -/* Uploader: Error status */ - -.is-error .uploader-item:hover, -.is-active.is-error .uploader-item { - border-color: #900; -} - -.is-error .uploader-item:hover .uploader-item-title, -.is-active.is-error .uploader-item .uploader-item-title { - background-color: rgba(153, 0, 0, 0.6); -} - -.is-error .uploader-item-creating-thumbnail { - display: none; -} - -.marker-cluster { - background-color: rgba(253, 156, 115, 0.6); - -webkit-background-clip: padding-box; - background-clip: padding-box; - border-radius: 20px; -} - -.marker-cluster div { - background-color: rgba(241, 128, 23, 0.6); - width: 30px; - height: 30px; - margin-left: 5px; - margin-top: 5px; - text-align: center; - border-radius: 15px; - font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif; -} - -.marker-cluster span { - line-height: 30px; -} - /************************************* New styles ****************************************/ .projectSection { background: $projectBackground; @@ -4820,13 +4581,15 @@ table.surveyDetails { transition: none; -moz-background-clip: padding; -webkit-background-clip: padding-box; + a { + @include noWrapTxt; + } &.aFormTab { background: rgba(32, 32, 36, 0.5); &:hover { background: rgba(32, 32, 36, 1); } a { - max-width: 150px; @include noWrapTxt; } &.current { @@ -5067,31 +4830,31 @@ table.surveyDetails { margin: 5px auto; box-shadow: 0 2px 3px rgba(32, 32, 36, 0.1); border-top: 1px solid rgba(32, 32, 36, 0.1); - + li { width: 49.75%; text-align: center; padding: 5px 0; color: rgb(128, 130, 133); margin-right: 0.5%; - + &:last-of-type { margin-right: 0; } - + span { display: block; margin-top: -5px; font-weight: 600; - + &.projectForm, &.projectMonitoring, &.cascadeStatus { color: white; } - + &.cascadeStatus.redColor { color: $akvoRed2; } - + &.cascadeStatus.published { color: $green; } @@ -5978,3 +5741,458 @@ svg { } } } + +#gdprBtn { + position: absolute; + right: 15px; + top: 10px; + margin-bottom: 20px; +} + +#gdprSwitch { + float: left; + width: calc(35% - 1px); + margin-right: 1px; + height: calc(100vh - 255px); + box-sizing: border-box; + // background: rgba(gray, 0.05); + // border: 1px solid rgba($akvoBlack, 0.05); + text-align: center; + h3 { + font-size: 1em; + } +} + +.gdprSwitchSteps { + * { + box-sizing: border-box; + } + height: calc(100vh - 255px); + display: grid; + overflow-y: scroll; + li { + text-align: center; + position: relative; + height: calc((100% -150px) / 3); + width: 100%; + margin-bottom: 25px; + &:first-of-type { + margin-top: 20px; + } + .innerFrame { + display: table; + width: 100%; + .wrap { + display: table-cell; + text-align: center; + margin: 0; + padding: 0; + img { + max-width: 50%; + max-height: 80%; + min-height: 95px !important; + } + } + } + h3 { + font-weight: bold; + color: $akvoDarkBlue; + margin: 0 auto !important; + } + p { + max-width: 90%; + margin: 10px auto 0 auto; + } + } +} + +.bulkUpload { + float: right; + margin-right: 1%; + width: 64%; + height: calc(100vh - 335px); + /* Uploader: Drag & Drop */ + position: relative; + .resumable-error { + font-style: italic; + } + .resumable-drop { + position: relative; + padding: 3em 0; + color: rgb(32, 32, 36); + background-color: white; + background-color: rgba(44, 42, 116, 0); + border: 1px dashed rgb(171, 170, 200); + margin: 0em auto 1.5em; + z-index: 9999; + height: 100%; + .dragTxt { + width: 100%; + max-width: 450px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + text-align: center; + .zipIcn { + height: 80px; + background: url(../images/zipIcn.svg) center top no-repeat; + background-size: 60px; + } + p { + .warningMsg { + font-size: 0.8em; + margin-top: 10px; + } + } + } + } + .resumable-drop u { + font-weight: bold; + cursor: pointer; + } + .resumable-drop input { + cursor: pointer; + } + .resumable-dragover { + padding: 30px; + color: #555; + background-color: #ddd; + border: 1px solid #999; + } + /* Uploader: Progress bar */ + .resumable-progress { + margin: -100px auto 0.5em auto; + width: 95%; + display: none; + } + .progress-text { + line-height: 9px; + padding-left: 10px; + } + .progress-pause { + padding: 0 0 0 7px; + } + .progress-resume-link { + display: none; + } + .is-paused .progress-resume-link { + display: inline; + } + .is-paused .progress-pause-link { + display: none; + } + .is-complete .progress-pause { + display: none; + } + /* Uploader: List of items being uploaded */ + .resumable-list { + position: absolute; + bottom: 0; + width: 90%; + text-align: left; + max-height: 150px; + overflow-y: scroll; + margin: 0 0 0 5%; + padding: 0.25em 1em; + color: rgb(180, 180, 180); + transition-property: all; + transition-duration: .5s; + transition-timing-function: cubic-bezier(0, 1, 0.5, 1); + li { + margin: 0 0 1px 0; + padding: 15px 0.25em; + border-bottom: 1px solid rgba($akvoBlack, 0.05); + font-size: 0.85em; + &:last-child { + border-bottom: none; + } + .resumable-file-name { + margin-left: 5px; + margin-right: 15px; + color: $akvoBlack; + } + .resumable-file-progress {} + } + } + .uploader-item { + width: 148px; + height: 90px; + background-color: #666; + position: relative; + border: 2px solid black; + float: left; + margin: 0 6px 6px 0; + padding: 3em 0; + } + .uploader-item-thumbnail { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + } + .uploader-item img.uploader-item-thumbnail { + opacity: 0; + } + .uploader-item-creating-thumbnail { + padding: 0 5px; + color: white; + } + .uploader-item-title { + position: absolute; + line-height: 11px; + padding: 3px 50px 3px 5px; + bottom: 0; + left: 0; + right: 0; + color: white; + background-color: rgba(0, 0, 0, 0.6); + min-height: 27px; + } + .uploader-item-status { + position: absolute; + bottom: 3px; + right: 3px; + } + /* Uploader: Hover & Active status */ + .uploader-item:hover, + .is-active .uploader-item { + border-color: #4a873c; + cursor: pointer; + } + .uploader-item:hover .uploader-item-title, + .is-active .uploader-item .uploader-item-title { + background-color: rgba(74, 135, 60, 0.8); + } + /* Uploader: Error status */ + .is-error .uploader-item:hover, + .is-active.is-error .uploader-item { + border-color: #900; + } + .is-error .uploader-item:hover .uploader-item-title, + .is-active.is-error .uploader-item .uploader-item-title { + background-color: rgba(153, 0, 0, 0.6); + } + .is-error .uploader-item-creating-thumbnail { + display: none; + } + .marker-cluster { + background-color: rgba(253, 156, 115, 0.6); + -webkit-background-clip: padding-box; + background-clip: padding-box; + border-radius: 20px; + } + .marker-cluster div { + background-color: rgba(241, 128, 23, 0.6); + width: 30px; + height: 30px; + margin-left: 5px; + margin-top: 5px; + text-align: center; + border-radius: 15px; + font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif; + } + .marker-cluster span { + line-height: 30px; + } +} + +/* Uploader: Drag & Drop */ + +.resumable-error { + font-style: italic; +} + +.resumable-dragover { + padding: 30px; + color: #555; + background-color: #ddd; + border: 1px solid #999; +} + +/* Uploader: Progress bar */ + +.resumable-progress { + margin: 0 0 0.5em 0; + width: 100%; + display: none; +} + +.progress-container { + height: 10px; + background: rgb(234, 185, 45); + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2VhYjkyZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNjNzk4MTAiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(234, 185, 45, 1)), color-stop(100%, rgba(199, 152, 16, 1))); + background: -webkit-linear-gradient(top, rgba(234, 185, 45, 1) 0%, rgba(199, 152, 16, 1) 100%); + background: -webkit-gradient(linear, left top, left bottom, from(rgba(234, 185, 45, 1)), to(rgba(199, 152, 16, 1))); + background: linear-gradient(to bottom, rgba(234, 185, 45, 1) 0%, rgba(199, 152, 16, 1) 100%); + position: relative; + -o-border-radius: 0.5em; + border-radius: 0.5em; +} + +.progress-bar { + height: 10px; + left: -1px; + background: rgb(191, 210, 85); + /* Old browsers */ + /* IE9 SVG, needs conditional override of 'filter' to 'none' */ + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2JmZDI1NSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iIzhlYjkyYSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjUxJSIgc3RvcC1jb2xvcj0iIzcyYWEwMCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiM5ZWNiMmQiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); + /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(191, 210, 85, 1)), color-stop(50%, rgba(142, 185, 42, 1)), color-stop(51%, rgba(114, 170, 0, 1)), color-stop(100%, rgba(158, 203, 45, 1))); + /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, rgba(191, 210, 85, 1) 0%, rgba(142, 185, 42, 1) 50%, rgba(114, 170, 0, 1) 51%, rgba(158, 203, 45, 1) 100%); + /* Chrome10+,Safari5.1+ */ + /* Opera 11.10+ */ + /* IE10+ */ + background: -webkit-gradient(linear, left top, left bottom, from(rgba(191, 210, 85, 1)), color-stop(50%, rgba(142, 185, 42, 1)), color-stop(51%, rgba(114, 170, 0, 1)), to(rgba(158, 203, 45, 1))); + background: linear-gradient(to bottom, rgba(191, 210, 85, 1) 0%, rgba(142, 185, 42, 1) 50%, rgba(114, 170, 0, 1) 51%, rgba(158, 203, 45, 1) 100%); + width: 0; + border-right: 1px solid white; + -o-border-radius: 0.5em; + border-radius: 0.5em; +} + +.progress-text { + line-height: 9px; + padding-left: 10px; +} + +.progress-pause { + padding: 0 0 0 7px; +} + +.progress-resume-link { + display: none; +} + +.is-paused .progress-resume-link { + display: inline; +} + +.is-paused .progress-pause-link { + display: none; +} + +.is-complete .progress-pause { + display: none; +} + +/* Uploader: List of items being uploaded */ +.unsupportedFile { + display: inline; + width: 15px; + height: 15px; +} + +.uploadComplete { + display: inline; + width: 15px; + height: 15px; +} + +.uploadStatus { + float: right; +} + +.resumable-file-progress { + color: rgb(44, 42, 116); + font-weight: bold; +} + +.uploader-item { + width: 148px; + height: 90px; + background-color: #666; + position: relative; + border: 2px solid black; + float: left; + margin: 0 6px 6px 0; +} + +.uploader-item-thumbnail { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; +} + +.uploader-item img.uploader-item-thumbnail { + opacity: 0; +} + +.uploader-item-creating-thumbnail { + padding: 0 5px; + color: white; +} + +.uploader-item-title { + position: absolute; + line-height: 11px; + padding: 3px 50px 3px 5px; + bottom: 0; + left: 0; + right: 0; + color: white; + background-color: rgba(0, 0, 0, 0.6); + min-height: 27px; +} + +.uploader-item-status { + position: absolute; + bottom: 3px; + right: 3px; +} + +/* Uploader: Hover & Active status */ + +.uploader-item:hover, +.is-active .uploader-item { + border-color: #4a873c; + cursor: pointer; +} + +.uploader-item:hover .uploader-item-title, +.is-active .uploader-item .uploader-item-title { + background-color: rgba(74, 135, 60, 0.8); +} + +/* Uploader: Error status */ + +.is-error .uploader-item:hover, +.is-active.is-error .uploader-item { + border-color: #900; +} + +.is-error .uploader-item:hover .uploader-item-title, +.is-active.is-error .uploader-item .uploader-item-title { + background-color: rgba(153, 0, 0, 0.6); +} + +.is-error .uploader-item-creating-thumbnail { + display: none; +} + +.marker-cluster { + background-color: rgba(253, 156, 115, 0.6); + -webkit-background-clip: padding-box; + background-clip: padding-box; + border-radius: 20px; +} + +.marker-cluster div { + background-color: rgba(241, 128, 23, 0.6); + width: 30px; + height: 30px; + margin-left: 5px; + margin-top: 5px; + text-align: center; + border-radius: 15px; + font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif; +} + +.marker-cluster span { + line-height: 30px; +} diff --git a/Dashboard/app/js/lib/views/data/bulk-upload-view.js b/Dashboard/app/js/lib/views/data/bulk-upload-view.js index 359b511603..22b065d978 100644 --- a/Dashboard/app/js/lib/views/data/bulk-upload-view.js +++ b/Dashboard/app/js/lib/views/data/bulk-upload-view.js @@ -61,9 +61,8 @@ FLOW.uploader = Ember.Object.create({ // Show progress pabr $('.resumable-list').show(); if (li.length === 0) { - $(".resumable-list").append("
  • "); + $(".resumable-list").append("
  • ").scrollTop($('.resumable-list').outerHeight(true)); } - // Add the file to the list if (file.file.type !== "application/zip" && file.file.type !== "application/x-zip-compressed" && FLOW.uploader.get('bulkUpload')) { $("#resumable-file-"+ file.uniqueIdentifier).html( @@ -71,14 +70,13 @@ FLOW.uploader = Ember.Object.create({ + Ember.String.loc('_unsupported_file_type') + " "); $("#resumable-file-"+ file.uniqueIdentifier).css({ - color: '#FF0000' - }); + color: '#FF0000'}); r.removeFile(file); //remove file } else { $("#resumable-file-"+ file.uniqueIdentifier).html( ''+file.fileName+'' +'' - +'
    '); + +'
    ').css('position','sticky'); $('#progress-bar-'+file.uniqueIdentifier).css({ width: '0%' @@ -133,7 +131,7 @@ FLOW.uploader = Ember.Object.create({ $("#resumable-file-"+ file.uniqueIdentifier).html( ''+file.fileName+'' +'' - ); + ).slideDown( "slow", function() {}); setTimeout(function() { $.ajax({ url : target, diff --git a/Dashboard/app/js/templates/navData/bulk-upload.handlebars b/Dashboard/app/js/templates/navData/bulk-upload.handlebars index 7418811e64..e9f66fbc22 100644 --- a/Dashboard/app/js/templates/navData/bulk-upload.handlebars +++ b/Dashboard/app/js/templates/navData/bulk-upload.handlebars @@ -1,16 +1,73 @@
    {{#view FLOW.BulkUploadAppletView}} +
    +

    {{t _gdpr_wakthrough_title}}

    + + + +
    {{#if FLOW.uploader.support}}
    - {{t _drop_files}} {{t _select_files}} +
    +
    +

    {{t _drop_files}} {{t _select_files}}

    +
    +
      - {{else}}
      {{t _bulk_upload_unsupported_browser}}
      {{/if}}
      - {{/view}} -
      +{{/view}} + \ No newline at end of file diff --git a/GAE/pom.xml b/GAE/pom.xml index 71267c0392..5d8d445e17 100644 --- a/GAE/pom.xml +++ b/GAE/pom.xml @@ -39,8 +39,6 @@ 1.7 false true - akvoflowsandbox - ${project.basedir}/../../akvo-flow-server-config @@ -247,10 +245,15 @@ appengine-maven-plugin 1.9.59 + 20 1 true 8888
      0.0.0.0
      + + -Xdebug + -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 +
      @@ -281,28 +284,6 @@
      - - - org.codehaus.mojo - versions-maven-plugin - 2.3 - - - compile - - display-dependency-updates - display-plugin-updates - - - - - - javax.servlet:javax.servlet-api - com.google.guava:guava - - - - maven-war-plugin 3.1.0 @@ -315,6 +296,7 @@ /admin/** /WEB-INF/**/*.xml /WEB-INF/logging.properties + /WEB-INF/dev-logging.properties /publicmap/** /vendorjs/** CurrentUser.vm @@ -328,6 +310,12 @@ + + /WEB-INF/appengine-generated/**, + /WEB-INF/dev-logging.properties, + /WEB-INF/flow*.log, + /WEB-INF/classes/services/** + @@ -365,27 +353,6 @@ maven-resources-plugin 3.0.2 - - - copy-resources - process-resources - - copy-resources - - - ${project.basedir}/target/akvo-flow/WEB-INF - true - - - ${project.configFilesDir}/${appId} - - appengine-web.xml - - - - - - @@ -416,33 +383,9 @@ - - enforce-flow-config - - enforce - - - ${skip.appengine.file.check} - - - - ${project.configFilesDir}/${appId}/appengine-web.xml - - - - - - - - ci - - true - - - diff --git a/GAE/src/org/waterforpeople/mapping/app/web/DeviceApplicationRestService.java b/GAE/src/org/waterforpeople/mapping/app/web/DeviceApplicationRestService.java index f54ef285cf..859fe4335d 100644 --- a/GAE/src/org/waterforpeople/mapping/app/web/DeviceApplicationRestService.java +++ b/GAE/src/org/waterforpeople/mapping/app/web/DeviceApplicationRestService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Stichting Akvo (Akvo Foundation) + * Copyright (C) 2010-2012,2018 Stichting Akvo (Akvo Foundation) * * This file is part of Akvo FLOW. * @@ -16,29 +16,28 @@ package org.waterforpeople.mapping.app.web; -import java.util.List; -import java.util.Properties; - -import javax.servlet.http.HttpServletRequest; - +import com.gallatinsystems.framework.rest.AbstractRestApiServlet; +import com.gallatinsystems.framework.rest.RestRequest; +import com.gallatinsystems.framework.rest.RestResponse; import org.json.JSONObject; import org.waterforpeople.mapping.app.web.dto.DeviceApplicationRestRequest; import org.waterforpeople.mapping.app.web.dto.DeviceApplicationRestResponse; import org.waterforpeople.mapping.dao.DeviceApplicationDao; import org.waterforpeople.mapping.domain.DeviceApplication; -import com.gallatinsystems.framework.rest.AbstractRestApiServlet; -import com.gallatinsystems.framework.rest.RestRequest; -import com.gallatinsystems.framework.rest.RestResponse; +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.Properties; /** * restful service for DeviceApplications - * + * * @author Christopher Fagiani */ public class DeviceApplicationRestService extends AbstractRestApiServlet { private static final long serialVersionUID = -830140106880504436L; + private static final int MINIMUM_SUPPORTED_ANDROID_VERSION = 15; private DeviceApplicationDao devAppDao; public DeviceApplicationRestService() { @@ -64,18 +63,40 @@ protected RestResponse handleRequest(RestRequest req) throws Exception { && autoUpdateApk.equalsIgnoreCase("true")) { DeviceApplicationRestRequest daReq = (DeviceApplicationRestRequest) req; - List devAppList = devAppDao - .listByDeviceTypeAndAppCode(daReq.getDeviceType(), - daReq.getAppCode(), 1); - if (devAppList != null && devAppList.size() > 0) { - resp.setVersion(devAppList.get(0).getVersion()); - resp.setFileName(devAppList.get(0).getFileName()); - resp.setMd5Checksum(devAppList.get(0).getMd5Checksum()); + String androidBuildVersion = daReq.getAndroidBuildVersion(); + if (androidBuildVersion == null || parseBuildVersion( + androidBuildVersion) < MINIMUM_SUPPORTED_ANDROID_VERSION) { + DeviceApplication devApp = devAppDao + .listAppVersionForUnsupportedDevices(daReq.getDeviceType(), + daReq.getAppCode()); + if (devApp != null) { + resp.setVersion(devApp.getVersion()); + resp.setFileName(devApp.getFileName()); + resp.setMd5Checksum(devApp.getMd5Checksum()); + } + } else { + List devAppList = devAppDao + .listByDeviceTypeAndAppCode(daReq.getDeviceType(), + daReq.getAppCode(), 1); + if (devAppList != null && devAppList.size() > 0) { + DeviceApplication deviceApplication = devAppList.get(0); + resp.setVersion(deviceApplication.getVersion()); + resp.setFileName(deviceApplication.getFileName()); + resp.setMd5Checksum(deviceApplication.getMd5Checksum()); + } } } return resp; } + private int parseBuildVersion(String androidBuildVersion) { + try { + return Integer.parseInt(androidBuildVersion); + } catch (NumberFormatException e) { + return 0; + } + } + @Override protected void writeOkResponse(RestResponse resp) throws Exception { getResponse().setStatus(200); diff --git a/GAE/src/org/waterforpeople/mapping/app/web/dto/DeviceApplicationRestRequest.java b/GAE/src/org/waterforpeople/mapping/app/web/dto/DeviceApplicationRestRequest.java index 5bed3ec2b6..5215c4526c 100644 --- a/GAE/src/org/waterforpeople/mapping/app/web/dto/DeviceApplicationRestRequest.java +++ b/GAE/src/org/waterforpeople/mapping/app/web/dto/DeviceApplicationRestRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Stichting Akvo (Akvo Foundation) + * Copyright (C) 2010-2012,2018 Stichting Akvo (Akvo Foundation) * * This file is part of Akvo FLOW. * @@ -16,11 +16,12 @@ package org.waterforpeople.mapping.app.web.dto; -import javax.servlet.http.HttpServletRequest; - import com.gallatinsystems.framework.rest.RestError; import com.gallatinsystems.framework.rest.RestRequest; +import javax.annotation.Nullable; +import javax.servlet.http.HttpServletRequest; + /** * encapsulates request to the devapp service * @@ -31,16 +32,21 @@ public class DeviceApplicationRestRequest extends RestRequest { private static final long serialVersionUID = -158448412036367889L; public static final String GET_LATEST_VERSION_ACTION = "getLatestVersion"; - public static final String DEV_TYPE_PARAM = "deviceType"; - public static final String APP_CODE_PARAM = "appCode"; + private static final String DEV_TYPE_PARAM = "deviceType"; + private static final String APP_CODE_PARAM = "appCode"; + private static final String ANDROID_BUILD_VERSION_PARAM = "androidBuildVersion"; private String deviceType; private String appCode; + @Nullable + private String androidBuildVersion; + @Override protected void populateFields(HttpServletRequest req) throws Exception { deviceType = req.getParameter(DEV_TYPE_PARAM); appCode = req.getParameter(APP_CODE_PARAM); + androidBuildVersion = req.getParameter(ANDROID_BUILD_VERSION_PARAM); } @Override @@ -73,4 +79,12 @@ public void setAppCode(String appCode) { this.appCode = appCode; } + @Nullable + public String getAndroidBuildVersion() { + return androidBuildVersion; + } + + public void setAndroidBuildVersion(@Nullable String androidBuildVersion) { + this.androidBuildVersion = androidBuildVersion; + } } diff --git a/GAE/src/org/waterforpeople/mapping/dao/DeviceApplicationDao.java b/GAE/src/org/waterforpeople/mapping/dao/DeviceApplicationDao.java index a5c6fa7cf0..574f98129e 100644 --- a/GAE/src/org/waterforpeople/mapping/dao/DeviceApplicationDao.java +++ b/GAE/src/org/waterforpeople/mapping/dao/DeviceApplicationDao.java @@ -1,19 +1,33 @@ - +/* + * Copyright (C) 2018 Stichting Akvo (Akvo Foundation) + * + * This file is part of Akvo FLOW. + * + * Akvo FLOW is free software: you can redistribute it and modify it under the terms of + * the GNU Affero General Public License (AGPL) as published by the Free Software Foundation, + * either version 3 of the License or any later version. + * + * Akvo FLOW is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Affero General Public License included below for more details. + * + * The full license text can also be seen at . + */ package org.waterforpeople.mapping.dao; +import com.gallatinsystems.framework.dao.BaseDAO; +import com.gallatinsystems.framework.servlet.PersistenceFilter; +import org.waterforpeople.mapping.domain.DeviceApplication; + +import javax.jdo.PersistenceManager; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.jdo.PersistenceManager; - -import org.waterforpeople.mapping.domain.DeviceApplication; - -import com.gallatinsystems.framework.dao.BaseDAO; -import com.gallatinsystems.framework.servlet.PersistenceFilter; - public class DeviceApplicationDao extends BaseDAO { + private static final String LATEST_SUPPORTED_VERSION = "2.4.8"; + public DeviceApplicationDao() { super(DeviceApplication.class); } @@ -23,11 +37,11 @@ public List listByDeviceTypeAndAppCode( String deviceType, String appCode, int maxResults) { PersistenceManager pm = PersistenceFilter.getManager(); javax.jdo.Query query = pm.newQuery(DeviceApplication.class); - Map paramMap = null; + Map paramMap; StringBuilder filterString = new StringBuilder(); StringBuilder paramString = new StringBuilder(); - paramMap = new HashMap(); + paramMap = new HashMap<>(); appendNonNullParam("deviceType", filterString, paramString, "String", deviceType, paramMap); @@ -40,4 +54,32 @@ public List listByDeviceTypeAndAppCode( return (List) query.executeWithMap(paramMap); } + @SuppressWarnings("unchecked") + public DeviceApplication listAppVersionForUnsupportedDevices(String deviceType, + String appCode) { + PersistenceManager pm = PersistenceFilter.getManager(); + javax.jdo.Query query = pm.newQuery(DeviceApplication.class); + Map paramMap; + + StringBuilder filterString = new StringBuilder(); + StringBuilder paramString = new StringBuilder(); + paramMap = new HashMap<>(); + appendNonNullParam("deviceType", filterString, paramString, "String", + deviceType, paramMap); + appendNonNullParam("appCode", filterString, paramString, "String", + appCode, paramMap); + appendNonNullParam("version", filterString, paramString, "String", + LATEST_SUPPORTED_VERSION, paramMap); + query.setFilter(filterString.toString()); + query.setOrdering("createdDateTime desc"); + query.declareParameters(paramString.toString()); + query.setRange(0, 1); + List deviceApplications = (List) query + .executeWithMap(paramMap); + + if (deviceApplications == null || deviceApplications.size() == 0) { + return null; + } + return deviceApplications.get(0); + } } diff --git a/GAE/src/org/waterforpeople/mapping/domain/DeviceApplication.java b/GAE/src/org/waterforpeople/mapping/domain/DeviceApplication.java index c0b1397f01..c45ea2bd91 100644 --- a/GAE/src/org/waterforpeople/mapping/domain/DeviceApplication.java +++ b/GAE/src/org/waterforpeople/mapping/domain/DeviceApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Stichting Akvo (Akvo Foundation) + * Copyright (C) 2010-2012,2018 Stichting Akvo (Akvo Foundation) * * This file is part of Akvo FLOW. * @@ -16,10 +16,10 @@ package org.waterforpeople.mapping.domain; -import javax.jdo.annotations.PersistenceCapable; - import com.gallatinsystems.framework.domain.BaseDomain; +import javax.jdo.annotations.PersistenceCapable; + @PersistenceCapable public class DeviceApplication extends BaseDomain { diff --git a/GAE/war/WEB-INF/dev-logging.properties b/GAE/war/WEB-INF/dev-logging.properties new file mode 100644 index 0000000000..05fe979540 --- /dev/null +++ b/GAE/war/WEB-INF/dev-logging.properties @@ -0,0 +1,36 @@ +# A default java.util.logging configuration. +# (All App Engine logging is through java.util.logging by default). +# +# To use this configuration, copy it into your application's WEB-INF +# folder and add the following to your appengine-web.xml: +# +# +# +# +# + +# Set the default logging level for all loggers to WARNING +.level = DEBUG + +handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler + +java.util.logging.FileHandler.pattern = flow%u.log +java.util.logging.FileHandler.limit = 500000 +java.util.logging.FileHandler.count = 1 +java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter +java.util.logging.SimpleFormatter.format = [%1$tc] %4$s: %2$s - %5$s %6$s%n + +# Set the default logging level for ORM, specifically, to WARNING +DataNucleus.JDO.level=WARNING +DataNucleus.Persistence.level=WARNING +DataNucleus.Cache.level=WARNING +DataNucleus.MetaData.level=WARNING +DataNucleus.General.level=WARNING +DataNucleus.Utility.level=WARNING +DataNucleus.Transaction.level=WARNING +DataNucleus.Datastore.level=WARNING +DataNucleus.ClassLoading.level=WARNING +DataNucleus.Plugin.level=WARNING +DataNucleus.ValueGeneration.level=WARNING +DataNucleus.Enhancer.level=WARNING +DataNucleus.SchemaTool.level=WARNING diff --git a/GAE/war/WEB-INF/lib/activation.jar b/GAE/war/WEB-INF/lib/activation.jar deleted file mode 100644 index e31e71c188..0000000000 Binary files a/GAE/war/WEB-INF/lib/activation.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/aopalliance-1.0.jar b/GAE/war/WEB-INF/lib/aopalliance-1.0.jar deleted file mode 100644 index 578b1a0c35..0000000000 Binary files a/GAE/war/WEB-INF/lib/aopalliance-1.0.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/commons-beanutils-1.8.3.jar b/GAE/war/WEB-INF/lib/commons-beanutils-1.8.3.jar deleted file mode 100644 index 218510bc5d..0000000000 Binary files a/GAE/war/WEB-INF/lib/commons-beanutils-1.8.3.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/commons-codec-1.4.jar b/GAE/war/WEB-INF/lib/commons-codec-1.4.jar deleted file mode 100644 index 458d432da8..0000000000 Binary files a/GAE/war/WEB-INF/lib/commons-codec-1.4.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/commons-fileupload-1.2.1.jar b/GAE/war/WEB-INF/lib/commons-fileupload-1.2.1.jar deleted file mode 100644 index aa209b3887..0000000000 Binary files a/GAE/war/WEB-INF/lib/commons-fileupload-1.2.1.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/commons-io-2.4.jar b/GAE/war/WEB-INF/lib/commons-io-2.4.jar deleted file mode 100644 index 90035a4fe0..0000000000 Binary files a/GAE/war/WEB-INF/lib/commons-io-2.4.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/commons-logging-1.1-1.jar b/GAE/war/WEB-INF/lib/commons-logging-1.1-1.jar deleted file mode 100644 index 8758a96b70..0000000000 Binary files a/GAE/war/WEB-INF/lib/commons-logging-1.1-1.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/commons-logging-1.1.1.jar b/GAE/war/WEB-INF/lib/commons-logging-1.1.1.jar deleted file mode 100644 index 1deef144cb..0000000000 Binary files a/GAE/war/WEB-INF/lib/commons-logging-1.1.1.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/gdata-client-1.0.jar b/GAE/war/WEB-INF/lib/gdata-client-1.0.jar deleted file mode 100644 index d9d4bebea1..0000000000 Binary files a/GAE/war/WEB-INF/lib/gdata-client-1.0.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/gdata-core-1.0.jar b/GAE/war/WEB-INF/lib/gdata-core-1.0.jar deleted file mode 100644 index de6a112295..0000000000 Binary files a/GAE/war/WEB-INF/lib/gdata-core-1.0.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/gdata-spreadsheet-3.0.jar b/GAE/war/WEB-INF/lib/gdata-spreadsheet-3.0.jar deleted file mode 100644 index 31f2a303f4..0000000000 Binary files a/GAE/war/WEB-INF/lib/gdata-spreadsheet-3.0.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/geoapi-2.3-M1.jar b/GAE/war/WEB-INF/lib/geoapi-2.3-M1.jar deleted file mode 100644 index d0b32270d2..0000000000 Binary files a/GAE/war/WEB-INF/lib/geoapi-2.3-M1.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/geoapi-pending-2.3-M1.jar b/GAE/war/WEB-INF/lib/geoapi-pending-2.3-M1.jar deleted file mode 100644 index 54b7ca1e6d..0000000000 Binary files a/GAE/war/WEB-INF/lib/geoapi-pending-2.3-M1.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/geocell-0.0.3-SNAPSHOT.jar b/GAE/war/WEB-INF/lib/geocell-0.0.3-SNAPSHOT.jar deleted file mode 100644 index ffd6a1d474..0000000000 Binary files a/GAE/war/WEB-INF/lib/geocell-0.0.3-SNAPSHOT.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/jackson-core-asl-1.8.5.jar b/GAE/war/WEB-INF/lib/jackson-core-asl-1.8.5.jar deleted file mode 100644 index a2df7fe8d1..0000000000 Binary files a/GAE/war/WEB-INF/lib/jackson-core-asl-1.8.5.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/jackson-mapper-asl-1.8.5.jar b/GAE/war/WEB-INF/lib/jackson-mapper-asl-1.8.5.jar deleted file mode 100644 index 61e2393598..0000000000 Binary files a/GAE/war/WEB-INF/lib/jackson-mapper-asl-1.8.5.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/javax.inject-1.jar b/GAE/war/WEB-INF/lib/javax.inject-1.jar deleted file mode 100644 index b2a9d0bf7b..0000000000 Binary files a/GAE/war/WEB-INF/lib/javax.inject-1.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/jdom.jar b/GAE/war/WEB-INF/lib/jdom.jar deleted file mode 100644 index 7ccb9fda84..0000000000 Binary files a/GAE/war/WEB-INF/lib/jdom.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/json.jar b/GAE/war/WEB-INF/lib/json.jar deleted file mode 100644 index 1e4ae77ecd..0000000000 Binary files a/GAE/war/WEB-INF/lib/json.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/jsr305.jar b/GAE/war/WEB-INF/lib/jsr305.jar deleted file mode 100644 index cf5f561678..0000000000 Binary files a/GAE/war/WEB-INF/lib/jsr305.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/jts-1.11-serializable-indexes.jar b/GAE/war/WEB-INF/lib/jts-1.11-serializable-indexes.jar deleted file mode 100644 index 012b77bb47..0000000000 Binary files a/GAE/war/WEB-INF/lib/jts-1.11-serializable-indexes.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/jtsio-1.8.jar b/GAE/war/WEB-INF/lib/jtsio-1.8.jar deleted file mode 100644 index 70d6c71469..0000000000 Binary files a/GAE/war/WEB-INF/lib/jtsio-1.8.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/log4j-1.2.16.jar b/GAE/war/WEB-INF/lib/log4j-1.2.16.jar deleted file mode 100644 index 3f9d847618..0000000000 Binary files a/GAE/war/WEB-INF/lib/log4j-1.2.16.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/s3-shell-1.0.5.jar b/GAE/war/WEB-INF/lib/s3-shell-1.0.5.jar deleted file mode 100644 index 06715deb18..0000000000 Binary files a/GAE/war/WEB-INF/lib/s3-shell-1.0.5.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/spring-aop-3.1.0.RELEASE.jar b/GAE/war/WEB-INF/lib/spring-aop-3.1.0.RELEASE.jar deleted file mode 100644 index 89122c6193..0000000000 Binary files a/GAE/war/WEB-INF/lib/spring-aop-3.1.0.RELEASE.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/spring-asm-3.1.0.RELEASE.jar b/GAE/war/WEB-INF/lib/spring-asm-3.1.0.RELEASE.jar deleted file mode 100644 index 63780c76fe..0000000000 Binary files a/GAE/war/WEB-INF/lib/spring-asm-3.1.0.RELEASE.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/spring-beans-3.1.0.RELEASE.jar b/GAE/war/WEB-INF/lib/spring-beans-3.1.0.RELEASE.jar deleted file mode 100644 index 70843919c0..0000000000 Binary files a/GAE/war/WEB-INF/lib/spring-beans-3.1.0.RELEASE.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/spring-context-3.1.0.RELEASE.jar b/GAE/war/WEB-INF/lib/spring-context-3.1.0.RELEASE.jar deleted file mode 100644 index e84b39e3b6..0000000000 Binary files a/GAE/war/WEB-INF/lib/spring-context-3.1.0.RELEASE.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/spring-context-support-3.1.0.RELEASE.jar b/GAE/war/WEB-INF/lib/spring-context-support-3.1.0.RELEASE.jar deleted file mode 100644 index b332c85feb..0000000000 Binary files a/GAE/war/WEB-INF/lib/spring-context-support-3.1.0.RELEASE.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/spring-core-3.1.0.RELEASE.jar b/GAE/war/WEB-INF/lib/spring-core-3.1.0.RELEASE.jar deleted file mode 100644 index 7c2bced19a..0000000000 Binary files a/GAE/war/WEB-INF/lib/spring-core-3.1.0.RELEASE.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/spring-expression-3.1.0.RELEASE.jar b/GAE/war/WEB-INF/lib/spring-expression-3.1.0.RELEASE.jar deleted file mode 100644 index 64388b3658..0000000000 Binary files a/GAE/war/WEB-INF/lib/spring-expression-3.1.0.RELEASE.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/spring-security-config-3.1.3.RELEASE.jar b/GAE/war/WEB-INF/lib/spring-security-config-3.1.3.RELEASE.jar deleted file mode 100644 index 37f66bc2bd..0000000000 Binary files a/GAE/war/WEB-INF/lib/spring-security-config-3.1.3.RELEASE.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/spring-security-core-3.1.3.RELEASE.jar b/GAE/war/WEB-INF/lib/spring-security-core-3.1.3.RELEASE.jar deleted file mode 100644 index 81e3566811..0000000000 Binary files a/GAE/war/WEB-INF/lib/spring-security-core-3.1.3.RELEASE.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/spring-security-web-3.1.3.RELEASE.jar b/GAE/war/WEB-INF/lib/spring-security-web-3.1.3.RELEASE.jar deleted file mode 100644 index 0c3c431fe4..0000000000 Binary files a/GAE/war/WEB-INF/lib/spring-security-web-3.1.3.RELEASE.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/spring-web-3.1.0.RELEASE.jar b/GAE/war/WEB-INF/lib/spring-web-3.1.0.RELEASE.jar deleted file mode 100644 index bb6c8ab597..0000000000 Binary files a/GAE/war/WEB-INF/lib/spring-web-3.1.0.RELEASE.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/spring-webmvc-3.1.0.RELEASE.jar b/GAE/war/WEB-INF/lib/spring-webmvc-3.1.0.RELEASE.jar deleted file mode 100644 index 7f6f153b3f..0000000000 Binary files a/GAE/war/WEB-INF/lib/spring-webmvc-3.1.0.RELEASE.jar and /dev/null differ diff --git a/GAE/war/WEB-INF/lib/velocity-1.6.2-dep.jar b/GAE/war/WEB-INF/lib/velocity-1.6.2-dep.jar deleted file mode 100644 index 184f13312f..0000000000 Binary files a/GAE/war/WEB-INF/lib/velocity-1.6.2-dep.jar and /dev/null differ diff --git a/README.md b/README.md index 41fd12f1fc..800bd20363 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,86 @@ You can read more about the [motivation and history of Akvo Flow](http://www.akvo.org/blog/?p=4836) as well as its place in [the platform of tools created by Akvo](http://www.akvo.org/blog/?p=4822). +## Development + +### Start + +To run Flow: + + docker-compose up --build -d && docker-compose logs -f + +Flow should be running [here](http://localhost:8888) and you can login with user "akvo.flow.user.test@gmail.com" + +You also have the appengine admin console [here](http://localhost:8888/_ah/admin) + +The Docker-Compose environment will have: + +1. A fake s3 server. +2. A fake flow services, that always returns 200. +3. The dev environment. + +It downloads a prepopulated database from https://s3-eu-west-1.amazonaws.com/akvoflow/test-data/local_db.bin *if* there is none. + +It will use the [dev appengine-web.xml](tests/dev-appengine-web.xml) *if* there is none. + +See the [devserver.sh](ci/devserver.sh) for more details. + +### UI development + +Once Flow is started, any changes in the Dashboard folder will trigger a build of the UI code, except for the ClojureScript bit. + +If you are going to work on the ClojureScript side, you can run a watch process with: + + docker-compose exec akvo-flow /bin/bash -c "cd Dashboard/app/cljs && lein watch" + +Or run the commands from a terminal inside the container: + + docker-compose exec akvo-flow /bin/bash + cd Dashboard/app/cljs + lein watch + +### Backend development + +The appengine dev server is started in debug mode, listening in port 5005. + +It is expected that your IDE understand the Maven pom and that it compiles the Java classes to the right place. + +After you IDE compiles the classes, the dev server should refresh the webcontext. Due to some Mac performance issues with Docker, the refresh interval is 20 secs instead of the default 5 secs. You can change the scan interval in GAE/pom.xml. You can also trigger a reload hitting [the reload url](http://localhost:8888/_ah/reloadwebapp). + +If you need to restart the server: + + docker-compose exec akvo-flow /bin/bash -c "cd GAE && mvn appengine:devserver_stop appengine:devserver_start" + +If you also need to recompile the code, add a package target: + + docker-compose exec akvo-flow /bin/bash -c "cd GAE && mvn appengine:devserver_stop package appengine:devserver_start" + +Remember that you also can run those commands from a terminal inside the container. + +### Stop + + docker-compose stop + +### Tear down and reset + + docker-compose down + rm -rf GAE/target + +### Test instances and Manual deployments + +If you want to use a configuration different from the dev one, checkout the akvo-flow-server-config directory into `..` and run: + + switch_tenant.sh akvoflowsandbox + +To switch back to the dev setup: + + swith_to_local_tenant.sh + +To deploy the current state of the docker container to whatever tenant you last switched to, run: + + docker-compose exec akvo-flow /bin/bash -c "cd GAE && mvn appengine:update appengine:backends_update" + +---

       

      diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 72e906127a..3b1dca032d 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,14 @@ # Akvo Flow Release Notes ---- +# Akvo Flow Dashboard v1.9.32 - Internal release +Date: 15th May 2018 +## New and noteworthy +* **Development environment** - Further improvements to our development workflow including, the user of docker containers to homogenise and ease setup of dev environment [#2406][#2553][#2624][#2633], speeding up parallel deployments of our instances [#2562] + +* **UI Improvment** - Implement a walkthrough for the bulk upload page explaining how the new GDPR compliant bulk upload will function [#2466]. + +* **App downloads** - Prevent devices containing old android versions (< Android 4.0.3) from downloading recent app versions [#2603]. + # Akvo Flow Dashboard v1.9.31 - Epic Elm Date: 19 April 2018 diff --git a/ci/build.sh b/ci/build.sh index 716aab976c..94258feb62 100755 --- a/ci/build.sh +++ b/ci/build.sh @@ -40,4 +40,4 @@ cp -f build.properties.template build.properties sed -i "s|^sdk\\.dir=.*|sdk\\.dir=${HOME}/.cache/appengine-java-sdk-${APP_ENGINE_SDK_VERSION}|" build.properties -mvn -P ci package +mvn package diff --git a/ci/deploy.sh b/ci/deploy.sh index 515cf64c3b..14bfd037da 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -49,7 +49,9 @@ curl -s -o GAE/target/akvo-flow/WEB-INF/appengine-web.xml \ log Update __VERSION__ version=$(git describe) + sed -i "s/__VERSION__/${version}/" GAE/target/akvo-flow/admin/js/app.js +gsutil cp GAE/target/akvo-flow.war "gs://akvoflowsandbox-deployment/${version}.war" log Updating default service version 1 diff --git a/ci/devserver.sh b/ci/devserver.sh new file mode 100755 index 0000000000..318dcbc904 --- /dev/null +++ b/ci/devserver.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +# +# Copyright (C) 2017 Stichting Akvo (Akvo Foundation) +# +# This file is part of Akvo FLOW. +# +# Akvo FLOW is free software: you can redistribute it and modify it under the terms of +# the GNU Affero General Public License (AGPL) as published by the Free Software Foundation, +# either version 3 of the License or any later version. +# +# Akvo FLOW is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License included below for more details. +# +# The full license text can also be seen at . +# + +set -eu + +SRC_DIR="/app/src" + +cd "$SRC_DIR/Dashboard" + +bundle exec rake watchbg > "$SRC_DIR/rake.log" 2>&1 & + +if [[ ! -f "$SRC_DIR/GAE/target/akvo-flow/admin/frames/users.js" ]]; then + cd "$SRC_DIR/Dashboard/app/cljs" + lein build +else + echo "Skipping ClojureScript build ..." +fi + +cd "$SRC_DIR/GAE" + +if [[ ! -f "$SRC_DIR/GAE/target/akvo-flow/WEB-INF/appengine-generated/local_db.bin" ]]; then + mkdir -p "$SRC_DIR/GAE/target/akvo-flow/WEB-INF/appengine-generated/" + wget "https://s3-eu-west-1.amazonaws.com/akvoflow/test-data/local_db.bin" -O "$SRC_DIR/GAE/target/akvo-flow/WEB-INF/appengine-generated/local_db.bin" +fi + +if [[ ! -f "$SRC_DIR/GAE/target/akvo-flow/WEB-INF/appengine-web.xml" ]]; then + mkdir -p "$SRC_DIR/GAE/target/akvo-flow/WEB-INF/" + cp "$SRC_DIR/tests/dev-appengine-web.xml" "$SRC_DIR/GAE/target/akvo-flow/WEB-INF/appengine-web.xml" +fi + +mvn package appengine:devserver_start + +tail -F ./target/akvo-flow/flow0.log "$SRC_DIR/rake.log" \ No newline at end of file diff --git a/ci/setup-dev-user-in-container.sh b/ci/setup-dev-user-in-container.sh new file mode 100755 index 0000000000..53e46d210b --- /dev/null +++ b/ci/setup-dev-user-in-container.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License") +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set -ue + +HOST_UID=$(stat -c "%u" docker-compose.yml) +HOST_GID=$(stat -c "%g" docker-compose.yml) + +HOST_USER=akvo + +GROUP_EXISTS=$(id -g ${HOST_GID} || echo "") + +if [ -z ${GROUP_EXISTS} ]; then + echo "Creating group $HOST_UID in container" + groupadd --gid "$HOST_GID" "$HOST_USER" +else + echo "Group $HOST_UID already exists" +fi + +USER_EXISTS=$(id -u ${HOST_UID} || echo "") + +if [ -z ${USER_EXISTS} ]; then + echo "Creating user 'akvo' with uid $HOST_UID in container" + + useradd "$HOST_USER" --home "/home/$HOST_USER" --gid "$HOST_GID" --uid "$HOST_UID" --shell /bin/bash + echo "$HOST_USER:pw" | chpasswd + + cp -r /root/.lein "/home/$HOST_USER/" + + chown -R "$HOST_USER":"$HOST_USER" "/home/$HOST_USER" +else + echo "Not creating any user in container" +fi + + +if [ ${HOST_UID} -eq "0" ]; then + echo "Guessing you are in a Mac, running as root" + $@ +else + echo "Guessing you are in Linux, running as akvo" + su "$HOST_USER" -c "$@" +fi diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..c477572d05 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +version: "3" +services: + fake-flow-services: + image: solsson/http-echo + s3: + image: technekes/fake-s3-ssl:latest + akvo-flow: + build: . + entrypoint: /app/src/ci/setup-dev-user-in-container.sh + command: /app/src/ci/devserver.sh + working_dir: /app/src + links: + - s3:akvoflowsandbox.s3.amazonaws.com + ports: + - 8888:8888 + - 5005:5005 + volumes: + - .:/app/src/:delegated + - ~/.m2:/root/.m2:delegated + - ~/.m2:/home/akvo/.m2:delegated + diff --git a/scripts/deploy/deploy.sh b/scripts/deploy/deploy.sh new file mode 100755 index 0000000000..ba80587f9c --- /dev/null +++ b/scripts/deploy/deploy.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash + +set -euo pipefail + +export SHELL=/bin/bash + +yellow='\033[1;33m' +green='\033[0;32m' +nc='\033[0m' + +if [[ "$#" -lt 2 ]]; then + echo "Usage: ./scripts/deploy/run.sh ... " + exit 1 +fi + +export version="${1}" # as "$1" +shift # we want "$@" to be the instances to deploy + +export config_repo="${CONFIG_REPO:=/akvo-flow-server-config}" +export deploy_bucket_name="${deploy_bucket_name:=akvoflowsandbox-deployment}" +export api_root="https://appengine.googleapis.com/v1" + +deploy_id="$(date +%s)" +tmp="/tmp/${deploy_id}" +target_dir="${tmp}/akvo-flow" +gh_user="${GH_USER:=unknown}" +gh_token="${GH_TOKEN:=unknown}" + +# Install requirements assuming Debian jessie +echo "Installing dependencies..." +echo "deb http://ftp.debian.org/debian jessie-backports main" >> /etc/apt/sources.list && \ + apt-get update && \ + apt-get -t jessie-backports install -y -qq --no-install-recommends \ + jq=1.5+dfsg-1.3~bpo8+1 \ + unzip=6.0-16+deb8u3 \ + parallel=20130922-1 + +# Force login +gcloud auth login --brief --activate --force + +akvo_org_account=$( (gcloud auth list --filter="active" 2>&1 | grep -E '^\*.*akvo\.org$') || echo "") + +if [[ -z "${akvo_org_account}" ]]; then + echo >&2 "Unable to detect an akvo.org account for gcloud" + exit 1 +fi + +echo "Cloning akvo-flow-server-config..." + +if [[ "${gh_user}" != "unknown" ]] && [[ "${gh_token}" != "unknown" ]]; then + git clone --depth=50 --branch=master \ + "https://${gh_user}:${gh_token}@github.com/akvo/akvo-flow-server-config.git" "${config_repo}" > /dev/null +else + echo -e "${yellow}WARNING:${nc} If you have 2FA enabled in GitHub, make sure you have a + ${green}personal access token${nc} available and use it as password" + echo "Visit for more info: https://blog.github.com/2013-09-03-two-factor-authentication/#how-does-it-work-for-command-line-git" + git clone --depth=50 --branch=master \ + "https://github.com/akvo/akvo-flow-server-config.git" "${config_repo}" > /dev/null +fi + +echo "Deploying to akvoflowsandbox using gcloud..." +mkdir -p "${tmp}" +gsutil cp "gs://${deploy_bucket_name}/${version}.war" "${tmp}" +unzip "${tmp}/${version}.war" -d "${target_dir}" +rm -rf "${tmp}/${version}.war" +cp -v "${config_repo}/akvoflowsandbox/appengine-web.xml" "${target_dir}/WEB-INF/" +sed -i -e "s/__VERSION__/${version}/" "${target_dir}/admin/js/app.js" + +gcloud app deploy "${target_dir}/WEB-INF/appengine-web.xml" \ + --project=akvoflowsandbox \ + --bucket="gs://${deploy_bucket_name}" \ + --version=1 \ + --promote + +gcloud app deploy "${target_dir}/WEB-INF/appengine-web.xml" \ + --project=akvoflowsandbox \ + --bucket="gs://${deploy_bucket_name}" \ + --version=dataprocessor \ + --no-promote + +echo "Retrieving version definitions..." + +access_token=$(gcloud auth print-access-token) +export access_token + +curl -s -H "Authorization: Bearer ${access_token}" \ + "${api_root}/apps/akvoflowsandbox/services/default/versions/1?view=FULL" \ + > "${tmp}/1.json" + +find "${config_repo}" -name 'appengine-web.xml' -exec sha1sum {} + > "${tmp}/sha1sum.txt" + +echo "Deploying instances..." + +# Move to tmp folder and work there +cd "${tmp}" + +function deploy_instance { + instance_id="${1}" + instance_file="${instance_id}.json" + backend_file="${instance_id}_dataprocessor.json" + + # select required keys + jq -M ". | {id, inboundServices, instanceClass, runtime, env, threadsafe, handlers, deployment}" \ + 1.json > "${instance_file}.tmp" + + # remove __static__ entries + jq '.deployment.files |= with_entries(select (.key | test("^__static__") | not))' "${instance_file}.tmp" \ + > "${instance_file}" + rm -rf "${instance_file}.tmp" + + sed -i "s|apps/akvoflowsandbox/|apps/${instance_id}/|g" "${instance_file}" + + sandbox_sha1_sum=$(awk '$2 ~ "/akvoflowsandbox/appengine-web.xml$" {print $1}' sha1sum.txt) + instance_sha1_sum=$(awk -v instance="${instance_id}" '$2 ~ "/"instance"/appengine-web.xml$" {print $1}' sha1sum.txt) + + sed -i "s|${sandbox_sha1_sum}|${instance_sha1_sum}|g" "${instance_file}" + + jq ". + {id: \"dataprocessor\", manualScaling: {instances: 1}, instanceClass: \"B2\"}" "${instance_file}" > "${backend_file}" + + gsutil cp -J "${config_repo}/${instance_id}/appengine-web.xml" "gs://${deploy_bucket_name}/${instance_sha1_sum}" + + echo "Deploying ${instance_id} using GAE Admin API..." + + curl -s -X POST -T "${instance_file}" -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${access_token}" \ + "${api_root}/apps/${instance_id}/services/default/versions" > \ + "${instance_id}_operation.json" + + instance_operation_path=$(jq -r .name "${instance_id}_operation.json") + + if [ "${instance_operation_path}" == "null" ]; then + echo "Deployment to ${instance_id} failed" + exit 1 + fi + + curl -s -X POST -T "${backend_file}" -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${access_token}" \ + "${api_root}/apps/${instance_id}/services/default/versions" > \ + "${instance_id}_dataprocessor_operation.json" + + if [[ "$(jq -r .name "${instance_id}_dataprocessor_operation.json")" == "null" ]]; then + echo "Deployment to dataprocessor of ${instance_id} failed" + exit 1 + fi + + # We only check for liveness of version 1 + for i in {1..20} + do + sleep 5 + echo "Checking deployment status - Attempt ${i}" + done=$( (curl -s \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${access_token}" \ + "${api_root}/${instance_operation_path}" | jq -r .done) || "") + if [[ "${done}" == "true" ]]; then + break + fi + done + + if [[ "${done}" != "true" ]]; then + echo "Deployment to ${instance_id} failed" + exit 1 + fi +} + +export -f deploy_instance +parallel -j 8 --joblog "${deploy_id}.log" deploy_instance ::: "$@" +echo "Done" diff --git a/scripts/deploy/run.sh b/scripts/deploy/run.sh new file mode 100755 index 0000000000..5842615410 --- /dev/null +++ b/scripts/deploy/run.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -euo pipefail + +CLOUD_SDK_VERSION="${CLOUD_SDK_VERSION:=196.0.0}" + +if [[ ! -d "tmp" ]]; then + mkdir "tmp" +fi + +docker run --rm \ + --interactive \ + --tty \ + --volume "$(pwd):/akvo-flow:delegated" \ + --volume "$(pwd)/tmp:/tmp:delegated" \ + --workdir "/akvo-flow" \ + --env GH_USER \ + --env GH_TOKEN \ + "google/cloud-sdk:${CLOUD_SDK_VERSION}" \ + "/akvo-flow/scripts/deploy/deploy.sh" "$@" diff --git a/switch_tenant.sh b/switch_tenant.sh new file mode 100755 index 0000000000..fad017de5c --- /dev/null +++ b/switch_tenant.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +set -e + +APP_ID=$1 +FLOW_CONFIG_DIR=../akvo-flow-server-config + +if [ ! -d "${FLOW_CONFIG_DIR}" ]; then + echo "Flow config repository not found at ${FLOW_CONFIG_DIR}" + exit 1 +fi + +if [ -z "$APP_ID" ]; then + echo "First param must be the tenant folder (for example akvoflow-uat2 or akvoflowsandbox)" + exit 2 +fi + +TARGET_DIR=GAE/target/akvo-flow/WEB-INF/ + +mkdir -p "${TARGET_DIR}" + +cp "$FLOW_CONFIG_DIR/${APP_ID}/appengine-web.xml" "${TARGET_DIR}" \ No newline at end of file diff --git a/switch_to_local_tenant.sh b/switch_to_local_tenant.sh new file mode 100755 index 0000000000..f8de3d3692 --- /dev/null +++ b/switch_to_local_tenant.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -eu + +TARGET_DIR=GAE/target/akvo-flow/WEB-INF/ + +mkdir -p "${TARGET_DIR}" + +cp "tests/dev-appengine-web.xml" "${TARGET_DIR}/appengine-web.xml" \ No newline at end of file diff --git a/tests/dev-appengine-web.xml b/tests/dev-appengine-web.xml new file mode 100644 index 0000000000..48ddba38f2 --- /dev/null +++ b/tests/dev-appengine-web.xml @@ -0,0 +1,61 @@ + + + akvoflowsandbox + 1 + true + true + legacy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file