├── frontend ├── .nvmrc ├── _redirects ├── static │ ├── css │ │ ├── imported │ │ │ └── bootstrap.min.css.map.css │ │ └── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ ├── js │ │ └── plugins │ │ │ ├── datatables │ │ │ ├── extensions │ │ │ │ ├── Responsive │ │ │ │ │ ├── Readme.md │ │ │ │ │ └── License.txt │ │ │ │ ├── FixedHeader │ │ │ │ │ ├── css │ │ │ │ │ │ ├── dataTables.fixedHeader.min.css │ │ │ │ │ │ └── dataTables.fixedHeader.css │ │ │ │ │ └── Readme.txt │ │ │ │ ├── KeyTable │ │ │ │ │ ├── css │ │ │ │ │ │ ├── dataTables.keyTable.min.css │ │ │ │ │ │ └── dataTables.keyTable.css │ │ │ │ │ └── Readme.txt │ │ │ │ ├── TableTools │ │ │ │ │ ├── images │ │ │ │ │ │ ├── csv.png │ │ │ │ │ │ ├── pdf.png │ │ │ │ │ │ ├── xls.png │ │ │ │ │ │ ├── copy.png │ │ │ │ │ │ ├── print.png │ │ │ │ │ │ ├── collection.png │ │ │ │ │ │ ├── copy_hover.png │ │ │ │ │ │ ├── csv_hover.png │ │ │ │ │ │ ├── pdf_hover.png │ │ │ │ │ │ ├── xls_hover.png │ │ │ │ │ │ ├── print_hover.png │ │ │ │ │ │ ├── psd │ │ │ │ │ │ │ ├── printer.psd │ │ │ │ │ │ │ ├── collection.psd │ │ │ │ │ │ │ ├── file_types.psd │ │ │ │ │ │ │ └── copy document.psd │ │ │ │ │ │ └── collection_hover.png │ │ │ │ │ ├── swf │ │ │ │ │ │ ├── copy_csv_xls.swf │ │ │ │ │ │ └── copy_csv_xls_pdf.swf │ │ │ │ │ └── Readme.md │ │ │ │ ├── AutoFill │ │ │ │ │ ├── images │ │ │ │ │ │ └── filler.png │ │ │ │ │ ├── css │ │ │ │ │ │ ├── dataTables.autoFill.min.css │ │ │ │ │ │ └── dataTables.autoFill.css │ │ │ │ │ └── Readme.txt │ │ │ │ ├── ColReorder │ │ │ │ │ ├── images │ │ │ │ │ │ └── insert.png │ │ │ │ │ ├── css │ │ │ │ │ │ ├── dataTables.colReorder.min.css │ │ │ │ │ │ └── dataTables.colReorder.css │ │ │ │ │ ├── License.txt │ │ │ │ │ └── Readme.md │ │ │ │ ├── Scroller │ │ │ │ │ ├── images │ │ │ │ │ │ └── loading-background.png │ │ │ │ │ └── css │ │ │ │ │ │ ├── dataTables.scroller.min.css │ │ │ │ │ │ └── dataTables.scroller.css │ │ │ │ ├── FixedColumns │ │ │ │ │ ├── css │ │ │ │ │ │ ├── dataTables.fixedColumns.min.css │ │ │ │ │ │ └── dataTables.fixedColumns.css │ │ │ │ │ └── License.txt │ │ │ │ └── ColVis │ │ │ │ │ ├── css │ │ │ │ │ └── dataTables.colvis.jqueryui.css │ │ │ │ │ ├── License.txt │ │ │ │ │ └── Readme.md │ │ │ └── images │ │ │ │ ├── sort_asc.png │ │ │ │ ├── sort_both.png │ │ │ │ ├── sort_desc.png │ │ │ │ ├── sort_asc_disabled.png │ │ │ │ └── sort_desc_disabled.png │ │ │ ├── datepicker │ │ │ └── locales │ │ │ │ ├── bootstrap-datepicker.kr.js │ │ │ │ ├── bootstrap-datepicker.gl.js │ │ │ │ ├── bootstrap-datepicker.ja.js │ │ │ │ ├── bootstrap-datepicker.hr.js │ │ │ │ ├── bootstrap-datepicker.zh-CN.js │ │ │ │ ├── bootstrap-datepicker.az.js │ │ │ │ ├── bootstrap-datepicker.cy.js │ │ │ │ ├── bootstrap-datepicker.he.js │ │ │ │ ├── bootstrap-datepicker.ms.js │ │ │ │ ├── bootstrap-datepicker.no.js │ │ │ │ ├── bootstrap-datepicker.ca.js │ │ │ │ ├── bootstrap-datepicker.el.js │ │ │ │ ├── bootstrap-datepicker.rs.js │ │ │ │ ├── bootstrap-datepicker.th.js │ │ │ │ ├── bootstrap-datepicker.bg.js │ │ │ │ ├── bootstrap-datepicker.es.js │ │ │ │ ├── bootstrap-datepicker.nl.js │ │ │ │ ├── bootstrap-datepicker.sl.js │ │ │ │ ├── bootstrap-datepicker.rs-latin.js │ │ │ │ ├── bootstrap-datepicker.nb.js │ │ │ │ ├── bootstrap-datepicker.sq.js │ │ │ │ ├── bootstrap-datepicker.ua.js │ │ │ │ ├── bootstrap-datepicker.id.js │ │ │ │ ├── bootstrap-datepicker.kk.js │ │ │ │ ├── bootstrap-datepicker.tr.js │ │ │ │ ├── bootstrap-datepicker.da.js │ │ │ │ ├── bootstrap-datepicker.pt-BR.js │ │ │ │ ├── bootstrap-datepicker.ru.js │ │ │ │ ├── bootstrap-datepicker.cs.js │ │ │ │ ├── bootstrap-datepicker.is.js │ │ │ │ ├── bootstrap-datepicker.sk.js │ │ │ │ ├── bootstrap-datepicker.sv.js │ │ │ │ ├── bootstrap-datepicker.fa.js │ │ │ │ ├── bootstrap-datepicker.hu.js │ │ │ │ ├── bootstrap-datepicker.ro.js │ │ │ │ ├── bootstrap-datepicker.zh-TW.js │ │ │ │ ├── bootstrap-datepicker.de.js │ │ │ │ ├── bootstrap-datepicker.fr.js │ │ │ │ ├── bootstrap-datepicker.mk.js │ │ │ │ ├── bootstrap-datepicker.vi.js │ │ │ │ ├── bootstrap-datepicker.it.js │ │ │ │ ├── bootstrap-datepicker.pt.js │ │ │ │ ├── bootstrap-datepicker.ar.js │ │ │ │ ├── bootstrap-datepicker.fi.js │ │ │ │ ├── bootstrap-datepicker.lv.js │ │ │ │ ├── bootstrap-datepicker.nl-BE.js │ │ │ │ ├── bootstrap-datepicker.lt.js │ │ │ │ ├── bootstrap-datepicker.pl.js │ │ │ │ ├── bootstrap-datepicker.sw.js │ │ │ │ ├── bootstrap-datepicker.ka.js │ │ │ │ └── bootstrap-datepicker.et.js │ │ │ └── select2 │ │ │ └── i18n │ │ │ ├── zh-TW.js │ │ │ ├── zh-CN.js │ │ │ ├── az.js │ │ │ ├── fi.js │ │ │ ├── ja.js │ │ │ ├── hu.js │ │ │ ├── th.js │ │ │ ├── tr.js │ │ │ ├── ko.js │ │ │ ├── nb.js │ │ │ ├── id.js │ │ │ ├── vi.js │ │ │ ├── is.js │ │ │ ├── ar.js │ │ │ ├── de.js │ │ │ ├── et.js │ │ │ ├── sv.js │ │ │ ├── bg.js │ │ │ ├── ms.js │ │ │ ├── gl.js │ │ │ ├── da.js │ │ │ ├── fr.js │ │ │ ├── ro.js │ │ │ ├── en.js │ │ │ ├── he.js │ │ │ ├── hi.js │ │ │ ├── fa.js │ │ │ ├── hr.js │ │ │ ├── eu.js │ │ │ ├── mk.js │ │ │ ├── pt-BR.js │ │ │ ├── lv.js │ │ │ ├── pt.js │ │ │ ├── ca.js │ │ │ ├── es.js │ │ │ ├── lt.js │ │ │ ├── it.js │ │ │ ├── nl.js │ │ │ ├── pl.js │ │ │ ├── sr.js │ │ │ ├── uk.js │ │ │ ├── sr-Cyrl.js │ │ │ ├── ru.js │ │ │ ├── sk.js │ │ │ └── cs.js │ └── img │ │ ├── logo.png │ │ ├── favicon.ico │ │ ├── logo_sm.png │ │ ├── demo │ │ ├── icons.png │ │ ├── avatar.png │ │ ├── avatar2.png │ │ ├── avatar3.png │ │ ├── avatar5.png │ │ ├── photo1.png │ │ ├── photo2.png │ │ ├── photo3.jpg │ │ ├── photo4.jpg │ │ ├── avatar04.png │ │ ├── boxed-bg.jpg │ │ ├── boxed-bg.png │ │ ├── default-50x50.gif │ │ ├── user1-128x128.jpg │ │ ├── user2-160x160.jpg │ │ ├── user3-128x128.jpg │ │ ├── user4-128x128.jpg │ │ ├── user5-128x128.jpg │ │ ├── user6-128x128.jpg │ │ ├── user7-128x128.jpg │ │ └── user8-128x128.jpg │ │ ├── fa-expand.png │ │ ├── logo_blk.png │ │ ├── logo_blk_sm.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── apple-touch-icon.png │ │ ├── stock │ │ └── user1-128x128.jpg │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── color_logo_transparent_no_container.png │ │ ├── color_logo_transparent_no_container_no_slogan.png │ │ ├── white_logo_transparent_no_container_no_slogan.png │ │ └── site.webmanifest ├── .prettierrc ├── .dockerignore ├── test │ ├── unit │ │ ├── .eslintrc │ │ ├── coverage │ │ │ └── lcov-report │ │ │ │ ├── sort-arrow-sprite.png │ │ │ │ └── prettify.css │ │ ├── specs │ │ │ └── 404.spec.js │ │ ├── index.js │ │ └── karma.conf.js │ └── e2e │ │ ├── specs │ │ └── test.js │ │ ├── reports │ │ ├── CHROME_61.0.3163.100_Mac OS X_test.xml │ │ └── FIREFOX_undefined_undefined_test.xml │ │ ├── runner.js │ │ ├── custom-assertions │ │ └── elementCount.js │ │ └── nightwatch.conf.js ├── config │ ├── prod.env.js │ ├── test.env.js │ └── dev.env.js ├── src │ ├── store │ │ ├── state.js │ │ ├── mutations.js │ │ ├── index.js │ │ ├── actions.js │ │ └── utilities │ │ │ └── generate-mutations.js │ ├── services │ │ ├── event-bus.service.js │ │ ├── document.service.js │ │ ├── file.service.js │ │ ├── stats.service.js │ │ ├── index.js │ │ └── auth-interceptor.service.js │ ├── routes │ │ ├── audit-logs.route.js │ │ ├── connections.route.js │ │ ├── images.route.js │ │ ├── members.route.js │ │ ├── roles.route.js │ │ ├── users.route.js │ │ ├── groups.route.js │ │ ├── permissions.route.js │ │ ├── documents.route.js │ │ ├── index.js │ │ └── main.route.js │ ├── components │ │ ├── App.vue │ │ ├── 404.vue │ │ └── views │ │ │ └── main │ │ │ └── ContentHeader.vue │ ├── filters │ │ └── index.js │ └── plugins │ │ └── repository-plugin.js ├── .babelrc ├── build │ ├── dev-client.js │ ├── vue-loader.conf.js │ ├── webpack.test.conf.js │ ├── build.js │ ├── check-versions.js │ └── webpack.dev.conf.js ├── appveyor.yml ├── Dockerfile └── .eslintrc.js ├── .dockerignore ├── backend ├── .eslintignore ├── .prettierrc ├── .dockerignore ├── run_server.sh ├── seed_data.sh ├── .idea │ ├── vcs.xml │ ├── modules.xml │ ├── jsLibraryMappings.xml │ ├── appy.iml │ └── misc.xml ├── server │ ├── emails │ │ ├── contact.hbs.md │ │ ├── welcome.hbs.md │ │ ├── forgot-password.hbs.md │ │ └── invite.hbs.md │ ├── utilities │ │ ├── error-helper.js │ │ └── create-token.js │ ├── models │ │ ├── linking-models │ │ │ ├── user_document.model.js │ │ │ ├── user_conversation.model.js │ │ │ ├── group_permission.model.js │ │ │ ├── role_permission.model.js │ │ │ └── user_permission.model.js │ │ ├── visitor.model.js │ │ ├── conversation.model.js │ │ └── group.model.js │ ├── plugins │ │ ├── api.plugin.js │ │ └── sockets.plugin.js │ ├── api │ │ └── notification.api.js │ └── policies │ │ ├── connection-auth.policy.js │ │ ├── notification-auth.policy.js │ │ └── demo-auth.policy.js ├── scripts │ └── update-permissions.js ├── .env-docker-sample ├── .env-sample ├── .gitrepo ├── Dockerfile ├── index.js ├── .eslintrc.js ├── docker-compose.yml ├── CONTRIBUTING.md ├── LICENSE.txt ├── test │ └── unit │ │ └── auth.plugin.test.js └── config │ └── manifest.conf.js ├── .gitattributes ├── .travis.yml ├── run_app.sh ├── .idea ├── markdown-navigator │ └── profiles_settings.xml ├── misc.xml ├── vcs.xml ├── jsLibraryMappings.xml ├── markdown-exported-files.xml ├── codeStyleSettings.xml ├── modules.xml └── watcherTasks.xml ├── seed_data.sh ├── .editorconfig ├── netlify.toml ├── LICENSE.txt └── docker-compose.yml /frontend/.nvmrc: -------------------------------------------------------------------------------- 1 | v8.11.1 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | undefined 2 | .idea -------------------------------------------------------------------------------- /backend/.eslintignore: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /frontend/_redirects: -------------------------------------------------------------------------------- 1 | /* / 200 -------------------------------------------------------------------------------- /frontend/static/css/imported/bootstrap.min.css.map.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/Responsive/Readme.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /frontend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | backend/* linguist-vendored 2 | frontend/static/* linguist-vendored 3 | -------------------------------------------------------------------------------- /backend/.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/assets 3 | **/.idea 4 | .gitignore 5 | .prettierrc 6 | -------------------------------------------------------------------------------- /frontend/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/logo.png -------------------------------------------------------------------------------- /frontend/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/favicon.ico -------------------------------------------------------------------------------- /frontend/static/img/logo_sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/logo_sm.png -------------------------------------------------------------------------------- /frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/build 3 | **/test 4 | .prettierrc 5 | yarn.lock 6 | packge-lock.json 7 | -------------------------------------------------------------------------------- /frontend/static/img/demo/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/icons.png -------------------------------------------------------------------------------- /frontend/static/img/fa-expand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/fa-expand.png -------------------------------------------------------------------------------- /frontend/static/img/logo_blk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/logo_blk.png -------------------------------------------------------------------------------- /frontend/static/img/demo/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/avatar.png -------------------------------------------------------------------------------- /frontend/static/img/demo/avatar2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/avatar2.png -------------------------------------------------------------------------------- /frontend/static/img/demo/avatar3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/avatar3.png -------------------------------------------------------------------------------- /frontend/static/img/demo/avatar5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/avatar5.png -------------------------------------------------------------------------------- /frontend/static/img/demo/photo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/photo1.png -------------------------------------------------------------------------------- /frontend/static/img/demo/photo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/photo2.png -------------------------------------------------------------------------------- /frontend/static/img/demo/photo3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/photo3.jpg -------------------------------------------------------------------------------- /frontend/static/img/demo/photo4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/photo4.jpg -------------------------------------------------------------------------------- /frontend/static/img/logo_blk_sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/logo_blk_sm.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 'node' 4 | install: 5 | - 'npm install' 6 | script: 7 | - 'npm run build' -------------------------------------------------------------------------------- /frontend/static/img/demo/avatar04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/avatar04.png -------------------------------------------------------------------------------- /frontend/static/img/demo/boxed-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/boxed-bg.jpg -------------------------------------------------------------------------------- /frontend/static/img/demo/boxed-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/boxed-bg.png -------------------------------------------------------------------------------- /frontend/static/img/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/favicon-16x16.png -------------------------------------------------------------------------------- /frontend/static/img/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/favicon-32x32.png -------------------------------------------------------------------------------- /run_app.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./backend/.env-docker 4 | export SERVER_PORT=${SERVER_PORT} 5 | docker-compose up --build -------------------------------------------------------------------------------- /frontend/static/img/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/apple-touch-icon.png -------------------------------------------------------------------------------- /frontend/static/img/demo/default-50x50.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/default-50x50.gif -------------------------------------------------------------------------------- /frontend/static/img/demo/user1-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/user1-128x128.jpg -------------------------------------------------------------------------------- /frontend/static/img/demo/user2-160x160.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/user2-160x160.jpg -------------------------------------------------------------------------------- /frontend/static/img/demo/user3-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/user3-128x128.jpg -------------------------------------------------------------------------------- /frontend/static/img/demo/user4-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/user4-128x128.jpg -------------------------------------------------------------------------------- /frontend/static/img/demo/user5-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/user5-128x128.jpg -------------------------------------------------------------------------------- /frontend/static/img/demo/user6-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/user6-128x128.jpg -------------------------------------------------------------------------------- /frontend/static/img/demo/user7-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/user7-128x128.jpg -------------------------------------------------------------------------------- /frontend/static/img/demo/user8-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/demo/user8-128x128.jpg -------------------------------------------------------------------------------- /frontend/static/img/stock/user1-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/stock/user1-128x128.jpg -------------------------------------------------------------------------------- /frontend/static/img/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/android-chrome-192x192.png -------------------------------------------------------------------------------- /frontend/static/img/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/android-chrome-512x512.png -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /frontend/static/css/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/css/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /frontend/static/css/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/css/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /frontend/static/css/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/css/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /frontend/static/img/color_logo_transparent_no_container.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/color_logo_transparent_no_container.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/images/sort_asc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/images/sort_asc.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/images/sort_both.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/images/sort_both.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/images/sort_desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/images/sort_desc.png -------------------------------------------------------------------------------- /seed_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./backend/.env-docker 4 | export SERVER_PORT=${SERVER_PORT} 5 | docker-compose build && docker-compose run --rm api npm run seed -------------------------------------------------------------------------------- /backend/run_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source .env-docker 4 | export SERVER_PORT=${SERVER_PORT} 5 | export COMPOSE_PROJECT_NAME=appy_backend 6 | docker-compose up --build -------------------------------------------------------------------------------- /frontend/static/css/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/css/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /frontend/test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /frontend/test/unit/coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/test/unit/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/images/sort_asc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/images/sort_asc_disabled.png -------------------------------------------------------------------------------- /frontend/static/img/color_logo_transparent_no_container_no_slogan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/color_logo_transparent_no_container_no_slogan.png -------------------------------------------------------------------------------- /frontend/static/img/white_logo_transparent_no_container_no_slogan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/img/white_logo_transparent_no_container_no_slogan.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/FixedHeader/css/dataTables.fixedHeader.min.css: -------------------------------------------------------------------------------- 1 | div.FixedHeader_Cloned th,div.FixedHeader_Cloned td{background-color:white !important} 2 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/KeyTable/css/dataTables.keyTable.min.css: -------------------------------------------------------------------------------- 1 | table.KeyTable th.focus,table.KeyTable td.focus{outline:3px solid #3366FF;outline-offset:-3px} 2 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/images/sort_desc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/images/sort_desc_disabled.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/csv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/csv.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/pdf.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/xls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/xls.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/AutoFill/images/filler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/AutoFill/images/filler.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/copy.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/print.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/ColReorder/images/insert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/ColReorder/images/insert.png -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /backend/seed_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source .env-docker 4 | export SERVER_PORT=${SERVER_PORT} 5 | export COMPOSE_PROJECT_NAME=appy_backend 6 | docker-compose build && docker-compose run --rm api npm run seed -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/collection.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/copy_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/copy_hover.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/csv_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/csv_hover.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/pdf_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/pdf_hover.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/xls_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/xls_hover.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/swf/copy_csv_xls.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/swf/copy_csv_xls.swf -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/FixedHeader/css/dataTables.fixedHeader.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | div.FixedHeader_Cloned th, 4 | div.FixedHeader_Cloned td { 5 | background-color: white !important; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/print_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/print_hover.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/psd/printer.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/psd/printer.psd -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/swf/copy_csv_xls_pdf.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/swf/copy_csv_xls_pdf.swf -------------------------------------------------------------------------------- /backend/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/KeyTable/css/dataTables.keyTable.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | table.KeyTable th.focus, 4 | table.KeyTable td.focus { 5 | outline: 3px solid #3366FF; 6 | outline-offset: -3px; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/psd/collection.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/psd/collection.psd -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/psd/file_types.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/psd/file_types.psd -------------------------------------------------------------------------------- /frontend/config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"', 3 | SERVER_URI: '"https://api.appyapp.io"', 4 | WEBSOCKET_URI: '"wss://api.appyapp.io"', 5 | APP_URI: '"https://demo.appyapp.io"' 6 | } 7 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/Scroller/images/loading-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/Scroller/images/loading-background.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/collection_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/collection_hover.png -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/images/psd/copy document.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JKHeadley/appy/HEAD/frontend/static/js/plugins/datatables/extensions/TableTools/images/psd/copy document.psd -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/ColReorder/css/dataTables.colReorder.min.css: -------------------------------------------------------------------------------- 1 | table.DTCR_clonedTable{background-color:rgba(255,255,255,0.7);z-index:202}div.DTCR_pointer{width:1px;background-color:#0259C4;z-index:201} 2 | -------------------------------------------------------------------------------- /.idea/markdown-exported-files.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /frontend/src/store/state.js: -------------------------------------------------------------------------------- 1 | export default { 2 | breadcrumbs: [], 3 | conversations: [], 4 | notifications: [], 5 | userInfo: { 6 | messages: [{ 1: 'test', 2: 'test' }], 7 | notifications: [], 8 | tasks: [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /backend/server/emails/contact.hbs.md: -------------------------------------------------------------------------------- 1 | ### Contact Form 2 | 3 | | Field | Value | 4 | | --------:|:----------- | 5 | | Name: | {{name}} | 6 | | Email: | {{email}} | 7 | | Message: | {{message}} | 8 | 9 | Love, 10 | 11 | The appy Team 12 | -------------------------------------------------------------------------------- /backend/server/emails/welcome.hbs.md: -------------------------------------------------------------------------------- 1 | ### Welcome Aboard 2 | 3 | Thanks for signing up! You're almost done, please click on the link below within 24 hours to activate your account: 4 | 5 | {{clientURL}}/activate?token={{key}} 6 | 7 | 8 | Love, 9 | 10 | The {{websiteName}} Team 11 | -------------------------------------------------------------------------------- /frontend/src/services/event-bus.service.js: -------------------------------------------------------------------------------- 1 | // We use a global event bus to enable events defined in the config. 2 | // Learn more about global event buses here: https://alligator.io/vuejs/global-event-bus/ 3 | import Vue from 'vue' 4 | const eventBus = new Vue() 5 | export default eventBus 6 | -------------------------------------------------------------------------------- /backend/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /backend/.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /backend/server/emails/forgot-password.hbs.md: -------------------------------------------------------------------------------- 1 | ### Forgot your password? 2 | 3 | We received a request to reset the password for your account, please click the link below to continue. 4 | 5 | {{clientURL}}/login/reset?token={{key}}&pinRequired={{pinRequired}} 6 | 7 | Love, 8 | 9 | The {{websiteName}} Team 10 | -------------------------------------------------------------------------------- /frontend/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { "modules": false }], 4 | "stage-2" 5 | ], 6 | "plugins": ["transform-runtime"], 7 | "comments": false, 8 | "env": { 9 | "test": { 10 | "presets": ["env", "stage-2"], 11 | "plugins": [ "istanbul" ] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /frontend/config/test.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var devEnv = require('./dev.env') 3 | 4 | module.exports = merge(devEnv, { 5 | NODE_ENV: '"testing"', 6 | SERVER_URI: '"http://localhost:8080"', 7 | WEBSOCKET_URI: '"ws://localhost:8080"', 8 | APP_URI: '"http://localhost:3000"' 9 | }) 10 | -------------------------------------------------------------------------------- /.idea/codeStyleSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /backend/server/utilities/error-helper.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | let Boom = require('@hapi/boom') 3 | 4 | function handleError(err, Log) { 5 | if (err.isBoom) { 6 | throw err 7 | } else { 8 | Log.error(err) 9 | throw Boom.badImplementation(err) 10 | } 11 | } 12 | 13 | module.exports = { 14 | handleError 15 | } 16 | -------------------------------------------------------------------------------- /frontend/config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"', 6 | SERVER_URI: '"http://localhost:8080"', 7 | WEBSOCKET_URI: '"ws://localhost:8080"', 8 | APP_URI: '"http://localhost:3000"' 9 | // APP_URI: '"https://appyapp.io"' 10 | }) 11 | -------------------------------------------------------------------------------- /frontend/appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | nodejs_version: "7" 3 | install: 4 | - ps: Install-Product node $env:nodejs_version 5 | - npm install --loglevel=error # no warnings 6 | test_script: 7 | # Output useful info for debugging. 8 | - node --version 9 | - npm --version 10 | # run tests 11 | - npm run build 12 | 13 | # Don't actually build. 14 | build: off -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/ColReorder/css/dataTables.colReorder.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Namespace DTCR - "DataTables ColReorder" plug-in 3 | */ 4 | 5 | table.DTCR_clonedTable { 6 | background-color: rgba(255, 255, 255, 0.7); 7 | z-index: 202; 8 | } 9 | 10 | div.DTCR_pointer { 11 | width: 1px; 12 | background-color: #0259C4; 13 | z-index: 201; 14 | } -------------------------------------------------------------------------------- /frontend/test/unit/specs/404.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import c404 from '@/components/404.vue' 3 | 4 | describe('404.vue', () => { 5 | it('should render correct contents', () => { 6 | const Constructor = Vue.extend(c404) 7 | const vm = new Constructor().$mount() 8 | expect(vm.$el.querySelector('h1').textContent).to.equal('You are lost.') 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /frontend/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var config = require('../config') 3 | var isProduction = process.env.NODE_ENV === 'production' 4 | 5 | module.exports = { 6 | loaders: utils.cssLoaders({ 7 | sourceMap: isProduction 8 | ? config.build.productionSourceMap 9 | : config.dev.cssSourceMap, 10 | extract: isProduction 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /backend/server/models/linking-models/user_document.model.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | 3 | module.exports = function() { 4 | var Types = mongoose.Schema.Types 5 | 6 | var Model = { 7 | Schema: { 8 | canEdit: { 9 | type: Types.Boolean, 10 | default: false 11 | } 12 | }, 13 | modelName: 'user_document' 14 | } 15 | 16 | return Model 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/routes/audit-logs.route.js: -------------------------------------------------------------------------------- 1 | import AuditLogs from '../components/views/audit-logs/AuditLogs.vue' 2 | 3 | const routes = [ 4 | { 5 | path: 'audit-logs', 6 | component: AuditLogs, 7 | name: 'AuditLogs', 8 | meta: { 9 | description: 'List of audit logs', 10 | title: 'AuditLogs', 11 | requiresAuth: true 12 | } 13 | } 14 | ] 15 | 16 | export default routes 17 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/FixedColumns/css/dataTables.fixedColumns.min.css: -------------------------------------------------------------------------------- 1 | table.DTFC_Cloned thead,table.DTFC_Cloned tfoot{background-color:white}div.DTFC_Blocker{background-color:white}div.DTFC_LeftWrapper table.dataTable,div.DTFC_RightWrapper table.dataTable{margin-bottom:0;z-index:2}div.DTFC_LeftWrapper table.dataTable.no-footer,div.DTFC_RightWrapper table.dataTable.no-footer{border-bottom:none} 2 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/AutoFill/css/dataTables.autoFill.min.css: -------------------------------------------------------------------------------- 1 | div.AutoFill_filler{display:none;position:absolute;height:14px;width:14px;background:url(../images/filler.png) no-repeat center center;z-index:1002}div.AutoFill_border{display:none;position:absolute;background-color:#0063dc;z-index:1001;box-shadow:0px 0px 5px #76b4ff;-moz-box-shadow:0px 0px 5px #76b4ff;-webkit-box-shadow:0px 0px 5px #76b4ff} 2 | -------------------------------------------------------------------------------- /frontend/src/routes/connections.route.js: -------------------------------------------------------------------------------- 1 | import Connections from '../components/views/connections/Connections.vue' 2 | 3 | const routes = [ 4 | { 5 | path: 'connections', 6 | component: Connections, 7 | name: 'Connections', 8 | meta: { 9 | description: 'Users connected to you', 10 | title: 'Connections', 11 | requiresAuth: true 12 | } 13 | } 14 | ] 15 | 16 | export default routes 17 | -------------------------------------------------------------------------------- /backend/scripts/update-permissions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.NODE_ENV = 'local' 4 | 5 | const updatePermissions = require('../utilities/update-permissions.utility') 6 | 7 | /** 8 | * A wrapper to run the update-permissions utility as a script. 9 | */ 10 | ;(async function() { 11 | try { 12 | await updatePermissions() 13 | process.exit(0) 14 | } catch (err) { 15 | console.error(err) 16 | process.exit(1) 17 | } 18 | })() 19 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | # Global settings applied to the whole site. 2 | # 3 | # “publish” is the directory to publish (relative to root of your repo), 4 | # “command” is your build command, 5 | # “base” is directory to change to before starting build. if you set base: 6 | # that is where we will look for package.json/.nvmrc/etc not repo root! 7 | 8 | [build] 9 | base = "frontend" 10 | publish = "frontend/dist" 11 | command = "npm install --only=dev && npm run build" 12 | -------------------------------------------------------------------------------- /backend/.env-docker-sample: -------------------------------------------------------------------------------- 1 | JWT_SECRET=secret 2 | SOCIAL_PASSWORD=secret 3 | SMTP_PASSWORD=secret 4 | MONGODB_URI=mongodb://mongo:27017/appy 5 | SERVER_HOST=localhost 6 | SERVER_PORT=8080 7 | CLIENT_URI=http://localhost:3000 8 | FACEBOOK_ID=1234 9 | FACEBOOK_SECRET=abcd 10 | FACEBOOK_ACCESS_TOKEN=5678 11 | GOOGLE_ID=1234 12 | GOOGLE_SECRET=abcd 13 | GITHUB_ID=1234 14 | GITHUB_SECRET=abcd 15 | AWS_ACCESS_KEY_ID=1234 16 | AWS_SECRET_ACCESS_KEY=abcd 17 | IPSTACK_ACCESS_KEY=4321 18 | -------------------------------------------------------------------------------- /backend/.env-sample: -------------------------------------------------------------------------------- 1 | JWT_SECRET=secret 2 | SOCIAL_PASSWORD=secret 3 | SMTP_PASSWORD=secret 4 | MONGODB_URI=mongodb://localhost:27017/appy 5 | SERVER_HOST=localhost 6 | SERVER_PORT=8080 7 | CLIENT_URI=http://localhost:3000 8 | FACEBOOK_ID=1234 9 | FACEBOOK_SECRET=abcd 10 | FACEBOOK_ACCESS_TOKEN=5678 11 | GOOGLE_ID=1234 12 | GOOGLE_SECRET=abcd 13 | GITHUB_ID=1234 14 | GITHUB_SECRET=abcd 15 | AWS_ACCESS_KEY_ID=1234 16 | AWS_SECRET_ACCESS_KEY=abcd 17 | IPSTACK_ACCESS_KEY=4321 18 | -------------------------------------------------------------------------------- /frontend/test/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': function(browser) { 6 | browser 7 | .url('http://localhost:3000') 8 | .waitForElementVisible('#app', 5000) 9 | .assert.elementPresent('.logo') 10 | .assert.containsText('h1', 'DASHBOARD Overview of environment') 11 | .assert.elementCount('p', 4) 12 | .end() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /backend/.gitrepo: -------------------------------------------------------------------------------- 1 | ; DO NOT EDIT (unless you know what you are doing) 2 | ; 3 | ; This subdirectory is a git "subrepo", and this file is maintained by the 4 | ; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme 5 | ; 6 | [subrepo] 7 | remote = https://github.com/JKHeadley/appy-backend.git 8 | branch = master 9 | commit = 36fd63078e2fa0a67277fab023eefa93e43dcf4c 10 | parent = da7468bbc13f6effabea7b38b8a38b5cd27511ba 11 | method = merge 12 | cmdver = 0.4.1 13 | -------------------------------------------------------------------------------- /frontend/src/store/mutations.js: -------------------------------------------------------------------------------- 1 | export default { 2 | TOGGLE_LOADING(state) { 3 | state.callingAPI = !state.callingAPI 4 | }, 5 | TOGGLE_SEARCHING(state) { 6 | state.searching = state.searching === '' ? 'loading' : '' 7 | } 8 | // SET_USER (state, user) { 9 | // state.user = user 10 | // }, 11 | // SET_TOKEN (state, token) { 12 | // state.token = token 13 | // }, 14 | // SET_SESSION (state, session) { 15 | // state.session = session 16 | // } 17 | } 18 | -------------------------------------------------------------------------------- /backend/.idea/appy.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /backend/server/emails/invite.hbs.md: -------------------------------------------------------------------------------- 1 | ### Welcome Aboard 2 | 3 | Hello! {{inviteeName}} has invited you to join {{websiteName}}. An account has already been created for you, 4 | please click on the link below within 24 hours to activate your account: 5 | 6 | {{clientURL}}/activate?token={{key}} 7 | 8 | You can login using the following credentials: 9 | 10 | Email: {{email}} 11 | 12 | Password: {{password}} 13 | 14 | NOTE: You will be required to update your password and PIN once you login. 15 | 16 | Love, 17 | 18 | The Scal.io Team 19 | -------------------------------------------------------------------------------- /frontend/static/img/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "appy", 3 | "short_name": "appy", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/services/document.service.js: -------------------------------------------------------------------------------- 1 | import vm from '../main' 2 | 3 | const internals = {} 4 | 5 | internals.updateDocument = function(document) { 6 | document = Object.assign({}, document) 7 | 8 | delete document.users 9 | delete document.scope 10 | delete document.owner 11 | 12 | return vm.$documentRepository.update(document._id, document) 13 | } 14 | 15 | internals.updateDocumentUsers = function(documentId, usersToInvite) { 16 | return vm.$documentRepository.addManyUsers(documentId, usersToInvite) 17 | } 18 | 19 | export default internals 20 | -------------------------------------------------------------------------------- /backend/server/models/linking-models/user_conversation.model.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | 3 | module.exports = function() { 4 | var Types = mongoose.Schema.Types 5 | 6 | var Model = { 7 | Schema: { 8 | // This property is true if the user has read all the messages, false if there are new messages that 9 | // the user hasn't read 10 | hasRead: { 11 | type: Types.Boolean, 12 | required: true, 13 | default: false 14 | } 15 | }, 16 | modelName: 'user_conversation' 17 | } 18 | 19 | return Model 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/services/file.service.js: -------------------------------------------------------------------------------- 1 | import { httpClient as http } from '../services' 2 | 3 | const internals = {} 4 | 5 | internals.uploadProfileImage = (name, file, options) => { 6 | let data = new FormData() 7 | data.append('name', name) 8 | data.append('file', file) 9 | return http.post('/file/upload/profile-image', data, options) 10 | } 11 | 12 | internals.uploadImage = (name, file, options) => { 13 | let data = new FormData() 14 | data.append('name', name) 15 | data.append('file', file) 16 | return http.post('/file/upload/image', data, options) 17 | } 18 | 19 | export default internals 20 | -------------------------------------------------------------------------------- /backend/server/plugins/api.plugin.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const mongoose = require('mongoose') 4 | const RestHapi = require('rest-hapi') 5 | 6 | const Config = require('../../config') 7 | 8 | module.exports = { 9 | plugin: { 10 | name: 'api', 11 | register 12 | } 13 | } 14 | 15 | async function register(server, options) { 16 | try { 17 | await server.register({ 18 | plugin: RestHapi, 19 | options: { 20 | mongoose, 21 | config: Config.get('/restHapiConfig') 22 | } 23 | }) 24 | } catch (err) { 25 | console.error('Failed to load plugin:', err) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /frontend/test/e2e/reports/CHROME_61.0.3163.100_Mac OS X_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.kr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Korean translation for bootstrap-datepicker 3 | * Gu Youn 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['kr'] = { 7 | days: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일", "일요일"], 8 | daysShort: ["일", "월", "화", "수", "목", "금", "토", "일"], 9 | daysMin: ["일", "월", "화", "수", "목", "금", "토", "일"], 10 | months: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"], 11 | monthsShort: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"] 12 | }; 13 | }(jQuery)); 14 | -------------------------------------------------------------------------------- /frontend/src/routes/images.route.js: -------------------------------------------------------------------------------- 1 | import Images from '../components/views/images/Images.vue' 2 | import ImageCreate from '../components/views/images/ImageCreate.vue' 3 | 4 | const routes = [ 5 | { 6 | path: 'images', 7 | component: Images, 8 | name: 'Images', 9 | meta: { description: 'Your images', title: 'Images', requiresAuth: true } 10 | }, 11 | { 12 | path: '/images/create', 13 | component: ImageCreate, 14 | name: 'ImageCreate', 15 | meta: { 16 | description: 'Create a new image', 17 | title: 'Image', 18 | requiresAuth: true 19 | } 20 | } 21 | ] 22 | 23 | export default routes 24 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/Scroller/css/dataTables.scroller.min.css: -------------------------------------------------------------------------------- 1 | div.DTS tbody th,div.DTS tbody td{white-space:nowrap}div.DTS tbody tr.even{background-color:white}div.DTS div.DTS_Loading{position:absolute;top:50%;left:50%;width:200px;height:20px;margin-top:-20px;margin-left:-100px;z-index:1;border:1px solid #999;padding:20px 0;text-align:center;background-color:white;background-color:rgba(255,255,255,0.5)}div.DTS div.dataTables_scrollHead,div.DTS div.dataTables_scrollFoot{background-color:white}div.DTS div.dataTables_scrollBody{z-index:2}div.DTS div.dataTables_scroll{background:url("../images/loading-background.png") repeat 0 0} 2 | -------------------------------------------------------------------------------- /backend/server/models/linking-models/group_permission.model.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | 3 | const _ = require('lodash') 4 | const Config = require('../../../config') 5 | 6 | const PERMISSION_STATES = Config.get('/constants/PERMISSION_STATES') 7 | 8 | module.exports = function() { 9 | var Types = mongoose.Schema.Types 10 | 11 | var Model = { 12 | Schema: { 13 | state: { 14 | type: Types.String, 15 | enum: _.values(PERMISSION_STATES), 16 | required: true, 17 | default: PERMISSION_STATES.INCLUDED 18 | } 19 | }, 20 | modelName: 'group_permission' 21 | } 22 | 23 | return Model 24 | } 25 | -------------------------------------------------------------------------------- /backend/server/models/linking-models/role_permission.model.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | 3 | const _ = require('lodash') 4 | const Config = require('../../../config') 5 | 6 | const PERMISSION_STATES = Config.get('/constants/PERMISSION_STATES') 7 | 8 | module.exports = function() { 9 | var Types = mongoose.Schema.Types 10 | 11 | var Model = { 12 | Schema: { 13 | state: { 14 | type: Types.String, 15 | enum: _.values(PERMISSION_STATES), 16 | required: true, 17 | default: PERMISSION_STATES.INCLUDED 18 | } 19 | }, 20 | modelName: 'role_permission' 21 | } 22 | 23 | return Model 24 | } 25 | -------------------------------------------------------------------------------- /backend/server/models/linking-models/user_permission.model.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | 3 | const _ = require('lodash') 4 | const Config = require('../../../config') 5 | 6 | const PERMISSION_STATES = Config.get('/constants/PERMISSION_STATES') 7 | 8 | module.exports = function() { 9 | var Types = mongoose.Schema.Types 10 | 11 | var Model = { 12 | Schema: { 13 | state: { 14 | type: Types.String, 15 | enum: _.values(PERMISSION_STATES), 16 | required: true, 17 | default: PERMISSION_STATES.INCLUDED 18 | } 19 | }, 20 | modelName: 'user_permission' 21 | } 22 | 23 | return Model 24 | } 25 | -------------------------------------------------------------------------------- /frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:carbon-alpine 2 | 3 | # Create and set the working directory 4 | RUN mkdir /frontend 5 | WORKDIR /frontend 6 | 7 | # Only copy package.json. All other files wil be shared with the host through a volume. 8 | # NOTE: For a production image, we should COPY all files so that the image is self-sufficient (and only use volumes 9 | # for data storage/persistent data). 10 | COPY ./package.json /frontend 11 | # Install node dependencies 12 | RUN npm install 13 | 14 | # Make port 3000 available to the world outside this container 15 | EXPOSE 3000 16 | 17 | # Run the start script when the container launches 18 | CMD ["npm", "run", "start"] 19 | -------------------------------------------------------------------------------- /frontend/src/components/App.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.gl.js: -------------------------------------------------------------------------------- 1 | ;(function($){ 2 | $.fn.datepicker.dates['gl'] = { 3 | days: ["Domingo", "Luns", "Martes", "Mércores", "Xoves", "Venres", "Sábado", "Domingo"], 4 | daysShort: ["Dom", "Lun", "Mar", "Mér", "Xov", "Ven", "Sáb", "Dom"], 5 | daysMin: ["Do", "Lu", "Ma", "Me", "Xo", "Ve", "Sa", "Do"], 6 | months: ["Xaneiro", "Febreiro", "Marzo", "Abril", "Maio", "Xuño", "Xullo", "Agosto", "Setembro", "Outubro", "Novembro", "Decembro"], 7 | monthsShort: ["Xan", "Feb", "Mar", "Abr", "Mai", "Xun", "Xul", "Ago", "Sep", "Out", "Nov", "Dec"], 8 | today: "Hoxe", 9 | clear: "Limpar" 10 | }; 11 | }(jQuery)); 12 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/zh-TW.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="請刪掉"+t+"個字元";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="請再輸入"+t+"個字元";return n},loadingMore:function(){return"載入中…"},maximumSelected:function(e){var t="你只能選擇最多"+e.maximum+"項";return t},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/test/unit/index.js: -------------------------------------------------------------------------------- 1 | // Polyfill fn.bind() for PhantomJS 2 | /* eslint-disable no-extend-native */ 3 | Function.prototype.bind = require('function-bind') 4 | 5 | require('es6-promise').polyfill() 6 | 7 | // require all test files (files that ends with .spec.js) 8 | var testsContext = require.context('./specs', true, /\.spec$/) 9 | testsContext.keys().forEach(testsContext) 10 | 11 | // require all src files except main.js for coverage. 12 | // you can also change this to match only the subset of files that 13 | // you want coverage for. 14 | var srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/) 15 | srcContext.keys().forEach(srcContext) 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.ja.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Japanese translation for bootstrap-datepicker 3 | * Norio Suzuki 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ja'] = { 7 | days: ["日曜", "月曜", "火曜", "水曜", "木曜", "金曜", "土曜", "日曜"], 8 | daysShort: ["日", "月", "火", "水", "木", "金", "土", "日"], 9 | daysMin: ["日", "月", "火", "水", "木", "金", "土", "日"], 10 | months: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], 11 | monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], 12 | today: "今日", 13 | format: "yyyy/mm/dd" 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/AutoFill/css/dataTables.autoFill.css: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * AutoFill styles 3 | */ 4 | 5 | div.AutoFill_filler { 6 | display: none; 7 | position: absolute; 8 | height: 14px; 9 | width: 14px; 10 | background: url(../images/filler.png) no-repeat center center; 11 | z-index: 1002; 12 | } 13 | 14 | div.AutoFill_border { 15 | display: none; 16 | position: absolute; 17 | background-color: #0063dc; 18 | z-index: 1001; 19 | 20 | box-shadow: 0px 0px 5px #76b4ff; 21 | -moz-box-shadow: 0px 0px 5px #76b4ff; 22 | -webkit-box-shadow: 0px 0px 5px #76b4ff; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /frontend/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import createPersistedState from 'vuex-persistedstate' 4 | import generateMutations from './utilities/generate-mutations' 5 | 6 | import auth from './modules/auth' 7 | // import websocket from './modules/websocket' 8 | 9 | import state from './state' 10 | import actions from './actions' 11 | import mutations from './mutations' 12 | 13 | Vue.use(Vuex) 14 | 15 | export default new Vuex.Store({ 16 | state, 17 | actions, 18 | mutations: Object.assign(mutations, generateMutations(state)), 19 | modules: { 20 | auth 21 | // websocket 22 | }, 23 | plugins: [createPersistedState()] 24 | }) 25 | -------------------------------------------------------------------------------- /backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:erbium 2 | 3 | # Create and set the working directory 4 | RUN mkdir /backend 5 | WORKDIR /backend 6 | 7 | # Only copy package.json. All other files wil be shared with the host through a volume. 8 | # NOTE: For a production image, we should COPY all files so that the image is self-sufficient (and only use volumes 9 | # for data storage/persistent data). 10 | COPY ./package.json /backend 11 | # Install node dependencies 12 | RUN npm install 13 | 14 | ARG SERVER_PORT=8080 15 | # Make the server port available to the world outside this container 16 | EXPOSE ${SERVER_PORT} 17 | 18 | # Run the start script when the container launches 19 | CMD ["npm", "run", "start"] 20 | -------------------------------------------------------------------------------- /backend/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const Glue = require('@hapi/glue') 3 | const RestHapi = require('rest-hapi') 4 | const Manifest = require('./config/manifest.conf') 5 | 6 | const composeOptions = { 7 | relativeTo: __dirname 8 | } 9 | 10 | const startServer = async function() { 11 | try { 12 | const manifest = Manifest.get('/') 13 | const server = await Glue.compose(manifest, composeOptions) 14 | 15 | await server.start() 16 | 17 | RestHapi.logUtil.logActionComplete( 18 | RestHapi.logger, 19 | 'Server Initialized', 20 | server.info 21 | ) 22 | } catch (err) { 23 | console.error(err) 24 | process.exit(1) 25 | } 26 | } 27 | 28 | startServer() 29 | -------------------------------------------------------------------------------- /frontend/src/components/404.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | You are lost. 8 | This page doesn't exist. 9 | Take me home. 10 | 11 | 12 | 13 | 14 | 15 | 20 | 21 | -------------------------------------------------------------------------------- /backend/server/api/notification.api.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // const Chalk = require('chalk') 4 | 5 | module.exports = function(server, mongoose, logger) { 6 | // Create the notification subscription 7 | ;(function() { 8 | // const Log = logger.bind(Chalk.magenta('Notification Subscription')) 9 | 10 | server.subscription('/notification/{userId}', { 11 | filter: function(path, message, options) { 12 | return true 13 | }, 14 | auth: { 15 | scope: ['root', 'receiveNotifications', '!-receiveNotifications'], 16 | entity: 'user', 17 | index: true 18 | }, 19 | onSubscribe: function(socket, path, params) {} 20 | }) 21 | })() 22 | } 23 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.hr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Croatian localisation 3 | */ 4 | ;(function($){ 5 | $.fn.datepicker.dates['hr'] = { 6 | days: ["Nedjelja", "Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota", "Nedjelja"], 7 | daysShort: ["Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub", "Ned"], 8 | daysMin: ["Ne", "Po", "Ut", "Sr", "Če", "Pe", "Su", "Ne"], 9 | months: ["Siječanj", "Veljača", "Ožujak", "Travanj", "Svibanj", "Lipanj", "Srpanj", "Kolovoz", "Rujan", "Listopad", "Studeni", "Prosinac"], 10 | monthsShort: ["Sij", "Velj", "Ožu", "Tra", "Svi", "Lip", "Srp", "Kol", "Ruj", "Lis", "Stu", "Pro"], 11 | today: "Danas" 12 | }; 13 | }(jQuery)); 14 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/zh-CN.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="请删除"+t+"个字符";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="请再输入至少"+t+"个字符";return n},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(e){var t="最多只能选择"+e.maximum+"个项目";return t},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/test/unit/coverage/lcov-report/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/az.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/az",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return t+" simvol silin"},inputTooShort:function(e){var t=e.minimum-e.input.length;return t+" simvol daxil edin"},loadingMore:function(){return"Daha çox nəticə yüklənir…"},maximumSelected:function(e){return"Sadəcə "+e.maximum+" element seçə bilərsiniz"},noResults:function(){return"Nəticə tapılmadı"},searching:function(){return"Axtarılır…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.zh-CN.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Simplified Chinese translation for bootstrap-datepicker 3 | * Yuan Cheung 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['zh-CN'] = { 7 | days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], 8 | daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"], 9 | daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], 10 | months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], 11 | monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], 12 | today: "今日", 13 | format: "yyyy年mm月dd日", 14 | weekStart: 1 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /backend/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/fi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Ole hyvä ja anna "+t+" merkkiä vähemmän"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Ole hyvä ja anna "+t+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(e){return"Voit valita ainoastaan "+e.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/FixedColumns/css/dataTables.fixedColumns.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* Block out what is behind the fixed column's header and footer */ 4 | table.DTFC_Cloned thead, 5 | table.DTFC_Cloned tfoot { 6 | background-color: white; 7 | } 8 | 9 | /* Block out the gap above the scrollbar on the right, when there is a fixed 10 | * right column 11 | */ 12 | div.DTFC_Blocker { 13 | background-color: white; 14 | } 15 | 16 | div.DTFC_LeftWrapper table.dataTable, 17 | div.DTFC_RightWrapper table.dataTable { 18 | margin-bottom: 0; 19 | z-index: 2; 20 | } 21 | 22 | div.DTFC_LeftWrapper table.dataTable.no-footer, 23 | div.DTFC_RightWrapper table.dataTable.no-footer { 24 | border-bottom: none; 25 | } 26 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/ja.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ja",[],function(){return{errorLoading:function(){return"結果が読み込まれませんでした"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" 文字を削除してください";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="少なくとも "+t+" 文字を入力してください";return n},loadingMore:function(){return"読み込み中…"},maximumSelected:function(e){var t=e.maximum+" 件しか選択できません";return t},noResults:function(){return"対象が見つかりません"},searching:function(){return"検索しています…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.az.js: -------------------------------------------------------------------------------- 1 | // Azerbaijani 2 | ;(function($){ 3 | $.fn.datepicker.dates['az'] = { 4 | days: ["Bazar", "Bazar ertəsi", "Çərşənbə axşamı", "Çərşənbə", "Cümə axşamı", "Cümə", "Şənbə", "Bazar"], 5 | daysShort: ["B.", "B.e", "Ç.a", "Ç.", "C.a", "C.", "Ş.", "B."], 6 | daysMin: ["B.", "B.e", "Ç.a", "Ç.", "C.a", "C.", "Ş.", "B."], 7 | months: ["Yanvar", "Fevral", "Mart", "Aprel", "May", "İyun", "İyul", "Avqust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr"], 8 | monthsShort: ["Yan", "Fev", "Mar", "Apr", "May", "İyun", "İyul", "Avq", "Sen", "Okt", "Noy", "Dek"], 9 | today: "Bu gün", 10 | weekStart: 1 11 | }; 12 | }(jQuery)); 13 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.cy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welsh translation for bootstrap-datepicker 3 | * S. Morris 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['cy'] = { 7 | days: ["Sul", "Llun", "Mawrth", "Mercher", "Iau", "Gwener", "Sadwrn", "Sul"], 8 | daysShort: ["Sul", "Llu", "Maw", "Mer", "Iau", "Gwe", "Sad", "Sul"], 9 | daysMin: ["Su", "Ll", "Ma", "Me", "Ia", "Gwe", "Sa", "Su"], 10 | months: ["Ionawr", "Chewfror", "Mawrth", "Ebrill", "Mai", "Mehefin", "Gorfennaf", "Awst", "Medi", "Hydref", "Tachwedd", "Rhagfyr"], 11 | monthsShort: ["Ion", "Chw", "Maw", "Ebr", "Mai", "Meh", "Gor", "Aws", "Med", "Hyd", "Tach", "Rha"], 12 | today: "Heddiw" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.he.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hebrew translation for bootstrap-datepicker 3 | * Sagie Maoz 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['he'] = { 7 | days: ["ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת", "ראשון"], 8 | daysShort: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], 9 | daysMin: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], 10 | months: ["ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"], 11 | monthsShort: ["ינו", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ"], 12 | today: "היום", 13 | rtl: true 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.ms.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Malay translation for bootstrap-datepicker 3 | * Ateman Faiz 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ms'] = { 7 | days: ["Ahad", "Isnin", "Selasa", "Rabu", "Khamis", "Jumaat", "Sabtu", "Ahad"], 8 | daysShort: ["Aha", "Isn", "Sel", "Rab", "Kha", "Jum", "Sab", "Aha"], 9 | daysMin: ["Ah", "Is", "Se", "Ra", "Kh", "Ju", "Sa", "Ah"], 10 | months: ["Januari", "Februari", "Mac", "April", "Mei", "Jun", "Julai", "Ogos", "September", "Oktober", "November", "Disember"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ogo", "Sep", "Okt", "Nov", "Dis"], 12 | today: "Hari Ini" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/hu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Túl hosszú. "+t+" karakterrel több, mint kellene."},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Túl rövid. Még "+t+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/th.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/th",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="โปรดลบออก "+t+" ตัวอักษร";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="โปรดพิมพ์เพิ่มอีก "+t+" ตัวอักษร";return n},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(e){var t="คุณสามารถเลือกได้ไม่เกิน "+e.maximum+" รายการ";return t},noResults:function(){return"ไม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/tr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/tr",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" karakter daha girmelisiniz";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="En az "+t+" karakter daha girmelisiniz";return n},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(e){var t="Sadece "+e.maximum+" seçim yapabilirsiniz";return t},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.no.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Norwegian translation for bootstrap-datepicker 3 | **/ 4 | ;(function($){ 5 | $.fn.datepicker.dates['no'] = { 6 | days: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'], 7 | daysShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'], 8 | daysMin: ['Sø','Ma','Ti','On','To','Fr','Lø'], 9 | months: ['Januar','Februar','Mars','April','Mai','Juni','Juli','August','September','Oktober','November','Desember'], 10 | monthsShort: ['Jan','Feb','Mar','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Des'], 11 | today: 'I dag', 12 | clear: 'Nullstill', 13 | weekStart: 1, 14 | format: 'dd.mm.yyyy' 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/ko.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="너무 깁니다. "+t+" 글자 지워주세요.";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="너무 짧습니다. "+t+" 글자 더 입력해주세요.";return n},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(e){var t="최대 "+e.maximum+"개까지만 선택 가능합니다.";return t},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/nb.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nb",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Vennligst fjern "+t+" tegn"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vennligst skriv inn ";return t>1?n+=" flere tegn":n+=" tegn til",n},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.ca.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Catalan translation for bootstrap-datepicker 3 | * J. Garcia 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ca'] = { 7 | days: ["Diumenge", "Dilluns", "Dimarts", "Dimecres", "Dijous", "Divendres", "Dissabte", "Diumenge"], 8 | daysShort: ["Diu", "Dil", "Dmt", "Dmc", "Dij", "Div", "Dis", "Diu"], 9 | daysMin: ["dg", "dl", "dt", "dc", "dj", "dv", "ds", "dg"], 10 | months: ["Gener", "Febrer", "Març", "Abril", "Maig", "Juny", "Juliol", "Agost", "Setembre", "Octubre", "Novembre", "Desembre"], 11 | monthsShort: ["Gen", "Feb", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Oct", "Nov", "Des"], 12 | today: "Avui" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.el.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Greek translation for bootstrap-datepicker 3 | */ 4 | ;(function($){ 5 | $.fn.datepicker.dates['el'] = { 6 | days: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο", "Κυριακή"], 7 | daysShort: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ"], 8 | daysMin: ["Κυ", "Δε", "Τρ", "Τε", "Πε", "Πα", "Σα", "Κυ"], 9 | months: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"], 10 | monthsShort: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μάι", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"], 11 | today: "Σήμερα" 12 | }; 13 | }(jQuery)); 14 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.rs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Serbian cyrillic translation for bootstrap-datepicker 3 | * Bojan Milosavlević 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['rs'] = { 7 | days: ["Недеља","Понедељак", "Уторак", "Среда", "Четвртак", "Петак", "Субота", "Недеља"], 8 | daysShort: ["Нед", "Пон", "Уто", "Сре", "Чет", "Пет", "Суб", "Нед"], 9 | daysMin: ["Н", "По", "У", "Ср", "Ч", "Пе", "Су", "Н"], 10 | months: ["Јануар", "Фебруар", "Март", "Април", "Мај", "Јун", "Јул", "Август", "Септембар", "Октобар", "Новембар", "Децембар"], 11 | monthsShort: ["Јан", "Феб", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Нов", "Дец"], 12 | today: "Данас" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.th.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Thai translation for bootstrap-datepicker 3 | * Suchau Jiraprapot 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['th'] = { 7 | days: ["อาทิตย์", "จันทร์", "อังคาร", "พุธ", "พฤหัส", "ศุกร์", "เสาร์", "อาทิตย์"], 8 | daysShort: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], 9 | daysMin: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], 10 | months: ["มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม"], 11 | monthsShort: ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."], 12 | today: "วันนี้" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.bg.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bulgarian translation for bootstrap-datepicker 3 | * Apostol Apostolov 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['bg'] = { 7 | days: ["Неделя", "Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота", "Неделя"], 8 | daysShort: ["Нед", "Пон", "Вто", "Сря", "Чет", "Пет", "Съб", "Нед"], 9 | daysMin: ["Н", "П", "В", "С", "Ч", "П", "С", "Н"], 10 | months: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"], 11 | monthsShort: ["Ян", "Фев", "Мар", "Апр", "Май", "Юни", "Юли", "Авг", "Сеп", "Окт", "Ное", "Дек"], 12 | today: "днес" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.es.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Spanish translation for bootstrap-datepicker 3 | * Bruno Bonamin 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['es'] = { 7 | days: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo"], 8 | daysShort: ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb", "Dom"], 9 | daysMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa", "Do"], 10 | months: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"], 11 | monthsShort: ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"], 12 | today: "Hoy" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.nl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dutch translation for bootstrap-datepicker 3 | * Reinier Goltstein 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['nl'] = { 7 | days: ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"], 8 | daysShort: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], 9 | daysMin: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], 10 | months: ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mrt", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], 12 | today: "Vandaag" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.sl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Slovene translation for bootstrap-datepicker 3 | * Gregor Rudolf 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['sl'] = { 7 | days: ["Nedelja", "Ponedeljek", "Torek", "Sreda", "Četrtek", "Petek", "Sobota", "Nedelja"], 8 | daysShort: ["Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob", "Ned"], 9 | daysMin: ["Ne", "Po", "To", "Sr", "Če", "Pe", "So", "Ne"], 10 | months: ["Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], 12 | today: "Danes" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.rs-latin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Serbian latin translation for bootstrap-datepicker 3 | * Bojan Milosavlević 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['rs-latin'] = { 7 | days: ["Nedelja","Ponedeljak", "Utorak", "Sreda", "Četvrtak", "Petak", "Subota", "Nedelja"], 8 | daysShort: ["Ned", "Pon", "Uto", "Sre", "Čet", "Pet", "Sub", "Ned"], 9 | daysMin: ["N", "Po", "U", "Sr", "Č", "Pe", "Su", "N"], 10 | months: ["Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], 12 | today: "Danas" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /backend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // http://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module', 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 13 | extends: ['prettier-standard'], 14 | plugins: ['prettier'], 15 | // add your custom rules here 16 | rules: { 17 | // allow paren-less arrow functions 18 | 'arrow-parens': 0, 19 | // allow async-await 20 | 'generator-star-spacing': 0, 21 | // allow debugger during development 22 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 23 | 'prettier/prettier': 'error', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.nb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Norwegian (bokmål) translation for bootstrap-datepicker 3 | * Fredrik Sundmyhr 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['nb'] = { 7 | days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], 8 | daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], 9 | daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], 10 | months: ["Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"], 12 | today: "I Dag" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.sq.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Albanian translation for bootstrap-datepicker 3 | * Tomor Pupovci 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['sq'] = { 7 | days: ["E Diel", "E Hënë", "E martē", "E mërkurë", "E Enjte", "E Premte", "E Shtunë", "E Diel"], 8 | daysShort: ["Die", "Hën", "Mar", "Mër", "Enj", "Pre", "Shtu", "Die"], 9 | daysMin: ["Di", "Hë", "Ma", "Më", "En", "Pr", "Sht", "Di"], 10 | months: ["Janar", "Shkurt", "Mars", "Prill", "Maj", "Qershor", "Korrik", "Gusht", "Shtator", "Tetor", "Nëntor", "Dhjetor"], 11 | monthsShort: ["Jan", "Shk", "Mar", "Pri", "Maj", "Qer", "Korr", "Gu", "Sht", "Tet", "Nën", "Dhjet"], 12 | today: "Sot" 13 | }; 14 | }(jQuery)); 15 | 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.ua.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ukrainian translation for bootstrap-datepicker 3 | * Igor Polynets 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ua'] = { 7 | days: ["Неділя", "Понеділок", "Вівторок", "Середа", "Четвер", "П'ятница", "Субота", "Неділя"], 8 | daysShort: ["Нед", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Нед"], 9 | daysMin: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Нд"], 10 | months: ["Cічень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"], 11 | monthsShort: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру"], 12 | today: "Сьогодні", 13 | weekStart: 1 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.id.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bahasa translation for bootstrap-datepicker 3 | * Azwar Akbar 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['id'] = { 7 | days: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu"], 8 | daysShort: ["Mgu", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab", "Mgu"], 9 | daysMin: ["Mg", "Sn", "Sl", "Ra", "Ka", "Ju", "Sa", "Mg"], 10 | months: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ags", "Sep", "Okt", "Nov", "Des"], 12 | today: "Hari Ini", 13 | clear: "Kosongkan" 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/id.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/id",[],function(){return{errorLoading:function(){return"Data tidak boleh diambil."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Hapuskan "+t+" huruf"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Masukkan "+t+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(e){return"Anda hanya dapat memilih "+e.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/vi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/vi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vui lòng nhập ít hơn "+t+" ký tự";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vui lòng nhập nhiều hơn "+t+' ký tự"';return n},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(e){var t="Chỉ có thể chọn được "+e.maximum+" lựa chọn";return t},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.kk.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Kazakh translation for bootstrap-datepicker 3 | * Yerzhan Tolekov 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['kk'] = { 7 | days: ["Жексенбі", "Дүйсенбі", "Сейсенбі", "Сәрсенбі", "Бейсенбі", "Жұма", "Сенбі", "Жексенбі"], 8 | daysShort: ["Жек", "Дүй", "Сей", "Сәр", "Бей", "Жұм", "Сен", "Жек"], 9 | daysMin: ["Жк", "Дс", "Сс", "Ср", "Бс", "Жм", "Сн", "Жк"], 10 | months: ["Қаңтар", "Ақпан", "Наурыз", "Сәуір", "Мамыр", "Маусым", "Шілде", "Тамыз", "Қыркүйек", "Қазан", "Қараша", "Желтоқсан"], 11 | monthsShort: ["Қаң", "Ақп", "Нау", "Сәу", "Мамыр", "Мау", "Шлд", "Тмз", "Қыр", "Қзн", "Қар", "Жел"], 12 | today: "Бүгін", 13 | weekStart: 1 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.tr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Turkish translation for bootstrap-datepicker 3 | * Serkan Algur 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['tr'] = { 7 | days: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi", "Pazar"], 8 | daysShort: ["Pz", "Pzt", "Sal", "Çrş", "Prş", "Cu", "Cts", "Pz"], 9 | daysMin: ["Pz", "Pzt", "Sa", "Çr", "Pr", "Cu", "Ct", "Pz"], 10 | months: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"], 11 | monthsShort: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"], 12 | today: "Bugün", 13 | format: "dd.mm.yyyy" 14 | }; 15 | }(jQuery)); 16 | 17 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/is.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/is",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vinsamlegast styttið texta um "+t+" staf";return t<=1?n:n+"i"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vinsamlegast skrifið "+t+" staf";return t>1&&(n+="i"),n+=" í viðbót",n},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(e){return"Þú getur aðeins valið "+e.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.da.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Danish translation for bootstrap-datepicker 3 | * Christian Pedersen 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['da'] = { 7 | days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], 8 | daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], 9 | daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], 10 | months: ["Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], 12 | today: "I Dag", 13 | clear: "Nulstil" 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.pt-BR.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Brazilian translation for bootstrap-datepicker 3 | * Cauan Cabral 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['pt-BR'] = { 7 | days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], 8 | daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], 9 | daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], 10 | months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], 11 | monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], 12 | today: "Hoje", 13 | clear: "Limpar" 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.ru.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Russian translation for bootstrap-datepicker 3 | * Victor Taranenko 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ru'] = { 7 | days: ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"], 8 | daysShort: ["Вск", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Вск"], 9 | daysMin: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"], 10 | months: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"], 11 | monthsShort: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"], 12 | today: "Сегодня", 13 | weekStart: 1 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.cs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Czech translation for bootstrap-datepicker 3 | * Matěj Koubík 4 | * Fixes by Michal Remiš 5 | */ 6 | ;(function($){ 7 | $.fn.datepicker.dates['cs'] = { 8 | days: ["Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"], 9 | daysShort: ["Ned", "Pon", "Úte", "Stř", "Čtv", "Pát", "Sob", "Ned"], 10 | daysMin: ["Ne", "Po", "Út", "St", "Čt", "Pá", "So", "Ne"], 11 | months: ["Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"], 12 | monthsShort: ["Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Čnc", "Srp", "Zář", "Říj", "Lis", "Pro"], 13 | today: "Dnes" 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.is.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Icelandic translation for bootstrap-datepicker 3 | * Hinrik Örn Sigurðsson 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['is'] = { 7 | days: ["Sunnudagur", "Mánudagur", "Þriðjudagur", "Miðvikudagur", "Fimmtudagur", "Föstudagur", "Laugardagur", "Sunnudagur"], 8 | daysShort: ["Sun", "Mán", "Þri", "Mið", "Fim", "Fös", "Lau", "Sun"], 9 | daysMin: ["Su", "Má", "Þr", "Mi", "Fi", "Fö", "La", "Su"], 10 | months: ["Janúar", "Febrúar", "Mars", "Apríl", "Maí", "Júní", "Júlí", "Ágúst", "September", "Október", "Nóvember", "Desember"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maí", "Jún", "Júl", "Ágú", "Sep", "Okt", "Nóv", "Des"], 12 | today: "Í Dag" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/ar.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ar",[],function(){return{errorLoading:function(){return"لا يمكن تحميل النتائج"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="الرجاء حذف "+t+" عناصر";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="الرجاء إضافة "+t+" عناصر";return n},loadingMore:function(){return"جاري تحميل نتائج إضافية..."},maximumSelected:function(e){var t="تستطيع إختيار "+e.maximum+" بنود فقط";return t},noResults:function(){return"لم يتم العثور على أي نتائج"},searching:function(){return"جاري البحث…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/de.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/de",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Bitte "+t+" Zeichen weniger eingeben"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Bitte "+t+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var t="Sie können nur "+e.maximum+" Eintr";return e.maximum===1?t+="ag":t+="äge",t+=" auswählen",t},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/et.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" vähem",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" rohkem",n},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var t="Saad vaid "+e.maximum+" tulemus";return e.maximum==1?t+="e":t+="t",t+=" valida",t},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.sk.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Slovak translation for bootstrap-datepicker 3 | * Marek Lichtner 4 | * Fixes by Michal Remiš 5 | */ 6 | ;(function($){ 7 | $.fn.datepicker.dates["sk"] = { 8 | days: ["Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota", "Nedeľa"], 9 | daysShort: ["Ned", "Pon", "Uto", "Str", "Štv", "Pia", "Sob", "Ned"], 10 | daysMin: ["Ne", "Po", "Ut", "St", "Št", "Pia", "So", "Ne"], 11 | months: ["Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December"], 12 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Máj", "Jún", "Júl", "Aug", "Sep", "Okt", "Nov", "Dec"], 13 | today: "Dnes" 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.sv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Swedish translation for bootstrap-datepicker 3 | * Patrik Ragnarsson 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['sv'] = { 7 | days: ["Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag", "Söndag"], 8 | daysShort: ["Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör", "Sön"], 9 | daysMin: ["Sö", "Må", "Ti", "On", "To", "Fr", "Lö", "Sö"], 10 | months: ["Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], 12 | today: "Idag", 13 | format: "yyyy-mm-dd", 14 | weekStart: 1 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/sv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vänligen sudda ut "+t+" tecken";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vänligen skriv in "+t+" eller fler tecken";return n},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(e){var t="Du kan max välja "+e.maximum+" element";return t},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.fa.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Persian translation for bootstrap-datepicker 3 | * Mostafa Rokooie 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['fa'] = { 7 | days: ["یکشنبه", "دوشنبه", "سهشنبه", "چهارشنبه", "پنجشنبه", "جمعه", "شنبه", "یکشنبه"], 8 | daysShort: ["یک", "دو", "سه", "چهار", "پنج", "جمعه", "شنبه", "یک"], 9 | daysMin: ["ی", "د", "س", "چ", "پ", "ج", "ش", "ی"], 10 | months: ["ژانویه", "فوریه", "مارس", "آوریل", "مه", "ژوئن", "ژوئیه", "اوت", "سپتامبر", "اکتبر", "نوامبر", "دسامبر"], 11 | monthsShort: ["ژان", "فور", "مار", "آور", "مه", "ژون", "ژوی", "اوت", "سپت", "اکت", "نوا", "دسا"], 12 | today: "امروز", 13 | clear: "پاک کن", 14 | weekStart: 1, 15 | format: "yyyy/mm/dd" 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/bg.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/bg",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Моля въведете с "+t+" по-малко символ";return t>1&&(n+="a"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Моля въведете още "+t+" символ";return t>1&&(n+="a"),n},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(e){var t="Можете да направите до "+e.maximum+" ";return e.maximum>1?t+="избора":t+="избор",t},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/build/webpack.test.conf.js: -------------------------------------------------------------------------------- 1 | // This is the webpack config used for unit tests. 2 | 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var merge = require('webpack-merge') 6 | var baseConfig = require('./webpack.base.conf') 7 | 8 | var webpackConfig = merge(baseConfig, { 9 | // use inline sourcemap for karma-sourcemap-loader 10 | module: { 11 | rules: utils.styleLoaders() 12 | }, 13 | devtool: '#inline-source-map', 14 | plugins: [ 15 | new webpack.DefinePlugin({ 16 | 'process.env': require('../config/test.env') 17 | }), 18 | new webpack.ProvidePlugin({ 19 | $: 'jquery', 20 | jQuery: 'jquery', 21 | }) 22 | ] 23 | }) 24 | 25 | // no need for app entry during tests 26 | delete webpackConfig.entry 27 | 28 | module.exports = webpackConfig 29 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.hu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hungarian translation for bootstrap-datepicker 3 | * Sotus László 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['hu'] = { 7 | days: ["Vasárnap", "Hétfő", "Kedd", "Szerda", "Csütörtök", "Péntek", "Szombat", "Vasárnap"], 8 | daysShort: ["Vas", "Hét", "Ked", "Sze", "Csü", "Pén", "Szo", "Vas"], 9 | daysMin: ["Va", "Hé", "Ke", "Sz", "Cs", "Pé", "Sz", "Va"], 10 | months: ["Január", "Február", "Március", "Április", "Május", "Június", "Július", "Augusztus", "Szeptember", "Október", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Már", "Ápr", "Máj", "Jún", "Júl", "Aug", "Sze", "Okt", "Nov", "Dec"], 12 | today: "Ma", 13 | weekStart: 1, 14 | format: "yyyy.mm.dd" 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.ro.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Romanian translation for bootstrap-datepicker 3 | * Cristian Vasile 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ro'] = { 7 | days: ["Duminică", "Luni", "Marţi", "Miercuri", "Joi", "Vineri", "Sâmbătă", "Duminică"], 8 | daysShort: ["Dum", "Lun", "Mar", "Mie", "Joi", "Vin", "Sâm", "Dum"], 9 | daysMin: ["Du", "Lu", "Ma", "Mi", "Jo", "Vi", "Sâ", "Du"], 10 | months: ["Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"], 11 | monthsShort: ["Ian", "Feb", "Mar", "Apr", "Mai", "Iun", "Iul", "Aug", "Sep", "Oct", "Nov", "Dec"], 12 | today: "Astăzi", 13 | clear: "Șterge", 14 | weekStart: 1 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.zh-TW.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Traditional Chinese translation for bootstrap-datepicker 3 | * Rung-Sheng Jang 4 | * FrankWu Fix more appropriate use of Traditional Chinese habit 5 | */ 6 | ;(function($){ 7 | $.fn.datepicker.dates['zh-TW'] = { 8 | days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], 9 | daysShort: ["週日", "週一", "週二", "週三", "週四", "週五", "週六", "週日"], 10 | daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], 11 | months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], 12 | monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], 13 | today: "今天", 14 | format: "yyyy年mm月dd日", 15 | weekStart: 1 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/ms.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ms",[],function(){return{errorLoading:function(){return"Keputusan tidak berjaya dimuatkan."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Sila hapuskan "+t+" aksara"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Sila masukkan "+t+" atau lebih aksara"},loadingMore:function(){return"Sedang memuatkan keputusan…"},maximumSelected:function(e){return"Anda hanya boleh memilih "+e.maximum+" pilihan"},noResults:function(){return"Tiada padanan yang ditemui"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/gl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/gl",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Elimine ";return t===1?n+="un carácter":n+=t+" caracteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Engada ";return t===1?n+="un carácter":n+=t+" caracteres",n},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){var t="Só pode ";return e.maximum===1?t+="un elemento":t+=e.maximum+" elementos",t},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/ColVis/css/dataTables.colvis.jqueryui.css: -------------------------------------------------------------------------------- 1 | 2 | button.ColVis_Button, 3 | ul.ColVis_collection li { 4 | padding: 0.5em; 5 | } 6 | 7 | ul.ColVis_collection { 8 | margin: 0; 9 | padding: 0; 10 | overflow: hidden; 11 | z-index: 2002; 12 | } 13 | 14 | ul.ColVis_collection li { 15 | clear: both; 16 | display: block; 17 | text-align: left; 18 | margin: -1px 0 0 0; 19 | } 20 | 21 | ul.ColVis_collection li span { 22 | display: inline-block; 23 | padding-left: 0.5em; 24 | cursor: pointer; 25 | } 26 | 27 | div.ColVis_collectionBackground { 28 | position: fixed; 29 | top: 0; 30 | left: 0; 31 | height: 100%; 32 | width: 100%; 33 | background-color: black; 34 | z-index: 1100; 35 | } 36 | 37 | 38 | div.ColVis_catcher { 39 | position: absolute; 40 | z-index: 1101; 41 | } -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.de.js: -------------------------------------------------------------------------------- 1 | /** 2 | * German translation for bootstrap-datepicker 3 | * Sam Zurcher 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['de'] = { 7 | days: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"], 8 | daysShort: ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam", "Son"], 9 | daysMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"], 10 | months: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], 11 | monthsShort: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], 12 | today: "Heute", 13 | clear: "Löschen", 14 | weekStart: 1, 15 | format: "dd.mm.yyyy" 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.fr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * French translation for bootstrap-datepicker 3 | * Nico Mollet 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['fr'] = { 7 | days: ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"], 8 | daysShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"], 9 | daysMin: ["D", "L", "Ma", "Me", "J", "V", "S", "D"], 10 | months: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"], 11 | monthsShort: ["Jan", "Fév", "Mar", "Avr", "Mai", "Jui", "Jul", "Aou", "Sep", "Oct", "Nov", "Déc"], 12 | today: "Aujourd'hui", 13 | clear: "Effacer", 14 | weekStart: 1, 15 | format: "dd/mm/yyyy" 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.mk.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Macedonian translation for bootstrap-datepicker 3 | * Marko Aleksic 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['mk'] = { 7 | days: ["Недела", "Понеделник", "Вторник", "Среда", "Четврток", "Петок", "Сабота", "Недела"], 8 | daysShort: ["Нед", "Пон", "Вто", "Сре", "Чет", "Пет", "Саб", "Нед"], 9 | daysMin: ["Не", "По", "Вт", "Ср", "Че", "Пе", "Са", "Не"], 10 | months: ["Јануари", "Февруари", "Март", "Април", "Мај", "Јуни", "Јули", "Август", "Септември", "Октомври", "Ноември", "Декември"], 11 | monthsShort: ["Јан", "Фев", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Ное", "Дек"], 12 | today: "Денес", 13 | format: "dd.mm.yyyy" 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.vi.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Vietnamese translation for bootstrap-datepicker 3 | * An Vo 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['vi'] = { 7 | days: ["Chủ nhật", "Thứ hai", "Thứ ba", "Thứ tư", "Thứ năm", "Thứ sáu", "Thứ bảy", "Chủ nhật"], 8 | daysShort: ["CN", "Thứ 2", "Thứ 3", "Thứ 4", "Thứ 5", "Thứ 6", "Thứ 7", "CN"], 9 | daysMin: ["CN", "T2", "T3", "T4", "T5", "T6", "T7", "CN"], 10 | months: ["Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5", "Tháng 6", "Tháng 7", "Tháng 8", "Tháng 9", "Tháng 10", "Tháng 11", "Tháng 12"], 11 | monthsShort: ["Th1", "Th2", "Th3", "Th4", "Th5", "Th6", "Th7", "Th8", "Th9", "Th10", "Th11", "Th12"], 12 | today: "Hôm nay", 13 | clear: "Xóa", 14 | format: "dd/mm/yyyy" 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/da.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"Resultaterne kunne ikke indlæses."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Angiv venligst "+t+" tegn mindre";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Angiv venligst "+t+" tegn mere";return n},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var t="Du kan kun vælge "+e.maximum+" emne";return e.maximum!=1&&(t+="r"),t},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/fr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fr",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Supprimez "+t+" caractère";return t!==1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Saisissez "+t+" caractère";return t!==1&&(n+="s"),n},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){var t="Vous pouvez seulement sélectionner "+e.maximum+" élément";return e.maximum!==1&&(t+="s"),t},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.it.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Italian translation for bootstrap-datepicker 3 | * Enrico Rubboli 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['it'] = { 7 | days: ["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato", "Domenica"], 8 | daysShort: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"], 9 | daysMin: ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"], 10 | months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], 11 | monthsShort: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"], 12 | today: "Oggi", 13 | clear: "Cancella", 14 | weekStart: 1, 15 | format: "dd/mm/yyyy" 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.pt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Portuguese translation for bootstrap-datepicker 3 | * Original code: Cauan Cabral 4 | * Tiago Melo 5 | */ 6 | ;(function($){ 7 | $.fn.datepicker.dates['pt'] = { 8 | days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], 9 | daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], 10 | daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], 11 | months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], 12 | monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], 13 | today: "Hoje", 14 | clear: "Limpar" 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/ro.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ro",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să introduceți mai puțin de "+t;return n+=" caracter",n!==1&&(n+="e"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vă rugăm să introduceți incă "+t;return n+=" caracter",n!==1&&(n+="e"),n},loadingMore:function(){return"Se încarcă…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",t!==1&&(t+="e"),t},noResults:function(){return"Nu a fost găsit nimic"},searching:function(){return"Căutare…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.ar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Arabic translation for bootstrap-datepicker 3 | * Mohammed Alshehri 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ar'] = { 7 | days: ["الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"], 8 | daysShort: ["أحد", "اثنين", "ثلاثاء", "أربعاء", "خميس", "جمعة", "سبت", "أحد"], 9 | daysMin: ["ح", "ن", "ث", "ع", "خ", "ج", "س", "ح"], 10 | months: ["يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو", "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر"], 11 | monthsShort: ["يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو", "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر"], 12 | today: "هذا اليوم", 13 | rtl: true 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.fi.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Finnish translation for bootstrap-datepicker 3 | * Jaakko Salonen 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['fi'] = { 7 | days: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai", "sunnuntai"], 8 | daysShort: ["sun", "maa", "tii", "kes", "tor", "per", "lau", "sun"], 9 | daysMin: ["su", "ma", "ti", "ke", "to", "pe", "la", "su"], 10 | months: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"], 11 | monthsShort: ["tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mar", "jou"], 12 | today: "tänään", 13 | weekStart: 1, 14 | format: "d.m.yyyy" 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.lv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Latvian translation for bootstrap-datepicker 3 | * Artis Avotins 4 | */ 5 | 6 | ;(function($){ 7 | $.fn.datepicker.dates['lv'] = { 8 | days: ["Svētdiena", "Pirmdiena", "Otrdiena", "Trešdiena", "Ceturtdiena", "Piektdiena", "Sestdiena", "Svētdiena"], 9 | daysShort: ["Sv", "P", "O", "T", "C", "Pk", "S", "Sv"], 10 | daysMin: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "Se", "Sv"], 11 | months: ["Janvāris", "Februāris", "Marts", "Aprīlis", "Maijs", "Jūnijs", "Jūlijs", "Augusts", "Septembris", "Oktobris", "Novembris", "Decembris"], 12 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jūn", "Jūl", "Aug", "Sep", "Okt", "Nov", "Dec"], 13 | today: "Šodien", 14 | weekStart: 1 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/en.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Please delete "+t+" character";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Please enter "+t+" or more characters";return n},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var t="You can only select "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/he.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"שגיאה בטעינת התוצאות"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="נא למחוק ";return t===1?n+="תו אחד":n+=t+" תווים",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="נא להכניס ";return t===1?n+="תו אחד":n+=t+" תווים",n+=" או יותר",n},loadingMore:function(){return"טוען תוצאות נוספות…"},maximumSelected:function(e){var t="באפשרותך לבחור עד ";return e.maximum===1?t+="פריט אחד":t+=e.maximum+" פריטים",t},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/hi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" अक्षर को हटा दें";return t>1&&(n=t+" अक्षरों को हटा दें "),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="कृपया "+t+" या अधिक अक्षर दर्ज करें";return n},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(e){var t="आप केवल "+e.maximum+" आइटम का चयन कर सकते हैं";return t},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/fa.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="لطفاً "+t+" کاراکتر را حذف نمایید";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="لطفاً تعداد "+t+" کاراکتر یا بیشتر وارد نمایید";return n},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(e){var t="شما تنها میتوانید "+e.maximum+" آیتم را انتخاب نمایید";return t},noResults:function(){return"هیچ نتیجهای یافت نشد"},searching:function(){return"در حال جستجو..."}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/hr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hr",[],function(){function e(e){var t=" "+e+" znak";return e%10<5&&e%10>0&&(e%100<5||e%100>19)?e%10>1&&(t+="a"):t+="ova",t}return{errorLoading:function(){return"Preuzimanje nije uspjelo."},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Unesite "+e(n)},inputTooShort:function(t){var n=t.minimum-t.input.length;return"Unesite još "+e(n)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(e){return"Maksimalan broj odabranih stavki je "+e.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /backend/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.4" 2 | 3 | volumes: 4 | mongo_data: 5 | name: appy_mongo_data 6 | 7 | networks: 8 | backend: 9 | 10 | services: 11 | 12 | mongo: 13 | image: mongo:3.6.4 14 | ports: 15 | - 27017:27017 16 | volumes: 17 | - "mongo_data:/data/db" 18 | networks: 19 | - backend 20 | restart: always 21 | 22 | api: 23 | build: ./ 24 | ports: 25 | - "${SERVER_PORT}:${SERVER_PORT}" 26 | volumes: 27 | # Share the entire project except "node_modules". This prevents us from having to COPY the project files 28 | # in the Dockerfile, while still keeping separate node dependency files. 29 | - "./:/backend" 30 | - "/backend/node_modules" 31 | networks: 32 | - backend 33 | depends_on: 34 | - mongo 35 | env_file: 36 | - ./.env-docker 37 | -------------------------------------------------------------------------------- /frontend/src/routes/members.route.js: -------------------------------------------------------------------------------- 1 | import Members from '../components/views/members/Members.vue' 2 | import MemberProfile from '../components/views/members/MemberProfile.vue' 3 | 4 | const routes = [ 5 | { 6 | path: 'members', 7 | component: Members, 8 | name: 'Members', 9 | meta: { 10 | description: 'List of appy members', 11 | title: 'Members', 12 | requiresAuth: true 13 | } 14 | }, 15 | { 16 | path: '/members/:_id', 17 | beforeEnter: (to, from, next) => { 18 | to.params._id === 'create' ? next({ name: 'MemberCreate' }) : next() 19 | }, 20 | component: MemberProfile, 21 | name: 'MemberProfile', 22 | meta: { 23 | description: 'Profile for the selected member', 24 | title: 'Member Profile', 25 | requiresAuth: true 26 | } 27 | } 28 | ] 29 | 30 | export default routes 31 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/eu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gutxiago",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gehiago",n},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return e.maximum===1?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/mk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/mk",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Ве молиме внесете "+e.maximum+" помалку карактер";return e.maximum!==1&&(n+="и"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Ве молиме внесете уште "+e.maximum+" карактер";return e.maximum!==1&&(n+="и"),n},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(e){var t="Можете да изберете само "+e.maximum+" ставк";return e.maximum===1?t+="а":t+="и",t},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.nl-BE.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Belgium-Dutch translation for bootstrap-datepicker 3 | * Julien Poulin 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['nl-BE'] = { 7 | days: ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"], 8 | daysShort: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], 9 | daysMin: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], 10 | months: ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"], 11 | monthsShort: ["Jan", "Feb", "Mrt", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], 12 | today: "Vandaag", 13 | clear: "Leegmaken", 14 | weekStart: 1, 15 | format: "dd/mm/yyyy" 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /frontend/test/e2e/reports/FIREFOX_undefined_undefined_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | at Object.module.exports.default e2e tests (/Users/Justin/Documents/appy-frontend/test/e2e/specs/test.js:8:8) 11 | at _combinedTickCallback (internal/process/next_tick.js:67:7) 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/pt-BR.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Apague "+t+" caracter";return t!=1&&(n+="es"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Digite "+t+" ou mais caracteres";return n},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var t="Você só pode selecionar "+e.maximum+" ite";return e.maximum==1?t+="m":t+="ns",t},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.lt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Lithuanian translation for bootstrap-datepicker 3 | * Šarūnas Gliebus 4 | */ 5 | 6 | ;(function($){ 7 | $.fn.datepicker.dates['lt'] = { 8 | days: ["Sekmadienis", "Pirmadienis", "Antradienis", "Trečiadienis", "Ketvirtadienis", "Penktadienis", "Šeštadienis", "Sekmadienis"], 9 | daysShort: ["S", "Pr", "A", "T", "K", "Pn", "Š", "S"], 10 | daysMin: ["Sk", "Pr", "An", "Tr", "Ke", "Pn", "Št", "Sk"], 11 | months: ["Sausis", "Vasaris", "Kovas", "Balandis", "Gegužė", "Birželis", "Liepa", "Rugpjūtis", "Rugsėjis", "Spalis", "Lapkritis", "Gruodis"], 12 | monthsShort: ["Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rugp", "Rugs", "Spa", "Lap", "Gru"], 13 | today: "Šiandien", 14 | weekStart: 1 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/lv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lv",[],function(){function e(e,t,n,r){return e===11?t:e%10===1?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Lūdzu ievadiet par "+n;return r+=" simbol"+e(n,"iem","u","iem"),r+" mazāk"},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Lūdzu ievadiet vēl "+n;return r+=" simbol"+e(n,"us","u","us"),r},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(t){var n="Jūs varat izvēlēties ne vairāk kā "+t.maximum;return n+=" element"+e(t.maximum,"us","u","us"),n},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/pt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor apague "+t+" ";return n+=t!=1?"caracteres":"carácter",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Introduza "+t+" ou mais caracteres";return n},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var t="Apenas pode seleccionar "+e.maximum+" ";return t+=e.maximum!=1?"itens":"item",t},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server 2 | var server = require('../../build/dev-server.js') 3 | 4 | // 2. run the nightwatch test suite against it 5 | // to run in additional browsers: 6 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" 7 | // 2. add it to the --env flag below 8 | // For more information on Nightwatch's config file, see 9 | // http://nightwatchjs.org/guide#settings-file 10 | var spawn = require('cross-spawn') 11 | var runner = spawn( 12 | './node_modules/.bin/nightwatch', 13 | [ 14 | '--config', 'test/e2e/nightwatch.conf.js', 15 | '--env', 'chrome' 16 | ], 17 | { 18 | stdio: 'inherit' 19 | } 20 | ) 21 | 22 | runner.on('exit', function (code) { 23 | server.close() 24 | process.exit(code) 25 | }) 26 | 27 | runner.on('error', function (err) { 28 | server.close() 29 | throw err 30 | }) 31 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.pl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Polish translation for bootstrap-datepicker 3 | * Robert 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['pl'] = { 7 | days: ["Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota", "Niedziela"], 8 | daysShort: ["Nie", "Pn", "Wt", "Śr", "Czw", "Pt", "So", "Nie"], 9 | daysMin: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So", "N"], 10 | months: ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"], 11 | monthsShort: ["Sty", "Lu", "Mar", "Kw", "Maj", "Cze", "Lip", "Sie", "Wrz", "Pa", "Lis", "Gru"], 12 | today: "Dzisiaj", 13 | weekStart: 1 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/ca.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Si us plau, elimina "+t+" car";return t==1?n+="àcter":n+="àcters",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Si us plau, introdueix "+t+" car";return t==1?n+="àcter":n+="àcters",n},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var t="Només es pot seleccionar "+e.maximum+" element";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/es.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"La carga falló"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor, elimine "+t+" car";return t==1?n+="ácter":n+="acteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Por favor, introduzca "+t+" car";return t==1?n+="ácter":n+="acteres",n},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var t="Sólo puede seleccionar "+e.maximum+" elemento";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/lt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lt",[],function(){function e(e,t,n,r){return e%100>9&&e%100<21||e%10===0?e%10>1?n:r:t}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Pašalinkite "+n+" simbol";return r+=e(n,"ių","ius","į"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Įrašykite dar "+n+" simbol";return r+=e(n,"ių","ius","į"),r},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(t){var n="Jūs galite pasirinkti tik "+t.maximum+" element";return n+=e(t.maximum,"ų","us","ą"),n},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.sw.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Swahili translation for bootstrap-datepicker 3 | * Edwin Mugendi 4 | * Source: http://scriptsource.org/cms/scripts/page.php?item_id=entry_detail&uid=xnfaqyzcku 5 | */ 6 | ;(function($){ 7 | $.fn.datepicker.dates['sw'] = { 8 | days: ["Jumapili", "Jumatatu", "Jumanne", "Jumatano", "Alhamisi", "Ijumaa", "Jumamosi", "Jumapili"], 9 | daysShort: ["J2", "J3", "J4", "J5", "Alh", "Ij", "J1", "J2"], 10 | daysMin: ["2", "3", "4", "5", "A", "I", "1", "2"], 11 | months: ["Januari", "Februari", "Machi", "Aprili", "Mei", "Juni", "Julai", "Agosti", "Septemba", "Oktoba", "Novemba", "Desemba"], 12 | monthsShort: ["Jan", "Feb", "Mac", "Apr", "Mei", "Jun", "Jul", "Ago", "Sep", "Okt", "Nov", "Des"], 13 | today: "Leo" 14 | }; 15 | }(jQuery)); 16 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/it.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Per favore cancella "+t+" caratter";return t!==1?n+="i":n+="e",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Per favore inserisci "+t+" o più caratteri";return n},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var t="Puoi selezionare solo "+e.maximum+" element";return e.maximum!==1?t+="i":t+="o",t},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/src/services/stats.service.js: -------------------------------------------------------------------------------- 1 | import { httpClient as http } from '../services' 2 | import vm from '../main' 3 | 4 | const internals = {} 5 | 6 | internals.getDashboardStats = () => { 7 | let promises = [] 8 | 9 | // This function sometimes gets called before the global vm is ready 10 | if (vm) { 11 | promises.push(http.get('/stats/dashboard')) 12 | promises.push(vm.$visitorRepository.list()) 13 | 14 | return Promise.all(promises).then(result => { 15 | let stats = result[0].data.stats 16 | stats.visitorData = result[1].data.docs 17 | return stats 18 | }) 19 | } else { 20 | return new Promise(resolve => { 21 | setTimeout(() => { 22 | resolve(internals.getDashboardStats()) 23 | }, 100) 24 | }) 25 | } 26 | } 27 | 28 | internals.postVisit = () => { 29 | return http.post('visitor') 30 | } 31 | 32 | export default internals 33 | -------------------------------------------------------------------------------- /frontend/src/services/index.js: -------------------------------------------------------------------------------- 1 | export { default as authService } from './auth.service' 2 | export { default as userService } from './user.service' 3 | export { default as roleService } from './role.service' 4 | export { default as groupService } from './group.service' 5 | export { default as permissionService } from './permission.service' 6 | export { default as documentService } from './document.service' 7 | export { default as formService } from './form.service' 8 | export { default as httpClient } from './http-client.service' 9 | export { default as wsClient } from './ws-client.service' 10 | export { default as authInterceptor } from './auth-interceptor.service' 11 | export { default as eventBus } from './event-bus.service' 12 | export { default as fileService } from './file.service' 13 | export { default as chatService } from './chat.service' 14 | export { default as statsService } from './stats.service' 15 | -------------------------------------------------------------------------------- /frontend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // http://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 13 | extends: ['prettier-standard'], 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html', 17 | 'prettier' 18 | ], 19 | // add your custom rules here 20 | 'rules': { 21 | // allow paren-less arrow functions 22 | 'arrow-parens': 0, 23 | // allow async-await 24 | 'generator-star-spacing': 0, 25 | // allow debugger during development 26 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 27 | }, 28 | "globals": { 29 | "$": false, 30 | "ClassicEditor": false, 31 | "Chart": false 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/nl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Gelieve "+t+" karakters te verwijderen";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Gelieve "+t+" of meer karakters in te voeren";return n},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var t=e.maximum==1?"kan":"kunnen",n="Er "+t+" maar "+e.maximum+" item";return e.maximum!=1&&(n+="s"),n+=" worden geselecteerd",n},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.ka.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Georgian translation for bootstrap-datepicker 3 | * Levan Melikishvili 4 | */ 5 | ;(function($){ 6 | $.fn.datepicker.dates['ka'] = { 7 | days: ["კვირა", "ორშაბათი", "სამშაბათი", "ოთხშაბათი", "ხუთშაბათი", "პარასკევი", "შაბათი", "კვირა"], 8 | daysShort: ["კვი", "ორშ", "სამ", "ოთხ", "ხუთ", "პარ", "შაბ", "კვი"], 9 | daysMin: ["კვ", "ორ", "სა", "ოთ", "ხუ", "პა", "შა", "კვ"], 10 | months: ["იანვარი", "თებერვალი", "მარტი", "აპრილი", "მაისი", "ივნისი", "ივლისი", "აგვისტო", "სექტემბერი", "ოქტომები", "ნოემბერი", "დეკემბერი"], 11 | monthsShort: ["იან", "თებ", "მარ", "აპრ", "მაი", "ივნ", "ივლ", "აგვ", "სექ", "ოქტ", "ნოე", "დეკ"], 12 | today: "დღეს", 13 | clear: "გასუფთავება", 14 | weekStart: 1, 15 | format: "dd.mm.yyyy" 16 | }; 17 | }(jQuery)); 18 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datepicker/locales/bootstrap-datepicker.et.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Estonian translation for bootstrap-datepicker 3 | * Ando Roots 4 | * Fixes by Illimar Tambek < 5 | */ 6 | ;(function($){ 7 | $.fn.datepicker.dates['et'] = { 8 | days: ["Pühapäev", "Esmaspäev", "Teisipäev", "Kolmapäev", "Neljapäev", "Reede", "Laupäev", "Pühapäev"], 9 | daysShort: ["Pühap", "Esmasp", "Teisip", "Kolmap", "Neljap", "Reede", "Laup", "Pühap"], 10 | daysMin: ["P", "E", "T", "K", "N", "R", "L", "P"], 11 | months: ["Jaanuar", "Veebruar", "Märts", "Aprill", "Mai", "Juuni", "Juuli", "August", "September", "Oktoober", "November", "Detsember"], 12 | monthsShort: ["Jaan", "Veebr", "Märts", "Apr", "Mai", "Juuni", "Juuli", "Aug", "Sept", "Okt", "Nov", "Dets"], 13 | today: "Täna", 14 | clear: "Tühjenda", 15 | weekStart: 1, 16 | format: "dd.mm.yyyy" 17 | }; 18 | }(jQuery)); 19 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/pl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pl",[],function(){var e=["znak","znaki","znaków"],t=["element","elementy","elementów"],n=function(t,n){if(t===1)return n[0];if(t>1&&t<=4)return n[1];if(t>=5)return n[2]};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Usuń "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Podaj przynajmniej "+r+" "+n(r,e)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(e){return"Możesz zaznaczyć tylko "+e.maximum+" "+n(e.maximum,t)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // the name of the method is the filename. 3 | // can be used in tests like this: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // for how to write custom assertions see 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | exports.assertion = function (selector, count) { 10 | this.message = 'Testing if element <' + selector + '> has count: ' + count 11 | this.expected = count 12 | this.pass = function (val) { 13 | return val === this.expected 14 | } 15 | this.value = function (res) { 16 | return res.value 17 | } 18 | this.command = function (cb) { 19 | var self = this 20 | return this.api.execute(function (selector) { 21 | return document.querySelectorAll(selector).length 22 | }, [selector], function (res) { 23 | cb.call(self, res) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/sr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Preuzimanje nije uspelo."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Obrišite "+n+" simbol";return r+=e(n,"","a","a"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Ukucajte bar još "+n+" simbol";return r+=e(n,"","a","a"),r},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(t){var n="Možete izabrati samo "+t.maximum+" stavk";return n+=e(t.maximum,"u","e","i"),n},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/uk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/uk",[],function(){function e(e,t,n,r){return e%100>10&&e%100<15?r:e%10===1?t:e%10>1&&e%10<5?n:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Будь ласка, видаліть "+n+" "+e(t.maximum,"літеру","літери","літер")},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Будь ласка, введіть "+t+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(t){return"Ви можете вибрати лише "+t.maximum+" "+e(t.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/sr-Cyrl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr-Cyrl",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Преузимање није успело."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Обришите "+n+" симбол";return r+=e(n,"","а","а"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Укуцајте бар још "+n+" симбол";return r+=e(n,"","а","а"),r},loadingMore:function(){return"Преузимање још резултата…"},maximumSelected:function(t){var n="Можете изабрати само "+t.maximum+" ставк";return n+=e(t.maximum,"у","е","и"),n},noResults:function(){return"Ништа није пронађено"},searching:function(){return"Претрага…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/ru.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ru",[],function(){function e(e,t,n,r){return e%10<5&&e%10>0&&e%100<5||e%100>20?e%10>1?n:t:r}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Пожалуйста, введите на "+n+" символ";return r+=e(n,"","a","ов"),r+=" меньше",r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Пожалуйста, введите еще хотя бы "+n+" символ";return r+=e(n,"","a","ов"),r},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(t){var n="Вы можете выбрать не более "+t.maximum+" элемент";return n+=e(t.maximum,"","a","ов"),n},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /backend/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | #How To Contribute 2 | 3 | 1. Fork the repo 4 | 2. Create a branch off of the *master* branch. Prefix your branch with either "FEATURE\_", "BUGFIX\_", or something similar describing the type of update, and then add a descriptive name such as "BUGFIX\_random\_files_erased". 5 | 3. Add your changes. 6 | * Please try to avoid monolithic commits. 7 | * We currently don't have a styleguide, but please try to match the current project style as closely as possible. 8 | 4. Make sure your master branch is [in sync/up-to-date with the original](https://help.github.com/articles/syncing-a-fork/). 9 | 5. Before submitting a pull request, merge in your synced master branch with your current branch and resolve any conflicts. 10 | 6. Once all conflicts are resolved, submit a pull request to the origin master branch. 11 | 7. Your pull request will be reviewed along with change requests or comments. 12 | 8. After all requests are complete, your pull request will be merged in. 13 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/Scroller/css/dataTables.scroller.css: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Namespace: DTS (DataTables Scroller) 4 | */ 5 | 6 | div.DTS tbody th, 7 | div.DTS tbody td { 8 | white-space: nowrap; 9 | } 10 | 11 | div.DTS tbody tr.even { 12 | background-color: white; 13 | } 14 | 15 | div.DTS div.DTS_Loading { 16 | position: absolute; 17 | top: 50%; 18 | left: 50%; 19 | width: 200px; 20 | height: 20px; 21 | margin-top: -20px; 22 | margin-left: -100px; 23 | z-index: 1; 24 | 25 | border: 1px solid #999; 26 | padding: 20px 0; 27 | text-align: center; 28 | background-color: white; 29 | background-color: rgba(255, 255, 255, 0.5); 30 | } 31 | 32 | div.DTS div.dataTables_scrollHead, 33 | div.DTS div.dataTables_scrollFoot { 34 | background-color: white; 35 | } 36 | 37 | div.DTS div.dataTables_scrollBody { 38 | z-index: 2; 39 | } 40 | 41 | div.DTS div.dataTables_scroll { 42 | background: url('../images/loading-background.png') repeat 0 0; 43 | } 44 | 45 | -------------------------------------------------------------------------------- /frontend/src/filters/index.js: -------------------------------------------------------------------------------- 1 | const urlParser = document.createElement('a') 2 | 3 | export function domain(url) { 4 | urlParser.href = url 5 | return urlParser.hostname 6 | } 7 | 8 | export function count(arr) { 9 | return arr.length 10 | } 11 | 12 | export function prettyDate(date) { 13 | var a = new Date(date) 14 | return a.toDateString() 15 | } 16 | 17 | export function pluralize(time, label) { 18 | if (time === 1) { 19 | return time + label 20 | } 21 | 22 | return time + label + 's' 23 | } 24 | 25 | export function shortMessage(message, length) { 26 | if (message && message.length > (length || 40)) { 27 | message = message.slice(0, length || 40) 28 | message = message + '...' 29 | } 30 | return message 31 | } 32 | 33 | export function userList(users) { 34 | let list = '' 35 | for (let user of users) { 36 | if (list === '') { 37 | list = list + user.firstName 38 | } else { 39 | list = list + ', ' + user.firstName 40 | } 41 | } 42 | return list 43 | } 44 | -------------------------------------------------------------------------------- /frontend/build/build.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | 3 | process.env.NODE_ENV = 'production' 4 | 5 | var ora = require('ora') 6 | var rm = require('rimraf') 7 | var path = require('path') 8 | var chalk = require('chalk') 9 | var webpack = require('webpack') 10 | var config = require('../config') 11 | var webpackConfig = require('./webpack.prod.conf') 12 | 13 | var spinner = ora('building for production...') 14 | spinner.start() 15 | 16 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 17 | if (err) throw err 18 | webpack(webpackConfig, function (err, stats) { 19 | spinner.stop() 20 | if (err) throw err 21 | process.stdout.write(stats.toString({ 22 | colors: true, 23 | modules: false, 24 | children: false, 25 | chunks: false, 26 | chunkModules: false 27 | }) + '\n\n') 28 | 29 | console.log(chalk.cyan(' Build complete.\n')) 30 | console.log(chalk.yellow( 31 | ' Tip: built files are meant to be served over an HTTP server.\n' + 32 | ' Opening index.html over file:// won\'t work.\n' 33 | )) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /frontend/src/routes/roles.route.js: -------------------------------------------------------------------------------- 1 | import Roles from '../components/views/roles/Roles.vue' 2 | import RoleDetails from '../components/views/roles/RoleDetails.vue' 3 | import RoleCreate from '../components/views/roles/RoleCreate.vue' 4 | 5 | const routes = [ 6 | { 7 | path: 'roles', 8 | component: Roles, 9 | name: 'Roles', 10 | meta: { 11 | description: 'List of appy roles', 12 | title: 'Roles', 13 | requiresAuth: true 14 | } 15 | }, 16 | { 17 | path: '/roles/:_id', 18 | beforeEnter: (to, from, next) => { 19 | to.params._id === 'create' ? next({ name: 'RoleCreate' }) : next() 20 | }, 21 | component: RoleDetails, 22 | name: 'RoleDetails', 23 | meta: { 24 | description: 'Details for the selected role', 25 | title: 'Role Details', 26 | requiresAuth: true 27 | } 28 | }, 29 | { 30 | path: '/roles/create', 31 | component: RoleCreate, 32 | name: 'RoleCreate', 33 | meta: { 34 | description: 'Create a new role', 35 | title: 'Role Create', 36 | requiresAuth: true 37 | } 38 | } 39 | ] 40 | 41 | export default routes 42 | -------------------------------------------------------------------------------- /frontend/src/routes/users.route.js: -------------------------------------------------------------------------------- 1 | import Users from '../components/views/users/Users.vue' 2 | import UserDetails from '../components/views/users/UserDetails.vue' 3 | import UserCreate from '../components/views/users/UserCreate.vue' 4 | 5 | const routes = [ 6 | { 7 | path: 'users', 8 | component: Users, 9 | name: 'Users', 10 | meta: { 11 | description: 'List of appy users', 12 | title: 'Users', 13 | requiresAuth: true 14 | } 15 | }, 16 | { 17 | path: '/users/:_id', 18 | beforeEnter: (to, from, next) => { 19 | to.params._id === 'create' ? next({ name: 'UserCreate' }) : next() 20 | }, 21 | component: UserDetails, 22 | name: 'UserDetails', 23 | meta: { 24 | description: 'Details for the selected user', 25 | title: 'User Details', 26 | requiresAuth: true 27 | } 28 | }, 29 | { 30 | path: '/users/create', 31 | component: UserCreate, 32 | name: 'UserCreate', 33 | meta: { 34 | description: 'Create a new user', 35 | title: 'User Create', 36 | requiresAuth: true 37 | } 38 | } 39 | ] 40 | 41 | export default routes 42 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Justin Headley 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /backend/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Justin Headley 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /backend/test/unit/auth.plugin.test.js: -------------------------------------------------------------------------------- 1 | const rewire = require('rewire') 2 | 3 | let authPlugin = rewire('../../server/plugins/auth.plugin') 4 | 5 | describe('applyRefreshStrategy ', () => { 6 | let applyRefreshStrategy 7 | let server 8 | 9 | beforeAll(() => { 10 | applyRefreshStrategy = authPlugin.__get__('internals.applyRefreshStrategy') 11 | 12 | server = { 13 | ext: jest.fn(), 14 | auth: { 15 | strategy: jest.fn() 16 | } 17 | } 18 | }) 19 | 20 | test('calls server.ext', () => { 21 | expect.assertions(1); 22 | 23 | applyRefreshStrategy(server) 24 | 25 | let onPostHandlerCallback = server.ext.mock.calls[0][1] 26 | expect(server.ext).toBeCalledWith('onPostHandler', onPostHandlerCallback); 27 | }); 28 | 29 | test('calls server.auth.strategy', () => { 30 | expect.assertions(1); 31 | 32 | let AUTH_STRATEGIES = authPlugin.__get__('AUTH_STRATEGIES') 33 | 34 | applyRefreshStrategy(server) 35 | 36 | let authStrategyObj = server.auth.strategy.mock.calls[0][2] 37 | expect(server.auth.strategy).toBeCalledWith(AUTH_STRATEGIES.REFRESH, 'jwt', authStrategyObj); 38 | }); 39 | 40 | }); 41 | -------------------------------------------------------------------------------- /frontend/src/routes/groups.route.js: -------------------------------------------------------------------------------- 1 | import Groups from '../components/views/groups/Groups.vue' 2 | import GroupDetails from '../components/views/groups/GroupDetails.vue' 3 | import GroupCreate from '../components/views/groups/GroupCreate.vue' 4 | 5 | const routes = [ 6 | { 7 | path: 'groups', 8 | component: Groups, 9 | name: 'Groups', 10 | meta: { 11 | description: 'List of appy groups', 12 | title: 'Groups', 13 | requiresAuth: true 14 | } 15 | }, 16 | { 17 | path: '/groups/:_id', 18 | beforeEnter: (to, from, next) => { 19 | to.params._id === 'create' ? next({ name: 'GroupCreate' }) : next() 20 | }, 21 | component: GroupDetails, 22 | name: 'GroupDetails', 23 | meta: { 24 | description: 'Details for the selected group', 25 | title: 'Group Details', 26 | requiresAuth: true 27 | } 28 | }, 29 | { 30 | path: '/groups/create', 31 | component: GroupCreate, 32 | name: 'GroupCreate', 33 | meta: { 34 | description: 'Create a new group', 35 | title: 'Group Create', 36 | requiresAuth: true 37 | } 38 | } 39 | ] 40 | 41 | export default routes 42 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/sk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím, zadajte o jeden znak menej":n>=2&&n<=4?"Prosím, zadajte o "+e[n](!0)+" znaky menej":"Prosím, zadajte o "+n+" znakov menej"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím, zadajte ešte jeden znak":n<=4?"Prosím, zadajte ešte ďalšie "+e[n](!0)+" znaky":"Prosím, zadajte ešte ďalších "+n+" znakov"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(t){return t.maximum==1?"Môžete zvoliť len jednu položku":t.maximum>=2&&t.maximum<=4?"Môžete zvoliť najviac "+e[t.maximum](!1)+" položky":"Môžete zvoliť najviac "+t.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | // http://nightwatchjs.org/guide#settings-file 2 | module.exports = { 3 | 'src_folders': ['test/e2e/specs'], 4 | 'output_folder': 'test/e2e/reports', 5 | 'custom_assertions_path': ['test/e2e/custom-assertions'], 6 | 7 | 'selenium': { 8 | 'start_process': true, 9 | 'server_path': require('selenium-server').path, 10 | 'host': '127.0.0.1', 11 | 'port': 4444, 12 | 'cli_args': { 13 | 'webdriver.chrome.driver': require('chromedriver').path, 14 | 'webdriver.geckodriver.driver': require('chromedriver').path 15 | } 16 | }, 17 | 18 | 'test_settings': { 19 | 'default': { 20 | 'selenium_port': 4444, 21 | 'selenium_host': 'localhost', 22 | 'silent': true 23 | }, 24 | 25 | 'chrome': { 26 | 'desiredCapabilities': { 27 | 'browserName': 'chrome', 28 | 'javascriptEnabled': true, 29 | 'acceptSslCerts': true 30 | } 31 | }, 32 | 33 | 'firefox': { 34 | 'desiredCapabilities': { 35 | 'browserName': 'firefox', 36 | 'javascriptEnabled': true, 37 | 'acceptSslCerts': true 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /frontend/test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var webpackConfig = require('../../build/webpack.test.conf') 7 | 8 | module.exports = function (config) { 9 | config.set({ 10 | // to run in additional browsers: 11 | // 1. install corresponding karma launcher 12 | // http://karma-runner.github.io/0.13/config/browsers.html 13 | // 2. add it to the `browsers` array below. 14 | logLevel: config.LOG_INFO, 15 | browsers: ['PhantomJS'], 16 | frameworks: ['mocha', 'sinon-chai'], 17 | reporters: ['spec', 'coverage'], 18 | files: ['./index.js'], 19 | preprocessors: { 20 | './index.js': ['webpack', 'sourcemap'] 21 | }, 22 | webpack: webpackConfig, 23 | webpackMiddleware: { 24 | noInfo: true 25 | }, 26 | coverageReporter: { 27 | dir: './coverage', 28 | reporters: [ 29 | { type: 'lcov', subdir: '.' }, 30 | { type: 'text-summary' } 31 | ] 32 | } 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /backend/server/plugins/sockets.plugin.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const nes = require('@hapi/nes') 4 | 5 | const Config = require('../../config') 6 | 7 | const authStrategy = Config.get('/restHapiConfig/authStrategy') 8 | 9 | module.exports = { 10 | plugin: { 11 | name: 'sockets', 12 | register 13 | } 14 | } 15 | 16 | async function register(server, options) { 17 | try { 18 | await server.register({ 19 | plugin: nes, 20 | options: { 21 | auth: { 22 | type: 'direct', 23 | route: { 24 | strategy: authStrategy 25 | } 26 | }, 27 | // auth: false, 28 | headers: ['*'], 29 | onConnection: function(socket) { 30 | // console.log("connection established", socket.auth) 31 | if (!socket.auth.isAuthenticated) { 32 | console.log('NO AUTH, DISCONNECTING') 33 | socket.disconnect() 34 | } 35 | }, 36 | onDisconnection: function(socket) { 37 | console.log('connection closed') 38 | } 39 | } 40 | }) 41 | } catch (err) { 42 | console.error('Failed to load plugin:', err) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/select2/i18n/cs.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/cs",[],function(){function e(e,t){switch(e){case 2:return t?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím zadejte o jeden znak méně":n<=4?"Prosím zadejte o "+e(n,!0)+" znaky méně":"Prosím zadejte o "+n+" znaků méně"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím zadejte ještě jeden znak":n<=4?"Prosím zadejte ještě další "+e(n,!0)+" znaky":"Prosím zadejte ještě dalších "+n+" znaků"},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(t){var n=t.maximum;return n==1?"Můžete zvolit jen jednu položku":n<=4?"Můžete zvolit maximálně "+e(n,!1)+" položky":"Můžete zvolit maximálně "+n+" položek"},noResults:function(){return"Nenalezeny žádné položky"},searching:function(){return"Vyhledávání…"}}}),{define:e.define,require:e.require}})(); -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/ColVis/License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2015 SpryMedia Limited 2 | http://datatables.net 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/ColReorder/License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2015 SpryMedia Limited 2 | http://datatables.net 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/FixedColumns/License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2015 SpryMedia Limited 2 | http://datatables.net 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/Responsive/License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2015 SpryMedia Limited 2 | http://datatables.net 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /frontend/src/components/views/main/ContentHeader.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ $route.meta.title }} 6 | {{ $route.meta.description }} 7 | 8 | 9 | 10 | Home 11 | 12 | 13 | {{ breadcrumb.title }} 14 | 15 | 16 | 17 | 18 | 19 | 38 | 39 | -------------------------------------------------------------------------------- /frontend/src/routes/permissions.route.js: -------------------------------------------------------------------------------- 1 | import Permissions from '../components/views/permissions/Permissions.vue' 2 | import PermissionDetails from '../components/views/permissions/PermissionDetails.vue' 3 | import PermissionCreate from '../components/views/permissions/PermissionCreate.vue' 4 | 5 | const routes = [ 6 | { 7 | path: 'permissions', 8 | component: Permissions, 9 | name: 'Permissions', 10 | meta: { 11 | description: 'List of appy permissions', 12 | title: 'Permissions', 13 | requiresAuth: true 14 | } 15 | }, 16 | { 17 | path: '/permissions/:_id', 18 | beforeEnter: (to, from, next) => { 19 | to.params._id === 'create' ? next({ name: 'PermissionCreate' }) : next() 20 | }, 21 | component: PermissionDetails, 22 | name: 'PermissionDetails', 23 | meta: { 24 | description: 'Details for the selected permission', 25 | title: 'Permission Details', 26 | requiresAuth: true 27 | } 28 | }, 29 | { 30 | path: '/permission/create', 31 | component: PermissionCreate, 32 | name: 'PermissionCreate', 33 | meta: { 34 | description: 'Create a new permission', 35 | title: 'Permission Create', 36 | requiresAuth: true 37 | } 38 | } 39 | ] 40 | 41 | export default routes 42 | -------------------------------------------------------------------------------- /frontend/src/routes/documents.route.js: -------------------------------------------------------------------------------- 1 | import Documents from '../components/views/documents/Documents.vue' 2 | import DocumentCreate from '../components/views/documents/DocumentCreate.vue' 3 | import DocumentDetails from '../components/views/documents/DocumentDetails.vue' 4 | 5 | const routes = [ 6 | { 7 | path: 'documents', 8 | component: Documents, 9 | name: 'Documents', 10 | meta: { 11 | description: 'Your documents', 12 | title: 'Documents', 13 | requiresAuth: true 14 | } 15 | }, 16 | { 17 | path: '/documents/:_id', 18 | beforeEnter: (to, from, next) => { 19 | to.params._id === 'create' 20 | ? next({ name: 'DocumentCreate', requiresAuth: true }) 21 | : next() 22 | }, 23 | component: DocumentDetails, 24 | name: 'DocumentDetails', 25 | props: route => ({ canEdit: route.query.canEdit }), 26 | meta: { 27 | description: 'Details for the selected document', 28 | title: 'Document Details', 29 | requiresAuth: true 30 | } 31 | }, 32 | { 33 | path: '/documents/create', 34 | component: DocumentCreate, 35 | name: 'DocumentCreate', 36 | meta: { 37 | description: 'Create a new document', 38 | title: 'Document', 39 | requiresAuth: true 40 | } 41 | } 42 | ] 43 | 44 | export default routes 45 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.4" 2 | 3 | volumes: 4 | mongo_data: 5 | name: appy_mongo_data 6 | 7 | networks: 8 | backend: 9 | frontend: 10 | 11 | services: 12 | 13 | mongo: 14 | image: mongo:3.6.4 15 | ports: 16 | - 27017:27017 17 | volumes: 18 | - "mongo_data:/data/db" 19 | networks: 20 | - backend 21 | restart: always 22 | 23 | api: 24 | build: backend/ 25 | ports: 26 | - "${SERVER_PORT}:${SERVER_PORT}" 27 | volumes: 28 | # Share the entire project except "node_modules". This prevents us from having to COPY the project files 29 | # in the Dockerfile, while still keeping separate node dependency files. 30 | - "./backend:/backend" 31 | - "/backend/node_modules" 32 | networks: 33 | - backend 34 | depends_on: 35 | - mongo 36 | env_file: 37 | - ./backend/.env-docker 38 | 39 | web: 40 | build: frontend/ 41 | ports: 42 | - 3000:3000 43 | volumes: 44 | # Share the entire project except "node_modules". This prevents us from having to COPY the project files 45 | # in the Dockerfile, while still keeping separate node dependency files. 46 | - "./frontend:/frontend" 47 | - "/frontend/node_modules" 48 | networks: 49 | - frontend 50 | depends_on: 51 | - api 52 | -------------------------------------------------------------------------------- /.idea/watcherTasks.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /frontend/build/check-versions.js: -------------------------------------------------------------------------------- 1 | var chalk = require('chalk') 2 | var semver = require('semver') 3 | var packageConfig = require('../package.json') 4 | 5 | function exec (cmd) { 6 | return require('child_process').execSync(cmd).toString().trim() 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: 'node', 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | }, 15 | { 16 | name: 'npm', 17 | currentVersion: exec('npm --version'), 18 | versionRequirement: packageConfig.engines.npm 19 | } 20 | ] 21 | 22 | module.exports = function () { 23 | var warnings = [] 24 | for (var i = 0; i < versionRequirements.length; i++) { 25 | var mod = versionRequirements[i] 26 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 27 | warnings.push(mod.name + ': ' + 28 | chalk.red(mod.currentVersion) + ' should be ' + 29 | chalk.green(mod.versionRequirement) 30 | ) 31 | } 32 | } 33 | 34 | if (warnings.length) { 35 | console.log('') 36 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 37 | console.log() 38 | for (var i = 0; i < warnings.length; i++) { 39 | var warning = warnings[i] 40 | console.log(' ' + warning) 41 | } 42 | console.log() 43 | process.exit(1) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /backend/server/models/visitor.model.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = function(mongoose) { 4 | var modelName = 'visitor' 5 | var Types = mongoose.Schema.Types 6 | var Schema = new mongoose.Schema( 7 | { 8 | ip: { 9 | type: Types.String, 10 | required: true 11 | }, 12 | browser: { 13 | type: Types.String, 14 | required: true 15 | }, 16 | country_code: { 17 | type: Types.String 18 | }, 19 | country_name: { 20 | type: Types.String 21 | }, 22 | region_code: { 23 | type: Types.String 24 | }, 25 | region_name: { 26 | type: Types.String 27 | }, 28 | city: { 29 | type: Types.String 30 | }, 31 | zip_code: { 32 | type: Types.String 33 | }, 34 | time_zone: { 35 | type: Types.String 36 | }, 37 | latitude: { 38 | type: Types.Number 39 | }, 40 | longitude: { 41 | type: Types.Number 42 | }, 43 | metro_code: { 44 | type: Types.Number 45 | } 46 | }, 47 | { collection: modelName } 48 | ) 49 | 50 | Schema.statics = { 51 | collectionName: modelName, 52 | routeOptions: { 53 | policies: {}, 54 | associations: {}, 55 | allowCreate: false, 56 | allowUpdate: false, 57 | allowDelete: false 58 | } 59 | } 60 | 61 | return Schema 62 | } 63 | -------------------------------------------------------------------------------- /backend/server/policies/connection-auth.policy.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Boom = require('@hapi/boom') 4 | const RestHapi = require('rest-hapi') 5 | const errorHelper = require('../utilities/error-helper') 6 | 7 | const internals = {} 8 | 9 | /** 10 | * Policy to enforce auth for connection updates. 11 | * @param mongoose 12 | * @returns {connectionUpdateAuth} 13 | */ 14 | internals.connectionUpdateAuth = function(mongoose) { 15 | const connectionUpdateAuth = async function connectionAuth(request, h) { 16 | const Log = request.logger.bind('connectionAuth') 17 | 18 | try { 19 | const Connection = mongoose.model('connection') 20 | 21 | let userId = request.auth.credentials.user._id 22 | 23 | let result = await RestHapi.find(Connection, request.params._id, {}, Log) 24 | // Only the primary user and those with root permissions can update the connection 25 | if ( 26 | userId === result.primaryUser.toString() || 27 | request.auth.credentials.scope.includes('root') 28 | ) { 29 | return h.continue 30 | } else { 31 | throw Boom.forbidden('Not primary user') 32 | } 33 | } catch (err) { 34 | errorHelper.handleError(err, Log) 35 | } 36 | } 37 | 38 | connectionUpdateAuth.applyPoint = 'onPreHandler' 39 | return connectionUpdateAuth 40 | } 41 | internals.connectionUpdateAuth.applyPoint = 'onPreHandler' 42 | 43 | module.exports = internals.connectionUpdateAuth 44 | -------------------------------------------------------------------------------- /backend/server/utilities/create-token.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Jwt = require('jsonwebtoken') 4 | const Config = require('../../config') 5 | const errorHelper = require('./error-helper') 6 | 7 | function createToken(user, session, scope, expirationPeriod, logger) { 8 | const Log = logger.bind('token') 9 | try { 10 | let token = {} 11 | 12 | if (session) { 13 | token = Jwt.sign( 14 | { 15 | sessionId: session._id, 16 | sessionKey: session.key, 17 | passwordHash: session.passwordHash, 18 | scope: scope 19 | }, 20 | Config.get('/jwtSecret'), 21 | { algorithm: 'HS256', expiresIn: expirationPeriod } 22 | ) 23 | } else { 24 | const tokenUser = { 25 | firstName: user.firstName, 26 | lastName: user.lastName, 27 | email: user.email, 28 | role: user.role, 29 | roleName: user.roleName, 30 | roleRank: user.roleRank, 31 | createdAt: user.createdAt, 32 | updatedAt: user.updatedAt, 33 | _id: user._id 34 | } 35 | 36 | token = Jwt.sign( 37 | { 38 | user: tokenUser, 39 | scope: scope 40 | }, 41 | Config.get('/jwtSecret'), 42 | { algorithm: 'HS256', expiresIn: expirationPeriod } 43 | ) 44 | } 45 | 46 | return token 47 | } catch (err) { 48 | errorHelper.handleError(err, Log) 49 | } 50 | } 51 | 52 | module.exports = createToken 53 | -------------------------------------------------------------------------------- /frontend/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var webpack = require('webpack') 3 | var config = require('../config') 4 | var merge = require('webpack-merge') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 8 | 9 | // add hot-reload related code to entry chunks 10 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 11 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 12 | }) 13 | 14 | module.exports = merge(baseWebpackConfig, { 15 | module: { 16 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 17 | }, 18 | // cheap-module-eval-source-map is faster for development, but chrome doesn't stop at breakpoints 19 | // devtool: '#cheap-module-eval-source-map', 20 | devtool: '#source-map', 21 | 22 | plugins: [ 23 | new webpack.DefinePlugin({ 24 | 'process.env': config.dev.env 25 | }), 26 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 27 | new webpack.HotModuleReplacementPlugin(), 28 | new webpack.NoEmitOnErrorsPlugin(), 29 | // https://github.com/ampedandwired/html-webpack-plugin 30 | new HtmlWebpackPlugin({ 31 | filename: 'index.html', 32 | template: 'index.html', 33 | inject: true 34 | }), 35 | new FriendlyErrorsPlugin() 36 | ] 37 | }) 38 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/ColVis/Readme.md: -------------------------------------------------------------------------------- 1 | # ColVis 2 | 3 | ColVis adds a button to the toolbars around DataTables which gives the end user of the table the ability to dynamically change the visibility of the columns in the table: 4 | 5 | * Dynamically show and hide columns in a table 6 | * Very easy integration with DataTables 7 | * Ability to exclude columns from being either hidden or shown 8 | * Save saving integration with DataTables 9 | 10 | 11 | # Installation 12 | 13 | To use ColVis, first download DataTables ( http://datatables.net/download ) and place the unzipped ColVis package into a `extensions` directory in the DataTables package. This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser. 14 | 15 | 16 | # Basic usage 17 | 18 | ColVis is initialised using the `C` option that it adds to DataTables' `dom` option. For example: 19 | 20 | ```js 21 | $(document).ready( function () { 22 | $('#example').dataTable( { 23 | "dom": 'C<"clear">lfrtip' 24 | } ); 25 | } ); 26 | ``` 27 | 28 | 29 | # Documentation / support 30 | 31 | * Documentation: http://datatables.net/extensions/colvis/ 32 | * DataTables support forums: http://datatables.net/forums 33 | 34 | 35 | # GitHub 36 | 37 | If you fancy getting involved with the development of ColVis and help make it better, please refer to its GitHub repo: https://github.com/DataTables/ColVis 38 | 39 | -------------------------------------------------------------------------------- /backend/server/policies/notification-auth.policy.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Boom = require('@hapi/boom') 4 | const RestHapi = require('rest-hapi') 5 | const errorHelper = require('../utilities/error-helper') 6 | 7 | const internals = {} 8 | 9 | /** 10 | * Policy to enforce auth for notification updates. 11 | * @param mongoose 12 | * @returns {notificationUpdateAuth} 13 | */ 14 | internals.notificationUpdateAuth = function(mongoose) { 15 | const notificationUpdateAuth = async function notificationAuth(request, h) { 16 | const Log = request.logger.bind('notificationAuth') 17 | 18 | try { 19 | const Connection = mongoose.model('notification') 20 | 21 | let userId = request.auth.credentials.user._id 22 | 23 | let result = await RestHapi.find(Connection, request.params._id, {}, Log) 24 | // Only the primary user and those with root permissions can update the notification 25 | if ( 26 | userId === result.primaryUser.toString() || 27 | request.auth.credentials.scope.includes('root') 28 | ) { 29 | return h.continue 30 | } else { 31 | throw Boom.forbidden('Not primary user') 32 | } 33 | } catch (err) { 34 | errorHelper.handleError(err, Log) 35 | } 36 | } 37 | 38 | notificationUpdateAuth.applyPoint = 'onPreHandler' 39 | return notificationUpdateAuth 40 | } 41 | internals.notificationUpdateAuth.applyPoint = 'onPreHandler' 42 | 43 | module.exports = internals.notificationUpdateAuth 44 | -------------------------------------------------------------------------------- /frontend/src/services/auth-interceptor.service.js: -------------------------------------------------------------------------------- 1 | import store from '../store' 2 | import vm from '../main' 3 | 4 | import { RESPONSE_MESSAGES } from '../config' 5 | 6 | const internals = {} 7 | 8 | internals.responseError = function(error) { 9 | let response = error.response 10 | 11 | // var Notification = $injector.get('Notification'); 12 | 13 | // If the access token was expired, allow the apiHelperService to try a refresh token 14 | if ( 15 | response.status === 401 && 16 | response.data.message === RESPONSE_MESSAGES.EXPIRED_ACCESS_TOKEN 17 | ) { 18 | console.debug('authInterceptor.service: 401: response:', response) 19 | 20 | response = RESPONSE_MESSAGES.EXPIRED_ACCESS_TOKEN 21 | 22 | // If the token was invalid or the Refresh Token was expired, force user to login 23 | } else if (response.status === 401) { 24 | console.debug('authInterceptor.service: 401: response:', response) 25 | 26 | store.dispatch('auth/clearAuth') 27 | 28 | vm.$router.push('/login') 29 | } else if (response.status === 403) { 30 | // The user is unauthorized 31 | console.debug('authInterceptor.service: 403: response:', response) 32 | 33 | vm.$snotify.warning('Not authorized: ' + response.data.message, 'Warning') 34 | } 35 | // If not a 401 or 403, do nothing with this error. This is necessary to make a `responseError` 36 | // interceptor a no-op. */ 37 | return Promise.reject(response) 38 | } 39 | 40 | export default { 41 | responseError: internals.responseError 42 | } 43 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/ColReorder/Readme.md: -------------------------------------------------------------------------------- 1 | # ColReorder 2 | 3 | ColReorder adds the ability for the end user to click and drag column headers to reorder a table as they see fit, to DataTables. Key features include: 4 | 5 | * Very easy integration with DataTables 6 | * Tight integration with all other DataTables plug-ins 7 | * The ability to exclude the first (or more) column from being movable 8 | * Predefine a column order 9 | * Save staving integration with DataTables 10 | 11 | 12 | # Installation 13 | 14 | To use ColReorder, first download DataTables ( http://datatables.net/download ) and place the unzipped ColReorder package into a `extensions` directory in the DataTables package. This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser. 15 | 16 | 17 | # Basic usage 18 | 19 | ColReorder is initialised using the `$.fn.dataTable.ColReorder` constructor. For example: 20 | 21 | ```js 22 | $(document).ready( function () { 23 | $('#example').DataTable(); 24 | 25 | new $.fn.dataTable.ColReorder( table ); 26 | } ); 27 | ``` 28 | 29 | 30 | # Documentation / support 31 | 32 | * Documentation: http://datatables.net/extensions/colreorder/ 33 | * DataTables support forums: http://datatables.net/forums 34 | 35 | 36 | # GitHub 37 | 38 | If you fancy getting involved with the development of ColReorder and help make it better, please refer to its GitHub repo: https://github.com/DataTables/ColReorder 39 | 40 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/KeyTable/Readme.txt: -------------------------------------------------------------------------------- 1 | # KeyTable 2 | 3 | KeyTable provides enhanced accessibility and navigation options for DataTables enhanced tables, by allowing Excel like cell navigation on any table. Events (focus, blur, action etc) can be assigned to individual cells, columns, rows or all cells to allow advanced interaction options.. Key features include: 4 | 5 | * Easy to use spreadsheet like interaction 6 | * Fully integrated with DataTables 7 | * Wide range of supported events 8 | 9 | 10 | # Installation 11 | 12 | To use KeyTable, first download DataTables ( http://datatables.net/download ) and place the unzipped KeyTable package into a `extensions` directory in the DataTables package. This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser. 13 | 14 | 15 | # Basic usage 16 | 17 | KeyTable is initialised using the `C` option that it adds to DataTables' `dom` option. For example: 18 | 19 | ```js 20 | $(document).ready( function () { 21 | var table = $('#example').DataTable(); 22 | new $.fn.dataTable.KeyTable( table ); 23 | } ); 24 | ``` 25 | 26 | 27 | # Documentation / support 28 | 29 | * Documentation: http://datatables.net/extensions/keytable/ 30 | * DataTables support forums: http://datatables.net/forums 31 | 32 | 33 | # GitHub 34 | 35 | If you fancy getting involved with the development of KeyTable and help make it better, please refer to its GitHub repo: https://github.com/DataTables/KeyTable 36 | 37 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/AutoFill/Readme.txt: -------------------------------------------------------------------------------- 1 | # AutoFill 2 | 3 | AutoFill gives an Excel like option to a DataTable to click and drag over multiple cells, filling in information over the selected cells and incrementing numbers as needed. Key features include: 4 | 5 | * Click and drag cell content insertion 6 | * Automatic incrementing of numeric information 7 | * Enable and disable on any column 8 | * Detailed callback functions for customisation 9 | * Support for both DataTables and browser window scrolling 10 | 11 | 12 | # Installation 13 | 14 | To use AutoFill, first download DataTables ( http://datatables.net/download ) and place the unzipped AutoFill package into a `extensions` directory in the DataTables package. This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser. 15 | 16 | 17 | # Basic usage 18 | 19 | AutoFill is initialised using the `$.fn.dataTable.AutoFill` constructor. For example: 20 | 21 | ```js 22 | $(document).ready( function () { 23 | var table = $('#example').dataTable(); 24 | new $.fn.dataTable.AutoFill( table ); 25 | } ); 26 | ``` 27 | 28 | 29 | # Documentation / support 30 | 31 | * Documentation: http://datatables.net/extensions/autofill/ 32 | * DataTables support forums: http://datatables.net/forums 33 | 34 | 35 | # GitHub 36 | 37 | If you fancy getting involved with the development of AutoFill and help make it better, please refer to its GitHub repo: https://github.com/DataTables/AutoFill 38 | 39 | -------------------------------------------------------------------------------- /frontend/src/routes/index.js: -------------------------------------------------------------------------------- 1 | import NotFound from '../components/404.vue' 2 | 3 | import Login from '../components/views/login/Login.vue' 4 | import LoginSocial from '../components/views/login/LoginSocial.vue' 5 | import ForgotPassword from '../components/views/login/ForgotPassword.vue' 6 | import ResetPassword from '../components/views/login/ResetPassword.vue' 7 | 8 | import Register from '../components/views/register/Register.vue' 9 | import ActivateAccount from '../components/views/register/ActivateAccount.vue' 10 | 11 | import mainRoutes from './main.route' 12 | 13 | const routes = [ 14 | ...mainRoutes, 15 | { 16 | path: '/login', 17 | component: Login, 18 | name: 'Login', 19 | meta: { requiresUnauth: true } 20 | }, 21 | { 22 | path: '/login/social', 23 | component: LoginSocial, 24 | name: 'LoginSocial', 25 | meta: { requiresUnauth: true } 26 | }, 27 | { 28 | path: '/login/forgot', 29 | component: ForgotPassword, 30 | name: 'ForgotPassword', 31 | meta: { requiresUnauth: true } 32 | }, 33 | { 34 | path: '/login/reset', 35 | component: ResetPassword, 36 | name: 'ResetPassword' 37 | }, 38 | { 39 | path: '/activate', 40 | component: ActivateAccount, 41 | name: 'ActivateAccount' 42 | }, 43 | { 44 | path: '/register', 45 | component: Register, 46 | name: 'Register', 47 | meta: { requiresUnauth: true } 48 | }, 49 | { 50 | // not found handler 51 | path: '*', 52 | component: NotFound 53 | } 54 | ] 55 | 56 | export default routes 57 | -------------------------------------------------------------------------------- /frontend/src/plugins/repository-plugin.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import ResourceHelper from './restful-resource-utility' 3 | 4 | const RestHapiRepository = { 5 | install(Vue, { httpClient, resources, log }) { 6 | httpClient = httpClient || axios 7 | 8 | const fakeLogger = { 9 | log: function() {}, 10 | debug: function() {}, 11 | error: function() {} 12 | } 13 | 14 | var logger = log ? console : fakeLogger 15 | 16 | const resourceHelper = ResourceHelper(httpClient, logger) 17 | for (var resourceName in resources) { 18 | const resource = resources[resourceName] 19 | const resourceRoute = resource.alias || resourceName 20 | var repoCalls = resourceHelper.generateCrudCallers( 21 | resourceRoute, 22 | resource.options 23 | ) 24 | const associations = resource.associations 25 | 26 | for (var associationName in associations) { 27 | const association = associations[associationName] 28 | const associationRoute = association.alias || associationName 29 | repoCalls = Object.assign( 30 | {}, 31 | repoCalls, 32 | resourceHelper.generateAssociationCallers( 33 | resourceRoute, 34 | associationName, 35 | associationRoute, 36 | association.options 37 | ) 38 | ) 39 | } 40 | 41 | const repoName = '$' + resourceName + 'Repository' 42 | Vue.prototype[repoName] = repoCalls 43 | } 44 | } 45 | } 46 | 47 | export default RestHapiRepository 48 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/TableTools/Readme.md: -------------------------------------------------------------------------------- 1 | # TableTools 2 | 3 | TableTools is a plug-in for the DataTables HTML table enhancer, which adds a highly customisable button toolbar to a DataTable. Key features include: 4 | 5 | * Copy to clipboard 6 | * Save table data as CSV, XLS or PDF files 7 | * Print view for clean printing 8 | * Row selection options 9 | * Easy use predefined buttons 10 | * Simple customisation of buttons 11 | * Well defined API for advanced control 12 | 13 | 14 | # Installation 15 | 16 | To use TableTools, first download DataTables ( http://datatables.net/download ) and place the unzipped TableTools package into a `extensions` directory in the DataTables package (in DataTables 1.9- use the `extras` directory). This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser. 17 | 18 | 19 | # Basic usage 20 | 21 | TableTools is initialised using the `T` option that it adds to DataTables' `dom` option. For example: 22 | 23 | ```js 24 | $(document).ready( function () { 25 | $('#example').DataTable( { 26 | dom: 'T<"clear">lfrtip' 27 | } ); 28 | } ); 29 | ``` 30 | 31 | 32 | # Documentation / support 33 | 34 | * Documentation: http://datatables.net/extensions/tabletools/ 35 | * DataTables support forums: http://datatables.net/forums 36 | 37 | 38 | # GitHub 39 | 40 | If you fancy getting involved with the development of TableTools and help make it better, please refer to its GitHub repo: https://github.com/DataTables/TableTools 41 | 42 | -------------------------------------------------------------------------------- /backend/server/models/conversation.model.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const _ = require('lodash') 4 | const Config = require('../../config') 5 | 6 | const CHAT_TYPES = Config.get('/constants/CHAT_TYPES') 7 | 8 | module.exports = function(mongoose) { 9 | var modelName = 'conversation' 10 | var Types = mongoose.Schema.Types 11 | var Schema = new mongoose.Schema( 12 | { 13 | name: { 14 | type: Types.String, 15 | description: 'The name of the chat.' 16 | }, 17 | lastMessage: { 18 | type: Types.ObjectId, 19 | ref: 'message' 20 | }, 21 | chatType: { 22 | type: Types.String, 23 | required: true, 24 | enum: _.values(CHAT_TYPES) 25 | } 26 | }, 27 | { collection: modelName } 28 | ) 29 | 30 | Schema.statics = { 31 | collectionName: modelName, 32 | routeOptions: { 33 | routeScope: {}, 34 | policies: {}, 35 | associations: { 36 | lastMessage: { 37 | type: 'ONE_ONE', 38 | model: 'message' 39 | }, 40 | users: { 41 | type: '_MANY', 42 | model: 'user' 43 | }, 44 | userData: { 45 | type: 'MANY_MANY', 46 | alias: 'user-data', 47 | model: 'user', 48 | linkingModel: 'user_conversation' 49 | }, 50 | messages: { 51 | type: 'ONE_MANY', 52 | alias: 'message', 53 | foreignField: 'conversation', 54 | model: 'message' 55 | } 56 | } 57 | } 58 | } 59 | 60 | return Schema 61 | } 62 | -------------------------------------------------------------------------------- /frontend/static/js/plugins/datatables/extensions/FixedHeader/Readme.txt: -------------------------------------------------------------------------------- 1 | # FixedHeader 2 | 3 | At times it can be useful to ensure that column titles will remain always visible on a table, even when a user scrolls down a table. The FixedHeader plug-in for DataTables will float the 'thead' element above the table at all times to help address this issue. The column titles also remain click-able to perform sorting. Key features include: 4 | 5 | * Fix the header to the top of the window 6 | * Ability to fix the footer and left / right columns as well 7 | * z-Index ordering options 8 | 9 | 10 | # Installation 11 | 12 | To use FixedHeader, first download DataTables ( http://datatables.net/download ) and place the unzipped FixedHeader package into a `extensions` directory in the DataTables package. This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser. 13 | 14 | 15 | # Basic usage 16 | 17 | FixedHeader is initialised using the `$.fn.dataTable.FixedHeader()` object. For example: 18 | 19 | ```js 20 | $(document).ready( function () { 21 | var table = $('#example').dataTable(); 22 | new $.fn.dataTable.FixedHeader( table ); 23 | } ); 24 | ``` 25 | 26 | 27 | # Documentation / support 28 | 29 | * Documentation: http://datatables.net/extensions/FixedHeader/ 30 | * DataTables support forums: http://datatables.net/forums 31 | 32 | 33 | # GitHub 34 | 35 | If you fancy getting involved with the development of FixedHeader and help make it better, please refer to its GitHub repo: https://github.com/DataTables/FixedHeader 36 | 37 | -------------------------------------------------------------------------------- /frontend/src/store/actions.js: -------------------------------------------------------------------------------- 1 | import vm from '../main' 2 | 3 | export default { 4 | // Set a custom breadcrumb title for the current route 5 | setBreadcrumbTitle({ state, commit }, breadcrumbTitle) { 6 | const parts = vm.$router.currentRoute.path.split('/').slice(1) 7 | const breadcrumbs = state.breadcrumbs 8 | for (const [index] of parts.entries()) { 9 | let subPath = '' 10 | for (let i = 0; i <= index; i++) { 11 | subPath += '/' + parts[i] 12 | } 13 | if (subPath === vm.$router.currentRoute.path) { 14 | breadcrumbs[index].title = breadcrumbTitle 15 | commit('SET_BREADCRUMBS', breadcrumbs) 16 | return 17 | } 18 | } 19 | }, 20 | setBreadcrumbs({ state, commit }, { currentPath }) { 21 | if (vm) { 22 | const parts = currentPath.split('/').slice(1) 23 | const breadcrumbs = [] 24 | for (const [index] of parts.entries()) { 25 | let subPath = '' 26 | for (let i = 0; i <= index; i++) { 27 | subPath += '/' + parts[i] 28 | } 29 | // Use the current breadcrumb if it exists, else add the default breadcrumb 30 | let breadcrumb = state.breadcrumbs.find(breadcrumb => { 31 | return breadcrumb.path === subPath 32 | }) 33 | if (!breadcrumb) { 34 | let { route } = vm.$router.resolve(subPath) 35 | breadcrumb = { 36 | path: subPath, 37 | title: route.meta.title 38 | } 39 | } 40 | breadcrumbs.push(breadcrumb) 41 | } 42 | commit('SET_BREADCRUMBS', breadcrumbs) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /frontend/src/store/utilities/generate-mutations.js: -------------------------------------------------------------------------------- 1 | import changeCase from 'change-case' 2 | import _ from 'lodash' 3 | 4 | const generateMutations = function(initialState) { 5 | const mutations = {} 6 | 7 | for (const prop in initialState) { 8 | mutations['SET_' + changeCase.constantCase(prop)] = function(state, data) { 9 | state[prop] = data 10 | } 11 | 12 | mutations['DELETE_' + changeCase.constantCase(prop)] = function(state) { 13 | state[prop] = null 14 | } 15 | 16 | mutations['CLEAR_' + changeCase.constantCase(prop)] = function(state) { 17 | if (_.isString(state[prop])) { 18 | state[prop] = '' 19 | } 20 | if (_.isObject(state[prop])) { 21 | state[prop] = {} 22 | } 23 | if (_.isArray(state[prop])) { 24 | state[prop] = [] 25 | } 26 | if (_.isBoolean(state[prop])) { 27 | state[prop] = false 28 | } 29 | if (_.isNumber(state[prop])) { 30 | state[prop] = 0 31 | } 32 | } 33 | 34 | if (_.isArray(initialState[prop])) { 35 | mutations['ADD_' + changeCase.constantCase(prop)] = function( 36 | state, 37 | data 38 | ) { 39 | state[prop].push(data) 40 | } 41 | 42 | mutations['REMOVE_' + changeCase.constantCase(prop)] = function( 43 | state, 44 | data 45 | ) { 46 | const index = state[prop].indexOf(data) 47 | 48 | if (index !== -1) { 49 | state[prop].splice(index, 1) 50 | } 51 | } 52 | } 53 | } 54 | 55 | return mutations 56 | } 57 | 58 | export default generateMutations 59 | -------------------------------------------------------------------------------- /backend/server/models/group.model.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const permissionAuth = require('../policies/permission-auth.policy') 4 | const groupAuth = require('../policies/group-auth.policy') 5 | const rankAuth = require('../policies/role-auth.policy').rankAuth 6 | 7 | const Config = require('../../config') 8 | 9 | const enableDemoAuth = Config.get('/enableDemoAuth') 10 | const demoAuth = enableDemoAuth ? 'demoAuth' : null 11 | 12 | module.exports = function(mongoose) { 13 | var modelName = 'group' 14 | var Types = mongoose.Schema.Types 15 | var Schema = new mongoose.Schema( 16 | { 17 | name: { 18 | type: Types.String, 19 | required: true, 20 | unique: true 21 | }, 22 | description: { 23 | type: Types.String 24 | } 25 | }, 26 | { collection: modelName } 27 | ) 28 | 29 | Schema.statics = { 30 | collectionName: modelName, 31 | routeOptions: { 32 | policies: { 33 | associatePolicies: [ 34 | rankAuth(mongoose, 'child'), 35 | permissionAuth(mongoose, false), 36 | groupAuth(mongoose, true), 37 | demoAuth 38 | ], 39 | updatePolicies: [demoAuth], 40 | deletePolicies: [demoAuth] 41 | }, 42 | associations: { 43 | users: { 44 | type: 'MANY_MANY', 45 | alias: 'user', 46 | model: 'user' 47 | }, 48 | permissions: { 49 | type: 'MANY_MANY', 50 | alias: 'permission', 51 | model: 'permission', 52 | linkingModel: 'group_permission' 53 | } 54 | } 55 | } 56 | } 57 | 58 | return Schema 59 | } 60 | -------------------------------------------------------------------------------- /frontend/src/routes/main.route.js: -------------------------------------------------------------------------------- 1 | import Main from '../components/views/main/Main.vue' 2 | 3 | import Dashboard from '../components/views/dashboard/Dashboard.vue' 4 | 5 | import Profile from '../components/views/profile/Profile.vue' 6 | 7 | import userRoutes from './users.route' 8 | import roleRoutes from './roles.route' 9 | import groupRoutes from './groups.route' 10 | import permissionRoutes from './permissions.route' 11 | 12 | import memberRoutes from './members.route' 13 | import connectionRoutes from './connections.route' 14 | import documentRoutes from './documents.route' 15 | import imageRoutes from './images.route' 16 | 17 | import auditLogRoutes from './audit-logs.route' 18 | 19 | const routes = [ 20 | { 21 | path: '/', 22 | component: Main, 23 | children: [ 24 | { 25 | path: 'dashboard', 26 | alias: '', 27 | component: Dashboard, 28 | name: 'Dashboard', 29 | meta: { 30 | description: 'Overview of app', 31 | title: 'Dashboard', 32 | requiresAuth: true 33 | } 34 | }, 35 | { 36 | path: 'profile', 37 | component: Profile, 38 | name: 'Profile', 39 | meta: { 40 | description: 'Profile details', 41 | title: 'Profile', 42 | requiresAuth: true 43 | } 44 | }, 45 | ...userRoutes, 46 | ...roleRoutes, 47 | ...groupRoutes, 48 | ...permissionRoutes, 49 | ...memberRoutes, 50 | ...connectionRoutes, 51 | ...documentRoutes, 52 | ...imageRoutes, 53 | ...auditLogRoutes 54 | ] 55 | } 56 | ] 57 | 58 | export default routes 59 | -------------------------------------------------------------------------------- /backend/config/manifest.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const Confidence = require('confidence') 3 | const Config = require('./index') 4 | const RestHapi = require('rest-hapi') 5 | 6 | const criteria = { 7 | env: process.env.NODE_ENV 8 | } 9 | 10 | const manifest = { 11 | $meta: 'This file defines the server.', 12 | server: { 13 | // debug: { 14 | // request: ['error'] 15 | // }, 16 | port: Config.get('/port'), 17 | // connections: { 18 | // routes: { 19 | // security: true, 20 | // cors: true 21 | // } 22 | // } 23 | routes: { 24 | cors: { 25 | origin: ['*'] 26 | }, 27 | validate: { 28 | failAction: async (request, h, err) => { 29 | RestHapi.logger.error(err) 30 | throw err 31 | } 32 | } 33 | } 34 | }, 35 | // connections: [ 36 | // { 37 | // port: Config.get('/port') 38 | // } 39 | // ], 40 | register: { 41 | plugins: [ 42 | { 43 | plugin: 'hapi-auth-jwt2' 44 | }, 45 | { 46 | plugin: '@hapi/bell' 47 | }, 48 | { 49 | plugin: './server/plugins/mailer.plugin' 50 | }, 51 | { 52 | plugin: './server/plugins/auth.plugin' 53 | }, 54 | { 55 | plugin: './server/plugins/sockets.plugin' 56 | }, 57 | { 58 | plugin: './server/plugins/api.plugin' 59 | } 60 | ] 61 | } 62 | } 63 | 64 | const store = new Confidence.Store(manifest) 65 | 66 | exports.get = function(key) { 67 | return store.get(key, criteria) 68 | } 69 | 70 | exports.meta = function(key) { 71 | return store.meta(key, criteria) 72 | } 73 | -------------------------------------------------------------------------------- /backend/server/policies/demo-auth.policy.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Boom = require('@hapi/boom') 4 | const errorHelper = require('../utilities/error-helper') 5 | 6 | const internals = {} 7 | 8 | /** 9 | * Policy to restrict certain action for the live demo (such as super admins deleting users). 10 | * @param request 11 | * @param h 12 | * @returns {*} 13 | */ 14 | internals.demoAuth = function(request, h) { 15 | let Log = request.logger.bind('demoAuth') 16 | try { 17 | throw Boom.forbidden('Action not allowed for demo') 18 | } catch (err) { 19 | errorHelper.handleError(err, Log) 20 | } 21 | } 22 | internals.demoAuth.applyPoint = 'onPreHandler' 23 | 24 | /** 25 | * Policy to restrict certain action for the live demo (such as super admins deleting users). 26 | * @param request 27 | * @param h 28 | * @returns {*} 29 | */ 30 | internals.demoUser = async function(request, h) { 31 | let Log = request.logger.bind('demoUser') 32 | 33 | try { 34 | let user = request.auth.credentials.user 35 | 36 | if (internals.demoUsers.includes(user.email)) { 37 | throw Boom.forbidden('Cannot edit demo user') 38 | } 39 | 40 | return h.continue 41 | } catch (err) { 42 | errorHelper.handleError(err, Log) 43 | } 44 | } 45 | internals.demoUser.applyPoint = 'onPreHandler' 46 | 47 | internals.demoUsers = [ 48 | 'test@superadmin.com', 49 | 'test@admin.com', 50 | 'test@user.com', 51 | 'test@readonlyuser.com', 52 | 'test@readonlyadmin.com', 53 | 'test@editoradmin.com', 54 | 'test@superuseradmin.com' 55 | ] 56 | 57 | module.exports = { 58 | demoAuth: internals.demoAuth, 59 | demoUser: internals.demoUser 60 | } 61 | --------------------------------------------------------------------------------