├── .meteor ├── .gitignore ├── release ├── platforms ├── .id ├── .finished-upgraders └── packages ├── imports ├── api │ ├── nvcache │ │ ├── methods.js │ │ ├── server │ │ │ └── publications.js │ │ └── nvcache.js │ ├── roles │ │ └── server │ │ │ └── publications.js │ ├── reports │ │ ├── server │ │ │ └── publications.js │ │ ├── reports.js │ │ └── methods.js │ ├── timer │ │ ├── server │ │ │ └── publications.js │ │ └── timer.js │ ├── restrictedRoutes │ │ ├── server │ │ │ ├── publications.js │ │ │ └── publications.js.orig │ │ ├── restrictedRoutes.js │ │ ├── restrictedRoutes.js.orig │ │ ├── methods.js │ │ └── methods.js.orig │ ├── user_segments │ │ ├── server │ │ │ └── publications.js │ │ ├── methods.js │ │ └── user_segments.js │ ├── user_notify │ │ ├── server │ │ │ └── publications.js │ │ └── user_notify.tests.js │ ├── qnaire │ │ ├── server │ │ │ ├── publications.js │ │ │ └── qnair.js │ │ └── methods.js │ ├── qnaire_data │ │ ├── server │ │ │ └── publications.js │ │ └── methods.js │ ├── queue │ │ └── server │ │ │ └── queue.js │ ├── user_feedback │ │ ├── methods.js │ │ ├── server │ │ │ └── publications.js │ │ ├── user_feedback.js │ │ └── user_feedback.tests.js │ ├── teams │ │ ├── methods.js │ │ └── server │ │ │ └── publications.js │ ├── grf │ │ └── methods.js │ ├── learn_share │ │ ├── server │ │ │ └── publications.js │ │ └── methods.js │ ├── help │ │ ├── helperPagesCached.js │ │ └── helperPages.js │ ├── users │ │ └── server │ │ │ └── publications.js │ ├── airtable │ │ └── at.js │ ├── tsq │ │ ├── TSQData.js │ │ └── server │ │ │ └── publications.js │ ├── parse_range │ │ └── parse_range.js │ └── type_readings │ │ └── methods.js ├── ui │ ├── stylesheets │ │ ├── ask_questions │ │ ├── qnaire.less │ │ ├── char_sheet.less │ │ ├── qnaire_results.less │ │ ├── team_icon.less │ │ ├── mbti_char_report.less │ │ ├── user_profile.less │ │ ├── opposites.less │ │ ├── behavior_pattern_area.less │ │ ├── add_questions.less │ │ ├── not-found.less │ │ ├── select_feedback.less │ │ ├── header.less │ │ ├── mbti_graph.less │ │ ├── user_dashboard.less │ │ ├── tsq.less │ │ └── admin_teams.less │ ├── layouts │ │ ├── body │ │ │ ├── body.js │ │ │ └── body.html │ │ └── login │ │ │ ├── login.js │ │ │ └── login.html │ ├── pages │ │ ├── view_team │ │ │ ├── view_team.js │ │ │ └── view_team.html │ │ ├── not-found │ │ │ ├── not-found.js │ │ │ └── not-found.html │ │ ├── home │ │ │ ├── home.js │ │ │ └── home.html │ │ ├── comment_report │ │ │ ├── comment_report.html │ │ │ └── comment_report.js │ │ ├── admin_reports │ │ │ ├── custom_report_triage │ │ │ │ ├── custom_report_triage.html │ │ │ │ └── custom_report_triage.js │ │ │ ├── team_member_tsq │ │ │ │ ├── team_member_tsq.html │ │ │ │ └── team_member_tsq.js │ │ │ └── report_default │ │ │ │ └── report_default.html │ │ ├── ask_questions │ │ │ ├── ask_questions.html │ │ │ └── ask_questions.js │ │ ├── verify │ │ │ ├── verify.html │ │ │ └── verify.js │ │ ├── qnaire_results │ │ │ └── qnaire_results.html │ │ ├── user_dashboard │ │ │ ├── user_dashboard.html │ │ │ └── user_dashboard.js │ │ ├── admin_tools │ │ │ ├── admin_tools.js │ │ │ └── admin_tools.html │ │ ├── mbti_roles │ │ │ └── mbti_roles.html │ │ ├── char_sheet │ │ │ └── char_sheet.html │ │ ├── tsq │ │ │ ├── widget │ │ │ │ └── widget.html │ │ │ └── results_summary │ │ │ │ └── results_summary.html │ │ ├── mvp │ │ │ ├── mvp.html │ │ │ └── server │ │ │ │ └── tmp_pp.js │ │ ├── mbti_results │ │ │ ├── mbti_results.js │ │ │ └── mbti_results.html │ │ ├── results_descriptions │ │ │ └── results_descriptions.html │ │ ├── qnaire │ │ │ └── slider.html │ │ ├── question_responses │ │ │ ├── question_responses.test.js │ │ │ └── question_responses.html │ │ ├── weak_questions │ │ │ └── weak_questions.html │ │ ├── results │ │ │ ├── results.html │ │ │ └── results.js │ │ ├── user_segments │ │ │ ├── user_segments.html │ │ │ └── user_segments.js │ │ ├── qnaire_list │ │ │ ├── qnaire_list.js │ │ │ └── qnaire_list.html │ │ ├── learn_share_list │ │ │ └── learn_share_list.html │ │ ├── dash_min │ │ │ └── dash_min.html │ │ └── team_dashboard │ │ │ └── team_dashboard.html │ ├── .DS_Store │ └── components │ │ ├── .DS_Store │ │ ├── loading │ │ └── loading.html │ │ ├── mbtiGraph │ │ ├── mbtiGraphRender.html │ │ ├── mbtiGraphCall.js │ │ ├── mbtiGraphRenderMulti.html │ │ └── mbtiGraphCallMulti.js │ │ ├── behavior_pattern_area │ │ ├── behavior_pattern_area_render.html │ │ └── behavior_pattern_area_call.js │ │ ├── team_icon │ │ └── team_icon.html │ │ ├── label_list │ │ ├── label_list.html │ │ └── label_list.js │ │ ├── begin │ │ ├── begin.js │ │ └── begin.html │ │ ├── select_autocomplete │ │ ├── select_autocomplete.html │ │ └── select_autocomplete.js │ │ ├── video_embed │ │ ├── video_embed.html │ │ └── video_embed.js │ │ ├── dl_footer │ │ ├── dl_footer.html │ │ └── dl_footer.js │ │ ├── timer │ │ ├── timer.html │ │ └── timer.js │ │ ├── notification_list │ │ └── notification_list.html │ │ └── select_feedback │ │ └── select_feedback.html ├── .DS_Store ├── client │ ├── insertProdAnalytics.js │ ├── insertDevAnalytics.js │ ├── clientSideDbs.js │ └── callWithPromise.js └── startup │ ├── both │ ├── index.js │ ├── defaults.js │ └── at_config.tests.js │ ├── client │ ├── index.js │ └── config.js │ └── server │ ├── defaults.js │ ├── register-api.js │ └── index.js ├── .DS_Store ├── public └── img │ ├── bell.png │ ├── panda.png │ ├── load-sm1.gif │ ├── loading.gif │ ├── mbtiBackground.png │ ├── congruent_pentagon.png │ ├── mbtiBackgroundTest.png │ ├── DeveloperLevel_icon_bg.png │ └── DevLevelLogoAndWordsWhite.5.25.png ├── .gitignore ├── Logo Pack ├── PNG │ ├── White.png │ ├── black.png │ ├── color.png │ ├── color-sm.png │ ├── redcirclesm.png │ ├── whiteandonly.png │ ├── color-whitebg.png │ ├── redcirclesm300x300.png │ ├── white-circle-and-in.png │ ├── blackandonwhitecircle.png │ └── blackandonwhitecirclesm.png └── NotP&A │ ├── word.png │ ├── hiring.PNG │ ├── slack.png │ ├── trello.jpg │ ├── We're Hiring.PNG │ ├── projectpadawan.PNG │ └── developerlevelslack.PNG ├── docker ├── vagrant │ ├── docker_ps.png │ ├── entrypoint.sh │ ├── docker-compose.yml │ ├── Dockerfile │ └── README.md ├── staging │ ├── entrypoint.sh │ ├── padawan-node-setup.sh │ ├── docker-compose.yml │ └── Dockerfile ├── production │ ├── entrypoint.sh │ ├── padawan-node-setup.sh │ ├── Dockerfile │ ├── docker-compose.yml │ └── nginx.conf └── dev │ ├── entrypoint.sh │ ├── docker-compose.yml │ ├── Dockerfile │ └── nginx.conf ├── vagrantDock.sh ├── padawan_workspace.code-workspace ├── client ├── main.js ├── head.html └── main.less ├── entrypoint.sh ├── server └── main.js ├── config └── settings.json ├── private ├── README.md └── html-email.html ├── .vagrant └── rgloader │ └── loader.rb ├── .vscode └── launch.json ├── dump └── onAnswered.js ├── utils ├── db_restore.sh └── db_backup.sh ├── settings.staging.json ├── settings.dev-docker.json ├── settings.local.json ├── settings.prod.json ├── Vagrantfile ├── nightwatch.json ├── package.json └── tests └── changePassword.test.js /.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@1.8.1 2 | -------------------------------------------------------------------------------- /imports/api/nvcache/methods.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/ask_questions: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.meteor/platforms: -------------------------------------------------------------------------------- 1 | server 2 | browser 3 | -------------------------------------------------------------------------------- /imports/api/nvcache/server/publications.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imports/ui/layouts/body/body.js: -------------------------------------------------------------------------------- 1 | import './body.html'; 2 | -------------------------------------------------------------------------------- /imports/ui/pages/view_team/view_team.js: -------------------------------------------------------------------------------- 1 | import './view_team.html'; -------------------------------------------------------------------------------- /imports/ui/pages/not-found/not-found.js: -------------------------------------------------------------------------------- 1 | import './not-found.html'; 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/.DS_Store -------------------------------------------------------------------------------- /imports/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/imports/.DS_Store -------------------------------------------------------------------------------- /imports/ui/pages/view_team/view_team.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imports/ui/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/imports/ui/.DS_Store -------------------------------------------------------------------------------- /public/img/bell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/public/img/bell.png -------------------------------------------------------------------------------- /public/img/panda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/public/img/panda.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *~ 3 | *# 4 | bin/ 5 | dump/ 6 | /reports/ 7 | .coverage 8 | .idea 9 | -------------------------------------------------------------------------------- /Logo Pack/PNG/White.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/PNG/White.png -------------------------------------------------------------------------------- /Logo Pack/PNG/black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/PNG/black.png -------------------------------------------------------------------------------- /Logo Pack/PNG/color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/PNG/color.png -------------------------------------------------------------------------------- /public/img/load-sm1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/public/img/load-sm1.gif -------------------------------------------------------------------------------- /public/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/public/img/loading.gif -------------------------------------------------------------------------------- /Logo Pack/NotP&A/word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/NotP&A/word.png -------------------------------------------------------------------------------- /Logo Pack/NotP&A/hiring.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/NotP&A/hiring.PNG -------------------------------------------------------------------------------- /Logo Pack/NotP&A/slack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/NotP&A/slack.png -------------------------------------------------------------------------------- /Logo Pack/NotP&A/trello.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/NotP&A/trello.jpg -------------------------------------------------------------------------------- /Logo Pack/PNG/color-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/PNG/color-sm.png -------------------------------------------------------------------------------- /docker/vagrant/docker_ps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/docker/vagrant/docker_ps.png -------------------------------------------------------------------------------- /Logo Pack/PNG/redcirclesm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/PNG/redcirclesm.png -------------------------------------------------------------------------------- /Logo Pack/PNG/whiteandonly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/PNG/whiteandonly.png -------------------------------------------------------------------------------- /public/img/mbtiBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/public/img/mbtiBackground.png -------------------------------------------------------------------------------- /vagrantDock.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -rf .meteor/local 3 | dos2unix * 4 | dos2unix docker/vagrant/* 5 | vagrant up 6 | -------------------------------------------------------------------------------- /Logo Pack/NotP&A/We're Hiring.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/NotP&A/We're Hiring.PNG -------------------------------------------------------------------------------- /Logo Pack/PNG/color-whitebg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/PNG/color-whitebg.png -------------------------------------------------------------------------------- /imports/ui/components/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/imports/ui/components/.DS_Store -------------------------------------------------------------------------------- /padawan_workspace.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": {} 8 | } -------------------------------------------------------------------------------- /public/img/congruent_pentagon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/public/img/congruent_pentagon.png -------------------------------------------------------------------------------- /public/img/mbtiBackgroundTest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/public/img/mbtiBackgroundTest.png -------------------------------------------------------------------------------- /Logo Pack/NotP&A/projectpadawan.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/NotP&A/projectpadawan.PNG -------------------------------------------------------------------------------- /Logo Pack/PNG/redcirclesm300x300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/PNG/redcirclesm300x300.png -------------------------------------------------------------------------------- /Logo Pack/PNG/white-circle-and-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/PNG/white-circle-and-in.png -------------------------------------------------------------------------------- /public/img/DeveloperLevel_icon_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/public/img/DeveloperLevel_icon_bg.png -------------------------------------------------------------------------------- /Logo Pack/NotP&A/developerlevelslack.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/NotP&A/developerlevelslack.PNG -------------------------------------------------------------------------------- /Logo Pack/PNG/blackandonwhitecircle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/PNG/blackandonwhitecircle.png -------------------------------------------------------------------------------- /Logo Pack/PNG/blackandonwhitecirclesm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/Logo Pack/PNG/blackandonwhitecirclesm.png -------------------------------------------------------------------------------- /client/main.js: -------------------------------------------------------------------------------- 1 | // Client entry point, imports all client code 2 | 3 | import '/imports/startup/both'; 4 | import '/imports/startup/client'; 5 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #/usr/local/bin/meteor update 3 | /usr/local/bin/meteor --allow-superuser --settings /app/settings.staging.json 4 | -------------------------------------------------------------------------------- /public/img/DevLevelLogoAndWordsWhite.5.25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paladinarcher/padawan/HEAD/public/img/DevLevelLogoAndWordsWhite.5.25.png -------------------------------------------------------------------------------- /server/main.js: -------------------------------------------------------------------------------- 1 | // Server entry point, imports all server code 2 | 3 | import '/imports/startup/both'; 4 | import '/imports/startup/server'; 5 | -------------------------------------------------------------------------------- /docker/staging/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export METEOR_SETTINGS="$(cat settings.staging.json)" 4 | echo $METEOR_SETTINGS 5 | forever main.js 6 | -------------------------------------------------------------------------------- /docker/production/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export METEOR_SETTINGS="$(cat settings.prod.json)" 4 | echo $METEOR_SETTINGS 5 | forever main.js 6 | -------------------------------------------------------------------------------- /config/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": { 3 | "persistent_session": { 4 | "default_method": "persistent" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docker/vagrant/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | /usr/local/bin/meteor update 3 | /usr/local/bin/meteor npm install @babel/runtime@7.0.0-beta.55 4 | /usr/local/bin/meteor 5 | -------------------------------------------------------------------------------- /imports/api/roles/server/publications.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | 3 | Meteor.publish(null, function (){ 4 | return Meteor.roles.find({}) 5 | }); 6 | -------------------------------------------------------------------------------- /imports/ui/pages/home/home.js: -------------------------------------------------------------------------------- 1 | import './home.html'; 2 | 3 | import '../../components/questions/questions.js'; 4 | import '../../components/personality/personality.js'; 5 | -------------------------------------------------------------------------------- /imports/ui/components/loading/loading.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /imports/ui/components/mbtiGraph/mbtiGraphRender.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /imports/ui/pages/comment_report/comment_report.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /imports/client/insertProdAnalytics.js: -------------------------------------------------------------------------------- 1 | 2 | window.dataLayer = window.dataLayer || []; 3 | function gtag(){dataLayer.push(arguments);} 4 | gtag('js', new Date()); 5 | 6 | gtag('config', 'UA-139764993-1'); -------------------------------------------------------------------------------- /imports/ui/layouts/body/body.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /imports/client/insertDevAnalytics.js: -------------------------------------------------------------------------------- 1 | 2 | window.dataLayer = window.dataLayer || []; 3 | function gtag(){dataLayer.push(arguments);} 4 | gtag('js', new Date()); 5 | 6 | gtag('config', 'UA-139764993-2'); 7 | -------------------------------------------------------------------------------- /imports/ui/components/behavior_pattern_area/behavior_pattern_area_render.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /imports/api/reports/server/publications.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { Reports, Report } from '../reports.js'; 3 | 4 | Meteor.publish('reports', function reportsPublication () { 5 | return Reports.find({}) 6 | }) 7 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/qnaire.less: -------------------------------------------------------------------------------- 1 | .qnaire { 2 | .qq-outer { 3 | margin-bottom: 15px; 4 | } 5 | } 6 | .assessment-heading { 7 | float: right; 8 | } 9 | .modal-content .qnaire { 10 | width: 100% !important; 11 | } 12 | -------------------------------------------------------------------------------- /imports/api/timer/server/publications.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { Timer } from '../timer.js'; 3 | 4 | 5 | Meteor.publish('timersData', function ( lssid ) { 6 | return Timer.find({ learnShareSessionId:lssid }); 7 | }); -------------------------------------------------------------------------------- /imports/startup/both/index.js: -------------------------------------------------------------------------------- 1 | // Import modules used by both client and server through a single index entry point 2 | // e.g. useraccounts configuration file. 3 | if(Meteor.isClient) { Session.setDefault('refreshQuestions', Math.random()); } 4 | import './at_config.js'; -------------------------------------------------------------------------------- /imports/ui/components/team_icon/team_icon.html: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /imports/ui/pages/admin_reports/custom_report_triage/custom_report_triage.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /imports/startup/client/index.js: -------------------------------------------------------------------------------- 1 | // Import client startup through a single index entry point 2 | 3 | import './config.js'; 4 | import './routes.js'; 5 | import './../../client/clientSideDbs' 6 | import './../../client/callWithPromise.js' 7 | 8 | 9 | $('html').attr('lang', 'en'); -------------------------------------------------------------------------------- /imports/api/restrictedRoutes/server/publications.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { RestrictedRoutes } from '../restrictedRoutes.js'; 3 | 4 | Meteor.publish('restrictedRouteData', function() { 5 | return RestrictedRoutes.find({}, { fields: { roleName:1, teamNames:1 } }); 6 | }); -------------------------------------------------------------------------------- /imports/client/clientSideDbs.js: -------------------------------------------------------------------------------- 1 | const KeyData = new Mongo.Collection('tsqdata'); 2 | const SkillsData = new Mongo.Collection('tsqskills'); 3 | const HelpText = new Mongo.Collection('helperText'); 4 | 5 | export { KeyData, SkillsData, HelpText }// NOTE: need this for holding the tsq api data on the client -------------------------------------------------------------------------------- /imports/api/restrictedRoutes/server/publications.js.orig: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { RestrictedRoutes } from '../restrictedRoutes.js'; 3 | 4 | Meteor.publish('restrictedRouteData', function() { 5 | return RestrictedRoutes.find({}, { fields: { roleName:1, teamNames:1 } }); 6 | }); -------------------------------------------------------------------------------- /imports/ui/components/label_list/label_list.html: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/char_sheet.less: -------------------------------------------------------------------------------- 1 | .char-sheet { 2 | &.container { 3 | position: relative; 4 | max-width: 400px; 5 | } 6 | // #btn-group { 7 | // display: none; 8 | // position: absolute; 9 | // top: 10px; 10 | // right: 10px; 11 | // z-index: 100; 12 | // } 13 | } -------------------------------------------------------------------------------- /imports/ui/components/begin/begin.js: -------------------------------------------------------------------------------- 1 | import { Template } from 'meteor/templating'; 2 | import './begin.html'; 3 | 4 | 5 | 6 | Template.begin.helpers({ 7 | 8 | assessment() { 9 | let assess = FlowRouter.getParam('id'); 10 | console.log(assess); 11 | return (assess || "MBTI"); 12 | } 13 | 14 | }); 15 | 16 | -------------------------------------------------------------------------------- /imports/ui/pages/ask_questions/ask_questions.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | qcqgns92w0md.yphpdej9wth 8 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/qnaire_results.less: -------------------------------------------------------------------------------- 1 | table.result { 2 | font-family: arial, sans-serif; 3 | border-collapse: collapse; 4 | width: 100%; 5 | } 6 | 7 | td.result, th.result { 8 | border: 1px solid #000000; 9 | text-align: left; 10 | padding: 8px; 11 | } 12 | 13 | tr:nth-child(even).result { 14 | background-color: #dddddd; 15 | } 16 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/team_icon.less: -------------------------------------------------------------------------------- 1 | .team-icon img { 2 | width: 16px; 3 | height: 16px; 4 | border-radius: 3px; 5 | } 6 | 7 | h3 .team-icon img { 8 | width: 24px; 9 | height: 24px; 10 | margin-bottom: 3px; 11 | } 12 | 13 | h1 .team-icon img { 14 | width: 30px; 15 | height: 30px; 16 | margin-bottom: 8px; 17 | } 18 | -------------------------------------------------------------------------------- /docker/dev/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #/usr/local/bin/meteor update 4 | #/usr/local/bin/meteor npm install @babel/runtime@7.0.0-beta.55 5 | cat settings.dev-docker.json 6 | export METEOR_SETTINGS="$(cat settings.dev-docker.json)" 7 | echo $METEOR_SETTINGS 8 | /usr/local/bin/meteor npm i 9 | /usr/local/bin/meteor --settings settings.dev-docker.json 10 | -------------------------------------------------------------------------------- /imports/api/user_segments/server/publications.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { UserSegment } from '../user_segments.js'; 3 | 4 | Meteor.publish('segmentList', function () { 5 | //if (Meteor.userId()) { 6 | return UserSegment.find(); 7 | //} else { 8 | // this.stop(); 9 | // return; 10 | //} 11 | }); 12 | -------------------------------------------------------------------------------- /private/README.md: -------------------------------------------------------------------------------- 1 | **private folder** 2 | 3 | All files inside a top-level directory called `private/` are only accessible from server code and can be loaded via the [`Assets`](http://docs.meteor.com/#/full/assets_getText) API. This can be used for private data files and any files that are in your project directory that you don't want to be accessible from the outside. 4 | -------------------------------------------------------------------------------- /imports/api/user_notify/server/publications.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { UserNotify } from '../user_notify.js'; 3 | 4 | Meteor.publish('notificationList', function (userId) { 5 | if (this.userId == userId) { 6 | let un = UserNotify.find( {userId:this.userId} ); 7 | return un; 8 | } else { 9 | return []; 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /imports/ui/pages/not-found/not-found.html: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /imports/ui/components/select_autocomplete/select_autocomplete.html: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /imports/api/qnaire/server/publications.js: -------------------------------------------------------------------------------- 1 | import { Qnaire } from '../qnaire.js'; 2 | 3 | Meteor.publish('qnaire', function (qid) { 4 | if ("undefined" !== typeof qid && "" !== qid && null !== qid) { 5 | console.log("findone", qid); 6 | return Qnaire.find( {_id:qid} ); 7 | } else { 8 | console.log("findall"); 9 | return Qnaire.find(); 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /imports/ui/pages/home/home.html: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.vagrant/rgloader/loader.rb: -------------------------------------------------------------------------------- 1 | # This file loads the proper rgloader/loader.rb file that comes packaged 2 | # with Vagrant so that encoded files can properly run with Vagrant. 3 | 4 | if ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"] 5 | require File.expand_path( 6 | "rgloader/loader", ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"]) 7 | else 8 | raise "Encoded files can't be read outside of the Vagrant installer." 9 | end 10 | -------------------------------------------------------------------------------- /imports/ui/components/video_embed/video_embed.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /imports/api/qnaire_data/server/publications.js: -------------------------------------------------------------------------------- 1 | import { QRespondent } from '../qnaire_data.js'; 2 | 3 | Meteor.publish('qnaireData', function (qid) { 4 | if ("undefined" !== typeof qid && "" !== qid && null !== qid) { 5 | console.log("findone", qid); 6 | return QRespondent.find( {qnrid:qid} ); 7 | } else { 8 | console.log("findall"); 9 | return QRespondent.find(); 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /imports/api/queue/server/queue.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { SrvDefaults } from '../../../startup/server/defaults.js'; 3 | //import Bull from 'bull'; 4 | var Bull = require('bull'); 5 | 6 | const UserActivitiesQueue = new Bull('User Activities Processing', { 7 | limiter: Meteor.settings.private.Queue.Limiter, 8 | redis: Meteor.settings.private.Queue.Redis 9 | }); 10 | 11 | export { UserActivitiesQueue }; -------------------------------------------------------------------------------- /docker/staging/padawan-node-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export PATH=/apps/node/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin 3 | 4 | yum -y install make gcc gcc-c++ && yum -y clean all 5 | mkdir /apps && cd /apps && curl -s -L -O https://nodejs.org/dist/${NODEJS_VERSION}/node-${NODEJS_VERSION}-linux-x64.tar.xz && tar xf node-${NODEJS_VERSION}-linux-x64.tar.xz && mv node-${NODEJS_VERSION}-linux-x64 node 6 | 7 | npm -g config set user root 8 | -------------------------------------------------------------------------------- /imports/api/user_feedback/methods.js: -------------------------------------------------------------------------------- 1 | import { UserFeedback } from './user_feedback.js'; 2 | 3 | Meteor.methods({ 4 | 'feedback.createNewFeedback'(newFeedback) { 5 | if (!Meteor.userId()) { 6 | throw new Meteor.Error(403, "You are not authorized"); 7 | } 8 | 9 | newFeedback.userId = Meteor.userId(); 10 | let f = new UserFeedback(newFeedback); 11 | return f.save(); 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /imports/ui/components/dl_footer/dl_footer.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docker/production/padawan-node-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export PATH=/apps/node/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin 3 | 4 | yum -y install make gcc gcc-c++ && yum -y clean all 5 | mkdir /apps && cd /apps && curl -s -L -O https://nodejs.org/dist/${NODEJS_VERSION}/node-${NODEJS_VERSION}-linux-x64.tar.xz && tar xf node-${NODEJS_VERSION}-linux-x64.tar.xz && mv node-${NODEJS_VERSION}-linux-x64 node 6 | 7 | npm -g config set user root 8 | -------------------------------------------------------------------------------- /imports/api/teams/methods.js: -------------------------------------------------------------------------------- 1 | import {Team } from './teams.js'; 2 | 3 | Meteor.methods({ 4 | 'team.createNewTeam'(newTeam) { 5 | if ( !Roles.userIsInRole(Meteor.userId(), ['admin'], Roles.GLOBAL_GROUP) ) { 6 | throw new Meteor.Error(403, "You are not authorized"); 7 | } 8 | 9 | newTeam.CreatedBy = Meteor.userId(); 10 | let t = new Team(newTeam); 11 | return t.save(); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /imports/client/callWithPromise.js: -------------------------------------------------------------------------------- 1 | import { Promise } from 'meteor/promise' 2 | 3 | /** 4 | * 5 | * Meteor promise handler - testing this 6 | */ 7 | 8 | export const callWithPromise = (method, ...params) => { 9 | return new Promise((resolve, reject) => { 10 | Meteor.call(method, ...params, (error, result) => { 11 | // if (error) reject(error); 12 | if (error) resolve(error) 13 | else resolve(result); 14 | }); 15 | }); 16 | } -------------------------------------------------------------------------------- /imports/ui/layouts/login/login.js: -------------------------------------------------------------------------------- 1 | import { Template } from 'meteor/templating'; 2 | import './login.html'; 3 | 4 | 5 | // Template.begin.helpers({ 6 | 7 | // assessment() { 8 | // let login = FlowRouter.getRouteName; 9 | // let assess = FlowRouter.getParam('id'); 10 | // if (login === assess) { 11 | // return assess; 12 | // } else { 13 | // return "MBTI"; 14 | // } 15 | // }, 16 | -------------------------------------------------------------------------------- /imports/ui/pages/verify/verify.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /imports/ui/components/timer/timer.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${file}" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /imports/ui/pages/admin_reports/team_member_tsq/team_member_tsq.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imports/ui/pages/qnaire_results/qnaire_results.html: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /docker/staging/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | app: 4 | build: . 5 | ports: 6 | - "3000:3000" 7 | links: 8 | - database 9 | environment: 10 | - MONGO_URL=mongodb://database:27017/testing 11 | - ROOT_URL=http://18.221.137.142 12 | - PORT=3000 13 | database: 14 | image: mongo:3.4.1 15 | restart: always 16 | volumes: 17 | - "/home/ec2-user/stag_data:/data/db" 18 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/mbti_char_report.less: -------------------------------------------------------------------------------- 1 | #grfBehavior, #grfTraits { 2 | max-width: 100%; 3 | } 4 | .mbtiBarGraphDiv { 5 | padding: 10px; 6 | max-width: 100%; 7 | } 8 | #mbtiBarGraph { 9 | width: 400px; 10 | height: 200px; 11 | max-width: 100%; 12 | } 13 | #results_descriptions { 14 | width: 150px; 15 | height: 80px; 16 | } 17 | 18 | @media only screen and (max-width: 991px) { 19 | #grfBehavior, #grfTraits { 20 | width: 100%; 21 | height: auto; 22 | } 23 | } -------------------------------------------------------------------------------- /private/html-email.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML email test 6 | 7 | 8 | 9 | 10 |

{{text}}

11 |
12 | Click Here 13 |
14 | 15 | -------------------------------------------------------------------------------- /imports/api/user_segments/methods.js: -------------------------------------------------------------------------------- 1 | import { UserSegment } from './user_segments.js'; 2 | 3 | Meteor.methods({ 4 | 'segment.createNewSegment'(name, dscr) { 5 | if (!Roles.userIsInRole(Meteor.userId(), ['admin'], Roles.GLOBAL_GROUP)) { 6 | throw new Meteor.Error(403, "You are not authorized"); 7 | } else { 8 | let s = new UserSegment({ 9 | name: name, 10 | description: dscr 11 | }); 12 | return s.save(); 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /imports/api/qnaire_data/methods.js: -------------------------------------------------------------------------------- 1 | import { QRespondent } from './qnaire_data.js'; 2 | 3 | Meteor.methods({ 4 | 'qnaire.createNewQnaireData'(qid) { 5 | console.log("createNewQnaireData ------------------------------"); 6 | let qd = new QRespondent({ 7 | qnrid: qid 8 | }); 9 | return qd.save(); 10 | }, 11 | 'qnaireData.recordResponse'(qqlabel, val, finish, qid) { 12 | resp = QRespondent.findOne( {_id:qid} ); 13 | resp.recordResponse(qqlabel, val, finish); 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /imports/ui/components/dl_footer/dl_footer.js: -------------------------------------------------------------------------------- 1 | import { Template } from 'meteor/templating'; 2 | import './dl_footer.html'; 3 | import { User } from '/imports/api/users/users.js'; 4 | 5 | import '../../components/questions/questions.js'; 6 | import '../../components/personality/personality.js'; 7 | import '../../components/notification_list/notification_list.js'; 8 | 9 | import { FlowRouter } from 'meteor/kadira:flow-router'; 10 | 11 | Template.dl_footer.helpers({ 12 | getYear() { 13 | return new Date().getFullYear(); 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /imports/ui/components/video_embed/video_embed.js: -------------------------------------------------------------------------------- 1 | import './video_embed.html'; 2 | 3 | Template.video_embed.onCreated(function () { 4 | this._fileExists = new ReactiveVar(false); 5 | console.log(this.data); 6 | this.autorun( () => { 7 | Meteor.call('learnshare.recordingExists',this.data.id, (err,rslt) => { 8 | this._fileExists.set(rslt); 9 | }); 10 | }); 11 | }); 12 | 13 | Template.video_embed.helpers({ 14 | fileExists(fname) { 15 | return Template.instance()._fileExists.get(); 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /imports/api/user_feedback/server/publications.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from "meteor/meteor"; 2 | import { UserFeedback } from "../user_feedback.js"; 3 | 4 | Meteor.publish("feedback.userComments", function() { 5 | if (this.userId) { 6 | return UserFeedback.find({ userId: Meteor.userId() }); 7 | } else { 8 | return []; 9 | } 10 | }); 11 | 12 | Meteor.publish("userFeedback", function() { 13 | if (Roles.userIsInRole(this.userId, ["admin"], Roles.GLOBAL_GROUP)) { 14 | return UserFeedback.find({}); 15 | } else { 16 | return []; 17 | } 18 | }); 19 | -------------------------------------------------------------------------------- /imports/api/grf/methods.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { HTTP } from 'meteor/http'; 3 | 4 | // const GRF_URL = Meteor.settings.private.GRF_URL; 5 | const GRF_URL = Meteor.settings.public.GRF_URL; 6 | 7 | Meteor.methods({ 8 | 'grf.getHealthCheck'() { 9 | let healthy = true; 10 | try { 11 | let apiUrl = GRF_URL + 'healthCheck/'; 12 | let result = HTTP.get(apiUrl); 13 | if (result.statusCode !== 200) { 14 | healthy = false; 15 | } 16 | } catch (e) { 17 | healthy = false; 18 | } 19 | return healthy; 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /docker/vagrant/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | app: 4 | build: . 5 | ports: 6 | - "3000:3000" 7 | links: 8 | - database 9 | environment: 10 | - MONGO_URL=mongodb://database:27017/testing 11 | - ROOT_URL=http://localhost 12 | - PORT=3000 13 | volumes: 14 | - "../..:/app" 15 | database: 16 | image: mongo:3.6 17 | restart: always 18 | ports: 19 | - "3001:27017" 20 | volumes: 21 | - "db-data:/data/db" 22 | volumes: 23 | db-data: 24 | -------------------------------------------------------------------------------- /imports/api/learn_share/server/publications.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { LearnShareSession } from '../learn_share.js'; 3 | 4 | Meteor.publish('learnShareList', function() { 5 | if (this.userId) { 6 | return LearnShareSession.find( {}, { 7 | fields: { title: 1, teamId: 1 } 8 | }); 9 | } else { 10 | return [ ]; 11 | } 12 | }); 13 | 14 | Meteor.publish('learnShareDetails', function(lssid) { 15 | //if (this.userId) { 16 | return LearnShareSession.find( {_id:lssid} ); 17 | //} else { 18 | // return [ ]; 19 | //} 20 | }); 21 | -------------------------------------------------------------------------------- /imports/ui/pages/user_dashboard/user_dashboard.html: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /imports/api/user_segments/user_segments.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { Mongo } from 'meteor/mongo'; 3 | import { Class, Enum } from 'meteor/jagi:astronomy'; 4 | 5 | const UserSegment = Class.create({ 6 | name: 'UserSegment', 7 | collection: new Mongo.Collection('user_segments'), 8 | fields: { 9 | name: { 10 | type: String, 11 | default: 'Default user segment' 12 | }, 13 | description: { 14 | type: String, 15 | default: 'The default user segment for relevant content' 16 | } 17 | } 18 | }); 19 | 20 | export { UserSegment }; 21 | -------------------------------------------------------------------------------- /imports/ui/pages/ask_questions/ask_questions.js: -------------------------------------------------------------------------------- 1 | import { Question } from '/imports/api/questions/questions.js'; 2 | import { User, Profile, UserType, MyersBriggs, Answer } from '/imports/api/users/users.js'; 3 | import { Meteor } from 'meteor/meteor'; 4 | import './ask_questions.html'; 5 | import '../../components/questions/questions.js'; 6 | import '../../components/personality/personality.js'; 7 | 8 | 9 | 10 | 11 | Template.ask_questions.helpers({ 12 | answeredQuestionsLength() { 13 | let u = User.findOne({_id:Template.instance().userId}); 14 | return u.MyProfile.UserType.AnsweredQuestions.length; 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | notices-for-facebook-graph-api-2 9 | 1.2.0-standard-minifiers-package 10 | 1.2.0-meteor-platform-split 11 | 1.2.0-cordova-changes 12 | 1.2.0-breaking-changes 13 | 1.3.0-split-minifiers-package 14 | 1.4.0-remove-old-dev-bundle-link 15 | 1.4.1-add-shell-server-package 16 | 1.4.3-split-account-service-packages 17 | 1.5-add-dynamic-import-package 18 | 1.7-split-underscore-from-meteor-base 19 | -------------------------------------------------------------------------------- /dump/onAnswered.js: -------------------------------------------------------------------------------- 1 | /* 2 | if (qq.label[0] == 'q') { 3 | let categories = qq.list[2].split('|'); 4 | 5 | let catLetters = ["IE", "NS", "TF", "JP"]; 6 | 7 | for (let i = 0; i < categories.length; i++) { 8 | let totLbl = '_'+catLetters[categories[i]]; 9 | console.log("typeof $a",typeof $a(totLbl)); 10 | if ("undefined" === typeof $a(totLbl)) { 11 | $set(totLbl, 0); 12 | } 13 | if ("undefined" === typeof $a(totLbl+'_count')) { 14 | $set(totLbl+'_count', 0); 15 | } 16 | $set(totLbl+'_count', $a(totLbl+'_count')+1); 17 | $set(totLbl, $a(totLbl)+dbVal); 18 | } 19 | } 20 | */ 21 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/user_profile.less: -------------------------------------------------------------------------------- 1 | .user-profile { 2 | &.container { 3 | position: relative; 4 | max-width: 400px; 5 | } 6 | #btn-group { 7 | display: none; 8 | position: absolute; 9 | top: 10px; 10 | right: 10px; 11 | z-index: 11; 12 | } 13 | } 14 | .right{ 15 | float:right; 16 | } 17 | .left{ 18 | float:left; 19 | } 20 | .btn-space{ 21 | margin-left: 10px; 22 | } 23 | .alert-margin{ 24 | margin-top: 5px; 25 | margin-bottom: 1px; 26 | height: 20px; 27 | line-height:20px; 28 | padding:0px 15px; 29 | } 30 | #verifyButton { 31 | position: absolute; 32 | left: 100px; 33 | } 34 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/opposites.less: -------------------------------------------------------------------------------- 1 | .title1 { 2 | color: black; 3 | font-size: 18px; 4 | text-align: center; 5 | padding: 5px; 6 | } 7 | .title2 { 8 | color: black; 9 | font-size: 14px; 10 | } 11 | .title3 { 12 | color: black; 13 | } 14 | .title4 { 15 | color: black; 16 | font-size: 16px; 17 | text-align: center; 18 | } 19 | .space { 20 | margin: 10px; 21 | padding: 5px; 22 | } 23 | .border { 24 | padding: 8px; 25 | line-height: 1.42857143; 26 | vertical-align: top; 27 | border-top: 1px solid #ddd; 28 | } 29 | // .position1 { 30 | // position: absolute; 31 | // margin-left: -235px; 32 | // } 33 | // .position2 { 34 | 35 | // } -------------------------------------------------------------------------------- /imports/ui/stylesheets/behavior_pattern_area.less: -------------------------------------------------------------------------------- 1 | .behavior_pattern_area { 2 | width: 60%; 3 | background-image: url('/img/mbtiBackground.png'); 4 | background-repeat: no-repeat; 5 | background-position: center center; 6 | background-size: 54%; 7 | } 8 | @media (max-width: 576px) { 9 | .behavior_pattern_area { 10 | width: 100%; 11 | } 12 | } 13 | @media (min-width: 576px) and (max-width: 768px) { 14 | .behavior_pattern_area { 15 | width: 95%; 16 | } 17 | } 18 | @media (min-width: 768px) and (max-width: 992px) { 19 | .behavior_pattern_area { 20 | width: 90%; 21 | } 22 | } 23 | @media (min-width: 992px) and (max-width: 1200px) { 24 | .behavior_pattern_area { 25 | width: 80%; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docker/production/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos 2 | MAINTAINER Paladin and Archer 3 | #ENV NODEJS_VERSION=v8.7.0 4 | ENV NODEJS_VERSION=v10.15.0 5 | ENV PATH=/apps/node/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin 6 | ENV USER=root 7 | ENV HOME=/root/ 8 | 9 | WORKDIR /root/ 10 | COPY padawan-node-setup.sh /root/ 11 | RUN chmod +x padawan-node-setup.sh 12 | RUN ./padawan-node-setup.sh 13 | ENV TAG_WORKAROUND=201711240332 14 | ADD ./padawan.tar.gz /var/www/padawan/ 15 | WORKDIR /var/www/padawan/bundle/programs/server/ 16 | RUN npm i && npm i forever -g && npm i forever 17 | WORKDIR /var/www/padawan/bundle/ 18 | COPY entrypoint.sh . 19 | COPY settings.prod.json . 20 | RUN chmod +x entrypoint.sh 21 | ENTRYPOINT ["./entrypoint.sh"] 22 | -------------------------------------------------------------------------------- /docker/staging/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos 2 | MAINTAINER Paladin and Archer 3 | #ENV NODEJS_VERSION=v8.7.0 4 | ENV NODEJS_VERSION=v10.15.0 5 | ENV PATH=/apps/node/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin 6 | ENV USER=root 7 | ENV HOME=/root/ 8 | 9 | WORKDIR /root/ 10 | COPY padawan-node-setup.sh /root/ 11 | RUN chmod +x padawan-node-setup.sh 12 | RUN ./padawan-node-setup.sh 13 | ENV TAG_WORKAROUND=201711240332 14 | ADD ./padawan.tar.gz /var/www/padawan/ 15 | WORKDIR /var/www/padawan/bundle/programs/server/ 16 | RUN npm i && npm i forever -g && npm i forever 17 | WORKDIR /var/www/padawan/bundle/ 18 | COPY entrypoint.sh . 19 | COPY settings.staging.json . 20 | RUN chmod +x entrypoint.sh 21 | ENTRYPOINT ["./entrypoint.sh"] 22 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/add_questions.less: -------------------------------------------------------------------------------- 1 | #newQuestion { 2 | .selectize-input { 3 | border-radius: 3px 0 0 3px; 4 | background-color: #5cb85c; 5 | 6 | ::-webkit-input-placeholder { /* Chrome/Opera/Safari */ 7 | color: #eee; 8 | } 9 | ::-moz-placeholder { /* Firefox 19+ */ 10 | color: #eee; 11 | } 12 | :-ms-input-placeholder { /* IE 10+ */ 13 | color: #eee; 14 | } 15 | :-moz-placeholder { /* Firefox 18- */ 16 | color: #eee; 17 | } 18 | } 19 | .selectize-control.multi .selectize-input > div { 20 | * margin-bottom: 0; 21 | } 22 | } 23 | .container.questions { 24 | margin-top: 50px; 25 | } 26 | -------------------------------------------------------------------------------- /utils/db_restore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | show_usage() { 3 | echo "USAGE: $0 DB_INSTANCE RESTORE_FROM" 4 | } 5 | 6 | BAK_PATH=~/bak 7 | if [[ "$2" == "" ]]; then 8 | show_usage 9 | exit 0 10 | else 11 | if [[ "$1" == "production_database_1" ]]; then 12 | DATA_PATH=~/prod_data 13 | elif [[ "$1" == "staging_database_1" ]]; then 14 | DATA_PATH=~/stag_data 15 | else 16 | echo "Invalid database instance. Valid values are:" 17 | echo "- production_database_1" 18 | echo "- staging_database_1" 19 | exit 0 20 | fi 21 | cp $BAK_PATH/$2 $DATA_PATH 22 | cd $DATA_PATH 23 | tar xzvf $2 24 | sudo docker exec $1 /bin/bash -c 'cd /data/db && mongorestore dump/' 25 | fi 26 | -------------------------------------------------------------------------------- /imports/api/help/helperPagesCached.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { HelperPages } from './helperPages.js'; 3 | import { NVCache } from '../nvcache/nvcache.js'; 4 | 5 | const HelperPagesCached = { 6 | getPageObjectBySlug(slug) { 7 | var ret = NVCache.findOne({name:slug}); 8 | if(!ret) { 9 | ret = new NVCache(); 10 | ret.name = slug; 11 | } 12 | if (ret.isExpired(Meteor.settings.public.Pages.Base.CacheTTL)) { 13 | ret.value = HelperPages.getPageObjectBySlug(slug); 14 | ret.save(); 15 | } 16 | return ret.value; 17 | }, 18 | getPageContentBySlug(slug) { 19 | var data= this.getPageObjectBySlug(slug).content.rendered; 20 | return data; 21 | } 22 | }; 23 | 24 | export { HelperPagesCached }; -------------------------------------------------------------------------------- /imports/ui/layouts/login/login.html: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /docker/dev/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | app: 4 | build: . 5 | ports: 6 | - "3000:3000" 7 | links: 8 | - database 9 | environment: 10 | - MONGO_URL=mongodb://database:27017/testing 11 | - ROOT_URL=http://localhost 12 | - PORT=3000 13 | - NODE_DEBUG=bull 14 | volumes: 15 | - "../..:/app" 16 | - "uploads:/uploads" 17 | extra_hosts: 18 | - 'tsqapp:172.17.0.1' 19 | database: 20 | image: mongo:3.6 21 | restart: always 22 | ports: 23 | - "3001:27017" 24 | volumes: 25 | - "db-data:/data/db" 26 | redis: 27 | image: redis 28 | restart: always 29 | volumes: 30 | - "redis-data:/data/redis" 31 | volumes: 32 | db-data: 33 | uploads: 34 | redis-data: 35 | -------------------------------------------------------------------------------- /imports/ui/components/timer/timer.js: -------------------------------------------------------------------------------- 1 | import './timer.html'; 2 | import { Timer } from '/imports/api/timer/timer.js'; 3 | 4 | Template.timer.onCreated(function() { 5 | this.lssid = FlowRouter.getParam('lssid'); 6 | this.subscribe('timersData', this.lssid); 7 | }) 8 | Template.timer.helpers({ 9 | timeSinceLastPresenterSelectedMinutes() { 10 | let timer = Timer.findOne( {presenterId:Template.instance().data.presenter.id} ); 11 | if (!timer) { 12 | return null; 13 | } 14 | return ('0' + Math.floor(timer.time/60)).slice(-2); 15 | }, 16 | timeSinceLastPresenterSelectedSeconds() { 17 | let timer = Timer.findOne( {presenterId:Template.instance().data.presenter.id} ); 18 | if (!timer) { 19 | return null; 20 | } 21 | return ('0' + Math.floor(timer.time % 60)).slice(-2); 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /imports/ui/pages/verify/verify.js: -------------------------------------------------------------------------------- 1 | import { User } from '/imports/api/users/users.js'; 2 | import './verify.html'; 3 | 4 | Template.user_profile.onCreated(function () { 5 | this.autorun( () => { 6 | this.subscription = this.subscribe('userData', { 7 | onStop: function () { 8 | console.log("User profile subscription stopped! ", arguments, this); 9 | }, 10 | onReady: function () { 11 | console.log("User profile subscription ready! ", arguments, this); 12 | } 13 | }); 14 | }); 15 | }); 16 | 17 | Template.verify.events({ 18 | 'click #resend-verify'(event, instance) { 19 | event.preventDefault(); 20 | FlowRouter.redirect("/profile"); 21 | // Meteor.call( 'user.sendVerificationEmail', () => { 22 | // console.log('resent'); 23 | // }); 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /imports/api/user_feedback/user_feedback.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { Mongo } from 'meteor/mongo'; 3 | import { Class, Enum } from 'meteor/jagi:astronomy'; 4 | 5 | const UserFeedback = Class.create({ 6 | name: 'UserFeedback', 7 | collection: new Mongo.Collection('user_feedback'), 8 | fields: { 9 | userId: { 10 | type: String, 11 | default: '' 12 | }, 13 | source: { 14 | type: String, 15 | default: '' 16 | }, 17 | context: { 18 | type: String, 19 | default: '' 20 | }, 21 | comment: { 22 | type: String, 23 | default: '' 24 | }, 25 | dateCreated: { 26 | type: Date, 27 | default: function() { return new Date(); } 28 | } 29 | } 30 | }); 31 | 32 | export { UserFeedback }; 33 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/not-found.less: -------------------------------------------------------------------------------- 1 | #not-found { 2 | width: 700px; 3 | margin: 0 auto; 4 | .not-found-image { 5 | width: 25%; 6 | float: left; 7 | } 8 | .not-found-title { 9 | width: 70%; 10 | float: right; 11 | background: url(/img/bg-footer.svg); 12 | background-repeat: no-repeat; 13 | background-position: center; 14 | background-size: contain; 15 | min-height: 400px; 16 | h1 { 17 | font-size: 30px; 18 | color: #1f2128; 19 | margin-bottom: 20px; 20 | margin-top: 155px; 21 | } 22 | a.gotohomepage { 23 | background-color: #de4f4f; 24 | color: #fff; 25 | width: 180px; 26 | line-height: 40px; 27 | display: block; 28 | text-align: center; 29 | font-size: 14px; 30 | text-decoration: none; 31 | text-transform: uppercase; 32 | height: 40px; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /imports/api/users/server/publications.js: -------------------------------------------------------------------------------- 1 | // All users-related publications 2 | 3 | import { Meteor } from 'meteor/meteor'; 4 | import { User } from '../users.js'; 5 | 6 | Meteor.publish('userData', function () { 7 | if(this.userId) { 8 | return User.find({ _id: this.userId }, { 9 | fields: { roles: 1, MyProfile: 1 } 10 | }); 11 | } else { 12 | return this.ready(); 13 | } 14 | }); 15 | 16 | Meteor.publish('userList', function () { 17 | if ( Roles.userIsInRole(this.userId, ['admin'], Roles.GLOBAL_GROUP ) ) { 18 | return User.find( {} ); 19 | } else { 20 | return User.find( {}, { 21 | fields: { roles: 1, username: 1, MyProfile: 1 } 22 | } ); 23 | } 24 | }); 25 | 26 | Meteor.publish('tsqUserList', function () { 27 | return User.find( {}, { 28 | fields: { MyProfile: 1, createdAt: 1 } 29 | } ); 30 | }); 31 | -------------------------------------------------------------------------------- /imports/ui/pages/admin_tools/admin_tools.js: -------------------------------------------------------------------------------- 1 | import './admin_tools.html'; 2 | 3 | Template.admin_tools.onCreated(function () { 4 | this.autorun( () => { 5 | if (Roles.subscription.ready()) { 6 | if (!Roles.userIsInRole(Meteor.userId(),'admin',Roles.GLOBAL_GROUP)) { 7 | FlowRouter.redirect('/notfound'); 8 | } 9 | } 10 | }); 11 | }); 12 | 13 | Template.admin_tools.events({ 14 | 'click button.add_questions'(event, instance) { 15 | FlowRouter.go('/addQuestions/IE'); 16 | }, 17 | 'click button.reports'(event, instance) { 18 | FlowRouter.go('/tools/reports'); 19 | }, 20 | 'click button.add_descriptions'(event, instance) { 21 | FlowRouter.go('/addTraitDescriptions'); 22 | }, 23 | 'click button.user_management' (event, instance) { 24 | FlowRouter.go('/tools/userManagement') 25 | } 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /docker/vagrant/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos 2 | 3 | MAINTAINER Paladin and Archer 4 | 5 | ARG APP_PACKAGES=curl\ gzip\ python\ build-essential\ git 6 | ARG APP_LOCALE=en_US 7 | ARG APP_CHARSET=UTF-8 8 | ARG APP_USER=app 9 | ARG APP_USER_DIR=/home/${APP_USER} 10 | 11 | ENV APP_PORT=${APP_PORT:-3000} 12 | ENV APP_ROOT=${APP_ROOT:-/app} 13 | 14 | EXPOSE $APP_PORT 15 | VOLUME $APP_ROOT 16 | 17 | RUN yum -y install which 18 | RUN yum install -y ${APP_PACKAGES} 19 | #RUN yum install curl gzip python 20 | 21 | RUN yum -y install bsdtar \ 22 | && cp $(which tar) $(which tar)~ \ 23 | && ln -sf $(which bsdtar) $(which tar) 24 | 25 | RUN curl https://install.meteor.com/ | sh 26 | 27 | RUN mv $(which tar)~ $(which tar) 28 | 29 | RUN useradd -mUd ${APP_USER_DIR} ${APP_USER} 30 | RUN chown -Rh ${APP_USER} /usr/local 31 | USER ${APP_USER} 32 | 33 | WORKDIR ${APP_ROOT} 34 | 35 | COPY entrypoint.sh / 36 | 37 | ENTRYPOINT [ "/entrypoint.sh" ] -------------------------------------------------------------------------------- /imports/ui/components/label_list/label_list.js: -------------------------------------------------------------------------------- 1 | import './label_list.html'; 2 | 3 | Template.label_list.onCreated(function () { 4 | // 5 | }); 6 | 7 | Template.label_list.helpers({ 8 | customClass(item) { 9 | if ("guest" === item.value.slice(0,5)) { 10 | return "guest"; 11 | } else { 12 | return ""; 13 | } 14 | } 15 | }) 16 | Template.label_list.onRendered(function () { 17 | var self = this; 18 | self.autorun( function () { 19 | console.log("label_list autorun"); 20 | var dat = Template.currentData(); 21 | if (!dat.nextParticipant) { 22 | return; 23 | } 24 | $('.picking').removeClass('picking').css('background-color', ''); 25 | $('.label[data-value="' + dat.nextParticipant + '"]').addClass('picking'); 26 | 27 | $('.label[data-value="' + dat.nextParticipant + '"]').css('background-color', '#ffa07a'); 28 | }) 29 | }) -------------------------------------------------------------------------------- /imports/ui/pages/comment_report/comment_report.js: -------------------------------------------------------------------------------- 1 | import "./comment_report.html"; 2 | import { Meteor } from "meteor/meteor"; 3 | import { UserFeedback } from "../../../api/user_feedback/user_feedback.js"; 4 | 5 | Template.comment_report.onCreated(function() { 6 | this.autorun(() => { 7 | console.log("autorunning comment_report..."); 8 | this.subscription = this.subscribe("userFeedback", { 9 | onStop: function() { 10 | console.log("userFeedback subscription stopped: ", arguments, this); 11 | }, 12 | onReady: function() { 13 | console.log("userFeedback subscription ready: ", arguments, this); 14 | } 15 | }); 16 | console.log("userFeedback subscription: ", this.subscription); 17 | }); 18 | }); 19 | 20 | Template.comment_report.helpers({ 21 | getReport() { 22 | userFeedback = UserFeedback.find().fetch(); 23 | return JSON.stringify(userFeedback).slice(1, -1); 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /imports/api/airtable/at.js: -------------------------------------------------------------------------------- 1 | import {Meteor} from 'meteor/meteor' 2 | import { HTTP } from 'meteor/http'; 3 | 4 | //var Airtable = require('airtable'); 5 | //Airtable.configure({ 6 | // endpointUrl: 'https://api.airtable.com', 7 | // apiKey: 'keynpUHJS7l5QFWfQ' 8 | //}); 9 | //var base = Airtable.base('appXlqlAQhi8cedpP'); 10 | 11 | // const AT_URL = "https://api.airtable.com/v0/appXlqlAQhi8cedpP/"; 12 | // const AT_KEY = "keynpUHJS7l5QFWfQ"; 13 | 14 | function auth(method, endpoint, request, params) { 15 | let h = { 16 | "Authorization" : "Bearer "+AT_KEY 17 | }; 18 | if(method === 'PUT' || method === 'POST' || method === 'PATCH') { 19 | h = { 20 | "Authorization" : "Bearer "+AT_KEY, 21 | "Content-Type" : 'application/json' 22 | }; 23 | } 24 | result = HTTP.call(method, AT_URL+endpoint, { 25 | headers: h, 26 | data: request, 27 | params: params 28 | }); 29 | return result; 30 | } 31 | 32 | module.exports.getResult = auth; -------------------------------------------------------------------------------- /imports/startup/both/defaults.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | 3 | const Defaults = { 4 | 'user': { 5 | 'username': 'admin', 6 | 'email': 'admin@mydomain.com', 7 | 'isAdmin': true, 8 | 'profile': { 9 | 'first_name': 'Admin', 10 | 'last_name': 'Admin', 11 | 'gender': 'female' 12 | } 13 | }, 14 | 'team': { 15 | 'Name': "No Team", 16 | 'Public': true, 17 | 'Members': [], 18 | 'Active': true, 19 | }, 20 | 'role': { 21 | 'name': 'No-Permissions' 22 | }, 23 | 'supportEmail': 'support@developerlevel.com' 24 | } 25 | 26 | if (typeof Meteor.settings.public == "undefined") { 27 | Meteor.settings.public = { }; 28 | } 29 | if (typeof Meteor.settings.public.Pages == "undefined") { 30 | Meteor.settings.public.Pages = { 31 | Base: { 32 | URL: "http://developerlevel.com/wp-json/wp/v2/pages/", 33 | Password: "", 34 | Context: "view", 35 | CacheTTL: 3660 36 | }, 37 | "GRF_URL" : "http://stage.developerlevel.com/grf/" 38 | }; 39 | } 40 | 41 | export { Defaults }; 42 | -------------------------------------------------------------------------------- /imports/ui/pages/mbti_roles/mbti_roles.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imports/ui/pages/char_sheet/char_sheet.html: -------------------------------------------------------------------------------- 1 | 33 | -------------------------------------------------------------------------------- /settings.staging.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": { 3 | "GRF_URL": "http://stage.developerlevel.com/grf/", 4 | "Pages": { 5 | "Base": { 6 | "URL": "http://developerlevel.com/wp-json/wp/v2/pages/", 7 | "Password": "", 8 | "Context": "view", 9 | "CacheTTL": 15 10 | } 11 | } 12 | }, 13 | "private": { 14 | "TSQ_URL": "http://tsqapp:4000/tsq/", 15 | "Pages": { 16 | "TSQ": { 17 | "Slug": { 18 | "Intro" : "technical-skills-questionnaire-introduction", 19 | "Instructions" : "technical-skills-questionnaire-instructions" 20 | } 21 | }, 22 | "TraitSpectrum": { 23 | "Slug": { 24 | "Intro" : "trait-spectrum-introduction", 25 | "Instructions" : "trait-spectrum-instructions" 26 | } 27 | } 28 | } 29 | }, 30 | "Queue": { 31 | "Redis": { 32 | "server": "redis", 33 | "port": 6379 34 | }, 35 | "Limiter": { 36 | "max": 5, 37 | "duration": 5000, 38 | "bounceBack": true 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /docker/production/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | app: 4 | build: . 5 | ports: 6 | - "3000:3000" 7 | links: 8 | - database 9 | environment: 10 | - MONGO_URL=mongodb://database:27017/testing 11 | - ROOT_URL=http://app.paladinarcher.com 12 | - PORT=3000 13 | networks: 14 | - proxy-net 15 | database: 16 | image: mongo:3.6 17 | restart: always 18 | ports: 19 | - "27017:27017" 20 | volumes: 21 | - "/home/ec2-user/prod_data:/data/db" 22 | networks: 23 | - proxy-net 24 | proxy: 25 | image: nginx 26 | volumes: 27 | - "./nginx.conf:/etc/nginx/nginx.conf" 28 | - "/var/log/nginx/access.log:/var/log/nginx/access.log" 29 | ports: 30 | - "80:3002" 31 | links: 32 | - app 33 | networks: 34 | - proxy-net 35 | networks: 36 | proxy-net: 37 | external: 38 | name: devlvl_net 39 | -------------------------------------------------------------------------------- /settings.dev-docker.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": { 3 | "GRF_URL": "http://stage.developerlevel.com/grf/", 4 | "Pages": { 5 | "Base": { 6 | "URL": "http://developerlevel.com/wp-json/wp/v2/pages/", 7 | "Password": "", 8 | "Context": "view", 9 | "CacheTTL": 3600 10 | } 11 | } 12 | }, 13 | "private": { 14 | "TSQ_URL": "http://tsqapp:4000/tsq/", 15 | "Pages": { 16 | "TSQ": { 17 | "Slug": { 18 | "Intro" : "technical-skills-questionnaire-introduction", 19 | "Instructions" : "technical-skills-questionnaire-instructions" 20 | } 21 | }, 22 | "TraitSpectrum": { 23 | "Slug": { 24 | "Intro" : "trait-spectrum-introduction", 25 | "Instructions" : "trait-spectrum-instructions" 26 | } 27 | } 28 | }, 29 | "Queue": { 30 | "Redis": { 31 | "server": "redis", 32 | "port": 6379 33 | }, 34 | "Limiter": { 35 | "max": 5, 36 | "duration": 5000, 37 | "bounceBack": true 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /imports/api/timer/timer.js: -------------------------------------------------------------------------------- 1 | import { Class } from 'meteor/jagi:astronomy'; 2 | import { Mongo } from 'meteor/mongo'; 3 | 4 | const Timers = new Mongo.Collection('timers'); 5 | const Timer = Class.create({ 6 | name: 'Timer', 7 | collection:Timers, 8 | fields: { 9 | learnShareSessionId: { 10 | type: String 11 | }, 12 | presenterId: { 13 | type: String 14 | }, 15 | time: { 16 | type: Number, 17 | default: 0 18 | }, 19 | duration: { 20 | type: Number 21 | }, 22 | remainingTime: { 23 | type: String, 24 | default: '', 25 | resolve(doc) { 26 | const time = doc.time 27 | const min = Math.floor(time / 60) 28 | const aMin = ('0' + min).slice(-2); 29 | const sec = Math.floor(time - min * 60); 30 | const aSec = ('0' + sec).slice(-2); 31 | return `${aMin}:${aSec}` 32 | } 33 | } 34 | }, 35 | }); 36 | 37 | export { Timer }; 38 | -------------------------------------------------------------------------------- /imports/ui/components/notification_list/notification_list.html: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /settings.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": { 3 | "GRF_URL": "http://localhost:3100/grf/", 4 | "Pages": { 5 | "Base": { 6 | "URL": "http://developerlevel.com/wp-json/wp/v2/pages/", 7 | "Password": "", 8 | "Context": "view", 9 | "CacheTTL": 1 10 | } 11 | } 12 | }, 13 | "private": { 14 | "TSQ_URL": "http://localhost:4000/tsq/", 15 | "Pages": { 16 | "TSQ": { 17 | "Slug": { 18 | "Intro" : "technical-skills-questionnaire-introduction", 19 | "Instructions" : "technical-skills-questionnaire-instructions" 20 | } 21 | }, 22 | "TraitSpectrum": { 23 | "Slug": { 24 | "Intro" : "trait-spectrum-introduction", 25 | "Instructions" : "trait-spectrum-instructions" 26 | } 27 | } 28 | } 29 | }, 30 | "Queue": { 31 | "Redis": { 32 | "server": "localhost", 33 | "port": 6379 34 | }, 35 | "Limiter": { 36 | "max": 5, 37 | "duration": 5000, 38 | "bounceBack": true 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /settings.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": { 3 | "GRF_URL": "http://app.developerlevel.com/grf/", 4 | "Pages": { 5 | "Base": { 6 | "URL": "http://developerlevel.com/wp-json/wp/v2/pages/", 7 | "Password": "", 8 | "Context": "view", 9 | "CacheTTL": 1440 10 | } 11 | } 12 | }, 13 | "private": { 14 | "TSQ_URL": "http://app.developerlevel.com/tsq/", 15 | "Pages": { 16 | "TSQ": { 17 | "Slug": { 18 | "Intro" : "technical-skills-questionnaire-introduction", 19 | "Instructions" : "technical-skills-questionnaire-instructions" 20 | } 21 | }, 22 | "TraitSpectrum": { 23 | "Slug": { 24 | "Intro" : "trait-spectrum-introduction", 25 | "Instructions" : "trait-spectrum-instructions" 26 | } 27 | } 28 | } 29 | }, 30 | "Queue": { 31 | "Redis": { 32 | "server": "redis", 33 | "port": 6379 34 | }, 35 | "Limiter": { 36 | "max": 5, 37 | "duration": 5000, 38 | "bounceBack": true 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /imports/ui/pages/tsq/widget/widget.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imports/startup/client/config.js: -------------------------------------------------------------------------------- 1 | Meteor.subscribe('userData'); 2 | Meteor.subscribe('restrictedRoutes'); 3 | global.Buffer = global.Buffer || require("buffer").Buffer; 4 | /*Meteor.subscribe('teamsData', Meteor.userId(), { 5 | onReady: function() { 6 | console.log("teamsData subscription ready"); 7 | } 8 | }); */ 9 | 10 | // Accounts.onEmailVerificationLink((token, done) => { 11 | // console.log("token: ", token); 12 | // Accounts.verifyEmail(token, (error) => { 13 | // if (error) { 14 | // console.log("Error: ", error); 15 | // } else { 16 | // console.log("Email is verified"); 17 | // 18 | // 19 | // 20 | // // FlowRouter.redirect('/profile', { 21 | // // triggersEnter: [AccountsTemplates.ensureSignedIn,ensureEmailVerified], 22 | // // name: 'profile', 23 | // // action(params, queryParams) { 24 | // // BlazeLayout.render('App_body', { top: 'header', main: 'user_profile' }); 25 | // // } 26 | // // }); 27 | // 28 | // done(); 29 | // } 30 | // }); 31 | // }); 32 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | Vagrant.configure("2") do |config| 4 | config.vbguest.iso_path = "D:/Programs/Oracle/VirtualBox/VBoxGuestAdditions.iso" 5 | config.vm.define "padawan", primary: true do |machine| 6 | machine.vm.box = "centos/7" 7 | machine.vm.box_version = "1811.02" 8 | machine.vm.hostname = "padawan" 9 | 10 | machine.vm.provider "virtualbox" do |vb, override| 11 | vb.memory = "8192" 12 | vb.cpus = "2" 13 | vb.gui = true 14 | machine.vm.synced_folder ".", "/u01/padawan", owner: "vagrant", group: "vagrant" 15 | end 16 | # machine.vm.provider "hyperv" do |hp, override| 17 | # hp.memory = "8192" 18 | # hp.cpus = "2" 19 | # machine.vm.synced_folder ".", "/u01/padawan", owner: "vagrant", group: "vagrant" 20 | ####problem - as it comes up it asks for username/password 21 | # end 22 | 23 | machine.vm.provision :docker 24 | machine.vm.provision :docker_compose, yml: "/u01/padawan/docker/vagrant/docker-compose.yml", run: "always" 25 | end 26 | config.vm.network "forwarded_port", guest: 3000, host: 3000, host_ip: "127.0.0.1" 27 | end 28 | -------------------------------------------------------------------------------- /imports/ui/components/mbtiGraph/mbtiGraphCall.js: -------------------------------------------------------------------------------- 1 | import "./mbtiGraphRender.html"; 2 | import { User } from "/imports/api/users/users.js"; 3 | import { mbtiGraph } from "./mbtiGraph.js"; 4 | import { Template } from "meteor/templating"; 5 | 6 | Template.mbtiGraphRender.onCreated(function() { 7 | this.autorun(() => { 8 | this.subscription2 = this.subscribe("userList", this.userId, { 9 | onStop: function() { 10 | console.log("User List subscription stopped! ", arguments, this); 11 | }, 12 | onReady: function() { 13 | console.log("User List subscription ready! ", arguments, this); 14 | } 15 | }); 16 | }); 17 | }); 18 | 19 | Template.mbtiGraphRender.onRendered(function() { 20 | let userId = this.data.mbtiUID; 21 | let user = User.findOne({ _id: userId }); 22 | let personality = user.MyProfile.UserType.Personality 23 | 24 | let valueIE = personality.IE.Value 25 | let valueNS = personality.NS.Value 26 | let valueTF = personality.TF.Value 27 | let valueJP = personality.JP.Value 28 | mbtiGraph(valueIE, valueNS, valueTF, valueJP, $("#grfTraits"), true, 50); 29 | // mbtiGraph(canvas, -50, 50, 20, -20); 30 | }); 31 | -------------------------------------------------------------------------------- /imports/api/nvcache/nvcache.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { Mongo } from 'meteor/mongo'; 3 | import { Class, Enum } from 'meteor/jagi:astronomy'; 4 | 5 | const NVCache = Class.create({ 6 | name: 'NVCache', 7 | collection: new Mongo.Collection('nvcache'), 8 | fields:{ 9 | createdAt: Date, 10 | name: { 11 | type: String 12 | }, 13 | value: { 14 | type: Object 15 | }, 16 | updatedAt: Date 17 | }, 18 | resolveError({ nestedName, validator }) { 19 | console.log(nestedName, validator); 20 | }, 21 | events: { 22 | afterInit(e) { 23 | }, 24 | beforeSave(e) { 25 | } 26 | }, 27 | meteorMethods: { 28 | isExpired(ttl) { 29 | var date = new Date(); 30 | //date.setDate(date.getDate() - 15); 31 | date.setMinutes(date.getMinutes() - ttl); 32 | return typeof this.updatedAt == "undefined" || date >= this.updatedAt; 33 | } 34 | }, 35 | indexes: { 36 | name: { 37 | fields: { 38 | name: 1 39 | }, 40 | options: { 41 | unique: true 42 | } 43 | } 44 | }, 45 | behaviors: { 46 | timestamp: {} 47 | } 48 | }); 49 | 50 | export { NVCache }; -------------------------------------------------------------------------------- /imports/ui/pages/admin_tools/admin_tools.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imports/ui/components/mbtiGraph/mbtiGraphRenderMulti.html: -------------------------------------------------------------------------------- 1 | 40 | -------------------------------------------------------------------------------- /imports/ui/pages/mvp/mvp.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/select_feedback.less: -------------------------------------------------------------------------------- 1 | .feedback-box { 2 | position: fixed; 3 | top: 60px; 4 | right: 20px; 5 | width: 30%; 6 | background-color: #f0ad4e; 7 | color: #fff; 8 | z-index: 11; 9 | padding: 5px; 10 | border-radius: 3px; 11 | font-size: small; 12 | button { 13 | color: #000; 14 | } 15 | h3 { 16 | font-size: small; 17 | } 18 | .show-minimized { 19 | display: none; 20 | } 21 | .show-fullsize { 22 | display: block; 23 | } 24 | } 25 | .feedback-box.minimized { 26 | .show-minimized { 27 | display: block; 28 | } 29 | .show-fullsize { 30 | display: none; 31 | } 32 | } 33 | #personality-readings { 34 | .feedback-box { 35 | width: ~"calc(50% - 325px)"; 36 | } 37 | .feedback-box.minimized { 38 | width: auto; 39 | right: 0px; 40 | } 41 | } 42 | .jumbotron { 43 | .feedback-box { 44 | width: ~"calc(30% - 225px)"; 45 | } 46 | .feedback-box.minimized { 47 | width: auto; 48 | right: 0px; 49 | } 50 | } 51 | .sf-feedback-context { 52 | background-color: #D8BFD8; 53 | max-width: 100%; 54 | } 55 | .mytextarea { 56 | color: #000; 57 | width: 100%; 58 | height: 150px; 59 | } 60 | -------------------------------------------------------------------------------- /imports/ui/pages/admin_reports/team_member_tsq/team_member_tsq.js: -------------------------------------------------------------------------------- 1 | import "./team_member_tsq.html"; 2 | import { User } from '/imports/api/users/users.js'; 3 | 4 | let currentUserDisplayed = new ReactiveVar(); 5 | 6 | Template.team_member_tsq.onCreated(function () { 7 | this.autorun(() => { 8 | this.subscription = this.subscribe('userData', { 9 | onStop: function () { 10 | // console.log("User profile subscription stopped! ", arguments, this); 11 | }, 12 | onReady: function () { 13 | // console.log("User profile subscription ready! ", arguments, this); 14 | let userId = FlowRouter.getParam('userId'); 15 | let currentUser = User.findOne({ _id:userId }) 16 | currentUserDisplayed.set(currentUser); 17 | } 18 | }); 19 | }); 20 | }); 21 | 22 | Template.team_member_tsq.helpers({ 23 | getCurrentUserDisplayed(){ 24 | let currentUser = currentUserDisplayed.get(); 25 | let result = `Currently viewing ${currentUser.MyProfile.firstName} ${currentUser.MyProfile.lastName}'s TSQ results`; 26 | return result; 27 | }, 28 | isAdmin(){ 29 | let isAdmin = Roles.userIsInRole(Meteor.userId(), 'admin', '__global_roles__'); 30 | return isAdmin ? true : false; 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /imports/ui/pages/admin_reports/custom_report_triage/custom_report_triage.js: -------------------------------------------------------------------------------- 1 | import "./custom_report_triage.html"; 2 | import { Template } from "meteor/templating"; 3 | import { FlowRouter } from 'meteor/kadira:flow-router' 4 | import { Reports } from '/imports/api/reports/reports.js' 5 | 6 | 7 | 8 | //Template.custom_report_triage.onCreated(function () { 9 | // this.autorun(() => { 10 | // if (Roles.subscription.ready()) { 11 | // if (!Roles.userIsInRole(Meteor.userId(), 'admin', Roles.GLOBAL_GROUP)) { 12 | // FlowRouter.redirect('/notfound'); 13 | // } 14 | // } 15 | // // sub to reports 16 | // reportSub(this) 17 | // this.reportTitle = FlowRouter.getParam("title") 18 | // // console.log(this.reportTitle) 19 | // this.getReport = (reportTitle) => Reports.findOne({ title: reportTitle }) 20 | // this.report = this.getReport(this.reportTitle) 21 | // console.log(this.report) 22 | // 23 | // // Meteor.call('updateMBTIReport') 24 | // }) 25 | //}) 26 | 27 | Template.custom_report_triage.helpers({ 28 | titleIsQnaireMbti () { 29 | isQnaireMbti = false; 30 | reportTitle = FlowRouter.getParam("title"); 31 | if (reportTitle == 'Trait Spectrum') { 32 | isQnaireMbti = true; 33 | } 34 | return isQnaireMbti; 35 | } 36 | }); -------------------------------------------------------------------------------- /imports/api/tsq/TSQData.js: -------------------------------------------------------------------------------- 1 | const TSQ_DATA = [ 2 | { 3 | scriptingLanguages: [ 4 | { name: 'Python' }, 5 | { name: 'Java' }, 6 | { name: 'JavaScript' }, 7 | { name: 'CSharp' }, 8 | { name: 'C++' }, 9 | { name: 'Visual Basic' }, 10 | { name: 'PHP' }, 11 | { name: 'Delphi/Object Pascal' }, 12 | { name: 'Assembly' }, 13 | { name: 'Ruby' }, 14 | { name: 'R' }, 15 | { name: 'Swift' }, 16 | { name: 'Rust' }, 17 | { name: 'C' } 18 | ] 19 | }, 20 | { 21 | libraries: [ 22 | { name: 'TypeScript' }, 23 | { name: 'jQuery' }, 24 | { name: 'Lodash' }, 25 | { name: 'SASS' }, 26 | { name: 'LESS' } 27 | ] 28 | }, 29 | { 30 | markupLanguages: [ 31 | { name: 'HTML' }, 32 | { name: 'HTML5' }, 33 | { name: 'CSS' }, 34 | { name: 'CSS3' } 35 | ] 36 | }, 37 | { 38 | frameworks: [ 39 | { name: 'Nodejs' }, 40 | { name: 'MEAN' }, 41 | { name: 'MERN' }, 42 | { name: 'Django' }, 43 | { name: 'Flask' }, 44 | { name: '.Net' }, 45 | { name: 'WordPress' }, 46 | { name: 'Drupal' }, 47 | { name: 'October' }, 48 | { name: 'Angular' }, 49 | { name: 'React' }, 50 | { name: 'Vue' }, 51 | { name: 'Emberjs' } 52 | ] 53 | } 54 | ]; 55 | 56 | export default TSQ_DATA; 57 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/header.less: -------------------------------------------------------------------------------- 1 | .navbar { 2 | margin-bottom: 0px; 3 | li.li-button { 4 | text-align: right; 5 | padding: 5px; 6 | } 7 | h4 { 8 | padding: 5px; 9 | } 10 | .brand > img { 11 | margin-top: -7px; 12 | } 13 | } 14 | .video-embed { 15 | border: 1px solid #CCC; 16 | border-radius: 3px; 17 | } 18 | .navbar-nav > li > a[name=profile] { 19 | padding: 10px 0; 20 | } 21 | .cat-pct { 22 | font-size: xx-small; 23 | text-align: center; 24 | padding: 5px 0; 25 | } 26 | .cat-disp { 27 | width: 19.5px; 28 | display: inline-block; 29 | } 30 | .cat-letter-rows { 31 | display: inline-block; 32 | } 33 | .nav { 34 | .personality-display { 35 | .cat-pct { 36 | display: none; 37 | } 38 | .img-circle { 39 | margin: -20px 0 -20px 0; 40 | } 41 | } 42 | } 43 | .personality-display { 44 | .img-circle { 45 | margin: -48px 0 -20px 0; 46 | } 47 | } 48 | .list-group-item-action:hover { 49 | background-color: #E5FFE5; 50 | } 51 | .list-group-item > label { 52 | width: 100%; 53 | } 54 | .dropdown:hover > .dropdown-menu { 55 | display: block; 56 | } 57 | .hide{ 58 | display: none; 59 | } 60 | .first-name{ 61 | color: rgb(169,169,169); 62 | margin-top: 15px; 63 | } 64 | #context-menu-div { 65 | display: none; 66 | } -------------------------------------------------------------------------------- /imports/ui/stylesheets/mbti_graph.less: -------------------------------------------------------------------------------- 1 | .mbtiGraph { 2 | width: 60%; 3 | background-image: url('/img/mbtiBackground.png'); 4 | background-repeat: no-repeat; 5 | background-position: center center; 6 | background-size: 54%; 7 | } 8 | .mbtiGraphMulti { 9 | width: 100%; 10 | background-image: url('/img/mbtiBackground.png'); 11 | background-repeat: no-repeat; 12 | background-position: center center; 13 | background-size: 54%; 14 | } 15 | .is-visible { 16 | visibility: visible; 17 | } 18 | .not-visible { 19 | visibility: hidden; 20 | } 21 | .table-fixed-head { 22 | width:100%; 23 | overflow-y: auto; 24 | overflow-x: visible; 25 | height: 600px; 26 | } 27 | 28 | .table-fixed-head thead th { 29 | position: sticky; 30 | background-color: #ffffff; 31 | top: 0; 32 | } 33 | @media (max-width: 576px) { 34 | .mbtiGraph { 35 | width: 100%; 36 | } 37 | .table-fixed-head { 38 | height: 200px; 39 | } 40 | } 41 | @media (min-width: 576px) and (max-width: 768px) { 42 | .mbtiGraph { 43 | width: 95%; 44 | } 45 | .table-fixed-head { 46 | height: 200px; 47 | } 48 | } 49 | @media (min-width: 768px) and (max-width: 992px) { 50 | .mbtiGraph { 51 | width: 90%; 52 | } 53 | .table-fixed-head { 54 | height: 400px; 55 | } 56 | } 57 | @media (min-width: 992px) and (max-width: 1200px) { 58 | .mbtiGraph { 59 | width: 80%; 60 | } 61 | .table-fixed-head { 62 | height: 500px; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /imports/ui/pages/mbti_results/mbti_results.js: -------------------------------------------------------------------------------- 1 | import './mbti_results.html'; 2 | import { User } from '/imports/api/users/users.js'; 3 | import { Meteor } from 'meteor/meteor'; 4 | 5 | Template.mbti_results.onCreated(function () { 6 | this.autorun( () => { 7 | console.log("autorunning mbti_results..."); 8 | this.subscription = this.subscribe('userList', Meteor.userId(), { 9 | onStop: function () { 10 | console.log("User List subscription stopped! ", arguments, this); 11 | }, 12 | onReady: function () { 13 | console.log("User List subscription ready! ", arguments, this); 14 | } 15 | }); 16 | console.log(this.subscription); 17 | }); 18 | }); 19 | 20 | Template.mbti_results.helpers({ 21 | users() { 22 | let u = User.find().fetch(); 23 | userData = []; 24 | u.forEach((m) => { 25 | let email = m.emails[0]; 26 | if (typeof email == "undefined") { email = "NO EMAIL ADDRESS"; } 27 | else { email = email.address; } 28 | userData.push({ 29 | _id: m._id, 30 | name: m.MyProfile.firstName + ' ' + m.MyProfile.lastName, 31 | pTypes: Object.keys(m.MyProfile.UserType.Personality), 32 | personality: m.MyProfile.UserType.Personality, 33 | email: email 34 | }); 35 | }); 36 | 37 | return userData; 38 | } 39 | }); -------------------------------------------------------------------------------- /imports/api/help/helperPages.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { HTTP } from 'meteor/http'; 3 | 4 | const helpBaseURL = Meteor.settings.public.Pages.Base.URL; 5 | const helpContext = Meteor.settings.public.Pages.Base.Context; 6 | const helpPassword= Meteor.settings.public.Pages.Base.Password; 7 | 8 | const HelperPages = { 9 | getPageBySlug(slug) { 10 | var url = this.getPageURL()+"&slug="+slug; 11 | 12 | // console.log('in helper:'); 13 | // console.log('helpBaseURL: ', helpBaseURL); 14 | // console.log('helpContext: ', helpContext); 15 | // console.log('helpPassword: ', helpPassword); 16 | 17 | return url; 18 | }, 19 | getPageURL() { 20 | let pass = Meteor.settings.public.Pages.Base.Password; 21 | var url= helpBaseURL+"?context="+helpContext+(pass != "" ? "&password="+pass : ""); 22 | return url; 23 | }, 24 | getPageObject(url) { 25 | console.log("Getting help page from "+url); 26 | const response = HTTP.get(url); 27 | return response.data; 28 | }, 29 | getPageObjectBySlug(slug) { 30 | var obj = this.getPageObject(this.getPageBySlug(slug)); 31 | if (Array.isArray(obj) && obj.length > 0) { 32 | var page = obj[0]; 33 | return page; 34 | } 35 | return {content:{rendered:""}}; 36 | }, 37 | getPageContentBySlug(slug) { 38 | var data= this.getPageObjectBySlug(slug).content.rendered; 39 | //console.log(data); 40 | return data; 41 | } 42 | }; 43 | 44 | export { HelperPages }; -------------------------------------------------------------------------------- /imports/api/parse_range/parse_range.js: -------------------------------------------------------------------------------- 1 | function parsePart(str) { 2 | // just a number 3 | if(/^-?\d+$/.test(str)) { 4 | return parseInt(str, 10); 5 | } 6 | var m; 7 | // 1-5 or 1..5 (equivilant) or 1...5 (doesn't include 5) 8 | if((m = str.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/))) { 9 | var lhs = m[1]; 10 | var sep = m[2]; 11 | var rhs = m[3]; 12 | if(lhs && rhs) { 13 | lhs = parseInt(lhs); 14 | rhs = parseInt(rhs); 15 | var res = []; 16 | var incr = lhs < rhs ? 1 : -1; 17 | 18 | // Make it inclusive by moving the right 'stop-point' away by one. 19 | if(sep == '-' || sep == '..' || sep == '\u2025') { 20 | rhs += incr; 21 | } 22 | 23 | for(var i=lhs; i != rhs; i += incr) res.push(i); 24 | return res; 25 | } 26 | } 27 | return []; 28 | } 29 | 30 | const parseRange = function(str) { 31 | var parts = str.split(','); 32 | 33 | var toFlatten = parts.map(function(el) { 34 | return parsePart(el); 35 | }); 36 | 37 | // reduce can't handle single element arrays 38 | if(toFlatten.length === 0) return []; 39 | if(toFlatten.length === 1) { 40 | if(Array.isArray(toFlatten[0])) 41 | return toFlatten[0]; 42 | return toFlatten; 43 | } 44 | 45 | return toFlatten.reduce(function(lhs, rhs) { 46 | if(!Array.isArray(lhs)) lhs = [lhs]; 47 | if(!Array.isArray(rhs)) rhs = [rhs]; 48 | return lhs.concat(rhs); 49 | }); 50 | }; 51 | 52 | export { parseRange }; 53 | -------------------------------------------------------------------------------- /client/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Developer Level App 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/user_dashboard.less: -------------------------------------------------------------------------------- 1 | .user-dashboard { 2 | background-color: #CCC; 3 | width: 95%; 4 | height: 100%; 5 | padding: 5px 20px; 6 | border-radius: 6px; 7 | background: url(/img/congruent_pentagon.png); 8 | 9 | .dashboard-pane { 10 | background-color: rgba(255, 255, 255, 0.5); 11 | border: 1px solid #d0d0d0; 12 | border-radius: 6px; 13 | height: 400px; 14 | overflow: auto; 15 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(0, 0, 0, 0.6); 16 | padding: 5px; 17 | margin: 5px -10px; 18 | cursor: pointer; 19 | 20 | &:hover { 21 | box-shadow: 0 1px 1px rgba(255, 255, 255, 0.075) inset, 0 0 8px rgba(255, 255, 255, 0.6); 22 | background-color: rgba(255, 255, 255, 0.65); 23 | } 24 | 25 | .container { 26 | width: auto; 27 | } 28 | /* learn share session */ 29 | .create-new-session { 30 | display: none; 31 | } 32 | .jumbotron { 33 | padding: 10px; 34 | margin-bottom: 10px; 35 | } 36 | /* team list */ 37 | #form-new-team { 38 | display: none; 39 | } 40 | /* teams administration */ 41 | .btn-expand,.btn-accept-join,.btn-decline-join { 42 | display: none; 43 | } 44 | /* questions */ 45 | &.App_home .container { 46 | margin-top: 0px; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /imports/ui/pages/results_descriptions/results_descriptions.html: -------------------------------------------------------------------------------- 1 | 30 | 31 | 37 | -------------------------------------------------------------------------------- /utils/db_backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #cd /home/ec2-user/prod_data 3 | #sudo docker exec production_database_1 /bin/bash -c 'cd /data/db && mongodump' 4 | #bak_date=`date +"%Y_%m_%d"` 5 | #tar -zcvf prod_db_$bak_date.tar.gz dump 6 | #mv prod_db_$bak_date.tar.gz /home/ec2-user/bak 7 | #scp -i ~/.ssh/rigel-alpha.pem /home/ec2-user/bak/prod_db_$bak_date.tar.gz ec2-user@stage.developerlevel.com:/home/ec2-user/ext_bak/ 8 | 9 | 10 | processLine() { 11 | line=$1 12 | dir_name="$(echo $line | sed 's/.\/\([^\/]*\)\/dump/\1/g')" 13 | bak_data=`date +"%Y_%m_%d"` 14 | file_name="$dir_name-$bak_data.tar.gz" 15 | echo "Processing $dir_name from $line to $file_name" 16 | pushd $line/.. 17 | pwd 18 | tar -zcvf $file_name dump 19 | mv $file_name ~ec2-user/bak 20 | if [ "$HOSTNAME" = "stage.developerlevel.com" ]; then 21 | echo "On stage, not copying remotely" 22 | else 23 | echo "On $HOSTNAME, sending backup to stage" 24 | ssh -i ~ec2-user/.ssh/rigel-alpha.pem ec2-user@stage.developerlevel.com "mkdir -p ~ec2-user/ext_bak/$HOSTNAME" 25 | scp -i ~ec2-user/.ssh/rigel-alpha.pem ~ec2-user/bak/$file_name ec2-user@stage.developerlevel.com:/home/ec2-user/ext_bak/$HOSTNAME 26 | fi 27 | popd 28 | pwd 29 | } 30 | export -f processLine 31 | sudo docker container ls --format '{{.Names}}' | grep 'database' | xargs -I{} /bin/bash -c "echo {}; sudo docker exec {} /bin/bash -c 'cd /data/db && mongodump'" 32 | pushd ~ec2-user 33 | find . -type d | grep dump\$ | grep -v src | xargs -t -n1 -P1 bash -c 'processLine "$@"' _ 34 | popd -------------------------------------------------------------------------------- /docker/dev/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:latest 2 | 3 | MAINTAINER Rick Golden "golden@golden-garage.net" 4 | 5 | # build arguments 6 | ARG APP_PACKAGES=curl\ gzip\ python\ build-essential\ git 7 | ARG APP_LOCALE=en_US 8 | ARG APP_CHARSET=UTF-8 9 | ARG APP_USER=app 10 | ARG APP_USER_DIR=/home/${APP_USER} 11 | 12 | # run environment 13 | ENV APP_PORT=${APP_PORT:-3000} 14 | ENV APP_ROOT=${APP_ROOT:-/app} 15 | 16 | # exposed ports and volumes 17 | EXPOSE $APP_PORT 18 | VOLUME $APP_ROOT 19 | 20 | # add packages for building NPM modules (required by Meteor) 21 | RUN DEBIAN_FRONTEND=noninteractive apt-get update && \ 22 | apt-get -y dist-upgrade && \ 23 | apt-get install -y ${APP_PACKAGES} && \ 24 | apt-get autoremove && \ 25 | apt-get clean 26 | 27 | # set the locale (required by Meteor) 28 | #RUN localedef ${APP_LOCALE}.${APP_CHARSET} -i ${APP_LOCALE} -f ${APP_CHARSET} 29 | 30 | # create a non-root user that can write to /usr/local (suggested by Meteor) 31 | RUN useradd -mUd ${APP_USER_DIR} ${APP_USER} 32 | RUN chown -Rh ${APP_USER} /usr/local 33 | 34 | # meteor installer doesn't work with the default tar binary 35 | RUN apt-get install -y bsdtar \ 36 | && cp $(which tar) $(which tar)~ \ 37 | && ln -sf $(which bsdtar) $(which tar) 38 | 39 | # install Meteor 40 | RUN curl https://install.meteor.com/ | sh 41 | 42 | # put back the original tar 43 | RUN mv $(which tar)~ $(which tar) 44 | 45 | USER ${APP_USER} 46 | 47 | # run Meteor from the app directory 48 | WORKDIR ${APP_ROOT} 49 | COPY entrypoint.sh / 50 | #RUN /usr/local/bin/meteor update 51 | 52 | ENTRYPOINT [ "/entrypoint.sh" ] 53 | -------------------------------------------------------------------------------- /imports/api/reports/reports.js: -------------------------------------------------------------------------------- 1 | import {Meteor} from 'meteor/meteor' 2 | import {Mongo} from 'meteor/mongo' 3 | import {Class} from 'meteor/jagi:astronomy' 4 | 5 | /** 6 | * Class to hold the report data 7 | * @param {Object} reportData - object containing the data for each report 8 | */ 9 | const Report = Class.create({ 10 | name: 'Report', 11 | fields: { 12 | reportData: { 13 | type: Object, 14 | } 15 | } 16 | }) 17 | 18 | 19 | /** 20 | * Class to hold the report metadata and the report object 21 | * @param {String} reportTitle - report title information 22 | * @param {String} description - report description 23 | * @param {Report} data - report data 24 | */ 25 | const Reports = Class.create({ 26 | name: 'Reports', 27 | collection: new Mongo.Collection('reports'), 28 | fields: { 29 | title: { 30 | type: String, 31 | }, 32 | description: { 33 | type: String, 34 | }, 35 | dateCreated: { 36 | type: Date, 37 | }, 38 | custom: { 39 | type: Boolean, 40 | }, 41 | data: { 42 | type: Report 43 | } 44 | }, 45 | // TODO: add helper functions 46 | helpers: { 47 | // addReport() 48 | // removeReport() 49 | // viewAllReports() 50 | // viewReportById() 51 | // viewReportByName() 52 | }, 53 | // TODO: Add update method 54 | meteorMethods: { 55 | // update() 56 | } 57 | }) 58 | 59 | // export modules here 60 | export {Report, Reports} 61 | -------------------------------------------------------------------------------- /imports/api/reports/methods.js: -------------------------------------------------------------------------------- 1 | import { Reports, Report } from './reports.js' 2 | import { mbtiReport, qnaireMbtiReport } from './customReports.js'; 3 | 4 | Meteor.methods({ 5 | // MBTI report 6 | 'addMBTIReport': function () { 7 | let mbti = new mbtiReport(); 8 | mbti.addMBTIReport(); 9 | }, 10 | 'updateMBTIReport': function () { 11 | let currentMBTI = Reports.findOne({title: 'Legacy Trait Spectrum'}) 12 | let newMBTI = new mbtiReport() 13 | if(currentMBTI) { 14 | return Reports.update(currentMBTI._id, { 15 | title: 'Legacy Trait Spectrum', 16 | description: 'Legacy Trait Spectrum Results for all team members', 17 | dateCreated: new Date(), 18 | custom: true, 19 | data: newMBTI.createMBTIReport() 20 | }) 21 | } 22 | return false; 23 | }, 24 | // Qnaire MBTI report 25 | 'addQnaireMBTIReport': function () { 26 | let qnaireMbti = new qnaireMbtiReport(); 27 | qnaireMbti.addQnaireMBTIReport(); 28 | }, 29 | 'updateQnaireMBTIReport': function () { 30 | let currentMBTI = Reports.findOne({title: 'Trait Spectrum'}) 31 | let newMBTI = new qnaireMbtiReport() 32 | return Reports.update(currentMBTI._id, { 33 | title: 'Trait Spectrum', 34 | description: 'Trait Spectrum Results for all team members', 35 | dateCreated: new Date(), 36 | custom: true, 37 | data: newMBTI.createQnaireMBTIReport() 38 | }) 39 | }, 40 | 41 | }) -------------------------------------------------------------------------------- /imports/api/qnaire/methods.js: -------------------------------------------------------------------------------- 1 | import { Qnaire, QQuestion } from './qnaire.js'; 2 | 3 | Meteor.methods({ 4 | 'qnaire.createNewQnaire'(newQnaire) { 5 | /*if ( !Roles.userIsInRole(Meteor.userId(), ['admin'], Roles.GLOBAL_GROUP) ) { 6 | throw new Meteor.Error(403, "You are not authorized"); 7 | }*/ 8 | 9 | //newQnaire.CreatedBy = Meteor.userId(); 10 | let q = new Qnaire(newQnaire); 11 | return q.save(); 12 | }, 13 | 'qnaire.DeleteQuestion'(qnaireId, label) { 14 | let q = Qnaire.findOne({ _id: qnaireId }) 15 | q.deleteQuestion(qnaireId, label) 16 | }, 17 | 'qnaire.checkEditDisabled' (qnrid, label) { 18 | console.log('im running checkEditDisabled') 19 | console.log(qnrid) 20 | console.log(label) 21 | let q = Qnaire.findOne({ _id: qnrid }) 22 | q.disableQuestionEdit(label) 23 | }, 24 | 'qnaire.deleteQnaire' (qnaireId) { 25 | let q = Qnaire.findOne({ _id: qnaireId }) 26 | q.deleteQnaire( qnaireId ) 27 | }, 28 | 'qnaire.deactivateQuestion' (qnrid, label, checkedStatus) { 29 | let q = Qnaire.findOne({ _id: qnrid }) 30 | q.deactivateQuestion(qnrid, label, checkedStatus) 31 | }, 32 | 'qnaire.getIdByTitle' (t) { 33 | let q = Qnaire.findOne({title: t}); 34 | if(q) { 35 | return q._id; 36 | } 37 | return false; 38 | }, 39 | 'qnaire.getQnaireByTitle' (t) { 40 | let q = Qnaire.findOne({title: t}); 41 | if(q) { 42 | return q; 43 | } 44 | return false; 45 | } 46 | }); -------------------------------------------------------------------------------- /imports/api/qnaire/server/qnair.js: -------------------------------------------------------------------------------- 1 | import { HelperPages } from '../../help/helperPages.js'; 2 | import { Qnaire } from '../qnaire.js'; 3 | 4 | const cacheTTL = Meteor.settings.public.Pages.Base.CacheTTL; 5 | 6 | Qnaire.extend({ 7 | meteorMethods: { 8 | getIntroHTML() { 9 | var date = new Date(); 10 | //date.setDate(date.getDate() - 15); 11 | date.setMinutes(date.getMinutes() - cacheTTL); 12 | if(date < this.lastCheckedIntro) { return this.introCache; } 13 | if(this.introSlug == "") { 14 | this.introSlug = this.title.toLowerCase().replace(/[^\w]+/g, "-")+"-introduction"; 15 | console.log("Setting intro slug: "+this.introSlug); 16 | } 17 | var content = HelperPages.getPageContentBySlug(this.introSlug); 18 | this.introCache = content; 19 | this.lastCheckedIntro = new Date(); 20 | this.save(); 21 | }, 22 | getInstructionHTML() { 23 | var date = new Date(); 24 | //date.setDate(date.getDate() - 15); 25 | date.setMinutes(date.getMinutes() - cacheTTL); 26 | if(date < this.lastCheckedInstruction) { return this.instructionCache; } 27 | if(this.instructionSlug == "") { 28 | this.instructionSlug = this.title.toLowerCase().replace(/[^\w]+/g, "-")+"-instructions"; 29 | console.log("Setting instruction slug: "+this.instructionSlug); 30 | } 31 | var content = HelperPages.getPageContentBySlug(this.instructionSlug); 32 | this.instructionCache = content; 33 | this.lastCheckedInstruction = new Date(); 34 | this.save(); 35 | } 36 | } 37 | }); 38 | 39 | export { Qnaire }; 40 | -------------------------------------------------------------------------------- /imports/ui/pages/qnaire/slider.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imports/ui/pages/question_responses/question_responses.test.js: -------------------------------------------------------------------------------- 1 | 2 | import { Meteor } from 'meteor/meteor'; 3 | import { resetDatabase } from 'meteor/xolvio:cleaner'; 4 | import { User } from '/imports/api/users/users.js'; 5 | import { chai } from 'meteor/practicalmeteor:chai'; 6 | /* 7 | import { Question } from '/imports/api/questions/questions.js'; 8 | import { PolarStats } from '/imports/api/questions/questions.js'; 9 | import { Defaults } from '/imports/startup/both/defaults.js'; 10 | import { Answer } from "/imports/api/users/users.js"; 11 | import { UserType } from "/imports/api/users/users.js"; 12 | import { Profile } from "/imports/api/users/users.js"; 13 | import { UserNotify } from '/imports/api/user_notify/user_notify.js'; 14 | import '/imports/startup/both/at_config.js'; 15 | import { Random } from 'meteor/random' 16 | */ 17 | 18 | if (Meteor.isServer) { 19 | describe('Question Responses', function () { 20 | it('can create a new non admin user', function testCreateUser(done) { 21 | resetDatabase() 22 | FactoryBoy.create("nonAdminUser1", { _id: "1234567899912839" }) 23 | let dbLookupUser = User.findOne({ _id: "1234567899912839" }) 24 | chai.assert(dbLookupUser !== undefined, "Non Admin User was not created") 25 | done() 26 | }) 27 | it('can create a new admin user', function testCreateAdminUser(done) { 28 | resetDatabase() 29 | FactoryBoy.create("adminUser1", { _id: '999' }) 30 | let dbLookupUser = User.findOne({_id: "999"}) 31 | chai.assert(dbLookupUser !== undefined, "Admin User was not created") 32 | done() 33 | }); 34 | }); 35 | } -------------------------------------------------------------------------------- /imports/ui/pages/mvp/server/tmp_pp.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { Qnaire,QuestionType,QQuestion } from '/imports/api/qnaire/qnaire.js'; 3 | import { User } from '/imports/api/users/users.js'; 4 | 5 | Meteor.methods({ 6 | 'tmp_pp'(v) { 7 | function hashCode (t){ 8 | var hash = 0; 9 | if (t.length === 0) return hash; 10 | for (i = 0; i < t.length; i++) { 11 | char = t.charCodeAt(i); 12 | hash = ((hash<<5)-hash)+char; 13 | hash = hash & hash; // Convert to 32bit integer 14 | } 15 | return hash; 16 | } 17 | 18 | vp = v.split('@'); 19 | 20 | let pp = hashCode('T3mpP@$$'+v); 21 | let val = ''; 22 | 23 | if(Array.isArray(vp)) { 24 | val = vp[0]+Math.abs(pp); 25 | } else { 26 | val = Math.abs(pp); 27 | } 28 | 29 | let exists = false; 30 | let u = User.find({"emails.address": v}).fetch(); 31 | if(u.length < 1) { 32 | Accounts.createUser({ 33 | username: v, 34 | email: v, 35 | password: val, 36 | profile: { 37 | first_name: 'Temp', 38 | last_name: 'User', 39 | gender: 'unknown' 40 | } 41 | }); 42 | } else { 43 | exists = true; 44 | } 45 | 46 | return [val,exists]; 47 | }, 48 | 'find_trait_spectrum'() { 49 | let q = Qnaire.findOne({ title: 'Trait Spectrum' }); 50 | 51 | return q; 52 | } 53 | }); -------------------------------------------------------------------------------- /imports/api/learn_share/methods.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { LearnShareSession } from './learn_share.js'; 3 | 4 | var formattedDate = () => { 5 | let d = new Date(); 6 | let year = d.getFullYear(); 7 | let month = d.getMonth() + 1; 8 | let day = d.getDate(); 9 | return (year +"-"+ ("00"+month).slice(-2) +"-"+ ("00"+day).slice(-2)); 10 | } 11 | 12 | var randomChars = () => { 13 | var text = ""; 14 | var idLength = 2; 15 | var possible = "acdeghijklmnopqrstuvwxyz"; 16 | 17 | for (var i = 0; i < idLength; i++) { 18 | text += possible.charAt(Math.floor(Math.random() * possible.length)); 19 | } 20 | 21 | return text; 22 | } 23 | 24 | var lssidGenerate = () => { 25 | return (formattedDate() + "-" + randomChars()); 26 | } 27 | Meteor.methods({ 28 | 'learnshare.createNewSession'(sessTitle, teamId) { 29 | if (!Roles.userIsInRole(Meteor.userId(), ['admin','learn-share-host'], Roles.GLOBAL_GROUP)) { 30 | throw new Meteor.Error(403, "You are not authorized"); 31 | } 32 | 33 | let lssid = lssidGenerate(); 34 | 35 | let newSession = new LearnShareSession({ 36 | _id: lssid, 37 | title: sessTitle, 38 | teamId: teamId 39 | }); 40 | newSession.save(); 41 | return lssid; 42 | }, 43 | 'learnshare.recordingExists'(fname) { 44 | let fs = Npm.require('fs'); 45 | let uploadPath = '/uploads/'; 46 | console.log("exist",uploadPath+fname+".mp4"); 47 | if (fs.existsSync(uploadPath+fname+".mp4")) { 48 | return true; 49 | } else { 50 | return false; 51 | } 52 | } 53 | }) 54 | -------------------------------------------------------------------------------- /imports/ui/pages/weak_questions/weak_questions.html: -------------------------------------------------------------------------------- 1 | 40 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/tsq.less: -------------------------------------------------------------------------------- 1 | 2 | .tsq { 3 | margin-top: 60px; 4 | margin-bottom: 10px; 5 | } 6 | 7 | .panel { 8 | &-heading { 9 | text-align: center; 10 | font-size: 16px; 11 | padding: 5px 15px; 12 | } 13 | 14 | &-body { 15 | div, p { 16 | .subtitles { 17 | font-weight: 500; 18 | font-size: 20px; 19 | } 20 | .descriptions, .list-group-item, .list-group-item label { 21 | font-size: 16px; 22 | font-weight: 400; 23 | } 24 | } 25 | .lang_name { 26 | background: #eee; 27 | padding: 3px 5px; 28 | border: 1px solid #eee; 29 | border-radius: 4px; 30 | font-size: 18px; 31 | font-weight: 600; 32 | } 33 | } 34 | } 35 | 36 | .overview-widget .panel-footer { 37 | text-align: right; 38 | } 39 | .progress-amount td { 40 | font-size: 1px; 41 | text-align: center; 42 | vertical-align: bottom; 43 | } 44 | 45 | .mb_0 { 46 | margin-bottom: 0; 47 | } 48 | 49 | .select-autocomplete { 50 | position: relative; 51 | display: block; 52 | .loading { 53 | position: absolute; 54 | top: 0; 55 | bottom: 0; 56 | left: 0; 57 | right: 0; 58 | margin: auto; 59 | z-index: 999; 60 | text-align: center; 61 | vertical-align: middle; 62 | background: rgba(255,255,255,0.5); 63 | display: none; 64 | } 65 | } 66 | 67 | .selectize-control::before { 68 | content: ' '; 69 | z-index: 2; 70 | position: absolute; 71 | display: block; 72 | top: 12px; 73 | right: 34px; 74 | width: 16px; 75 | height: 16px; 76 | background: url(img/loading.gif); 77 | background-size: 16px 16px; 78 | opacity: 0; 79 | } 80 | .selectize-control.loading1::before { 81 | opacity: 1; 82 | } -------------------------------------------------------------------------------- /imports/startup/server/defaults.js: -------------------------------------------------------------------------------- 1 | import { Team } from '../../api/teams/teams.js'; 2 | import { Meteor } from 'meteor/meteor'; 3 | 4 | const SrvDefaults = { 5 | 'user': { 6 | 'password': 'admin' 7 | }, 8 | 'uploadPath': '/uploads/' 9 | } 10 | 11 | Meteor.methods({ 12 | insertTeams: function () { 13 | Team.insert({ 14 | Name: "TeamDev", 15 | Description: "Team of developers" 16 | }); 17 | }, 18 | }) 19 | 20 | if (typeof Meteor.settings.private == "undefined") { 21 | Meteor.settings.private = { }; 22 | } 23 | if (typeof Meteor.settings.private.GRF_URL == "undefined") { 24 | Meteor.settings.private.GRF_URL = "http://giraffe:3100/grf/"; 25 | } 26 | if (typeof Meteor.settings.private.TSQ_URL == "undefined") { 27 | Meteor.settings.private.TSQ_URL = "http://tsqapp:4000/tsq/"; 28 | } 29 | if (typeof Meteor.settings.private.Pages == "undefined") { 30 | Meteor.settings.private.Pages = {}; 31 | } 32 | if (typeof Meteor.settings.private.Pages.TSQ == "undefined") { 33 | Meteor.settings.private.Pages.TSQ = { 34 | Slug: { 35 | Intro : "technical-skills-questionnaire-introduction", 36 | Instructions : "technical-skills-questionnaire-instructions" 37 | } 38 | }; 39 | } 40 | if (typeof Meteor.settings.private.Pages.TraitSpectrum == "undefined") { 41 | Meteor.settings.private.Pages.TraitSpectrum = { 42 | Slug: { 43 | Intro : "trait-spectrum-introduction", 44 | Instructions : "trait-spectrum-instructions" 45 | } 46 | } 47 | } 48 | if (typeof Meteor.settings.private.Queue) { 49 | Meteor.settings.private.Queue = { 50 | "Redis": { 51 | "server": "redis", 52 | "port": 6379 53 | } 54 | }; 55 | } 56 | 57 | export { SrvDefaults }; 58 | -------------------------------------------------------------------------------- /imports/ui/pages/results/results.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imports/startup/server/register-api.js: -------------------------------------------------------------------------------- 1 | // Register your apis here 2 | 3 | import '../../api/questions/methods.js'; 4 | import '../../api/questions/server/publications.js'; 5 | import '../../api/users/methods.js'; 6 | import '../../api/users/server/publications.js'; 7 | import '../../api/type_readings/methods.js'; 8 | import '../../api/type_readings/server/publications.js'; 9 | import '../../api/teams/methods.js'; 10 | import '../../api/teams/server/publications.js'; 11 | import '../../api/learn_share/server/publications.js'; 12 | import '../../api/learn_share/methods.js'; 13 | import '../../api/roles/server/publications.js'; 14 | import '../../api/timer/server/publications.js'; 15 | import '../../api/timer/methods.js'; 16 | import '../../api/user_segments/server/publications.js'; 17 | import '../../api/user_segments/methods.js'; 18 | import '../../api/user_feedback/server/publications.js'; 19 | import '../../api/user_feedback/methods.js'; 20 | import '../../api/qnaire/methods.js'; 21 | import '../../api/qnaire/server/qnair.js'; 22 | import '../../api/qnaire_data/methods.js'; 23 | import '../../api/qnaire/server/publications.js'; 24 | import '../../api/qnaire_data/server/publications.js'; 25 | import '../../api/user_notify/server/publications.js'; 26 | import '../../api/reports/reports.js'; 27 | import '../../api/reports/customReports.js'; 28 | import '../../api/reports/methods.js'; 29 | import '../../api/reports/server/publications.js'; 30 | import '../../api/tsq/server/publications'; 31 | import '../../api/tsq/methods.js'; 32 | import '../../api/tsq/tsq.js'; 33 | import '../../ui/pages/mvp/server/tmp_pp.js'; 34 | import '../../api/airtable/methods.js'; 35 | import '../../api/restrictedRoutes/restrictedRoutes.js'; 36 | import '../../api/restrictedRoutes/methods.js'; 37 | import '../../api/grf/methods.js'; 38 | -------------------------------------------------------------------------------- /imports/ui/components/begin/begin.html: -------------------------------------------------------------------------------- 1 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /imports/ui/pages/user_segments/user_segments.html: -------------------------------------------------------------------------------- 1 | 36 | -------------------------------------------------------------------------------- /imports/ui/pages/qnaire_list/qnaire_list.js: -------------------------------------------------------------------------------- 1 | import { Qnaire } from '/imports/api/qnaire/qnaire.js'; 2 | import './qnaire_list.html'; 3 | import { ReactiveVar } from "meteor/reactive-var"; 4 | 5 | Template.qnaire_list.onCreated(function () { 6 | this.autorun( () => { 7 | this.subscription = this.subscribe('qnaire', { 8 | onStop: function () { 9 | console.log("Qnaire subscription stopped! ", arguments, this); 10 | }, 11 | onReady: function () { 12 | console.log("Qnaire subscription ready! ", arguments, this); 13 | } 14 | }); 15 | this.currentQnrid = new ReactiveVar() 16 | }); 17 | }); 18 | Template.qnaire_list.helpers({ 19 | questionnaires() { 20 | console.log('????'); 21 | let q = Qnaire.find( ); 22 | console.log("ppppppppppppppppp",q.fetch()); 23 | if (!q) { 24 | return []; 25 | } 26 | return q.fetch(); 27 | } 28 | }); 29 | Template.qnaire_list.events({ 30 | 'click button#create-qnaire'(event, instance) { 31 | let newQnaire = { title: $("#new-qnaire-title").val(), description: $("#new-qnaire-descr").val() }; 32 | Meteor.call('qnaire.createNewQnaire', newQnaire, function (err, rslt) { 33 | console.log(err, rslt); 34 | }) 35 | }, 36 | 'click button.delete-qnaire' (event, instance) { 37 | let qnrid = $(event.target).data('qnrid') 38 | Template.instance().currentQnrid.set(qnrid) 39 | 40 | $('#confirm-delete').modal() 41 | }, 42 | 'click button#delete' (event, instance) { 43 | qnrid = Template.instance().currentQnrid.get() 44 | Meteor.call('qnaire.deleteQnaire', qnrid, function (err, rslt) { 45 | (err) ? console.log(err) : console.log(rslt) 46 | }) 47 | $('#confirm-delete').modal('hide') 48 | } 49 | }); 50 | -------------------------------------------------------------------------------- /.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-base@1.4.0 # Packages every Meteor app needs to have 8 | mobile-experience@1.0.5 # Packages for a great mobile UX 9 | mongo@1.6.2 # The database Meteor supports right now 10 | blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views 11 | reactive-var@1.0.11 # Reactive variable for tracker 12 | tracker@1.2.0 # Meteor's client-side reactive programming library 13 | 14 | standard-minifier-css@1.5.3 # CSS minifier run for production mode 15 | es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers 16 | ecmascript@0.12.4 # Enable ECMAScript2015+ syntax in app code 17 | shell-server@0.4.0 # Server-side component of the `meteor shell` command 18 | 19 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping) 20 | practicalmeteor:chai 21 | useraccounts:bootstrap 22 | useraccounts:flow-routing 23 | kadira:flow-router 24 | kadira:blaze-layout 25 | reywood:publish-composite 26 | rcy:nouislider 27 | alanning:roles 28 | jeremy:selectize 29 | underscore@1.0.10 30 | meteortesting:mocha 31 | twbs:bootstrap 32 | jquery 33 | accounts-ui@1.3.1 34 | accounts-password@1.5.1 35 | less@2.8.0 36 | session@1.2.0 37 | jparker:gravatar 38 | tsega:bootstrap3-datetimepicker 39 | jagi:astronomy 40 | jagi:astronomy-softremove-behavior 41 | jagi:astronomy-timestamp-behavior 42 | jagi:astronomy-slug-behavior 43 | email@1.2.3 44 | xolvio:cleaner 45 | abernix:minifier-js 46 | cultofcoders:persistent-session 47 | aldeed:template-extension 48 | sungwoncho:factory-boy 49 | dburles:factory 50 | practicalmeteor:sinon 51 | meteorhacks:ssr 52 | http@1.4.2 53 | lmieulet:meteor-coverage 54 | -------------------------------------------------------------------------------- /imports/ui/components/behavior_pattern_area/behavior_pattern_area_call.js: -------------------------------------------------------------------------------- 1 | import "./behavior_pattern_area_render.html"; 2 | import { User } from "/imports/api/users/users.js"; 3 | import { behavior_pattern_area } from "./behavior_pattern_area.js"; 4 | import { Template } from "meteor/templating"; 5 | 6 | Template.behavior_pattern_area_render.onCreated(function() { 7 | this.autorun(() => { 8 | this.subscription2 = this.subscribe("userList", this.userId, { 9 | onStop: function() { 10 | console.log("User List subscription stopped! ", arguments, this); 11 | }, 12 | onReady: function() { 13 | console.log("User List subscription ready! ", arguments, this); 14 | } 15 | }); 16 | let handle = Meteor.subscribe('qnaire'); 17 | let handle2 = Meteor.subscribe('qnaireData'); 18 | let handle3 = Meteor.subscribe('userData'); 19 | }); 20 | }); 21 | 22 | Template.behavior_pattern_area_render.onRendered(function() { 23 | //let canvas = $("#bpaCanvas").get(0); 24 | let userId = this.data.mbtiUID; 25 | let user = User.findOne({ _id: userId }); 26 | let personality = user.MyProfile.UserType.Personality 27 | 28 | console.log('bpa1'); 29 | //let tsEval = eval(user.MyProfile.traitSpectrumQnaire('categoryLetters')); 30 | console.log('bpa2'); 31 | 32 | let valueIE = personality.IE.Value 33 | let valueNS = personality.NS.Value 34 | let valueTF = personality.TF.Value 35 | let valueJP = personality.JP.Value 36 | console.log("personality values",valueIE, valueNS, valueTF, valueJP) 37 | behavior_pattern_area(valueIE, valueNS, valueTF, valueJP, '0.5', '0, 0, 0', $("#grfBehavior"), 50); 38 | // behavior_pattern_area(canvas, -50, 50, 20, -20, 0.5, '128, 0, 0'); 39 | 40 | // ----uncomment for random personality---- 41 | // function rn() { 42 | // return (Math.random() * 100) -50 43 | // } 44 | // behavior_pattern_area(canvas, rn(), rn(), rn(), rn(), 0.5, '0, 0, 0'); 45 | }); 46 | -------------------------------------------------------------------------------- /imports/ui/pages/results/results.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from "meteor/meteor"; 2 | import { User } from "../../../api/users/users.js"; 3 | import "./results.html"; 4 | 5 | Template.results.onCreated(function() { 6 | if (this.data.userId) { 7 | this.userId = this.data.userId; 8 | } else { 9 | this.userId = Meteor.userId(); 10 | } 11 | }); 12 | 13 | Template.results.helpers({ 14 | user() { 15 | let user = User.findOne({ _id: Template.instance().userId }); 16 | return user; 17 | }, 18 | 19 | results(category, userObj, mbtiNumber) { 20 | if(typeof userObj == "undefined") { return 0; } 21 | let identifier = userObj.MyProfile.UserType.Personality.getIdentifierById( 22 | category 23 | ); 24 | 25 | let identifierValue = 26 | userObj.MyProfile.UserType.Personality[identifier].Value; 27 | 28 | let percentageValue = 29 | userObj.MyProfile.UserType.Personality[ 30 | userObj.MyProfile.UserType.Personality.getIdentifierById(category) 31 | ]; 32 | 33 | let percentage = Math.ceil(Math.abs(percentageValue.Value)); 34 | 35 | //checking if INTJ on screen and if user personality is INT or J 36 | if (mbtiNumber === 6 && identifierValue < 0) { 37 | return 50 + percentage; 38 | //checking if INTJ on screen and if user personality is ESF or P 39 | } else if (mbtiNumber === 6 && identifierValue > 0) { 40 | return 50 - percentage; 41 | } 42 | 43 | //checking if ESFP on screen and if user personality is ESF or P 44 | if (mbtiNumber === 7 && identifierValue > 0) { 45 | return 50 + percentage; 46 | //checking if ESFP on screen and if user personality is INT or J 47 | } else if (mbtiNumber === 7 && identifierValue < 0) { 48 | return 50 - percentage; 49 | } 50 | } 51 | }); 52 | 53 | Template.results.events({ 54 | "click a#results_descriptions"(event, instance) { 55 | event.preventDefault(); 56 | FlowRouter.go("/resultsDescriptions"); 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /imports/api/restrictedRoutes/restrictedRoutes.js: -------------------------------------------------------------------------------- 1 | import { Mongo } from 'meteor/mongo'; 2 | import { Class, Enum } from 'meteor/jagi:astronomy'; 3 | 4 | const RestrictedRoutes = Class.create({ 5 | name: "RestrictedRoutes", 6 | collection: new Mongo.Collection('restrictedRoutes'), 7 | fields: { 8 | routeName: { 9 | type: String, 10 | default: '' 11 | }, 12 | teamNames: { 13 | type: [String], 14 | default: ['Developer'] 15 | }, 16 | }, 17 | indexes: { 18 | nameIndex: { 19 | fields: { 20 | routeName: 1 21 | }, 22 | options: { 23 | unique: true 24 | }, 25 | } 26 | }, 27 | meteorMethods: { 28 | 29 | }, 30 | helpers: { 31 | addTeams(teams) { 32 | if (typeof teams === 'string') { 33 | teams = [teams]; 34 | } 35 | for (let i = 0; i < teams.length; i++) { 36 | if (this.teamNames.indexOf(teams[i]) === -1) { 37 | this.teamNames.push( teams[i] ); 38 | } 39 | } 40 | this.save(); 41 | }, 42 | removeTeams(teams) { 43 | if (typeof teams === 'string') { 44 | teams = [teams]; 45 | } 46 | for (let i = 0; i < teams.length; i++) { 47 | let idx = this.teamNames.indexOf(teams[i]); 48 | if (idx !== -1) { 49 | this.teamNames.splice( idx, 1 ); 50 | } 51 | } 52 | this.save(); 53 | } 54 | }, 55 | behaviors: { 56 | timestamp: {}, 57 | softremove: {} 58 | }, 59 | secured: { 60 | }, 61 | events: { 62 | afterInit(e) { 63 | // 64 | }, 65 | beforeSave(e) { 66 | // 67 | } 68 | } 69 | }); 70 | 71 | export { RestrictedRoutes }; -------------------------------------------------------------------------------- /imports/ui/pages/user_dashboard/user_dashboard.js: -------------------------------------------------------------------------------- 1 | import { User } from '/imports/api/users/users.js'; 2 | import './user_dashboard.html'; 3 | import '/imports/ui/pages/learn_share_list/learn_share_list.js'; 4 | import '/imports/ui/pages/home/home.js'; 5 | 6 | Template.user_dashboard.onCreated(function () { 7 | // 8 | }); 9 | 10 | Template.user_dashboard.helpers({ 11 | dashboardPanes() { 12 | let u = User.findOne( {_id: Meteor.userId()} ); 13 | if (u && "undefined" !== typeof u.MyProfile.dashboardPanes && u.MyProfile.dashboardPanes.length > 0) { 14 | return u.MyProfile.dashboardPanes; 15 | } else { 16 | return [ 17 | { 18 | size: 6, 19 | name: 'admin_teams', 20 | title: 'Teams', 21 | route: '/adminTeams', 22 | data: {} 23 | }, 24 | { 25 | size: 6, 26 | name: 'learn_share_list', 27 | title: 'Learn/Share', 28 | route: '/learnShareList', 29 | data: {} 30 | }, 31 | { 32 | size: 6, 33 | name: 'user_profile', 34 | title: 'Profile', 35 | route: '/profile', 36 | data: {} 37 | }, 38 | { 39 | size: 12, 40 | name: 'App_home', 41 | title: 'Questions', 42 | route: '/', 43 | data: {} 44 | }, 45 | ]; 46 | } 47 | } 48 | }) 49 | 50 | Template.user_dashboard.events({ 51 | 'click div.dashboard-pane'(event, instance) { 52 | let target = $(event.target).data("route"); 53 | if ("undefined" === target) { 54 | return; 55 | } 56 | FlowRouter.go(target); 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /imports/api/restrictedRoutes/restrictedRoutes.js.orig: -------------------------------------------------------------------------------- 1 | import { Mongo } from 'meteor/mongo'; 2 | import { Class, Enum } from 'meteor/jagi:astronomy'; 3 | 4 | const RestrictedRoutes = Class.create({ 5 | name: "RestrictedRoutes", 6 | collection: new Mongo.Collection('restrictedRoutes'), 7 | fields: { 8 | routeName: { 9 | type: String, 10 | default: '' 11 | }, 12 | teamNames: { 13 | type: [String], 14 | default: ['Developer'] 15 | }, 16 | }, 17 | indexes: { 18 | nameIndex: { 19 | fields: { 20 | routeName: 1 21 | }, 22 | options: { 23 | unique: true 24 | }, 25 | } 26 | }, 27 | meteorMethods: { 28 | 29 | }, 30 | helpers: { 31 | addTeams(teams) { 32 | if (typeof teams === 'string') { 33 | teams = [teams]; 34 | } 35 | for (let i = 0; i < teams.length; i++) { 36 | if (this.teamNames.indexOf(teams[i]) === -1) { 37 | this.teamNames.push( teams[i] ); 38 | } 39 | } 40 | this.save(); 41 | }, 42 | removeTeams(teams) { 43 | if (typeof teams === 'string') { 44 | teams = [teams]; 45 | } 46 | for (let i = 0; i < teams.length; i++) { 47 | let idx = this.teamNames.indexOf(teams[i]); 48 | if (idx !== -1) { 49 | this.teamNames.splice( idx, 1 ); 50 | } 51 | } 52 | this.save(); 53 | } 54 | }, 55 | behaviors: { 56 | timestamp: {}, 57 | softremove: {} 58 | }, 59 | secured: { 60 | }, 61 | events: { 62 | afterInit(e) { 63 | // 64 | }, 65 | beforeSave(e) { 66 | // 67 | } 68 | } 69 | }); 70 | 71 | export { RestrictedRoutes }; -------------------------------------------------------------------------------- /imports/ui/pages/user_segments/user_segments.js: -------------------------------------------------------------------------------- 1 | import { UserSegment } from '/imports/api/user_segments/user_segments.js'; 2 | import './user_segments.html'; 3 | 4 | Template.user_segments.onCreated(function () { 5 | this.autorun( () => { 6 | this.subscription = this.subscribe('segmentList', this.userId, { 7 | onStop: function () { 8 | console.log("Segment List subscription stopped! ", arguments, this); 9 | }, 10 | onReady: function () { 11 | console.log("Segment List subscription ready! ", arguments, this); 12 | } 13 | }); 14 | console.log(this.subscription); 15 | }); 16 | }); 17 | 18 | Template.user_segments.helpers({ 19 | segmentList() { 20 | let s = UserSegment.find(); 21 | return s.fetch(); 22 | } 23 | }); 24 | 25 | Template.user_segments.events({ 26 | 'keyup input.edit':_.debounce(function (event, instance) { 27 | let segid = $(event.target).closest("[data-segid]").data("segid"); 28 | console.log(segid, $(event.target).closest("[data-segid]")); 29 | let s = UserSegment.findOne( {_id:segid} ); 30 | let name = $("#seg-name-"+segid).val(); 31 | let dscr = $("#seg-dscr-"+segid).val(); 32 | s.update(name, dscr); 33 | }, 2000), 34 | 'keyup input.new':_.debounce(function (event, instance) { 35 | if ($("#seg-name-new").val() !== "") { 36 | $("#new-seg-save").prop("disabled", false); 37 | } else { 38 | $("#new-seg-save").prop("disabled", true); 39 | } 40 | }, 2000), 41 | 'click #new-seg-save'(event, instance) { 42 | if ($("#seg-name-new").val() !== "") { 43 | let name = $("#seg-name-new").val(); 44 | let dscr = $("#seg-dscr-new").val(); 45 | Meteor.call('segment.createNewSegment', name, dscr); 46 | $("#seg-name-new").val(""); 47 | $("#seg-dscr-new").val(""); 48 | } 49 | } 50 | }); 51 | -------------------------------------------------------------------------------- /imports/ui/pages/tsq/results_summary/results_summary.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /nightwatch.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_folders" : ["tests"], 3 | "output_folder" : "reports", 4 | "custom_commands_path" : "", 5 | "custom_assertions_path" : "", 6 | "page_objects_path" : "", 7 | "globals_path" : "", 8 | 9 | "selenium" : { 10 | "start_process" : false, 11 | "server_path" : "/opt/selenium/selenium-server-standalone.jar", 12 | "log_path" : "", 13 | "port" : 4444, 14 | "cli_args" : { 15 | "webdriver.gecko.driver" : "./bin/geckodriver", 16 | "webdriver.chrome.driver" : "/opt/selenium/chromedriver-2.35", 17 | "webdriver.edge.driver" : "" 18 | } 19 | }, 20 | 21 | "test_settings" : { 22 | "default" : { 23 | "launch_url" : "http://localhost:3000", 24 | "selenium_port" : 4444, 25 | "selenium_host" : "localhost", 26 | "silent": true, 27 | "screenshots" : { 28 | "enabled" : false, 29 | "path" : "" 30 | }, 31 | "desiredCapabilities": { 32 | "browserName": "chrome", 33 | "javascriptEnabled": true, 34 | "acceptSslCerts": true, 35 | "chromeOptions" : { 36 | "args" : ["--headless", "--no-sandbox", "--disable-gpu", "--verbose", "--incognito"] 37 | }, 38 | "marionette": true 39 | } 40 | }, 41 | 42 | "gecko" : { 43 | "desiredCapabilities": { 44 | "browserName": "gecko" 45 | } 46 | }, 47 | 48 | "chrome" : { 49 | "desiredCapabilities": { 50 | "browserName": "chrome" 51 | } 52 | }, 53 | 54 | "geckoHide" : { 55 | "desiredCapabilities": { 56 | "browserName": "gecko", 57 | "moz:firefoxOptions": { 58 | "args": ["--headless"] 59 | } 60 | } 61 | }, 62 | 63 | "chromeHide" : { 64 | "desiredCapabilities": { 65 | "browserName": "chrome", 66 | "chromeOptions": { 67 | "args": ["--headless"] 68 | } 69 | } 70 | }, 71 | 72 | "edge" : { 73 | "desiredCapabilities": { 74 | "browserName": "MicrosoftEdge" 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /imports/ui/stylesheets/admin_teams.less: -------------------------------------------------------------------------------- 1 | #div-new-team-details { 2 | display: none; 3 | } 4 | 5 | .team-list { 6 | input { 7 | background: none; 8 | } 9 | textarea { 10 | resize: vertical; 11 | } 12 | .selectize-input { 13 | background: none; 14 | } 15 | .row.summary-row { 16 | margin-bottom: 3px; 17 | } 18 | .team-title { 19 | font-weight: 800; 20 | } 21 | .team-view { 22 | border: 1px solid #d0d0d0; 23 | border-radius: 3px; 24 | background: #EDEFF0; 25 | padding: 5px 15px 5px; 26 | margin-bottom: 3px; 27 | 28 | &.collapsed { 29 | .row.summary-row { 30 | margin-bottom: 0; 31 | } 32 | .collapsed-summary { 33 | display: inline-flex; 34 | cursor: pointer; 35 | } 36 | .details, .team-description, .expanded-summary { 37 | display: none; 38 | } 39 | } 40 | .collapsed-summary { 41 | white-space: nowrap; 42 | display: none; 43 | span { 44 | margin: 10px 0 10px 10px; 45 | display: inline-block; 46 | white-space: nowrap; 47 | overflow: hidden; 48 | text-overflow: ellipsis; 49 | 50 | &.collapsed-description { 51 | max-width: fit-content; 52 | } 53 | } 54 | } 55 | .user-list-table { 56 | border-radius: 3px; 57 | background-color: #EEF; 58 | padding: 3px; 59 | border: 1px solid #AAA; 60 | margin: 3px 0; 61 | 62 | tr[data-user-id] { 63 | cursor: pointer; 64 | 65 | &:hover { 66 | background-color: #fff; 67 | } 68 | } 69 | } 70 | .label a{ 71 | color: #fff; 72 | } 73 | } 74 | } 75 | .hide { 76 | display: none; 77 | } 78 | -------------------------------------------------------------------------------- /imports/ui/pages/question_responses/question_responses.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imports/ui/pages/admin_reports/report_default/report_default.html: -------------------------------------------------------------------------------- 1 | 2 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /docker/vagrant/README.md: -------------------------------------------------------------------------------- 1 | #Using Docker With Vagrant 2 | 3 | This is currently only working with VirtualBox. To do that HyperV ***MUST*** be turned off. 4 | 5 | ##Installations 6 | I use the git bash shell to do all of the following. 7 | 1. Clone padawan with the vagrantDocker branch. 8 | 2. Install [Vagrant](https://www.vagrantup.com/docs/installation/) 9 | 3. Run ```vagrant plugin install docker-compose``` 10 | 4. Run ```vagrant plugin install vagrant-vbguest``` 11 | 5. Insure that there is no padawan/.meteor/local dir. **This must be done EVERYTIME ```vagrant up``` is run!!** 12 | 6. Copy padawan/docker/vagrant/entrypoint.sh to padawan. 13 | 7. Make sure VirtualBox is installed ( [VirtualBox Downloads](https://www.virtualbox.org/wiki/Downloads) if you have to install VirtualBox, restart shell window). 14 | 8. Make sure that "D:/Programs/Oracle/VirtualBox/VBoxGuestAdditions.iso" exists. You may have to edit the padawan/Vagrantfile to the correct location for your VBoxGuestAdditions.iso. 15 | 16 | ##Running 17 | #####Do 18 | 19 | ***A.*** 20 | 1. Run ```vagrantDock.sh``` 21 | 22 | #####OR 23 | 24 | ***B.*** 25 | 1. Run ```dos2unix *.* ``` in the padawan and padawan/docker/vagrant directories. This will change all of those pesky windows CRLFs into Unix line endings. 26 | 2. Run ```vagrant up```. 27 | 28 | #####Finally 29 | 3. A VirtualBox VM should appear. 30 | 4. Wait a few minutes, Open a browser and to enter ```localhost:3000``` as the URL. 31 | 32 | ##Troubleshooting 33 | 1. If you get errors like 'symlink has no referent: "/cygdrive/d/PaladinArcher/padCurr/padawan/.meteor/local/build/programs/server/npm/node_modules/meteor/webapp/node_modules/qs-middleware"', see **Installations #3**. 34 | 2. If you get errors like 'standard_init_linux.go:207: exec user process caused "no such file or directory" ', see **Running #1**. 35 | 3. If it just doesn't seem to work, first try **Running #1**. 36 | 4. To try and dig deeper into problems try logging into the VirtualBox VM. 37 | A. User name: vagrant with password :vagrant. 38 | B. Try ```docker ps```. You should see something like: 39 | ![Snip](docker_ps.png) Explore from there. 40 | 41 | 42 | -------------------------------------------------------------------------------- /imports/api/type_readings/methods.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { TypeReading, ReadingRange, TypeReadingCategory, TypeReadingCategories } from './type_readings.js'; 3 | import { User, MyersBriggs, Answer, UserType, Profile } from '../users/users.js'; 4 | import { MyersBriggsCategory } from "../questions/questions.js"; 5 | 6 | Meteor.methods({ 7 | 'typereadings.insert'(header, body) { 8 | if(!Roles.userIsInRole(Meteor.userId(), ['admin'], Roles.GLOBAL_GROUP)) { 9 | throw new Meteor.Error(403, "You are not authorized"); 10 | } 11 | let newReading = new TypeReading({ Header:header, Body:body, CreatedBy:Meteor.userId() }); 12 | console.log(header, body, newReading); 13 | newReading.validate({ 14 | cast: true 15 | }); 16 | 17 | return newReading.save(); 18 | }, 19 | 'typereadings.addCategoryToReading'(readingId, category, high, low) { 20 | if(!Roles.userIsInRole(Meteor.userId(), ['admin'], Roles.GLOBAL_GROUP)) { 21 | throw new Meteor.Error(403, "You are not authorized"); 22 | } 23 | let reading = TypeReading.findOne({_id:readingId}); 24 | let catReading = new TypeReadingCategory(); 25 | catReading.MyersBriggsCategory = parseInt(category); 26 | catReading.Range = new ReadingRange(); 27 | catReading.Range.high = parseInt(high); 28 | catReading.Range.low = parseInt(low); 29 | console.log(catReading); 30 | reading.addTypeCategory(catReading); 31 | reading.save(); 32 | }, 33 | 'typereadings.delete'(readingId) { 34 | if(!Roles.userIsInRole(Meteor.userId(), ['admin'], Roles.GLOBAL_GROUP)) { 35 | throw new Meteor.Error(403, "You are not authorized"); 36 | } 37 | let reading = TypeReading.findOne({_id:readingId}); 38 | reading.remove(); 39 | }, 40 | 'typereadings.toggle'(readingId) { 41 | if(!Roles.userIsInRole(Meteor.userId(), ['admin'], Roles.GLOBAL_GROUP)) { 42 | throw new Meteor.Error(403, "You are not authorized"); 43 | } 44 | let reading = TypeReading.findOne({_id:readingId}); 45 | reading.toggle(); 46 | }, 47 | }); -------------------------------------------------------------------------------- /imports/ui/pages/learn_share_list/learn_share_list.html: -------------------------------------------------------------------------------- 1 | 46 | -------------------------------------------------------------------------------- /imports/ui/pages/dash_min/dash_min.html: -------------------------------------------------------------------------------- 1 | 2 | 29 | 30 | 63 | -------------------------------------------------------------------------------- /imports/startup/server/index.js: -------------------------------------------------------------------------------- 1 | // Import server startup through a single index entry point 2 | 3 | import '../both/defaults.js'; 4 | import './defaults.js'; 5 | import './fixtures.js'; 6 | import './register-api.js'; 7 | 8 | // inserts google analytics based on if server is production, staging, or dev 9 | WebAppInternals.registerBoilerplateDataCallback('someKey', (request, data, arch) => { 10 | // console.log('Meteor.absoluteUrl: ', Meteor.absoluteUrl()); 11 | let url = Meteor.absoluteUrl(); 12 | let isApp = isStage = isDev = isLocal = false; 13 | isApp = (/app/g.test(url)) ? true : false; 14 | isStage = (/stage/g.test(url)) ? true : false; 15 | isDev = (/dev/g.test(url)) ? true : false; 16 | isLocal = (/local/g.test(url)) ? true : false; 17 | if(isApp && Meteor.isProduction) { 18 | data.head = data.head + ` 19 | 20 | `; 27 | } else if(isStage && Meteor.isProduction) { 28 | data.head = data.head + ` 29 | 30 | `; 37 | } else if(isDev && Meteor.isProduction) { 38 | data.head = data.head + ` 39 | 40 | `; 47 | } else if(isLocal && Meteor.isDevelopment) { 48 | data.head = data.head + ` 49 | 50 | `; 51 | } 52 | }); -------------------------------------------------------------------------------- /imports/api/user_feedback/user_feedback.tests.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { Meteor } from 'meteor/meteor'; 4 | import { chai } from 'meteor/practicalmeteor:chai'; 5 | import { UserFeedback } from './user_feedback.js'; 6 | 7 | let userID; 8 | let createdDate; 9 | let testData = { 10 | userFeedback: { 11 | source: 'User FB Unit Test Source', 12 | context: 'Unit Test User FB Context', 13 | comment: 'Unit Test User FB Comment' 14 | } 15 | } 16 | if (Meteor.isServer) { 17 | describe('UserFeedback', function () { 18 | this.timeout(15000); 19 | it('can create user feedback', function () { 20 | let uf = new UserFeedback( testData.userFeedback ); 21 | uf.save(); 22 | testData.userFeedback._id = uf._id; 23 | userID = uf._id; // for the next tests 24 | createdDate = uf.dateCreated; // for next test 25 | let ufTest = UserFeedback.findOne( {_id:uf._id} ); 26 | chai.assert( ufTest, true); 27 | }); 28 | it('the date stored is the same as the one created for the feedback', function () { 29 | let ufTest = UserFeedback.findOne( {_id:userID} ); 30 | chai.assert( ufTest.dateCreated, createdDate); 31 | }); 32 | it('the feedback created previously is an object', function () { 33 | let ufTest = UserFeedback.findOne( {_id:userID} ); 34 | chai.assert.typeOf(ufTest, "object"); 35 | }); 36 | it('the userId created previously is actually a string', function () { 37 | let ufTest = UserFeedback.findOne( {_id:userID} ); 38 | chai.assert.typeOf(ufTest.userId, "string"); 39 | }); 40 | it('the source created previously is actually a string', function () { 41 | let ufTest = UserFeedback.findOne( {_id:userID} ); 42 | chai.assert.typeOf(ufTest.source, "string"); 43 | }); 44 | it('the context created previously is actually a string', function () { 45 | let ufTest = UserFeedback.findOne( {_id:userID} ); 46 | chai.assert.typeOf(ufTest.context, "string"); 47 | }); 48 | it('the dateCreated created previously is actually a date', function () { 49 | let ufTest = UserFeedback.findOne( {_id:userID} ); 50 | chai.assert.typeOf(ufTest.dateCreated, "date"); 51 | console.log("UserFeedback",UserFeedback); 52 | }); 53 | }); 54 | } -------------------------------------------------------------------------------- /docker/dev/nginx.conf: -------------------------------------------------------------------------------- 1 | # For more information on configuration, see: 2 | # * Official English Documentation: http://nginx.org/en/docs/ 3 | # * Official Russian Documentation: http://nginx.org/ru/docs/ 4 | 5 | user nginx; 6 | worker_processes auto; 7 | error_log /var/log/nginx/error.log; 8 | pid /run/nginx.pid; 9 | 10 | # Load dynamic modules. See /usr/share/nginx/README.dynamic. 11 | include /usr/share/nginx/modules/*.conf; 12 | 13 | events { 14 | worker_connections 1024; 15 | } 16 | 17 | http { 18 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 19 | '$status $body_bytes_sent "$http_referer" ' 20 | '"$http_user_agent" "$http_x_forwarded_for"'; 21 | 22 | access_log /var/log/nginx/access.log main; 23 | 24 | sendfile on; 25 | tcp_nopush on; 26 | tcp_nodelay on; 27 | keepalive_timeout 65; 28 | types_hash_max_size 2048; 29 | 30 | include /etc/nginx/mime.types; 31 | default_type application/octet-stream; 32 | 33 | # Load modular configuration files from the /etc/nginx/conf.d directory. 34 | # See http://nginx.org/en/docs/ngx_core_module.html#include 35 | # for more information. 36 | include /etc/nginx/conf.d/*.conf; 37 | 38 | upstream padawan { 39 | server app:3000; 40 | } 41 | server { 42 | listen 3002 default_server; 43 | listen [::]:3002 default_server; 44 | server_name _; 45 | #root /usr/share/nginx/html; 46 | 47 | # Load configuration files for the default server block. 48 | #include /etc/nginx/default.d/*.conf; 49 | 50 | location / { 51 | proxy_pass http://padawan/; 52 | } 53 | location /authentication { 54 | resolver 127.0.0.11 valid=30s; 55 | set $upstreamone http://aarc_frontend:3333/; 56 | proxy_pass $upstreamone; 57 | } 58 | location /static { 59 | resolver 127.0.0.11 valid=30s; 60 | set $upstreamtwo aarc_frontend:3333; 61 | proxy_pass http://$upstreamtwo$uri; 62 | } 63 | location /api/v1/ { 64 | resolver 127.0.0.11 valid=30s; 65 | set $upstreamthree http://padawan/; 66 | proxy_pass $upstreamthree; 67 | } 68 | 69 | error_page 404 /404.html; 70 | location = /40x.html { 71 | } 72 | 73 | error_page 500 502 503 504 /50x.html; 74 | location = /50x.html { 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /imports/ui/components/select_feedback/select_feedback.html: -------------------------------------------------------------------------------- 1 | 58 | -------------------------------------------------------------------------------- /imports/api/user_notify/user_notify.tests.js: -------------------------------------------------------------------------------- 1 | import { UserNotify } from '/imports/api/user_notify/user_notify.js'; 2 | import { resetDatabase } from 'meteor/xolvio:cleaner'; 3 | import { sinon } from "meteor/practicalmeteor:sinon"; 4 | import { chai } from 'meteor/practicalmeteor:chai'; 5 | 6 | // UserNotify functions: markRead, markNotified, test, pushNotify, 7 | 8 | if(Meteor.isClient) { 9 | FactoryBoy.define('myUserNotify', UserNotify, { _id: '421234'}); 10 | 11 | describe('UserNotify', function() { 12 | afterEach(function() { 13 | resetDatabase(); 14 | }); 15 | it('pushNotify function', function() { 16 | resetDatabase(); 17 | let theUN = FactoryBoy.create('myUserNotify'); 18 | let myOpt = {onclick: 'cow'}; 19 | let bn = theUN.pushNotify(myOpt); 20 | chai.assert.strictEqual(Notification.permission, 'denied', 'the Notification permission should be denied'); 21 | chai.assert.strictEqual(bn, undefined, 'the browserNote should be undefined'); 22 | }); 23 | }); 24 | } 25 | 26 | if (Meteor.isServer) { 27 | FactoryBoy.define('myUserNotify', UserNotify, { _id: '421234'}); 28 | 29 | describe('UserNotify', function() { 30 | afterEach(function() { 31 | resetDatabase(); 32 | }); 33 | it('markRead function', function() { 34 | resetDatabase(); 35 | let theUN = FactoryBoy.create('myUserNotify'); 36 | chai.assert.isFalse(theUN.isRead, 'isRead should start out false'); 37 | theUN.markRead(); 38 | theUN = UserNotify.findOne({ _id: '421234' }); 39 | chai.assert.isTrue(theUN.isRead, 'markRead should have set isRead to true'); 40 | }); 41 | it('markNotified function', function() { 42 | resetDatabase(); 43 | let theUN = FactoryBoy.create('myUserNotify'); 44 | chai.assert.isFalse(theUN.isPushed, 'isPushed should start out false'); 45 | theUN.markNotified(); 46 | theUN = UserNotify.findOne({ _id: '421234' }); 47 | chai.assert.isTrue(theUN.isPushed, 'markNotified should have set isPushed to true'); 48 | }); 49 | it('test function', function() { 50 | resetDatabase(); 51 | let theUN = FactoryBoy.create('myUserNotify'); 52 | let consoleSpy = sinon.spy(console, 'log'); 53 | theUN.test(); 54 | chai.assert.isTrue(console.log.calledWith(' ##### '), 'the test function should have output face art to the console'); 55 | consoleSpy.restore(); 56 | }); 57 | }); 58 | } -------------------------------------------------------------------------------- /docker/production/nginx.conf: -------------------------------------------------------------------------------- 1 | # For more information on configuration, see: 2 | # * Official English Documentation: http://nginx.org/en/docs/ 3 | # * Official Russian Documentation: http://nginx.org/ru/docs/ 4 | 5 | user nginx; 6 | worker_processes auto; 7 | error_log /var/log/nginx/error.log; 8 | pid /run/nginx.pid; 9 | 10 | # Load dynamic modules. See /usr/share/nginx/README.dynamic. 11 | include /usr/share/nginx/modules/*.conf; 12 | 13 | events { 14 | worker_connections 1024; 15 | } 16 | 17 | http { 18 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 19 | '$status $body_bytes_sent "$http_referer" ' 20 | '"$http_user_agent" "$http_x_forwarded_for"'; 21 | 22 | access_log /var/log/nginx/access.log main; 23 | 24 | sendfile on; 25 | tcp_nopush on; 26 | tcp_nodelay on; 27 | keepalive_timeout 65; 28 | types_hash_max_size 2048; 29 | 30 | include /etc/nginx/mime.types; 31 | default_type application/octet-stream; 32 | 33 | # Load modular configuration files from the /etc/nginx/conf.d directory. 34 | # See http://nginx.org/en/docs/ngx_core_module.html#include 35 | # for more information. 36 | include /etc/nginx/conf.d/*.conf; 37 | 38 | upstream padawan { 39 | server app:3000; 40 | } 41 | #upstream aarc_fe { 42 | # server aarc_frontend:3333; 43 | #} 44 | #upstream aarc_be { 45 | # server aarc_api:8888; 46 | #} 47 | server { 48 | listen 3002 default_server; 49 | listen [::]:3002 default_server; 50 | server_name _; 51 | #root /usr/share/nginx/html; 52 | 53 | # Load configuration files for the default server block. 54 | #include /etc/nginx/default.d/*.conf; 55 | 56 | location / { 57 | proxy_pass http://padawan/; 58 | } 59 | location /grf/ { 60 | proxy_pass http://grf.developerlevel.com:3100/grf/; 61 | } 62 | location /tsq/ { 63 | proxy_pass http://tsq.developerlevel.com:4100/tsq/; 64 | } 65 | #location /authentication { 66 | # proxy_pass http://aarc_fe/; 67 | #} 68 | #location /static { 69 | # proxy_pass http://aarc_fe/static; 70 | #} 71 | #location /api/v1/ { 72 | # proxy_pass http://aarc_be/api/v1/; 73 | #} 74 | 75 | error_page 404 /404.html; 76 | location = /40x.html { 77 | } 78 | 79 | error_page 500 502 503 504 /50x.html; 80 | location = /50x.html { 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /client/main.less: -------------------------------------------------------------------------------- 1 | @import "{}/imports/ui/stylesheets/not-found.less"; 2 | @import "{}/imports/ui/stylesheets/team_icon.less"; 3 | @import "{}/imports/ui/stylesheets/learn_share.less"; 4 | @import "{}/imports/ui/stylesheets/add_questions.less"; 5 | @import "{}/imports/ui/stylesheets/admin_teams.less"; 6 | @import "{}/imports/ui/stylesheets/user_dashboard.less"; 7 | @import "{}/imports/ui/stylesheets/user_profile.less"; 8 | @import "{}/imports/ui/stylesheets/select_feedback.less"; 9 | @import "{}/imports/ui/stylesheets/header.less"; 10 | @import "{}/imports/ui/stylesheets/login.less"; 11 | @import "{}/imports/ui/stylesheets/qnaire.less"; 12 | @import "{}/imports/ui/stylesheets/qnaire_results.less"; 13 | @import "{}/imports/ui/stylesheets/mbti_graph.less"; 14 | @import "{}/imports/ui/stylesheets/tsq.less"; 15 | @import "{}/imports/ui/stylesheets/opposites.less"; 16 | @import "{}/imports/ui/stylesheets/behavior_pattern_area.less"; 17 | @import "{}/imports/ui/stylesheets/char_sheet.less"; 18 | @import "{}/imports/ui/stylesheets/context_menu.less"; 19 | @import "{}/imports/ui/stylesheets/mbti_char_report.less"; 20 | 21 | .badge { 22 | .close { 23 | margin-left: .25rem; 24 | color: inherit; 25 | font-size: 100%; 26 | text-shadow: 0 1px 0 fade(#000, 70%); 27 | } 28 | } 29 | 30 | img.dl-icon { 31 | width: 15px; 32 | height: 15px; 33 | } 34 | 35 | h1 img.dl-icon { 36 | width: auto; 37 | height: 30px; 38 | margin-bottom: 10px; 39 | } 40 | .row.spaced { 41 | margin-bottom: 3px; 42 | } 43 | 44 | .float-right { 45 | float: right; 46 | } 47 | 48 | .btn.btn-text-left { 49 | text-align: left; 50 | } 51 | 52 | .navbar-nav > li > a.nav-icon { 53 | padding-top: 10px; 54 | padding-bottom: 10px; 55 | } 56 | 57 | #nav-notifications.unread img { 58 | background: #900; 59 | border-radius: 10px; 60 | } 61 | .mb-1, .my-1 { 62 | margin-bottom: .25rem!important; 63 | } 64 | .dropdown-menu { 65 | // white-space: nowrap; // When removed, fixes item wrapping in bdate dropdown menu - Darren Moody 66 | max-width: 400px; 67 | 68 | a.li-notification { 69 | border-bottom: 1px solid #dddfe2; 70 | overflow: hidden; 71 | text-overflow: ellipsis; 72 | width: 100%; 73 | 74 | &.unread { 75 | background-color: #edf2fa; 76 | } 77 | 78 | h5 { 79 | margin-top: 0; 80 | font-weight: bold; 81 | display: inline-block; 82 | } 83 | p { 84 | overflow: hidden; 85 | text-overflow: ellipsis; 86 | width: 100%; 87 | } 88 | small.float-right { 89 | position: absolute; 90 | right: 10px; 91 | } 92 | } 93 | span.li-heading { 94 | padding-left: 3px; 95 | } 96 | } 97 | .btn-secondary { 98 | border-color: #666; 99 | } 100 | -------------------------------------------------------------------------------- /imports/ui/components/mbtiGraph/mbtiGraphCallMulti.js: -------------------------------------------------------------------------------- 1 | import "./mbtiGraphRenderMulti.html"; 2 | import { User } from "/imports/api/users/users.js"; 3 | import { mbtiGraphMulti } from "./mbtiGraphMulti.js"; 4 | import { Template } from "meteor/templating"; 5 | import { ReactiveVar } from 'meteor/reactive-var'; 6 | import { Session } from 'meteor/session'; 7 | 8 | const data = new ReactiveVar([]); 9 | 10 | Template.mbtiGraphRenderMulti.onCreated(function() { 11 | this.autorun(() => { 12 | this.subscription2 = this.subscribe("userList", this.userId, { 13 | onStop: function() { 14 | console.log("User List subscription stopped! ", arguments, this); 15 | }, 16 | onReady: function() { 17 | console.log("User List subscription ready! ", arguments, this); 18 | } 19 | }); 20 | }); 21 | }); 22 | 23 | Template.mbtiGraphRenderMulti.helpers({ 24 | graphData() { 25 | return Session.get('GraphData'); 26 | }, 27 | round(num) { 28 | return num.toFixed(1); 29 | } 30 | }); 31 | 32 | Template.mbtiGraphRenderMulti.onRendered(function() { 33 | //canvas.set($("#canvas").get(0)); 34 | // toolTip.set($("#toolTip").get(0)); 35 | // let records = Session.get('records'); 36 | // console.log("records",records); 37 | // if(records) { 38 | // data.set(records); 39 | // } else { 40 | // let userId = Meteor.userId(); 41 | // let user = User.findOne({ _id: userId }); 42 | // let personality = user.MyProfile.UserType.Personality 43 | 44 | // data.set([{IE: personality.IE.Value, NS: personality.NS.Value, TF: personality.TF.VAlue, JP: personality.JP.Value, intensity: false}]); 45 | // } 46 | // let canvas = $("#canvas").get(0); 47 | // let curData = data.get(); 48 | // curData.forEach(d => { 49 | // mbtiGraph(canvas, d.IE, d.NS, d.TF, d.JP, d.intensity); 50 | // }) 51 | 52 | // mbtiGraph(canvas, -50, 50, 20, -20); 53 | }); 54 | 55 | Template.mbtiGraphRenderMulti.events({ 56 | 'click .find-name': function(event, instance) { 57 | let records = Session.get("records"); 58 | let allEl = $('.find-name'); 59 | let curNames = []; 60 | allEl.each(function() { 61 | let el = $(this); 62 | let curName = el.val(); 63 | if(el.is(':checked')) { 64 | curNames.push(curName); 65 | } 66 | }); 67 | if(curNames.length >= 1) { 68 | mbtiGraphMulti('canvas', records, $('#traitGraphMulti'), curNames); 69 | } else { 70 | mbtiGraphMulti('canvas', records, $('#traitGraphMulti')); 71 | } 72 | } 73 | }); 74 | 75 | Tracker.autorun(function() { 76 | var records = Session.get("records"); 77 | console.log("Records",records); 78 | if(records) { 79 | mbtiGraphMulti('traitGraphMulti', records); 80 | } 81 | }); 82 | -------------------------------------------------------------------------------- /imports/startup/both/at_config.tests.js: -------------------------------------------------------------------------------- 1 | // import myPostLogout from '/imports/startup/both/at_config.js'; 2 | // import {myPostLogout} from './at_config.js'; 3 | // import myPostSubmitFunc from '/imports/startup/both/at_config.js'; 4 | import { myPostLogout, mySubmitFunc, myPreSubmitFunc, myPostSubmitFunc, accessCodeFunc } from '/imports/startup/both/at_config.js'; 5 | import { Meteor } from 'meteor/meteor'; 6 | import { Accounts } from 'meteor/accounts-base'; 7 | import { chai } from 'meteor/practicalmeteor:chai'; 8 | import { resetDatabase } from 'meteor/xolvio:cleaner'; 9 | import { Team } from '/imports/api/teams/teams.js'; 10 | 11 | import { Session } from 'meteor/session'; 12 | import { AssertionError } from 'assert'; 13 | import { firstNameFunc, lastNameFunc } from './at_config'; 14 | 15 | 16 | const user = { 17 | email: 'cool@email.com', 18 | password: 'coolPassword', 19 | profile: { 20 | name: { first: 'cool', last: 'karl' }, 21 | }, 22 | roles: { 'No Team': [] }, 23 | }; 24 | 25 | FactoryBoy.define('myTeam', Team, { 26 | Name: Team.Default.Name, 27 | CreatedBy: 'cool karl' 28 | }); 29 | 30 | if (Meteor.isServer) { 31 | describe('startup/both/at_config', function () { 32 | it('at_config should pass Istanbul coverage', function () { 33 | resetDatabase(); 34 | let myTeam = FactoryBoy.create('myTeam'); 35 | function conso() { 36 | console.log('fake function called'); 37 | console.log('umm second call'); 38 | eval('console.log("string log");'); 39 | eval('myPostSubmitFunc();'); 40 | return myTeam; 41 | } 42 | let t = Team.findOne({ Name: Team.Default.Name }); 43 | let uId = Accounts.createUser({ 44 | username: 'flyUserName', 45 | email: 'FlyUserNam@mydomain.com', 46 | password: 'password', 47 | profile: { 48 | first_name: 'Bob', 49 | last_name: 'Thompson', 50 | gender: 'male' 51 | } 52 | }); 53 | let u = Meteor.users.findOne({ _id: uId }); 54 | chai.assert.strictEqual('flyUserName', u.username, 'The users username should be flyUserName'); 55 | myPostLogout(); 56 | mySubmitFunc(false, 'signUp'); 57 | myPostSubmitFunc(uId, 'sample info'); 58 | accessCodeFunc('imaPADLo'); 59 | accessCodeFunc('nothere'); 60 | let stubLog = sinon.stub(console, 'log').returns('dont console log'); 61 | firstNameFunc('first'); 62 | lastNameFunc('last'); 63 | stubLog.restore(); 64 | }); 65 | }); 66 | } -------------------------------------------------------------------------------- /imports/ui/components/select_autocomplete/select_autocomplete.js: -------------------------------------------------------------------------------- 1 | import './select_autocomplete.html'; 2 | 3 | Template.select_autocomplete.onCreated(function () { 4 | // 5 | }); 6 | 7 | Template.select_autocomplete.onRendered(function () { 8 | var self = this; 9 | self.autorun( function () { 10 | console.log("select_autocomplete autorun"); 11 | var dat = Template.currentData(); 12 | 13 | if (!dat.list || dat.list.length < 1) { 14 | return; 15 | } 16 | var params = { 17 | plugins: ['remove_button'], 18 | options: dat.list, 19 | } 20 | if (typeof dat.onItemAdd !== "undefined") { 21 | params.onItemAdd = dat.onItemAdd; 22 | } 23 | if (typeof dat.onItemRemove !== "undefined") { 24 | params.onItemRemove = dat.onItemRemove; 25 | } 26 | if (typeof dat.readOnly !== "undefined") { 27 | params.readOnly = true; 28 | params.plugins = []; 29 | } 30 | if (typeof dat.create !== "undefined") { 31 | params.create = true; 32 | } 33 | let $select = $('#'+dat.id+dat.id2).selectize(params); 34 | if(dat.id2 === 'tsq') { 35 | $select[0].selectize.on('item_add', function() { 36 | // $select[0].selectize.disable(); 37 | // $('#continue').attr('disabled',true); 38 | }); 39 | $select[0].selectize.on('item_remove', function() { 40 | // $select[0].selectize.disable(); 41 | // $('#continue').attr('disabled',true); 42 | }); 43 | } 44 | //$select[0].selectize.clear(true); 45 | //$select[0].selectize.clearOptions(); 46 | $select[0].selectize.addOption(dat.list); 47 | if ("undefined" !== typeof dat.selected) { 48 | for (let i in dat.selected) { 49 | let id = dat.selected[i]; 50 | if ("string" !== typeof id) { 51 | id = id.value; 52 | } 53 | if ("undefined" === typeof _.find(dat.list,function(o){return o.value===id})) { 54 | $select[0].selectize.addOption(dat.selected[i]); 55 | $select[0].selectize.addItem(id,true); 56 | } else { 57 | $select[0].selectize.addItem(id,true); 58 | } 59 | } 60 | } 61 | $select[0].selectize.refreshOptions(false); 62 | //$select[0].selectize.refreshItems(); 63 | if(dat.nextParticipant) { 64 | $('.item[data-value="' + dat.nextParticipant + '"]').addClass('picking'); 65 | $("#p-on-deck-info").data("picking", dat.nextParticipant); 66 | $("#p-on-deck-info").html($('.item[data-value="' + dat.nextParticipant + '"]').html().slice(0, $('.item[data-value="' + dat.nextParticipant + '"]').html().indexOf('<'))); 67 | $("#p-on-deck").show(); 68 | $("#p-pick-first").hide(); 69 | } 70 | }); 71 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "testing", 3 | "private": true, 4 | "babel": { 5 | "env": { 6 | "COVERAGE": { 7 | "plugins": [ 8 | "istanbul" 9 | ] 10 | } 11 | } 12 | }, 13 | "scripts": { 14 | "chimp-watch": "chimp --ddp=http://localhost:3000 --watch --mocha --path=tests", 15 | "chimp-test": "chimp --mocha --path=tests", 16 | "test-e2e": "nightwatch", 17 | "test-chromeHide": "nightwatch -e chromeHide", 18 | "test-geckoHide": "nightwatch -e geckoHide", 19 | "test": "TEST_WATCH=1 meteor test --driver-package meteortesting:mocha", 20 | "local-env": "meteor run --settings settings.local.json", 21 | "dev-docker-env": "meteor run --settings settings.dev-docker.json", 22 | "coverage:unit": "BABEL_ENV=COVERAGE TEST_BROWSER_DRIVER=puppeteer COVERAGE=1 COVERAGE_OUT_HTML=1 COVERAGE_APP_FOLDER=$PWD/ meteor test --once --driver-package meteortesting:mocha", 23 | "coverage:unit_old": "BABEL_ENV=COVERAGE TEST_BROWSER_DRIVER=puppeteer COVERAGE=1 COVERAGE_OUT_HTML=1 COVERAGE_OUT_JSON=1 COVERAGE_OUT_JSON_SUMMARY=1 COVERAGE_OUT_TEXT_SUMMARY=1 COVERAGE_OUT_COVERAGE=1 COVERAGE_VERBOSE=1 COVERAGE_APP_FOLDER=$PWD/ meteor test --once --driver-package meteortesting:mocha", 24 | "coverage:watch": "BABEL_ENV=COVERAGE COVERAGE=1 COVERAGE_VERBOSE=1 COVERAGE_APP_FOLDER=$PWD/ TEST_WATCH=1 meteor test --driver-package meteortesting:mocha", 25 | "test-jenkins": "JUNIT_REPORT_PATH=reports/report.xml mocha --colors --reporter mocha-jenkins-reporter" 26 | }, 27 | "dependencies": { 28 | "@babel/runtime": "^7.5.5", 29 | "babel-runtime": "^6.26.0", 30 | "bcrypt": "^1.0.3", 31 | "braces": ">=2.3.1", 32 | "buffer": "^5.2.1", 33 | "bull": "^3.10.0", 34 | "live-mutex": "^0.2.1", 35 | "meteor-node-stubs": "^0.2.11", 36 | "mongo": "^0.1.0", 37 | "mongodb": "^3.3.0-beta2", 38 | "npm": "^6.10.1", 39 | "safe-buffer": "^5.1.2" 40 | }, 41 | "devDependencies": { 42 | "@meteorjs/eslint-config-meteor": "^1.0.5", 43 | "@types/bull": "^3.10.2", 44 | "babel-cli": "^6.26.0", 45 | "babel-eslint": "^7.2.2", 46 | "babel-plugin-istanbul": "^5.2.0", 47 | "chai": "^4.2.0", 48 | "chromedriver": "^2.45.0", 49 | "codacy-coverage": "^2.0.0", 50 | "coveralls": "^3.0.6", 51 | "eslint": "^4.19.1", 52 | "eslint-config-airbnb": "^14.1.0", 53 | "eslint-import-resolver-meteor": "^0.4.0", 54 | "eslint-plugin-import": "^2.2.0", 55 | "eslint-plugin-jsx-a11y": "^4.0.0", 56 | "eslint-plugin-meteor": "^4.1.4", 57 | "eslint-plugin-react": "^6.10.3", 58 | "geckodriver": "^1.16.2", 59 | "mocha": "^5.2.0", 60 | "nightwatch": "^1.1.12", 61 | "puppeteer": "^1.20.0", 62 | "selenium-server": "^3.141.59", 63 | "selenium-webdriver": "^4.0.0-alpha.1", 64 | "mocha-jenkins-reporter": "^0.4.2" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /imports/ui/pages/mbti_results/mbti_results.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imports/api/tsq/server/publications.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { HTTP } from 'meteor/http'; 3 | import { HelperPagesCached } from '../../help/helperPagesCached.js'; 4 | 5 | const POLL_INTERVAL = 1000; 6 | const TSQ_URL = Meteor.settings.private.TSQ_URL; 7 | const TSQ_SLUG_INTRO = Meteor.settings.private.Pages.TSQ.Slug.Intro; 8 | const TSQ_SLUG_INSTR = Meteor.settings.private.Pages.TSQ.Slug.Instructions; 9 | const TSQ_CACHE_TTL = Meteor.settings.public.Pages.Base.CacheTTL; 10 | 11 | let publishedData = { key: null }; 12 | 13 | function getKeyData (key) { 14 | const response = HTTP.get(`${TSQ_URL}skills/users/findOne/key/${key}`); 15 | //console.log(response); 16 | return response.data.data.payload; 17 | } 18 | 19 | Meteor.publish('tsq.keyData', function (key) { 20 | const poll = () => { 21 | const apiData = getKeyData(key); 22 | const { _id, skills } = apiData; 23 | var changed = false; 24 | if (typeof publishedData.key != "undefined" && publishedData.key === apiData.key) { 25 | try { 26 | this.changed('tsqdata', _id, { _id, key, skills }); 27 | changed = true; 28 | } catch(error) { 29 | if(!error.message.match(/Could not find element/)) { console.log("unable to change value", error); } 30 | } 31 | } 32 | if (!changed) { 33 | this.added('tsqdata', _id, { _id, key, skills }); 34 | publishedData.key = apiData.key; 35 | } 36 | } 37 | 38 | poll(); 39 | this.ready(); 40 | 41 | const interval = Meteor.setInterval(poll, POLL_INTERVAL); 42 | 43 | this.onStop(() => { 44 | publishedData.key = null; 45 | Meteor.clearInterval(interval); 46 | }); 47 | }); 48 | 49 | 50 | Meteor.publish('tsq.allSkills', function (key) { 51 | const poll = () => { 52 | const apiData = HTTP.get(`${TSQ_URL}skills/`); 53 | const { payload } = apiData.data.data; 54 | payload.forEach(skill => { 55 | this.added('tsqskills', skill._id, skill); 56 | }); 57 | } 58 | 59 | poll(); 60 | this.ready(); 61 | 62 | const interval = Meteor.setInterval(poll, 15000); // polling this less frequently 63 | 64 | this.onStop(() => { 65 | publishedData.key = null; 66 | Meteor.clearInterval(interval) 67 | }); 68 | }); 69 | 70 | Meteor.publish('tsq.helperTexts', function () { 71 | const poll = () => { 72 | const itms = { 73 | "_id": new Mongo.ObjectID()._str, 74 | "Intro": HelperPagesCached.getPageContentBySlug(TSQ_SLUG_INTRO), 75 | "Instructions": HelperPagesCached.getPageContentBySlug(TSQ_SLUG_INSTR) 76 | }; 77 | this.added('helperText', itms._id, itms); 78 | } 79 | 80 | poll(); 81 | this.ready(); 82 | 83 | const interval = Meteor.setInterval(poll, TSQ_CACHE_TTL * 60000); // polling this less frequently 84 | this.onStop(() => { 85 | publishedData.key = null; 86 | Meteor.clearInterval(interval); 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /imports/ui/pages/qnaire_list/qnaire_list.html: -------------------------------------------------------------------------------- 1 | 66 | -------------------------------------------------------------------------------- /tests/changePassword.test.js: -------------------------------------------------------------------------------- 1 | const randomNumber = (Math.floor(Math.random() * 100000) + 1) + Date.now(); 2 | 3 | module.exports = { 4 | "Registering a new user and changing password": function(browser) { 5 | browser.url("http://localhost:3000").waitForElementVisible("body", 12000); 6 | 7 | createNewUser(browser); 8 | createNewPassword(browser); 9 | signInWithNewPassword(browser); 10 | browser.end(); 11 | } 12 | } 13 | 14 | function createNewUser(browser) { 15 | browser.verify 16 | .visible("#at-signUp") 17 | .click("#at-signUp") 18 | browser 19 | .waitForElementVisible("#at-field-email", 12000) 20 | .setValue("#at-field-email", `testUserForNightwatchTesting${randomNumber}@mydomain.com`) 21 | browser.verify 22 | .visible("#at-field-password") 23 | .setValue("#at-field-password", "password") 24 | browser.verify 25 | .visible("#at-field-password_again") 26 | .setValue("#at-field-password_again", "password") 27 | browser.verify 28 | .visible("#at-field-first_name") 29 | .setValue("#at-field-first_name", "testUserForNightwatchTesting") 30 | browser.verify 31 | .visible("#at-field-last_name") 32 | .setValue("#at-field-last_name", "testing") 33 | browser.verify 34 | .visible("#at-field-access_code") 35 | .setValue("#at-field-access_code", "PADL") 36 | browser.verify 37 | .visible("#at-btn") 38 | .click("#at-btn") 39 | browser.waitForElementVisible("#last-dropdown") 40 | } 41 | 42 | function createNewPassword(browser) { 43 | browser.verify 44 | .visible("#last-dropdown") 45 | .click("#last-dropdown") 46 | browser.verify 47 | .visible("#nav-profile") 48 | .click("#nav-profile") 49 | browser 50 | .waitForElementVisible("#old-password", 10000) 51 | .setValue("#old-password", "password") 52 | browser.verify 53 | .visible("#input-password") 54 | .setValue("#input-password", "newPassword") 55 | browser.verify 56 | .visible("#input-password-check") 57 | .setValue("#input-password-check", "newPassword") 58 | browser.verify 59 | .visible("#passwordButton") 60 | .click("#passwordButton") 61 | browser.waitForElementVisible(".alert-success") 62 | } 63 | 64 | function signInWithNewPassword(browser) { 65 | browser.verify 66 | .visible("#last-dropdown") 67 | .click("#last-dropdown") 68 | browser.verify 69 | .visible("#at-nav-button") 70 | .click("#at-nav-button") 71 | browser.verify 72 | .visible("#at-field-email") 73 | .setValue("#at-field-email", `testUserForNightwatchTesting${randomNumber}@mydomain.com`) 74 | browser.verify 75 | .visible("#at-field-password") 76 | .setValue("#at-field-password", "newPassword") 77 | browser.verify 78 | .visible("#at-btn") 79 | .click("#at-btn") 80 | browser.waitForElementVisible("#last-dropdown") 81 | } 82 | -------------------------------------------------------------------------------- /imports/api/teams/server/publications.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { Team } from '../teams.js'; 3 | import { User } from '../../users/users.js'; 4 | 5 | Meteor.publish('teamsData', function() { 6 | if (this.userId) { 7 | return Team.find( 8 | { 9 | $or: [ 10 | {Public: true}, 11 | {Members: Meteor.userId()} 12 | ] 13 | }, 14 | { 15 | fields: { Name: 1, Description: 1, CreatedBy: 1, Icon: 1, Icon64: 1, IconType: 1 } 16 | } 17 | ); 18 | } else { 19 | return [ ]; 20 | } 21 | }); 22 | 23 | Meteor.publish('teamsMemberOfList', (userId) => { 24 | // if (userId == Meteor.userId() || Roles.userIsInRole(Meteor.userId(),'admin', Roles.GLOBAL_GROUP)) { 25 | return Team.find( {Members: userId} ); 26 | // } else { 27 | // return []; 28 | // } 29 | }); 30 | 31 | 32 | Meteor.publishComposite('teamMemberList', (userId) => { 33 | return { 34 | find() { 35 | let u = User.findOne( {_id: Meteor.userId()} ); 36 | 37 | if (typeof u === "undefined") { 38 | return; // []; 39 | } 40 | let teamsList = []; 41 | _.forEach(u.roles, (roles, team) => { 42 | if (roles.indexOf('admin') > -1 || roles.indexOf('view-members')) { 43 | teamsList.push(team); 44 | } 45 | }); 46 | let fieldsObj = { 47 | Name: 1, 48 | Description: 1, 49 | Members: 1, 50 | CreatedBy: 1, 51 | Icon: 1, 52 | Icon64: 1, 53 | IconType: 1 54 | }; 55 | 56 | return Team.find( {Name: {'$in': teamsList}}, { 57 | fields: fieldsObj 58 | }); 59 | }, 60 | children: [{ 61 | find(team) { 62 | if ( Roles.userIsInRole(userId, ['admin','view-members'], team.Name) || Roles.userIsInRole(userId, 'admin', Roles.GLOBAL_GROUP) ) { 63 | 64 | let memberList = team.Members; 65 | 66 | let reqQuery = {}; 67 | let fieldsObj = {}; 68 | fieldsObj["MyProfile.firstName"] = 1; 69 | fieldsObj["MyProfile.lastName"] = 1; 70 | fieldsObj["roles."+team.Name] = 1; 71 | fieldsObj["teams"] = 1; 72 | 73 | reqQuery['roles.'+team.Name] = "user-join-request"; 74 | let u = User.find( 75 | { 76 | $or: [ 77 | { _id: { '$in': memberList } }, 78 | reqQuery 79 | ] 80 | }, { fields: fieldsObj }); 81 | return u; 82 | } else { 83 | return this.ready(); 84 | } 85 | } 86 | }] 87 | } 88 | }); 89 | -------------------------------------------------------------------------------- /imports/api/restrictedRoutes/methods.js: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { User } from '../users/users.js'; 3 | import { RestrictedRoutes } from './restrictedRoutes.js'; 4 | import { Team } from '/imports/api/teams/teams.js'; 5 | 6 | Meteor.methods({ 7 | 'restricted.routes'() { 8 | let routes = RestrictedRoutes.find().fetch(); 9 | if (routes === undefined || routes === false || routes.length == 0) { 10 | let r = [ 11 | { 12 | "routeName":"tsq.results", 13 | "teamNames":["Developer"] 14 | }, 15 | { 16 | "routeName":"tsq.userLanguageList", 17 | "teamNames":["Developer"] 18 | }, 19 | { 20 | "routeName":"tsq.familiarVsUnfamiliar", 21 | "teamNames":["Developer"] 22 | }, 23 | { 24 | "routeName":"tsq.confidenceQuestionarie", 25 | "teamNames":["Developer"] 26 | }, 27 | { 28 | "routeName":"tsq", 29 | "teamNames":["Developer"] 30 | } 31 | ]; 32 | let save = []; 33 | for(let i = 0; i < r.length; i++) { 34 | let nrr = new RestrictedRoutes(r[i]); 35 | let s = nrr.save(); 36 | } 37 | routes = RestrictedRoutes.find().fetch(); 38 | } 39 | return routes; 40 | }, 41 | 'restricted.hasPermission'(route) { 42 | let rr = Meteor.call('restricted.routes'); 43 | //return rr; 44 | let r = rr.find(cur => { 45 | return cur.routeName === route 46 | }) 47 | //return [route, r] 48 | if(r) { 49 | let userId = Meteor.userId(); 50 | let user = User.findOne({ _id: userId }); 51 | let roles = user.roles; 52 | 53 | // let Paladin & Archer team members access tsq 54 | let paTeam = Team.findOne({ Name: "Paladin & Archer" }); 55 | // console.log('paTeam Members: ', paTeam.Members); 56 | let tsqRoutes = ['tsq.results', 'tsq.userLanguageList', 57 | 'tsq.familiarVsUnfamiliar', 'tsq.confidenceQuestionarie', 'tsq']; 58 | if (tsqRoutes.includes(r.routeName)) { 59 | if (paTeam.Members.includes(userId)) { 60 | return true; 61 | } 62 | } 63 | 64 | if(roles['__global_roles__'] != undefined) { 65 | let overide_roles = ['admin','developer'] 66 | for(let i = 0; i < overide_roles.length; i++) { 67 | return roles['__global_roles__'].includes(overide_roles[i]); 68 | } 69 | } 70 | 71 | //return roles; 72 | for(let i = 0; i < r.teamNames.length; i++) { 73 | let tn = r.teamNames[i]; 74 | //return tn; 75 | if(roles[tn] != undefined) { 76 | return true; 77 | } 78 | } 79 | return false; 80 | } 81 | return true; 82 | } 83 | }); -------------------------------------------------------------------------------- /imports/api/restrictedRoutes/methods.js.orig: -------------------------------------------------------------------------------- 1 | import { Meteor } from 'meteor/meteor'; 2 | import { User } from '../users/users.js'; 3 | import { RestrictedRoutes } from './restrictedRoutes.js'; 4 | import { Team } from '/imports/api/teams/teams.js'; 5 | 6 | Meteor.methods({ 7 | 'restricted.routes'() { 8 | let routes = RestrictedRoutes.find().fetch(); 9 | if (routes === undefined || routes === false || routes.length == 0) { 10 | let r = [ 11 | { 12 | "routeName":"tsq.results", 13 | "teamNames":["Developer"] 14 | }, 15 | { 16 | "routeName":"tsq.userLanguageList", 17 | "teamNames":["Developer"] 18 | }, 19 | { 20 | "routeName":"tsq.familiarVsUnfamiliar", 21 | "teamNames":["Developer"] 22 | }, 23 | { 24 | "routeName":"tsq.confidenceQuestionarie", 25 | "teamNames":["Developer"] 26 | }, 27 | { 28 | "routeName":"tsq", 29 | "teamNames":["Developer"] 30 | } 31 | ]; 32 | let save = []; 33 | for(let i = 0; i < r.length; i++) { 34 | let nrr = new RestrictedRoutes(r[i]); 35 | let s = nrr.save(); 36 | } 37 | routes = RestrictedRoutes.find().fetch(); 38 | } 39 | return routes; 40 | }, 41 | 'restricted.hasPermission'(route) { 42 | let rr = Meteor.call('restricted.routes'); 43 | //return rr; 44 | let r = rr.find(cur => { 45 | return cur.routeName === route 46 | }) 47 | //return [route, r] 48 | if(r) { 49 | let userId = Meteor.userId(); 50 | let user = User.findOne({ _id: userId }); 51 | let roles = user.roles; 52 | 53 | // let Paladin & Archer team members access tsq 54 | let paTeam = Team.findOne({ Name: "Paladin & Archer" }); 55 | // console.log('paTeam Members: ', paTeam.Members); 56 | let tsqRoutes = ['tsq.results', 'tsq.userLanguageList', 57 | 'tsq.familiarVsUnfamiliar', 'tsq.confidenceQuestionarie', 'tsq']; 58 | if (tsqRoutes.includes(r.routeName)) { 59 | if (paTeam.Members.includes(userId)) { 60 | return true; 61 | } 62 | } 63 | 64 | if(roles['__global_roles__'] != undefined) { 65 | let overide_roles = ['admin','developer'] 66 | for(let i = 0; i < overide_roles.length; i++) { 67 | return roles['__global_roles__'].includes(overide_roles[i]); 68 | } 69 | } 70 | 71 | //return roles; 72 | for(let i = 0; i < r.teamNames.length; i++) { 73 | let tn = r.teamNames[i]; 74 | //return tn; 75 | if(roles[tn] != undefined) { 76 | return true; 77 | } 78 | } 79 | return false; 80 | } 81 | return true; 82 | } 83 | }); -------------------------------------------------------------------------------- /imports/ui/pages/team_dashboard/team_dashboard.html: -------------------------------------------------------------------------------- 1 | 86 | --------------------------------------------------------------------------------