├── .circleci └── config.yml ├── .codacy.yml ├── .codeclimate.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE ├── PULL_REQUEST_TEMPLATE ├── dependabot.yml └── release-drafter.yml ├── .gitignore ├── .hound.yml ├── .scss-lint.yml ├── .slugignore ├── .travis.yml ├── .yaydoc.yml ├── Dockerfile ├── LICENSE ├── LICENSE.md ├── Procfile ├── README.md ├── app.json ├── app.yaml ├── build └── config.gypi ├── codecov.yml ├── config.json ├── docs ├── INSTALLATION.md ├── INSTALLATION_AWS.md ├── INSTALLATION_AWS_DOCKER.md ├── INSTALLATION_DIGITALOCEAN.md ├── INSTALLATION_DOCKER.md ├── INSTALLATION_GOOGLE.md ├── INSTALLATION_HEROKU.md ├── INSTALLATION_LOCAL.md └── images │ ├── generator_screenshot.png │ ├── heroku_1.png │ ├── heroku_2.png │ ├── heroku_3.png │ ├── heroku_4.png │ ├── heroku_5.png │ ├── heroku_6.png │ ├── heroku_7.png │ ├── open-event-webapp.gif │ ├── project.gif │ └── wsgen_branding.png ├── gh_deploy.sh ├── kubernetes ├── deploy.sh ├── images │ └── generator │ │ ├── Dockerfile │ │ └── setup.sh ├── travis │ ├── deploy.sh │ └── eventyay-cf9d0dcc3261.json.enc └── yamls │ └── generator │ ├── configmap.yml │ ├── generator-deployment.yml │ ├── generator-service.yml │ ├── ingress-notls.yml │ └── ingress-tls.yml ├── package.json ├── sample_cli.sh ├── src ├── .eslintignore ├── .eslintrc ├── app.js ├── backend │ ├── .gitignore │ ├── Gemfile │ ├── _scss │ │ ├── .gitignore │ │ ├── _base │ │ │ └── _config.scss │ │ ├── _themes │ │ │ ├── _dark-theme │ │ │ │ └── _dark.scss │ │ │ └── _light-theme │ │ │ │ └── _light.scss │ │ └── application.scss │ ├── assets │ │ ├── dependencies │ │ │ ├── .gitignore │ │ │ ├── async.min.js │ │ │ ├── avatar.png │ │ │ ├── bootstrap.min.css │ │ │ ├── bootstrap.min.js │ │ │ ├── font-awesome.min.css │ │ │ ├── fonts │ │ │ │ ├── FontAwesome.otf │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ └── fontawesome-webfont.woff2 │ │ │ ├── jquery.min.js │ │ │ ├── loader.gif │ │ │ ├── loklak-fetcher.js │ │ │ ├── manifest.json │ │ │ ├── offline.html │ │ │ ├── smooth-scroll.min.js │ │ │ ├── sweetalert.min.js │ │ │ ├── timeline.png │ │ │ └── tweets.js │ │ └── js │ │ │ ├── FileSaver.js │ │ │ ├── html2canvas.js │ │ │ ├── icsGen.js │ │ │ ├── jquery.lazyload.js │ │ │ ├── main.js │ │ │ ├── map.js │ │ │ ├── navbar.js │ │ │ ├── popover.js │ │ │ ├── scroll.js │ │ │ ├── session.js │ │ │ ├── social.js │ │ │ └── sw.js │ ├── buildlogger.js │ ├── deploy.js │ ├── dist.js │ ├── fold_v1.js │ ├── fold_v2.js │ ├── ftpdeploy.js │ ├── generator.js │ ├── gulpfile.js │ ├── mailer.js │ ├── overviewSite │ │ ├── OTS18.jpg │ │ ├── PyCon17.jpg │ │ ├── SparkSummit17.jpg │ │ ├── droidcon.jpg │ │ ├── fa16small.jpg │ │ ├── fasmall.jpg │ │ ├── favicon.ico │ │ ├── fbsmall.jpg │ │ ├── fossasia16.jpg │ │ ├── fossasia2010.JPG │ │ ├── fossasia2011.jpg │ │ ├── googleIO.jpg │ │ ├── index.html │ │ ├── mozilla2016.jpg │ │ ├── mozilla_banner.jpg │ │ ├── nextcloud2017.jpg │ │ ├── nextcloud2018.jpg │ │ ├── oscal17.jpg │ │ ├── oscon.png │ │ ├── ots16.jpg │ │ ├── otssmall.jpg │ │ └── redhat.jpg │ └── templates │ │ ├── CoC.hbs │ │ ├── event.hbs │ │ ├── partials │ │ ├── footer.hbs │ │ ├── googleanalytics.hbs │ │ ├── navbar.hbs │ │ ├── roomlist.hbs │ │ ├── scroll.hbs │ │ ├── social.hbs │ │ └── tracklist.hbs │ │ ├── rooms.hbs │ │ ├── schedule.hbs │ │ ├── session.hbs │ │ ├── speakers.hbs │ │ └── tracks.hbs ├── selenium │ ├── basePage.js │ ├── cocPage.js │ ├── eventPage.js │ ├── generatorPage.js │ ├── roomPage.js │ ├── schedulePage.js │ ├── sessionPage.js │ ├── speakerPage.js │ └── trackPage.js └── www │ ├── 404.html │ ├── css │ ├── bootstrap.min.css │ ├── font-awesome.min.css │ └── main.css │ ├── deploy.html │ ├── favicon.ico │ ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── fontawesome-webfont.woff2 │ └── glyphicons-halflings-regular.ttf │ ├── icons │ ├── Pslab.png │ ├── blog.png │ ├── bug.png │ ├── code.png │ ├── eventyay.png │ ├── fossasia.png │ ├── github.png │ ├── loklak.png │ ├── phimp.png │ ├── susi.png │ └── susper.png │ ├── index.html │ └── js │ ├── bootstrap.min.js │ ├── deployProgress.js │ ├── form.js │ ├── jquery.min.js │ ├── socket.io-stream.js │ └── validation.min.js ├── test ├── generatorAndSchedule.js ├── helper.js ├── roomsAndSpeakers.js ├── serverTest.js ├── sessionEventAndCoC.js └── tracks.js └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | jobs: 4 | test: 5 | docker: 6 | - image: cimg/node:12.20.0-browsers 7 | - image: circleci/redis:alpine 8 | parallelism: 4 9 | steps: 10 | - browser-tools/install-chrome 11 | - browser-tools/install-chromedriver 12 | - run: 13 | command: | 14 | google-chrome --version 15 | chromedriver --version 16 | name: Check install 17 | - checkout 18 | - restore_cache: 19 | keys: 20 | - node-v3-{{ checksum "yarn.lock" }} 21 | - node-v3- 22 | - run: 23 | name: Install all the dependencies 24 | command: yarn 25 | - run: | 26 | echo 'export PATH=$(yarn global bin):$PATH' >> $BASH_ENV 27 | source $BASH_ENV 28 | yarn global add nyc@15.1.0 mocha@8.4.0 29 | - save_cache: 30 | key: node-v3-{{ checksum "yarn.lock" }} 31 | paths: 32 | - ./node_modules 33 | - ~/.cache/yarn 34 | - ~/.yarn/bin 35 | - run: 36 | name: Run Tests 37 | command: | 38 | TEST=$(circleci tests glob "test/*.js" | circleci tests split) 39 | echo "Running $TEST..." 40 | nyc mocha --exit $TEST 41 | 42 | orbs: 43 | browser-tools: circleci/browser-tools@1.4.3 44 | workflows: 45 | version: 2.1 46 | Test: 47 | jobs: 48 | - test 49 | -------------------------------------------------------------------------------- /.codacy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | exclude_paths: 3 | - src/backend/assets/** 4 | - *.min.js 5 | - *.min.css 6 | 7 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | eslint: 3 | enabled: true 4 | csslint: 5 | enabled: true 6 | 7 | ratings: 8 | paths: 9 | - "**.js" 10 | - "**.css" 11 | 12 | exclude_paths: 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.html] 12 | indent_size = 4 13 | 14 | [*.{js,py}] 15 | charset = utf-8 16 | 17 | [*.py] 18 | indent_style = space 19 | indent_size = 4 20 | 21 | [*.js] 22 | indent_size = 4 23 | 24 | [*.css] 25 | indent_size = 4 26 | 27 | [Makefile] 28 | indent_style = tab 29 | 30 | [{package.json,.travis.yml}] 31 | indent_style = space 32 | indent_size = 2 33 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | src/www/js/socket.io-stream.js 2 | /src/backend/assets/** 3 | *.min.js 4 | *.min.css 5 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": {}, 3 | "env": { 4 | "es6": true, 5 | "browser": true, 6 | "node": true, 7 | "jquery": true 8 | }, 9 | "extends": "eslint:recommended" 10 | } 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | .travis.yml merge=ours 2 | README.md merge=ours 3 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributions Best Practices 2 | 3 | **Commits** 4 | * Write clear meaningful git commit messages (Do read http://chris.beams.io/posts/git-commit/) 5 | * Make sure your PR's description contains GitHub's special keyword references that automatically close the related issue when the PR is merged. (More info at https://github.com/blog/1506-closing-issues-via-pull-requests ) 6 | * When you make very very minor changes to a PR of yours (like for example fixing a failing travis build or some small style corrections or minor changes requested by reviewers) make sure you squash your commits afterwards so that you don't have an absurd number of commits for a very small fix. (Learn how to squash at https://davidwalsh.name/squash-commits-git ) 7 | * When you're submitting a PR for a UI-related issue, it would be really awesome if you add a screenshot of your change or a link to a deployment where it can be tested out along with your PR. It makes it very easy for the reviewers and you'll also get reviews quicker. 8 | 9 | **Code Styleguide** 10 | * Do follow the .editorconfig file regarding maintaining of code style (It's mandatory). 11 | * For more information regarding .editorconfig file, see [editorconfig](http://editorconfig.org/#download) 12 | 13 | **Feature Requests and Bug Reports** 14 | * When you file a feature request or when you are submitting a bug report to the [issue tracker](https://github.com/fossasia/susper.com/issues), make sure you add steps to reproduce it. Especially if that bug is some weird/rare one. 15 | 16 | **Join the development** 17 | * Before you join development, please set up the project on your local machine, run it and go through the application completely. Press on any button you can find and see where it leads to. Explore. (Don't worry ... Nothing will happen to the app or to you due to the exploring :wink: Only thing that will happen is, you'll be more familiar with what is where and might even get some cool ideas on how to improve various aspects of the app.) 18 | * If you would like to work on an issue, drop in a comment at the issue. If it is already assigned to someone, but there is no sign of any work being done, please free to drop in a comment so that the issue can be assigned to you if the previous assignee has dropped it entirely. 19 | 20 | Do read the [Open Source Developer Guide and Best Practices at FOSSASIA](https://blog.fossasia.org/open-source-developer-guide-and-best-practices-at-fossasia). 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE: -------------------------------------------------------------------------------- 1 | **Actual Behaviour** 2 | 3 | 4 | 5 | **Expected Behaviour** 6 | 7 | 8 | 9 | **Steps to reproduce it** 10 | 11 | 12 | 13 | **Log for the issue** 14 | 15 | 16 | 17 | **Screenshots of the issue** 18 | 19 | 20 | 21 | **Would you like to work on the issue?** 22 | 23 | 24 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE: -------------------------------------------------------------------------------- 1 | 4 | 5 | #### Checklist 6 | 7 | - [ ] I have read the [Contribution & Best practices Guide](https://blog.fossasia.org/open-source-developer-guide-and-best-practices-at-fossasia). 8 | - [ ] My branch is up-to-date with the Upstream `development` branch. 9 | - [ ] I have added necessary documentation (if appropriate) 10 | 11 | #### Short description of what this resolves: 12 | 13 | 14 | #### Changes proposed in this pull request: 15 | 16 | - 17 | - 18 | - 19 | 20 | 21 | Fixes # 22 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "21:00" 8 | open-pull-requests-limit: 10 9 | ignore: 10 | - dependency-name: aws-sdk 11 | versions: 12 | - "> 2.639.0, < 3" 13 | - dependency-name: npm 14 | versions: 15 | - 7.10.0 16 | - 7.11.0 17 | - 7.5.2 18 | - 7.5.3 19 | - 7.5.4 20 | - 7.5.6 21 | - 7.6.0 22 | - 7.6.1 23 | - 7.6.2 24 | - 7.6.3 25 | - 7.7.0 26 | - 7.7.3 27 | - 7.7.4 28 | - 7.7.5 29 | - 7.7.6 30 | - 7.8.0 31 | - 7.9.0 32 | - dependency-name: gulp-esbuild 33 | versions: 34 | - 0.3.20 35 | - 0.3.22 36 | - 0.4.2 37 | - 0.4.3 38 | - 0.5.0 39 | - 0.5.1 40 | - 0.5.2 41 | - 0.5.3 42 | - 0.5.4 43 | - 0.5.5 44 | - 0.6.0 45 | - 0.6.1 46 | - 0.6.2 47 | - 0.6.3 48 | - 0.6.4 49 | - 0.7.0 50 | - 0.7.1 51 | - 0.7.2 52 | - 0.7.3 53 | - 0.7.4 54 | - dependency-name: redis 55 | versions: 56 | - 3.1.0 57 | - 3.1.1 58 | - dependency-name: socket.io 59 | versions: 60 | - 3.1.0 61 | - 3.1.1 62 | - 3.1.2 63 | - 4.0.0 64 | - 4.0.1 65 | - dependency-name: eslint 66 | versions: 67 | - 7.20.0 68 | - 7.21.0 69 | - 7.22.0 70 | - 7.23.0 71 | - 7.24.0 72 | - dependency-name: folder-hash 73 | versions: 74 | - 4.0.1 75 | - dependency-name: "@octokit/rest" 76 | versions: 77 | - 18.0.15 78 | - 18.1.0 79 | - 18.1.1 80 | - 18.2.0 81 | - 18.2.1 82 | - 18.3.1 83 | - 18.3.2 84 | - 18.3.4 85 | - 18.3.5 86 | - 18.4.0 87 | - 18.5.1 88 | - 18.5.2 89 | - dependency-name: chai 90 | versions: 91 | - 4.3.1 92 | - 4.3.3 93 | - 4.3.4 94 | - dependency-name: husky 95 | versions: 96 | - 4.3.8 97 | - 5.0.9 98 | - 5.1.1 99 | - 5.1.2 100 | - 5.1.3 101 | - 5.2.0 102 | - 6.0.0 103 | - dependency-name: archiver 104 | versions: 105 | - 5.3.0 106 | - dependency-name: sharp 107 | versions: 108 | - 0.27.2 109 | - 0.28.0 110 | - 0.28.1 111 | - dependency-name: nodemailer 112 | versions: 113 | - 6.4.18 114 | - dependency-name: ftp-deploy 115 | versions: 116 | - 2.4.1 117 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: Release v$NEXT_MINOR_VERSION 🌈 2 | tag-template: v$NEXT_MINOR_VERSION 3 | categories: 4 | - title: 🚀 Features 5 | label: feature 6 | - title: 🐛 Bug Fixes 7 | label: fix 8 | - title: 🧰 Maintenance 9 | label: chore 10 | - title: 🕮 Documentation 11 | label: docs 12 | - title: ⚙ Dependencies and Libraries 13 | label: dependencies 14 | change-template: '- $TITLE (#$NUMBER) - @$AUTHOR' 15 | template: | 16 | ## Changes 17 | 18 | $CHANGES 19 | 20 | ## Contributors 21 | 22 | Thanks a lot to our contributors for making this release possible: 23 | $CONTRIBUTORS 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # Dist folder 40 | /dist 41 | 42 | # IDEs 43 | .idea/ 44 | 45 | # Temp files 46 | /uploads 47 | /mockjson 48 | 49 | configmap.yml.secret 50 | 51 | .tool-versions 52 | .env 53 | .vscode 54 | 55 | package-lock.json 56 | -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | eslint: 2 | enabled: true 3 | config_file: .eslintrc 4 | scss: 5 | config_file: .scss-lint.yml -------------------------------------------------------------------------------- /.scss-lint.yml: -------------------------------------------------------------------------------- 1 | # Default application configuration that all configurations inherit from. 2 | 3 | scss_files: "**/*.scss" 4 | plugin_directories: ['.scss-linters'] 5 | 6 | # List of gem names to load custom linters from (make sure they are already 7 | # installed) 8 | plugin_gems: [] 9 | 10 | # Default severity of all linters. 11 | severity: warning 12 | 13 | linters: 14 | BangFormat: 15 | enabled: true 16 | space_before_bang: true 17 | space_after_bang: false 18 | 19 | BemDepth: 20 | enabled: false 21 | max_elements: 1 22 | 23 | BorderZero: 24 | enabled: true 25 | convention: zero # or `none` 26 | 27 | ChainedClasses: 28 | enabled: false 29 | 30 | ColorKeyword: 31 | enabled: true 32 | 33 | ColorVariable: 34 | enabled: true 35 | 36 | Comment: 37 | enabled: true 38 | style: silent 39 | 40 | DebugStatement: 41 | enabled: true 42 | 43 | DeclarationOrder: 44 | enabled: true 45 | 46 | DisableLinterReason: 47 | enabled: false 48 | 49 | DuplicateProperty: 50 | enabled: true 51 | 52 | ElsePlacement: 53 | enabled: true 54 | style: same_line # or 'new_line' 55 | 56 | EmptyLineBetweenBlocks: 57 | enabled: true 58 | ignore_single_line_blocks: true 59 | 60 | EmptyRule: 61 | enabled: true 62 | 63 | ExtendDirective: 64 | enabled: false 65 | 66 | FinalNewline: 67 | enabled: true 68 | present: true 69 | 70 | HexLength: 71 | enabled: false 72 | style: short # or 'long' 73 | 74 | HexNotation: 75 | enabled: true 76 | style: lowercase # or 'uppercase' 77 | 78 | HexValidation: 79 | enabled: true 80 | 81 | IdSelector: 82 | enabled: true 83 | 84 | ImportantRule: 85 | enabled: true 86 | 87 | ImportPath: 88 | enabled: true 89 | leading_underscore: false 90 | filename_extension: false 91 | 92 | Indentation: 93 | enabled: true 94 | allow_non_nested_indentation: false 95 | character: space # or 'tab' 96 | width: 2 97 | 98 | LeadingZero: 99 | enabled: true 100 | style: include_zero # or 'exclude_zero' 101 | 102 | MergeableSelector: 103 | enabled: true 104 | force_nesting: true 105 | 106 | NameFormat: 107 | enabled: true 108 | allow_leading_underscore: true 109 | convention: hyphenated_lowercase # or 'camel_case', or 'snake_case', or a regex pattern 110 | 111 | NestingDepth: 112 | enabled: true 113 | max_depth: 4 114 | ignore_parent_selectors: false 115 | 116 | PlaceholderInExtend: 117 | enabled: false 118 | 119 | PrivateNamingConvention: 120 | enabled: false 121 | prefix: _ 122 | 123 | PropertyCount: 124 | enabled: true 125 | include_nested: false 126 | max_properties: 10 127 | 128 | PropertySortOrder: 129 | enabled: true 130 | ignore_unspecified: false 131 | min_properties: 2 132 | separate_groups: false 133 | 134 | PropertySpelling: 135 | enabled: true 136 | extra_properties: [] 137 | disabled_properties: [] 138 | 139 | PropertyUnits: 140 | enabled: true 141 | global: [ 142 | 'ch', 'em', 'ex', 'rem', # Font-relative lengths 143 | 'cm', 'in', 'mm', 'pc', 'pt', 'px', 'q', # Absolute lengths 144 | 'vh', 'vw', 'vmin', 'vmax', # Viewport-percentage lengths 145 | 'deg', 'grad', 'rad', 'turn', # Angle 146 | 'ms', 's', # Duration 147 | 'Hz', 'kHz', # Frequency 148 | 'dpi', 'dpcm', 'dppx', # Resolution 149 | '%'] # Other 150 | properties: {} 151 | 152 | PseudoElement: 153 | enabled: true 154 | 155 | QualifyingElement: 156 | enabled: true 157 | allow_element_with_attribute: false 158 | allow_element_with_class: false 159 | allow_element_with_id: false 160 | 161 | SelectorDepth: 162 | enabled: true 163 | max_depth: 4 164 | 165 | SelectorFormat: 166 | enabled: true 167 | convention: hyphenated_lowercase # or 'strict_BEM', or 'hyphenated_BEM', or 'snake_case', or 'camel_case', or a regex pattern 168 | 169 | Shorthand: 170 | enabled: true 171 | allowed_shorthands: [1, 2, 3] 172 | 173 | SingleLinePerProperty: 174 | enabled: true 175 | allow_single_line_rule_sets: true 176 | 177 | SingleLinePerSelector: 178 | enabled: true 179 | 180 | SpaceAfterComma: 181 | enabled: true 182 | style: one_space # or 'no_space', or 'at_least_one_space' 183 | 184 | SpaceAfterPropertyColon: 185 | enabled: true 186 | style: one_space # or 'no_space', or 'at_least_one_space', or 'aligned' 187 | 188 | SpaceAfterPropertyName: 189 | enabled: true 190 | 191 | SpaceAfterVariableColon: 192 | enabled: false 193 | style: one_space # or 'no_space', 'at_least_one_space' or 'one_space_or_newline' 194 | 195 | SpaceAfterVariableName: 196 | enabled: true 197 | 198 | SpaceAroundOperator: 199 | enabled: true 200 | style: one_space # or 'at_least_one_space', or 'no_space' 201 | 202 | SpaceBeforeBrace: 203 | enabled: true 204 | style: space # or 'new_line' 205 | allow_single_line_padding: false 206 | 207 | SpaceBetweenParens: 208 | enabled: true 209 | spaces: 0 210 | 211 | StringQuotes: 212 | enabled: true 213 | style: double_quotes # or single_quotes 214 | 215 | TrailingSemicolon: 216 | enabled: true 217 | 218 | TrailingWhitespace: 219 | enabled: true 220 | 221 | TrailingZero: 222 | enabled: false 223 | 224 | TransitionAll: 225 | enabled: false 226 | 227 | UnnecessaryMantissa: 228 | enabled: true 229 | 230 | UnnecessaryParentReference: 231 | enabled: true 232 | 233 | UrlFormat: 234 | enabled: true 235 | 236 | UrlQuotes: 237 | enabled: true 238 | 239 | VariableForProperty: 240 | enabled: false 241 | properties: [] 242 | 243 | VendorPrefix: 244 | enabled: true 245 | identifier_list: base 246 | additional_identifiers: [] 247 | excluded_identifiers: [] 248 | 249 | ZeroUnit: 250 | enabled: true 251 | 252 | Compass::*: 253 | enabled: false -------------------------------------------------------------------------------- /.slugignore: -------------------------------------------------------------------------------- 1 | /dist 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: bionic 2 | language: node_js 3 | node_js: 4 | - 12 5 | 6 | services: 7 | - docker 8 | - redis 9 | - xvfb 10 | 11 | env: 12 | - TESTFOLDER=test/serverTest.js 13 | - TESTFOLDER=test/roomsAndSpeakers.js 14 | - TESTFOLDER=test/tracks.js 15 | - TESTFOLDER=test/generatorAndSchedule.js 16 | - TESTFOLDER=test/sessionEventAndCoC.js 17 | 18 | addons: 19 | chrome: stable 20 | apt: 21 | sources: 22 | - ubuntu-toolchain-r-test 23 | packages: 24 | - g++-4.8 25 | - chromium-chromedriver 26 | # installing required items for build 27 | install: 28 | - npm install -g yarn 29 | - yarn global add nyc mocha 30 | - yarn 31 | 32 | # testing script 33 | script: 34 | - nyc mocha --exit -- $TESTFOLDER 35 | 36 | # notify codecov and deploy to cloud 37 | after_success: 38 | if ([ "$TESTFOLDER" == "test/serverTest.js" ]); then 39 | bash <(curl -s https://codecov.io/bash); 40 | fi 41 | 42 | branches: 43 | only: 44 | - master 45 | - development 46 | -------------------------------------------------------------------------------- /.yaydoc.yml: -------------------------------------------------------------------------------- 1 | metadata: 2 | author: FOSSASIA 3 | projectname: Open Event Webapp 4 | version: development 5 | build: 6 | theme: sphinx_fossasia_theme 7 | source: docs 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:carbon 2 | 3 | # Create app directory 4 | RUN mkdir -p /usr/src/app 5 | WORKDIR /usr/src/app 6 | 7 | # Install app dependencies 8 | COPY package.json /usr/src/app/ 9 | RUN npm install 10 | 11 | # Bundle app source 12 | COPY . /usr/src/app 13 | 14 | EXPOSE 5000 15 | CMD [ "npm", "start" ] 16 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: npm start 2 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open-event-webapp", 3 | "scripts": { 4 | }, 5 | "env": { 6 | }, 7 | "formation": { 8 | "web": { 9 | "quantity": 1 10 | } 11 | }, 12 | "addons": [ 13 | 14 | ], 15 | "buildpacks": [ 16 | { 17 | "url": "heroku/nodejs" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /app.yaml: -------------------------------------------------------------------------------- 1 | runtime: custom 2 | env: flex 3 | 4 | -------------------------------------------------------------------------------- /build/config.gypi: -------------------------------------------------------------------------------- 1 | # Do not edit. File was generated by node-gyp's "configure" step 2 | { 3 | "target_defaults": { 4 | "cflags": [], 5 | "default_configuration": "Release", 6 | "defines": [], 7 | "include_dirs": [], 8 | "libraries": [] 9 | }, 10 | "variables": { 11 | "asan": 0, 12 | "coverage": "false", 13 | "debug_http2": "false", 14 | "debug_nghttp2": "false", 15 | "force_dynamic_crt": 0, 16 | "host_arch": "x64", 17 | "icu_data_in": "../../deps/icu-small/source/data/in/icudt60l.dat", 18 | "icu_endianness": "l", 19 | "icu_gyp_path": "tools/icu/icu-generic.gyp", 20 | "icu_locales": "en,root", 21 | "icu_path": "deps/icu-small", 22 | "icu_small": "true", 23 | "icu_ver_major": "60", 24 | "llvm_version": 0, 25 | "node_byteorder": "little", 26 | "node_enable_d8": "false", 27 | "node_enable_v8_vtunejit": "false", 28 | "node_install_npm": "true", 29 | "node_module_version": 59, 30 | "node_no_browser_globals": "false", 31 | "node_prefix": "/", 32 | "node_release_urlbase": "https://nodejs.org/download/release/", 33 | "node_shared": "false", 34 | "node_shared_cares": "false", 35 | "node_shared_http_parser": "false", 36 | "node_shared_libuv": "false", 37 | "node_shared_nghttp2": "false", 38 | "node_shared_openssl": "false", 39 | "node_shared_zlib": "false", 40 | "node_tag": "", 41 | "node_target_type": "executable", 42 | "node_use_bundled_v8": "true", 43 | "node_use_dtrace": "true", 44 | "node_use_etw": "false", 45 | "node_use_lttng": "false", 46 | "node_use_openssl": "true", 47 | "node_use_perfctr": "false", 48 | "node_use_v8_platform": "true", 49 | "node_without_node_options": "false", 50 | "openssl_fips": "", 51 | "openssl_no_asm": 0, 52 | "shlib_suffix": "59.dylib", 53 | "target_arch": "x64", 54 | "v8_enable_gdbjit": 0, 55 | "v8_enable_i18n_support": 1, 56 | "v8_enable_inspector": 1, 57 | "v8_no_strict_aliasing": 1, 58 | "v8_optimized_debug": 0, 59 | "v8_promise_internal_field_count": 1, 60 | "v8_random_seed": 0, 61 | "v8_trace_maps": 0, 62 | "v8_use_snapshot": "true", 63 | "want_separate_host_toolset": 0, 64 | "xcode_version": "7.0", 65 | "nodedir": "/Users/akroh/.node-gyp/9.5.0", 66 | "standalone_static_library": 1, 67 | "f": "true" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: yes 4 | 5 | coverage: 6 | precision: 2 7 | round: down 8 | range: "70...100" 9 | 10 | status: 11 | project: yes 12 | patch: yes 13 | changes: no 14 | 15 | parsers: 16 | gcov: 17 | branch_detection: 18 | conditional: yes 19 | loop: yes 20 | method: no 21 | macro: no 22 | 23 | comment: 24 | layout: "reach, diff, flags, files, footer" 25 | behavior: default 26 | require_changes: no 27 | 28 | ignore: 29 | - "src/selenium" 30 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "PORT": 3000, 3 | "DEFAULT_MAIL_STRATEGY": "Sendgrid", 4 | "DEFAULT_FROM_EMAIL": "info@eventyay.com", 5 | "SMTP_HOST": "mail.smtp2go.com", 6 | "SMTP_PORT": 2525, 7 | "SMTP_USERNAME": "xxxx", 8 | "SMTP_PASSWORD": "xxxx", 9 | "SENDGRID_API_KEY": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 10 | "speaker_images": { 11 | "MAX_WIDTH": 262.5, 12 | "MAX_HEIGHT": 262.5, 13 | "TRACK_WIDTH_REM": 5, 14 | "TRACK_HEIGHT_REM": 5 15 | }, 16 | "audio_files": { 17 | "MAX_SIZE_MB": 100 18 | }, 19 | "proxy": "", 20 | "CLOUD_STORAGE": "s3", 21 | "AWS_BUCKET": "fossasia-app", 22 | "AWS_ACCESS_KEY_ID": "XXXXXXXXXXXXXXXXXX", 23 | "AWS_SECRET_ACCESS_KEY": "XXXXXXXXXXXXXXXXXXX", 24 | "GITHUB_CLIENT_ID" : "XXXXXXXXXXXXXXXXXXX", 25 | "GITHUB_CLIENT_SECRET" : "XXXXXXXXXXXXXXXXXXXXXX", 26 | "SESSION_SECRET": "XXXXXXXXXXXXXXXXXX", 27 | "CALLBACK_URL": "http://localhost:5000/auth/callback" 28 | } 29 | -------------------------------------------------------------------------------- /docs/INSTALLATION.md: -------------------------------------------------------------------------------- 1 | # How to install the Open Event Web App Generator on web server 2 | 3 | _This is assuming setup on a Linux distro_ 4 | 5 | To deploy on a web server you need to have **node.js** (v6.x or above) installed. 6 | 7 | Please make sure you able to run the app using 8 | ```shell 9 | npm run server.generator 10 | ``` 11 | 12 | Next install **PM2** (a package manager for Node) 13 | ```shell 14 | sudo npm install -g pm2 15 | ``` 16 | 17 | 18 | Run the app using `pm start src/generator/app.js` 19 | 20 | To make the server automatically run on startup, use this command `pm2 startup systemd` 21 | 22 | For a detailed tutorial on how to set up Node.js Apps for production usage, check out https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-16-04 23 | -------------------------------------------------------------------------------- /docs/INSTALLATION_AWS.md: -------------------------------------------------------------------------------- 1 | # How to install the Open Event Web App Generator on AWS 2 | 3 | ## Phase 1 4 | 5 | This phase involves creating the EC2 instance which will hold your app. 6 | 7 | * Go to Amazon Web Services console and [select EC2](https://console.aws.amazon.com/ec2/). 8 | 9 | * Click on the create button to create an instance. Select Ubuntu 14 x64 as the linux distribution. 10 | 11 | * Follow the other steps till you reach the 6th step which is about *configuring Security groups*. There add a rule to accept all HTTP connections. See the screenshot on how 12 | it should look like. 13 | 14 | ![ec2_security_grp](https://cloud.githubusercontent.com/assets/4047597/17800591/25add494-6602-11e6-9667-437c1626e745.png) 15 | 16 | * Click Launch in the 7th step and you will be presented with a dialog to create a key. Create a new key and give it a name. In this tutorial, I will use the name 'mykey'. 17 | Then download the key. Keep it safe because if you lose it, you will lose access to the server. 18 | 19 | ![ec2_create_key](https://cloud.githubusercontent.com/assets/4047597/17800590/256db530-6602-11e6-9256-30a2e7463148.png) 20 | 21 | * Once the instance is created, you will be forwarded to the instances list. Select the newly created instance and click on Connect button. You will see a dialog with instructions on how to connect to it using ssh. 22 | 23 | ![connect_ssh_ec2](https://cloud.githubusercontent.com/assets/4047597/17800592/25e77262-6602-11e6-8acd-6bd352a30950.png) 24 | 25 | * In the above case, the command is as follows. So open the terminal in your Downloads directory (which has the downloaded key file) and then run the command you got from the 26 | previous step. In my case, it was - 27 | 28 | ```sh 29 | chmod 400 mykey.pem 30 | ssh -i "mykey.pem" ubuntu@ec2-52-41-207-116.us-west-2.compute.amazonaws.com 31 | ``` 32 | 33 | * You will be into the server's shell. You will notice a text message stating to install the language pack. So run the following command. 34 | 35 | ```sh 36 | sudo apt-get install language-pack-en 37 | ``` 38 | 39 | ## Phase 2 40 | Now we need to install the requirements needed to run it on the server. 41 | 42 | First, update and upgrade all packages to ensure we are up-to-date on everything 43 | 44 | ```shell 45 | sudo apt-get update 46 | sudo apt-get upgrade 47 | ``` 48 | 49 | Next we need to install Nodejs to our system. For this project, we recommend you use Nodejs v6.x 50 | 51 | ```shell 52 | curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - 53 | sudo apt-get install -y nodejs 54 | ``` 55 | 56 | Also, additionally, install build tools 57 | 58 | ```shell 59 | sudo apt-get install -y build-essential 60 | ``` 61 | 62 | 63 | ## Phase 3 64 | 65 | Now you should clone this repository to a folder 66 | 67 | ```shell 68 | git clone https://github.com/fossasia/open-event-webapp -b development 69 | ``` 70 | (Leave use branch master for stable release, development for latest source) 71 | 72 | After that we need to install the dependencies 73 | 74 | ```shell 75 | cd open-event-webapp 76 | npm install 77 | ``` 78 | 79 | Run the app 80 | 81 | ```shell 82 | npm run start 83 | ``` 84 | or 85 | ```shell 86 | npm run server.generator 87 | ``` 88 | 89 | The app will be running on http://localhost:5000 90 | 91 | If you want the app to run on port 80, use the following command instead 92 | ```shell 93 | sudo PORT=80 npm run start 94 | ``` 95 | 96 | ### Note 97 | You'd like to keep the server running persistently, without having to keep ssh connection open. For that case, 98 | 99 | Next install **PM2** (a package manager for Node) 100 | ```shell 101 | sudo npm install -g pm2 102 | ``` 103 | 104 | 105 | Run the app using `pm start npm -- start` 106 | 107 | To make the server automatically run on startup, use this command `pm2 startup systemd` 108 | 109 | For a detailed tutorial on how to set up Node.js Apps for production usage, checkout https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-16-04 -------------------------------------------------------------------------------- /docs/INSTALLATION_AWS_DOCKER.md: -------------------------------------------------------------------------------- 1 | # How to install the Open Event Web App Generator on AWS Docker 2 | 3 | ## Phase 1 4 | 5 | This phase involves creating the EC2 instance which will hold your app. 6 | 7 | * Go to Amazon Web Services console and [select EC2](https://console.aws.amazon.com/ec2/). 8 | 9 | * Click on the create button to create an instance. Select Ubuntu 14 x64 as the linux distribution. 10 | 11 | * Follow the other steps till you reach the 6th step which is about *configuring Security groups*. There add a rule to accept all HTTP connections. See the screenshot on how 12 | it should look like. 13 | 14 | ![ec2_security_grp](https://cloud.githubusercontent.com/assets/4047597/17800591/25add494-6602-11e6-9667-437c1626e745.png) 15 | 16 | * Click Launch in the 7th step and you will be presented with a dialog to create a key. Create a new key and give it a name. In this tutorial, I will use the name 'mykey'. 17 | Then download the key. Keep it safe because if you lose it, you will lose access to the server. 18 | 19 | ![ec2_create_key](https://cloud.githubusercontent.com/assets/4047597/17800590/256db530-6602-11e6-9256-30a2e7463148.png) 20 | 21 | * Once the instance is created, you will be forwarded to the instances list. Select the newly created instance and click on Connect button. You will see a dialog with instructions on how to connect to it using ssh. 22 | 23 | ![connect_ssh_ec2](https://cloud.githubusercontent.com/assets/4047597/17800592/25e77262-6602-11e6-8acd-6bd352a30950.png) 24 | 25 | * In the above case, the command is as follows. So open the terminal in your Downloads directory (which has the downloaded key file) and then run the command you got from the 26 | previous step. In my case, it was - 27 | 28 | ```sh 29 | chmod 400 mykey.pem 30 | ssh -i "mykey.pem" ubuntu@ec2-52-41-207-116.us-west-2.compute.amazonaws.com 31 | ``` 32 | 33 | * You will be into the server's shell. You will notice a text message stating to install the language pack. So run the following command. 34 | 35 | ```sh 36 | sudo apt-get install language-pack-en 37 | ``` 38 | 39 | ## Phase 2 40 | Now we need to install the requirements needed to run it on the server. 41 | 42 | First, update and upgrade all packages to ensure we are up-to-date on everything 43 | 44 | ```shell 45 | sudo apt-get update 46 | sudo apt-get upgrade 47 | ``` 48 | 49 | Next we need to install docker into our systerm 50 | 51 | ```shell 52 | sudo apt-get install docker.io 53 | ``` 54 | 55 | 56 | ## Phase 3 57 | 58 | Now you should clone this repository to a folder 59 | 60 | ```shell 61 | git clone https://github.com/fossasia/open-event-webapp -b development 62 | ``` 63 | (Leave use branch master for stable release, development for latest source) 64 | 65 | After cloning change the directory to the project root folder 66 | 67 | ```shell 68 | cd open-event-webapp 69 | ``` 70 | Now you can build the docker image by executing this command 71 | ```shell 72 | docker build -t /open-event-webapp . 73 | ``` 74 | Finally run the dockerized image 75 | 76 | ```shell 77 | docker run -p 80:5000 -d /open-event-webapp 78 | 79 | ``` 80 | -------------------------------------------------------------------------------- /docs/INSTALLATION_DIGITALOCEAN.md: -------------------------------------------------------------------------------- 1 | # How to install the Open Event Web App Generator on [DigitalOcean.com] 2 | 3 | This guide will show you how to deploy Open Event on Digital Ocean. The basic idea is installing Docker on Digital Ocean droplet and then running Open Event in it. 4 | 5 | #### Phase 1 6 | 7 | * Create a droplet with Ubuntu x64 as the image. At the time of writing this guide, Ubuntu 16.04.1 was used. 8 | 9 | * Choose a size with **atleast 1 GB RAM**. We found 512 MB RAM to be insufficient when running Open Event inside Docker. 10 | 11 | * Choose other options according to need and then 'Create' the droplet. 12 | 13 | * Once droplet has been created, you will get email from DigitalOcean with its information IP Address, username and password. 14 | 15 | ![droplet_email](https://cloud.githubusercontent.com/assets/4047597/17770515/e2ea6f4c-655b-11e6-9211-78257a083e82.png) 16 | 17 | * Open a terminal window and ssh into the server. The command is `ssh USERNAME@IP`. When run, it will ask for the password you got through email. Ctrl-Shift-V to paste the password and ENTER. An example has been given below. 18 | 19 | ```bash 20 | ssh root@104.236.228.132 21 | # Enter password you got in the email and enter 22 | ``` 23 | 24 | * If you are ssh'ing into your droplet for the first time, you will get a prompt to change password. The step is compulsary so change the password here. 25 | Once this step is done, you will be running the droplet's shell. 26 | 27 | ## Phase 2 28 | Now we need to install the requirements needed to run it on the server. 29 | 30 | First, update and upgrade all packages to ensure we are up-to-date on everything 31 | 32 | ```shell 33 | sudo apt-get update 34 | sudo apt-get upgrade 35 | ``` 36 | 37 | Next we need to install Nodejs to our system. For this project, we recommend you use Nodejs v6.x 38 | 39 | ```shell 40 | curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - 41 | sudo apt-get install -y nodejs 42 | ``` 43 | 44 | Also, additionally, install build tools 45 | 46 | ```shell 47 | sudo apt-get install -y build-essential 48 | ``` 49 | 50 | 51 | ## Phase 3 52 | 53 | Now you should clone this repository to a folder 54 | 55 | ```shell 56 | git clone https://github.com/fossasia/open-event-webapp -b development 57 | ``` 58 | (Leave use branch master for stable release, development for latest source) 59 | 60 | After that we need to install the dependencies 61 | 62 | ```shell 63 | cd open-event-webapp 64 | npm install 65 | ``` 66 | 67 | Run the app 68 | 69 | ```shell 70 | npm run start 71 | ``` 72 | or 73 | ```shell 74 | npm run server.generator 75 | ``` 76 | 77 | The app will be running on http://localhost:5000 78 | 79 | If you want the app to run on port 80, use the following command instead 80 | ```shell 81 | sudo PORT=80 npm run start 82 | ``` 83 | 84 | ### Note 85 | You'd like to keep the server running persistently, without having to keep ssh connection open. For that case, 86 | 87 | Next install **PM2** (a package manager for Node) 88 | ```shell 89 | sudo npm install -g pm2 90 | ``` 91 | 92 | 93 | Run the app using `pm start npm -- start` 94 | 95 | To make the server automatically run on startup, use this command `pm2 startup systemd` 96 | 97 | For a detailed tutorial on how to set up Node.js Apps for production usage, checkout https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-16-04 -------------------------------------------------------------------------------- /docs/INSTALLATION_DOCKER.md: -------------------------------------------------------------------------------- 1 | 2 | # Deploying Open Event Web App with Docker 3 | 4 | > Docker is much more efficient than VM in allocating shared resources between various containers as shown in figure. To deploy Open Event Web App we need to create docker container. There are two ways to build it. First way is fork the open-event-webapp project in github. Then you can signup in dockerhub and create autobuild docker container. The second way is to manually build docker file from command prompt of your computer. The following instructions needs to be executed in cloud shell or linux machine. 5 | 6 | ``` 7 | sudo apt-get update 8 | sudo apt-get upgrade 9 | sudo apt-get -y install docker.io 10 | sudo fallocate -l 4G /swapfile 11 | sudo chmod 600 /swapfile 12 | sudo mkswap /swapfile 13 | sudo swapon /swapfile 14 | sudo docker build https://github.com/fossasia/open-event-webapp.git 15 | ``` 16 | 17 | 18 | The first three commands install docker software to the machine. Next three lines give required permissions and execution abilities to docker. Final command builds docker container from github. Thus, We have successfully made docker container. We can deploy it on the cloud by using following command. 19 | 20 | ``` 21 | sudo docker run -d -p 80:80 -p 443:443 open-event-webapp 22 | ``` -------------------------------------------------------------------------------- /docs/INSTALLATION_GOOGLE.md: -------------------------------------------------------------------------------- 1 | # How to install the Open Event Web App Generator on Google Cloud 2 | > This documentation provides instructions to deploy the Open Event Web App on Google Cloud using the App Engine flexible environment. 3 | 4 | * **[ASCII Cast of Complete Process](https://asciinema.org/a/156500)** 5 | 6 | ## Step 1 7 | ##### Create a new project on Google Cloud Console 8 | To start, visit this website to begin your free trial period for Google Cloud: 9 | https://cloud.google.com/free-trial/ 10 | 11 | _Note: You will have to enter credit card details to prove you are not a robot, but you will not be charged without your permission._ 12 | 13 | After creating an account, go to the Google Cloud Console: https://console.cloud.google.com/ 14 | When you finish the tutorial of the basics of the Console, click on the dropdown in the navigation panel on top, and select 'Create Project'. 15 | 16 | Enter your project name. Make sure the name is meaningful. 17 | You will be provided with a Project ID. Keep a copy of the ID on your system. 18 | 19 | The URL of your deployed app will have the following strucutre: `https://[YOUR_PROJECT_ID].appspot.com` 20 | ## Step 2 21 | ##### Download and initialize the Google Cloud SDK 22 | Google Cloud SDK is a set of tools that you can use to manage resources and applications hosted on Google Cloud Platform. 23 | 24 | Visit this website to download the SDK package for your respective operating system: https://cloud.google.com/sdk/docs 25 | 26 | After downloading, unzip the package and move the folder to the desktop. 27 | Open the terminal, and navigate to the desktop using the `cd` command. 28 | 29 | Next, enter the following command in the terminal: 30 | ``` 31 | ./google-cloud-sdk/bin/gcloud init 32 | ``` 33 | The terminal will then ask for a series of numeric choices. Remember to choose your existing Google Cloud account, and selecting the Cloud project you created in Step 1 34 | 35 | Your Google Cloud SDK will now be configured and ready to use. 36 | 37 | 38 | ## Step 3 39 | ##### Cloning the repository from Github and deploying the app 40 | The next step is to clone the Open Event Web App repository into a folder. 41 | Navigate to the folder where you want to clone, and then enter the command: 42 | ```shell 43 | git clone https://github.com/fossasia/open-event-webapp 44 | ``` 45 | Enter the location of the Web App repository using the command: 46 | ``` 47 | cd open-event-webapp 48 | ``` 49 | Initialize the Cloud SDK 50 | ``` 51 | gcloud init 52 | ``` 53 | _Note: Make sure your repository contains an app.yaml file in the root directory. Your app cannot be deployed without an app.yaml file_ 54 | 55 | Now, enter the following Cloud SDK command to deploy the app: 56 | ``` 57 | gcloud app deploy 58 | ``` 59 | 60 | 61 | Your app will now start deploying to the URL: 62 | `https://[YOUR_PROJECT_ID].appspot.com` 63 | 64 | You will get a message asking if you want to continue with deploying. Type 'y' (yes) to proceed. 65 | 66 | It will take a few minutes for your app to finish deploying. When the deployment finishes, you will get the following two messages: 67 | ###### Updating service ... Done 68 | ###### Deployed service to [https://[YOUR_PROJECT_ID].appspot.com] 69 | 70 | You can view the application in your web browser using: 71 | ``` 72 | gcloud app browse 73 | ``` 74 | The application will now open in a new tab in your browser for you to view. 75 | 76 | **See the entire process step by step :** 77 | 78 | ![GIF](images/open-event-webapp.gif) 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/INSTALLATION_HEROKU.md: -------------------------------------------------------------------------------- 1 | # How to install the Open Event Web App Generator on Heroku 2 | To setup the open-event-webapp on heroku follow the following steps: 3 | 4 | ## Automatic Deploy 5 | You can use the one click deployment: 6 | 7 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/fossasia/open-event-webapp/tree/development) 8 | 9 | If however you live out-side the United States or Europe you may need to manually deploy Open-Event WebApp generator on Heroku as many face problems through this process. However give it a go. 10 | 11 | ## Manual Deploy 12 | 13 | You can also setup your app on heroku manually: 14 | 15 | ## Requirements: 16 | - **heroku toolbelt** installed on your system 17 | For more info on heroku toolbelt: [here](https://devcenter.heroku.com/articles/heroku-cli) 18 | - **git** installed on your system 19 | - If you are MacOS users, you will need to install home-brew: [here](https://brew.sh/) 20 | 21 | ## Installation with Heroku 22 | 23 | **Note**: Our app has an [app.json](../app.json), so it can be directly forked and setup on Heroku. 24 | 25 | 1) First fork and clone the open-event-webapp git repository 26 | 27 | ```sh 28 | $ git clone https://github.com/yourusername/open-event-webapp.git 29 | ``` 30 | **Note:** replace 'yourusername' with your github username 31 | 32 | 2) login into heroku toolbelt 33 | ```sh 34 | $ heroku login 35 | Enter your Heroku credentials. 36 | Email: adam@example.com 37 | Password (typing will be hidden): 38 | Authentication successful. 39 | ``` 40 | 41 | 3) Now change your working directory into open event webapp folder 42 | ```sh 43 | $ cd open-event-webapp/ 44 | ``` 45 | ![cd into the repository](screenshots/heroku_1.png) 46 | 47 | 4) do heroku create to create an heroku app 48 | ```sh 49 | $ heroku create 50 | Creating app... done, ⬢ your-heroku-app-name 51 | https://your-heroku-app-name.herokuapp.com/ | https://git.heroku.com/your-heroku-app-name.git 52 | ``` 53 | 54 | **Note:** replace 'your-heroku-app-name' with your heroku app name 55 | 56 | ![Create the app](images/heroku_2.png) 57 | 58 | 5) check if heroku's git url is added into the remote by git remote -v 59 | ```sh 60 | $ git remote -v 61 | heroku https://git.heroku.com/your-heroku-app-name.git (fetch) 62 | heroku https://git.heroku.com/your-heroku-app-name.git (push) 63 | origin https://github.com/yourusername/open-event-webapp.git (push) 64 | origin https://github.com/yourusername/open-event-webapp.git (push) 65 | ``` 66 | 67 | ![View remotes](images/heroku_3.png) 68 | 69 | 6) if it is not added automatically add the link to heroku's repository by typing following command in terminal 70 | ```sh 71 | $ git remote add heroku https://git.heroku.com/your-heroku-app-name.git 72 | ``` 73 | 74 | 7) Open Event Webapp uses Redis. Run the following to create a redis instance. 75 | ```sh 76 | $ heroku addons:create heroku-redis:hobby-dev 77 | ``` 78 | 79 | 8) now push the code from the development branch to heroku's master branch 80 | ```sh 81 | $ git push heroku development:master 82 | ``` 83 | 84 | ![Build](images/heroku_4.png) 85 | ![Build](images/heroku_5.png) 86 | ![Build](images/heroku_6.png) 87 | 88 | 9) confirm the webapp is running 89 | ```sh 90 | $ heroku logs --tail 91 | ``` 92 | 93 | 10) sometimes the server may take a while to start, the logs would say `State changed from starting to up` when the server is ready. 94 | 95 | 11) open the URL of your server in your browser 96 | ```sh 97 | $ heroku open 98 | ``` 99 | 100 | It will fire up your deployed app like this: 101 | ![App running](images/heroku_7.png) 102 | 103 | However, if the web app does not fire up, try one of the following solution to resolve the issue: 104 | 1. Open a new terminal and write: `$ heroku open` 105 | 2. Go to your heroku account on the web and deploy your app from there 106 | 107 | > Congrats you are done now! 108 | 109 | - Your app should be available at : https://your-heroku-app-name.herokuapp.com/ 110 | -------------------------------------------------------------------------------- /docs/INSTALLATION_LOCAL.md: -------------------------------------------------------------------------------- 1 | # How to install the Open Event Web App Generator on my local machine 2 | 3 | ## Deploying Locally 4 | 5 | First install the dependencies. 6 | 7 | ```shell 8 | npm install or npm install bcrypt 9 | npm install --save-dev 10 | ``` 11 | if you get an error, then fix npm permissions globally. Then restart from step 1. 12 | refer this:"https://docs.npmjs.com/getting-started/fixing-npm-permissions" 13 | 14 | Sometimes it may give an error of fetch failed 15 | then type 16 | 17 | ```shell 18 | npm config set registry http://registry.npmjs.org/ 19 | ``` 20 | 21 | and then restart the terminal and start from step 1 22 | 23 | Install and run Redis 24 | ```shell 25 | sudo apt-get install redis-server 26 | redis-server 27 | ``` 28 | 29 | Run the app 30 | 31 | ```shell 32 | npm run start 33 | ``` 34 | or 35 | ```shell 36 | npm run server.generator 37 | ``` 38 | 39 | The app will be running on http://localhost:3000 40 | 41 | Note : If you are running the app behind a proxy, set the proxy option in config.json to `http://username:password@proxy_url:proxy_port`, and make sure it is url encoded. 42 | 43 | ## Requirements 44 | 45 | | Component | Name/Flavour | Minimum Version | 46 | |---|---|---| 47 | | OS | Mac/Windows/Linux | Any | 48 | | Node.js | | v4.0 (or above) | 49 | | Browser | Firefox/Chrome/Safari | 21+/11+/9+ 50 | 51 | Note: Computers running on **Windows OS** may encounter problems when installing the Webapp Generator on local machines. As Windows does not come bundled with a C++ compiler, which is needed in NodeJS, the command prompt may throw up a error which states that `node-gyp rebuild` fails on your system. Hence it is advised a further prerequisite (for Windows users) is to download Visual Studio Community 2015 which contains a C++ compiler (link is https://www.visualstudio.com/downloads/). 52 | 53 | Note: If you are using **Windows OS** and getting errors like `gyp ERR! configure error` or `gyp ERR! stack Error: Can't find Python executable "python"` then you can now install all node-gyp dependencies with these commands: 54 | (Run As Admin in Windows PowerShell) 55 | 56 | ```shell 57 | npm install --global --production windows-build-tools 58 | ``` 59 | and then install the package 60 | ```shell 61 | npm install --global node-gyp 62 | ``` 63 | 64 | -------------------------------------------------------------------------------- /docs/images/generator_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/docs/images/generator_screenshot.png -------------------------------------------------------------------------------- /docs/images/heroku_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/docs/images/heroku_1.png -------------------------------------------------------------------------------- /docs/images/heroku_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/docs/images/heroku_2.png -------------------------------------------------------------------------------- /docs/images/heroku_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/docs/images/heroku_3.png -------------------------------------------------------------------------------- /docs/images/heroku_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/docs/images/heroku_4.png -------------------------------------------------------------------------------- /docs/images/heroku_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/docs/images/heroku_5.png -------------------------------------------------------------------------------- /docs/images/heroku_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/docs/images/heroku_6.png -------------------------------------------------------------------------------- /docs/images/heroku_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/docs/images/heroku_7.png -------------------------------------------------------------------------------- /docs/images/open-event-webapp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/docs/images/open-event-webapp.gif -------------------------------------------------------------------------------- /docs/images/project.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/docs/images/project.gif -------------------------------------------------------------------------------- /docs/images/wsgen_branding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/docs/images/wsgen_branding.png -------------------------------------------------------------------------------- /gh_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset 4 | 5 | if [ "$TRAVIS_BRANCH" != "development" ] 6 | then 7 | echo "This commit was made against the $TRAVIS_BRANCH and not the master! No deploy!" 8 | exit 0 9 | fi 10 | 11 | rev=$(git rev-parse --short HEAD) 12 | 13 | eval cd dist/a@a.com/ 14 | # Project maintainer information 15 | git init 16 | git config --global user.name "Travis CI" 17 | git config --global user.email "noreply+travis@fossasia.org" 18 | 19 | git remote add upstream "https://$gh_token@github.com/"${TRAVIS_REPO_SLUG}".git" 20 | git fetch upstream 21 | git reset upstream/gh-pages 22 | 23 | echo $GH_CNAME > CNAME 24 | 25 | touch . 26 | 27 | git add -A . 28 | git commit -m "rebuild pages at ${rev}" 29 | git push -q upstream HEAD:gh-pages 30 | 31 | -------------------------------------------------------------------------------- /kubernetes/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export DIR=${BASH_SOURCE%/*} 3 | 4 | if [ "$1" = "delete" ]; then 5 | echo "Clearing the cluster." 6 | kubectl delete -f ${DIR}/yamls/generator 7 | echo "Done. The project was removed from the cluster." 8 | elif [ "$1" = "create" ]; then 9 | echo "Deploying the project to kubernetes cluster" 10 | kubectl create -f ${DIR}/yamls/generator 11 | echo "Done. The project was deployed to kubernetes. :)" 12 | fi 13 | -------------------------------------------------------------------------------- /kubernetes/images/generator/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:boron 2 | MAINTAINER Niranjan Rajendran 3 | 4 | ARG COMMIT_HASH 5 | ARG BRANCH 6 | ARG REPOSITORY 7 | 8 | ENV COMMIT_HASH ${COMMIT_HASH:-null} 9 | ENV BRANCH ${BRANCH:-master} 10 | ENV REPOSITORY ${REPOSITORY:-https://github.com/fossasia/open-event-webapp.git} 11 | 12 | ENV INSTALL_PATH /opev 13 | 14 | RUN mkdir -p $INSTALL_PATH 15 | 16 | WORKDIR $INSTALL_PATH 17 | 18 | COPY . . 19 | 20 | RUN bash setup.sh 21 | 22 | WORKDIR $INSTALL_PATH/webapp_generator 23 | 24 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /kubernetes/images/generator/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | git clone ${REPOSITORY} webapp_generator 3 | cd webapp_generator 4 | git checkout ${BRANCH} 5 | 6 | if [ -v COMMIT_HASH ]; then 7 | git reset --hard ${COMMIT_HASH} 8 | fi 9 | 10 | npm install --no-shrinkwrap -------------------------------------------------------------------------------- /kubernetes/travis/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export DEPLOY_BRANCH=${DEPLOY_BRANCH:-master} 4 | 5 | if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_REPO_SLUG" != "fossasia/open-event-webapp" -o "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]; then 6 | echo "Skip production deployment for a very good reason." 7 | exit 0 8 | fi 9 | 10 | export REPOSITORY="https://github.com/${TRAVIS_REPO_SLUG}.git" 11 | 12 | sudo rm -f /usr/bin/git-credential-gcloud.sh 13 | sudo rm -f /usr/bin/bq 14 | sudo rm -f /usr/bin/gsutil 15 | sudo rm -f /usr/bin/gcloud 16 | rm -rf node_modules 17 | 18 | curl https://sdk.cloud.google.com | bash; 19 | source ~/.bashrc 20 | gcloud components install kubectl 21 | 22 | gcloud config set compute/zone us-west1-a 23 | # Decrypt the credentials we added to the repo using the key we added with the Travis command line tool 24 | openssl aes-256-cbc -K $encrypted_1a655549843e_key -iv $encrypted_1a655549843e_iv -in ./kubernetes/travis/eventyay-cf9d0dcc3261.json.enc -out eventyay-cf9d0dcc3261.json -d 25 | mkdir -p lib 26 | gcloud auth activate-service-account --key-file eventyay-cf9d0dcc3261.json 27 | export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/eventyay-cf9d0dcc3261.json 28 | gcloud config set project eventyay 29 | gcloud container clusters get-credentials nextgen-cluster 30 | cd kubernetes/images/generator 31 | docker build --build-arg COMMIT_HASH=$TRAVIS_COMMIT --build-arg BRANCH=$DEPLOY_BRANCH --build-arg REPOSITORY=$REPOSITORY --no-cache -t eventyay/webapp-generator:$TRAVIS_COMMIT . 32 | docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD" 33 | docker tag eventyay/webapp-generator:$TRAVIS_COMMIT eventyay/webapp-generator:latest 34 | docker push eventyay/webapp-generator 35 | kubectl set image deployment/webapp-generator --namespace=web webapp-generator=eventyay/webapp-generator:$TRAVIS_COMMIT 36 | rm -rf $GOOGLE_APPLICATION_CREDENTIALS -------------------------------------------------------------------------------- /kubernetes/travis/eventyay-cf9d0dcc3261.json.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/kubernetes/travis/eventyay-cf9d0dcc3261.json.enc -------------------------------------------------------------------------------- /kubernetes/yamls/generator/configmap.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | metadata: 3 | name: webapp-generator 4 | namespace: web 5 | data: 6 | DEFAULT_MAIL_STRATEGY: "SMTP" 7 | DEFAULT_FROM_EMAIL: "info@eventyay.com" 8 | SMTP_HOST: "mail.smtp2go.com" 9 | SMTP_PORT: "2525" 10 | SMTP_USERNAME: "xxxx" 11 | SMTP_PASSWORD: "xxxx" 12 | SENDGRID_API_KEY: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 13 | CLOUD_STORAGE: 'google_cloud' 14 | AWS_BUCKET: "FOSSASIA" 15 | AWS_ACCESS_KEY_ID: "XXXXXXXXXXXXXXXXX" 16 | AWS_SECRET_ACCESS_KEY: "XXXXXXXXXXXXXXXXX" 17 | GITHUB_CLIENT_ID: "XXXXXXXXXXXXXXXXX" 18 | GITHUB_CLIENT_SECRET: "XXXXXXXXXXXXXXXXX" 19 | SESSION_SECRET: "XXXXXXXXXXXXXXXXX" 20 | CALLBACK_URL: "https://webgen.eventyay.com/auth/callback" 21 | kind: ConfigMap -------------------------------------------------------------------------------- /kubernetes/yamls/generator/generator-deployment.yml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1beta1 3 | metadata: 4 | name: webapp-generator 5 | namespace: web 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: webapp-generator 12 | spec: 13 | containers: 14 | - name: webapp-generator 15 | image: eventyay/webapp-generator:latest 16 | livenessProbe: 17 | httpGet: 18 | path: / 19 | port: 5000 20 | initialDelaySeconds: 15 21 | timeoutSeconds: 1 22 | ports: 23 | - containerPort: 5000 24 | protocol: TCP 25 | envFrom: 26 | - configMapRef: 27 | name: webapp-generator 28 | restartPolicy: Always 29 | -------------------------------------------------------------------------------- /kubernetes/yamls/generator/generator-service.yml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: webapp-generator 5 | namespace: web 6 | spec: 7 | ports: 8 | - port: 5000 9 | protocol: TCP 10 | targetPort: 5000 11 | selector: 12 | app: webapp-generator 13 | -------------------------------------------------------------------------------- /kubernetes/yamls/generator/ingress-notls.yml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Ingress 3 | metadata: 4 | name: webapp-generator-notls 5 | namespace: web 6 | annotations: 7 | kubernetes.io/ingress.class: "nginx" 8 | spec: 9 | rules: 10 | - host: webgen.eventyay.com 11 | http: 12 | paths: 13 | - path: / 14 | backend: 15 | serviceName: webapp-generator 16 | servicePort: 5000 17 | -------------------------------------------------------------------------------- /kubernetes/yamls/generator/ingress-tls.yml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Ingress 3 | metadata: 4 | name: webapp-generator 5 | namespace: web 6 | annotations: 7 | kubernetes.io/tls-acme: "true" 8 | kubernetes.io/ingress.class: "nginx" 9 | spec: 10 | tls: 11 | - hosts: 12 | - webgen.eventyay.com 13 | secretName: eventyay-webgen-tls 14 | rules: 15 | - host: webgen.eventyay.com 16 | http: 17 | paths: 18 | - path: / 19 | backend: 20 | serviceName: webapp-generator 21 | servicePort: 5000 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open-event-webapp", 3 | "version": "3.0.0", 4 | "description": "Open Event Webapp", 5 | "engines": { 6 | "node": "12" 7 | }, 8 | "main": "index.js", 9 | "scripts": { 10 | "start": "node src/app.js", 11 | "test": "mocha", 12 | "coverage": "nyc mocha", 13 | "lint": "eslint ./src", 14 | "precommit": "eslint ./src" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/fossasia/open-event-webapp.git" 19 | }, 20 | "author": "FOSSASIA", 21 | "license": "GPL-3.0", 22 | "bugs": { 23 | "url": "https://github.com/fossasia/open-event-webapp/issues" 24 | }, 25 | "homepage": "https://github.com/fossasia/open-event-webapp#readme", 26 | "dependencies": { 27 | "@octokit/rest": "^14.0.0", 28 | "archiver": "^5.3.0", 29 | "async": "^3.2.0", 30 | "aws-sdk": "^2.639.0", 31 | "bee-queue": "^1.3.0", 32 | "bluebird": "^3.4.7", 33 | "body-parser": "^1.15.2", 34 | "chai": "^4.3.0", 35 | "compression": "^1.6.2", 36 | "connect-domain": "^0.5.0", 37 | "cookie-parser": "^1.4.5", 38 | "decompress-zip": "^0.3.3", 39 | "del": "^6.0.0", 40 | "dotenv": "^8.2.0", 41 | "express": "^4.13.4", 42 | "express-session": "^1.17.1", 43 | "folder-hash": "^4.0.0", 44 | "fs": "0.0.2", 45 | "fs-extra": "^9.1.0", 46 | "ftp-deploy": "^2.3.7", 47 | "gulp": "^4.0.2", 48 | "gulp-concat": "^2.6.1", 49 | "gulp-esbuild": "^0.4.5", 50 | "handlebars": "^4.7.7", 51 | "jsonapi-serializer": "^3.6.7", 52 | "jsonfile": "^6.1.0", 53 | "moment": "^2.27.0", 54 | "node-sass": "^4.14.0", 55 | "node-uuid": "^1.4.7", 56 | "nodemailer": "^6.6.3", 57 | "nodemailer-smtp-transport": "^2.7.2", 58 | "npm": "^6.14.11", 59 | "passport": "^0.4.1", 60 | "passport-github": "^1.1.0", 61 | "path": "^0.12.7", 62 | "progress-stream": "^2.0.0", 63 | "promise-ftp-common": "^1.1.5", 64 | "raven": "^2.6.4", 65 | "recursive-readdir": "^2.1.0", 66 | "redis": "^3.0.2", 67 | "request": "^2.74.0", 68 | "selenium-webdriver": "^3.4.0", 69 | "sendgrid": "^5.1.1", 70 | "sharp": "^0.27.0", 71 | "socket.io": "^4.1.3", 72 | "socket.io-stream": "^0.9.1", 73 | "socketio-file-upload": "^0.7.3", 74 | "stream-buffers": "^3.0.1", 75 | "url-join": "^4.0.1" 76 | }, 77 | "devDependencies": { 78 | "eslint": "^7.20.0", 79 | "husky": "^0.14.3" 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /sample_cli.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit -o nounset 4 | 5 | HSAMPLE_TIMEOUT="${HSAMPLE_TIMEOUT:-150s}" 6 | 7 | HSAMPLE_ENDPOINT="${HSAMPLE_ENDPOINT:-https://raw.githubusercontent.com/fossasia/open-event/master/sample/OTS16}" 8 | 9 | node cli.js heroku_dir $HSAMPLE_ENDPOINT & timeout $HSAMPLE_TIMEOUT npm run start; 10 | -------------------------------------------------------------------------------- /src/.eslintignore: -------------------------------------------------------------------------------- 1 | ./src/www/js/socket.io-stream.js 2 | /backend/assets/** 3 | *.min.js 4 | *.min.css 5 | -------------------------------------------------------------------------------- /src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 2017 4 | }, 5 | "env": { 6 | "es6": true, 7 | "node": true 8 | }, 9 | "rules": { 10 | "strict": [2, "global"], 11 | 12 | "init-declarations": 0, 13 | "no-catch-shadow": 0, 14 | "no-delete-var": 1, 15 | "no-label-var": 2, 16 | "no-shadow-restricted-names": 2, 17 | "no-shadow": [1, {"builtinGlobals": false, "hoist": "all"}], 18 | "no-undef-init": 1, 19 | "no-undef": 2, 20 | "no-undefined": 0, 21 | "no-unused-vars": 0, 22 | "no-use-before-define": 0, 23 | "no-console": 0, 24 | "comma-dangle": [2, "never"], 25 | "no-cond-assign": [2, "except-parens"], 26 | "no-constant-condition": 2, 27 | "no-control-regex": 2, 28 | "no-debugger": 2, 29 | "no-dupe-args": 2, 30 | "no-dupe-keys": 2, 31 | "no-duplicate-case": 2, 32 | "no-empty-character-class": 2, 33 | "no-empty": 2, 34 | "no-ex-assign": 2, 35 | "no-extra-boolean-cast": 2, 36 | "no-extra-parens": [2, "all"], 37 | "no-extra-semi": 1, 38 | "no-func-assign": 2, 39 | "no-invalid-regexp": 2, 40 | "no-irregular-whitespace": 2, 41 | "no-negated-in-lhs": 2, 42 | "no-obj-calls": 2, 43 | "no-regex-spaces": 2, 44 | "no-sparse-arrays": 2, 45 | "no-unreachable": 2, 46 | "use-isnan": 2, 47 | "valid-jsdoc": 0, 48 | "valid-typeof": 2, 49 | "no-unexpected-multiline": 2, 50 | 51 | "accessor-pairs": [2, {"getWithoutSet": false, "setWithoutGet": true}], 52 | "block-scoped-var": 2, 53 | "complexity": [1, 25], 54 | "consistent-return": 0, 55 | "curly": [2, "all"], 56 | "default-case": 1, 57 | "dot-notation": [2, {"allowKeywords": true, "allowPattern": ""}], 58 | "dot-location": [2, "property"], 59 | "eqeqeq": 2, 60 | "guard-for-in": 2, 61 | "no-alert": 1, 62 | "no-caller": 2, 63 | "no-div-regex": 2, 64 | "no-else-return": 2, 65 | "no-empty-label": 2, 66 | "no-eq-null": 2, 67 | "no-eval": 2, 68 | "no-extend-native": 0, 69 | "no-extra-bind": 2, 70 | "no-fallthrough": 1, 71 | "no-floating-decimal": 1, 72 | "no-implicit-coercion": [1, {"boolean": false, "number": true, "string": false}], 73 | "no-implied-eval": 2, 74 | "no-invalid-this": 0, 75 | "no-iterator": 2, 76 | "no-labels": 2, 77 | "no-lone-blocks": 2, 78 | "no-loop-func": 2, 79 | "no-multi-spaces": [2, {"exceptions": {"VariableDeclarator": true, "ImportDeclaration": true, "AssignmentExpression": true, "ObjectExpression": true}}], 80 | "no-multi-str": 2, 81 | "no-native-reassign": 2, 82 | "no-new-func": 2, 83 | "no-new-wrappers": 2, 84 | "no-new": 2, 85 | "no-octal-escape": 2, 86 | "no-octal": 2, 87 | "no-param-reassign": 1, 88 | "no-process-env": 0, 89 | "no-proto": 2, 90 | "no-redeclare": [2, {"builtinGlobals": true}], 91 | "no-return-assign": [2, "except-parens"], 92 | "no-script-url": 2, 93 | "no-self-compare": 2, 94 | "no-sequences": 2, 95 | "no-throw-literal": 2, 96 | "no-unused-expressions": 2, 97 | "no-useless-call": 1, 98 | "no-useless-concat": 1, 99 | "no-void": 2, 100 | "no-warning-comments": [1, {"terms": ["todo", "fixme"], "location": "start"}], 101 | "no-with": 2, 102 | "radix": 1, 103 | "vars-on-top": 2, 104 | "wrap-iife": [2, "inside"], 105 | "yoda": [1, "never"], 106 | 107 | "array-bracket-spacing": [1, "never"], 108 | "block-spacing": [1, "always"], 109 | "brace-style": [1, "1tbs", {"allowSingleLine": false}], 110 | "camelcase": 0, 111 | "comma-spacing": [1, {"before": false, "after": true}], 112 | "comma-style": [1, "last"], 113 | "computed-property-spacing": [1, "never"], 114 | "consistent-this": [1, "self"], 115 | "eol-last": 1, 116 | "func-names": 0, 117 | "func-style": 0, 118 | "id-length": 0, 119 | "id-match": 0, 120 | "indent": [1, 2, {"SwitchCase": 1, "VariableDeclarator": 2}], 121 | "jsx-quotes": [1, "prefer-double"], 122 | "key-spacing": [1, {"beforeColon": false, "afterColon": true, "mode": "minimum"}], 123 | "lines-around-comment": 0, 124 | "linebreak-style": 0, 125 | "max-nested-callbacks": [1, 6], 126 | "new-cap": [1, {"newIsCap": true, "capIsNew": true}], 127 | "new-parens": 1, 128 | "newline-after-var": [1, "always"], 129 | "no-array-constructor": 1, 130 | "no-continue": 1, 131 | "no-inline-comments": 0, 132 | "no-lonely-if": 1, 133 | "no-mixed-spaces-and-tabs": 1, 134 | "no-multiple-empty-lines": [1, {"max": 1}], 135 | "no-nested-ternary": 1, 136 | "no-new-object": 1, 137 | "no-restricted-syntax": 0, 138 | "no-spaced-func": 1, 139 | "no-ternary": 0, 140 | "no-trailing-spaces": [1, {"skipBlankLines": false}], 141 | "no-underscore-dangle": 0, 142 | "no-unneeded-ternary": [1, {"defaultAssignment": true}], 143 | "object-curly-spacing": [1, "never"], 144 | "one-var": [1, {"uninitialized": "always", "initialized": "never"}], 145 | "operator-assignment": 0, 146 | "operator-linebreak": [1, "after"], 147 | "padded-blocks": [1, "never"], 148 | "quote-props": [1, "as-needed", {"keywords": false, "unnecessary": false, "numbers": true}], 149 | "quotes": [1, "single", "avoid-escape"], 150 | "require-jsdoc": 0, 151 | "semi-spacing": [1, {"before": false, "after": true}], 152 | "semi": [1, "always"], 153 | "sort-vars": 0, 154 | "space-before-blocks": [1, "always"], 155 | "space-before-function-paren": [1, "never"], 156 | "space-in-parens": [1, "never"], 157 | "space-infix-ops": [1, {"int32Hint": false}], 158 | "space-unary-ops": [1, {"words": true, "nonwords": false}], 159 | "spaced-comment": [1, "always", {"exceptions": ["/"]}], 160 | "keyword-spacing": [2, {"before": true, "after": true}], 161 | "wrap-regex": 1, 162 | 163 | "arrow-spacing": [2, {"before": true, "after": true}], 164 | "constructor-super": 2, 165 | "generator-star-spacing": [2, {"before": false, "after": true}], 166 | "no-class-assign": 2, 167 | "no-const-assign": 2, 168 | "no-dupe-class-members": 0, 169 | "no-this-before-super": 2, 170 | "no-var": 2, 171 | "object-shorthand": 0, 172 | "prefer-arrow-callback": 0, 173 | "prefer-const": 1, 174 | "prefer-spread": 0, 175 | "prefer-reflect": 0, 176 | "prefer-template": 0, 177 | "require-yield": 2, 178 | 179 | "callback-return": 0, 180 | "global-require": 0, 181 | "handle-callback-err": 0, 182 | "no-mixed-requires": 0, 183 | "no-new-require": 0, 184 | "no-path-concat": 0, 185 | "no-process-exit": 0, 186 | "no-restricted-modules": 0, 187 | "no-sync": 0, 188 | 189 | "max-depth": 0, 190 | "max-len": 0, 191 | "max-params": 0, 192 | "max-statements": 0, 193 | "no-bitwise": 0, 194 | "no-plusplus": 0, 195 | "no-useless-escape": 0 196 | } 197 | 198 | } 199 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const express = require('express'); 5 | const cookie = require('cookie'); 6 | const compression = require('compression'); 7 | const path = require('path'); 8 | const cookieParser = require('cookie-parser'); 9 | const bodyParser = require('body-parser'); 10 | const generator = require('./backend/generator.js'); 11 | const deploy = require('./backend/deploy.js'); 12 | const config = require('../config.json'); 13 | const passport = require('passport'); 14 | const logger = require('./backend/buildlogger.js'); 15 | const Strategy = require('passport-github').Strategy; 16 | const session = require('express-session'); 17 | const MemoryStore = session.MemoryStore; 18 | const sessionStore = new MemoryStore(); 19 | const fs = require('fs'); 20 | const clientId = process.env.GITHUB_CLIENT_ID || config.GITHUB_CLIENT_ID; 21 | const clientSecret = process.env.GITHUB_CLIENT_SECRET || config.GITHUB_CLIENT_SECRET; 22 | const sessionSecret = process.env.SESSION_SECRET || config.SESSION_SECRET; 23 | const callbackUrl = process.env.CALLBACK_URL || config.CALLBACK_URL; 24 | const sentryUrl = process.env.SENTRY_DSN; 25 | const ss = require('socket.io-stream'); 26 | const Raven = require('raven'); 27 | const redisClient = require('redis').createClient(process.env.REDIS_URL); 28 | const Queue = require('bee-queue'); 29 | const queue = new Queue('generator-queue', {redis: redisClient}); 30 | const app = express(); 31 | // eslint-disable-next-line new-cap 32 | const server = require('http').Server(app); 33 | const io = require('socket.io')(server); 34 | let parsedCookie, sid, folder; 35 | let id = 0; 36 | let count = 0; 37 | let filename = ''; 38 | const emitter = null; 39 | const socketObj = {}; 40 | 41 | if (sentryUrl) { 42 | Raven.config(sentryUrl).install(); 43 | } 44 | 45 | app.use(compression()); 46 | app.use(require('cookie-parser')()); 47 | app.use(session({secret: sessionSecret, resave: true, saveUninitialized: true, store: sessionStore})); 48 | app.use(passport.initialize()); 49 | app.use(passport.session()); 50 | 51 | passport.use(new Strategy({ 52 | clientID: clientId, 53 | clientSecret: clientSecret, 54 | callbackURL: callbackUrl 55 | }, function(accessToken, refreshToken, profile, cb) { 56 | profile.token = accessToken; 57 | return cb(null, profile); 58 | })); 59 | 60 | passport.serializeUser(function(user, cb) { 61 | cb(null, user); 62 | }); 63 | 64 | passport.deserializeUser(function(obj, cb) { 65 | cb(null, obj); 66 | }); 67 | 68 | io.on('connection', function(socket) { 69 | socket.on('disconnect', function() { 70 | }); 71 | 72 | id = id + 1; 73 | socket.connId = id; 74 | 75 | ss(socket).on('file', function(stream, file) { 76 | generator.startZipUpload(count, socket); 77 | console.log(file); 78 | filename = path.join(__dirname, '..', 'uploads/connection-' + count.toString()) + '/upload.zip'; 79 | count += 1; 80 | stream.pipe(fs.createWriteStream(filename)); 81 | }); 82 | 83 | socket.on('finished', function(msg) { 84 | console.log(msg); 85 | }); 86 | 87 | socket.on('progress', function(percent) { 88 | console.log(percent + ' %'); 89 | }); 90 | 91 | socket.on('cancelled', function(msg) { 92 | console.log(msg); 93 | }); 94 | 95 | socket.on('live', function(formData) { 96 | const req = {body: formData}; 97 | const job = queue.createJob(req); 98 | 99 | job.on('succeeded', function() { 100 | console.log('completed job ' + job.id); 101 | }); 102 | 103 | job.save(async function(err, currentJob) { 104 | if (err) { 105 | console.log('job failed to save'); 106 | } 107 | const currJobId = currentJob.id; 108 | 109 | socketObj[currJobId] = socket; 110 | console.log('saved job ' + currJobId); 111 | const jobs = await queue.getJobs('waiting', {start: 0, end: 25}); 112 | const activeJob = await queue.getJobs('active', {start: 0, end: 25}); 113 | const jobIds = jobs.map((currJob) => currJob.id); 114 | 115 | if (jobIds.indexOf(currJobId) !== -1) { 116 | socket.emit('waiting'); 117 | logger.addLog('Info', 'Request waiting number: ' + (currJobId - activeJob[0].id), socket); 118 | } 119 | }); 120 | }); 121 | 122 | socket.on('upload', function(fileData) { 123 | generator.uploadJsonZip(fileData, socket); 124 | }); 125 | }); 126 | 127 | function getSocket(jobId) { 128 | let tries = 0; 129 | return new Promise((resolve, reject) => { 130 | const tryGettingSocket = () => { 131 | if (tries > 1) 132 | console.log('Trying to get socket for job', jobId, 'Attempt: ', tries); 133 | const socket = socketObj[jobId]; 134 | if (socket) { 135 | resolve(socket); 136 | } else { 137 | if (tries > 5) { 138 | reject(new Error('Socket not found in object after ' + tries + ' tries')); 139 | return; 140 | } 141 | 142 | tries++; 143 | setTimeout(tryGettingSocket, 2**tries); 144 | } 145 | } 146 | 147 | tryGettingSocket(); 148 | }); 149 | } 150 | 151 | queue.on('ready', function() { 152 | queue.process(function(job, done) { 153 | console.log('processing job ' + job.id); 154 | const processId = job.id; 155 | const jobs = new Promise(function(resolve) { 156 | resolve(queue.getJobs('waiting', {start: 0, end: 25})); 157 | }); 158 | 159 | getSocket(processId) 160 | .then(socket => { 161 | generator.createDistDir(job.data, socket, done); 162 | jobs.then(function(waitingJobs) { 163 | waitingJobs.forEach(function(waitingJob) { 164 | logger.addLog('Info', 'Request waiting number: ' + (waitingJob.id - job.id), socketObj[waitingJob.id]); 165 | }); 166 | }); 167 | }) 168 | .catch(error => { 169 | console.error(error); 170 | done(null); 171 | }); 172 | }); 173 | console.log('processing jobs...'); 174 | }); 175 | 176 | io.of('/deploy').on('connection', function(socket) { 177 | socket.on('start', function(msg) { 178 | console.log(msg); 179 | socket.abortDeploy = false; 180 | parsedCookie = cookie.parse(socket.request.headers.cookie); 181 | sid = cookieParser.signedCookie(parsedCookie['connect.sid'], sessionSecret); 182 | folder = cookieParser.signedCookie(parsedCookie.folder, sessionSecret); 183 | 184 | sessionStore.get(sid, function(err, currSession) { 185 | if (err) { 186 | console.log('error while getting session information'); 187 | console.log(err); 188 | } 189 | deploy(currSession.token, folder, currSession.owner, socket, function() { 190 | console.log('Deploy Process Finished'); 191 | }); 192 | }); 193 | }); 194 | 195 | socket.on('stop', function(msg) { 196 | console.log(msg); 197 | socket.abortDeploy = true; 198 | }); 199 | }); 200 | 201 | const errorHandler = function(err, req, res, next) { 202 | res.sendFile(__dirname + '/www/404.html'); 203 | next(); 204 | console.log(err); 205 | }; 206 | 207 | app.set('port', process.env.PORT || config.PORT); 208 | 209 | // Use the www folder as static frontend 210 | app.use('/', express.static(__dirname + '/www')); 211 | app.use('/live/preview', express.static(__dirname + '/../dist')); 212 | 213 | app.get('/download/:email/:appname', function(req, res) { 214 | generator.pipeZipToRes(req.params.email, req.params.appname, res); 215 | }).use(errorHandler); 216 | 217 | app.use(bodyParser.urlencoded({extended: false})); 218 | app.use(bodyParser.json()); 219 | 220 | app.post('/generate', function(req, res) { 221 | generator.createDistDir(req, res, function(appFolder, url) { 222 | console.log('App folder is ' + appFolder + ' and URL is ' + url); 223 | }); 224 | }); 225 | 226 | app.get('/auth', passport.authenticate('github', { 227 | scope: ['public_repo', 'delete_repo', 'read:org'] 228 | })); 229 | 230 | app.get('/auth/callback', 231 | passport.authenticate('github', {failureRedirect: '/auth', successRedirect: '/deploy'})); 232 | 233 | app.get('/deploy', function(req, res) { 234 | if (req.user === undefined) { 235 | res.redirect('/'); 236 | return; 237 | } 238 | req.session.token = req.user.token; 239 | req.session.owner = req.user.username; 240 | res.sendFile(__dirname + '/www/deploy.html'); 241 | }); 242 | 243 | app.use('*', function(req, res) { 244 | res.sendFile(__dirname + '/www/404.html'); 245 | }); 246 | 247 | server.listen(app.get('port'), function() { 248 | console.log('Node app is running on port', app.get('port')); 249 | }); 250 | 251 | module.exports = { 252 | getApp: function() { 253 | return app; 254 | }, 255 | getCount: function() { 256 | return count; 257 | } 258 | }; 259 | -------------------------------------------------------------------------------- /src/backend/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/.gitignore -------------------------------------------------------------------------------- /src/backend/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'github-pages', group: :jekyll_plugins 3 | -------------------------------------------------------------------------------- /src/backend/_scss/.gitignore: -------------------------------------------------------------------------------- 1 | # cache for sass 2 | .sass-cache -------------------------------------------------------------------------------- /src/backend/_scss/_base/_config.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | // Colors 4 | $black: #000; 5 | $white: #fff; 6 | $red: #e2061c; 7 | $gray-light: #c9c8c8; 8 | $gray: #838282; 9 | $gray-dark: #777; 10 | $white-gray: #eee; 11 | $gray-dim: #696969; 12 | $gray-extra-dark: #757575; 13 | $gray-extra-light: #e7e7e7 !default; 14 | $gray-perfect: #ddd; 15 | $gray-medium: #b5b5b5; 16 | $blue: #253652; 17 | $orange: #e12b00; 18 | $vivid-blue: #2196f3; 19 | $pure-orange: #ff8700; 20 | $light-purple: #ebccd1; 21 | $red-dark: #e52d27; 22 | $light-black: #333333; 23 | $light-skyblue: #b7cdff !default; 24 | $gray-trackshade: #999; 25 | $blue-shade: #2482d3; 26 | $dark-black: rgba(22, 22, 22, 0.99) !default; 27 | $black-main: #23293a !default; 28 | $timeroom-color: rgba(0, 0, 0, 0.10) !default; 29 | $session-color: $gray-trackshade !default; 30 | $header-color: #f8f8f8 !default; 31 | $main-background: #fff !default; 32 | $filter-heading: $gray-extra-dark !default; 33 | $background-shade: #f8f8fa !default; 34 | $event-border: #d2d6df; 35 | $overlayimage: rgba(258, 258, 258, 0.3); 36 | $border-event: rgba(0, 0, 0, 0.15); 37 | $border-venue: #e6e6e6; 38 | $navbar-color: #ffffff; 39 | $navbar-shadow: rgba(0, 0, 0, 0.125); 40 | $white-classic-background: #f5f5f5 !default; 41 | $black-text-shadow: rgba(0, 0, 0, 0.6); 42 | $card-box-shadow: rgba(0, 0, 0, 0.125); 43 | $event-box-shadow: rgba(0, 0, 0, 0.25); 44 | $tracks-border-left: rgba(0, 0, 0, 0.10) !default; 45 | $span-box-shadow: rgba(255, 255, 255, 0.37); 46 | $span-border-left: #c1c1c1; 47 | $dropdown-background-color: #e7e7e7; 48 | $span-background: #efefef !default; 49 | $grey: #777777; 50 | $gold: #fcd910; 51 | $red: #ce0518; 52 | $light-blue: #1c94e0; 53 | $link-color: $gray-dark !default; 54 | $hover-color: $black !default; 55 | $speaker-name: $black !default; 56 | 57 | // Corp-Colors 58 | $corp-color: $white !default; 59 | $corp-color-dark: darken($corp-color, 15%) !default; 60 | $corp-color-second: $red !default; 61 | $corp-color-second-dark: darken($corp-color-second, 15%) !default; 62 | 63 | // Font 64 | $base-font-size: 1.8 !default; 65 | $base-font-family: Helvetica, Arial, Sans-Serif !default; 66 | $base-font-color: $gray-dark !default; 67 | 68 | // Border 69 | $base-border-radius: 2px !default; 70 | $rounded-border-radius: 50% !default; 71 | $base-border-color: $gray !default; 72 | 73 | // Icon colours for social buttons 74 | $facebook-icon: #3b5998; 75 | $twitter-icon: #55acee; 76 | $google-icon: #dd4b39; 77 | $linkedin-icon: #3b5998; 78 | -------------------------------------------------------------------------------- /src/backend/_scss/_themes/_dark-theme/_dark.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @import "../../_base/config"; 3 | 4 | // 1.Overwrite stuff 5 | 6 | $corp-color: $dark-black; 7 | $corp-color-darken: darken($corp-color, 10%); 8 | $corp-color-second: $blue; 9 | $corp-color-second-dark: darken($corp-color-second, 10%); 10 | $base-font-size: 1.6; 11 | $base-font-family: Droid Sans, Georgia, Arial; 12 | $base-border-radius: 0; 13 | $base-border-color: $gray-light; 14 | $main-background: $black-main; 15 | $gray-darkshade: #dbcfbf; 16 | $gray-extra-light: #111111; 17 | $header-color: #333d5a; 18 | $timeroom-color: #f8f0e3; 19 | $light-skyblue: #a58ea2; 20 | $session-color: #f8f0e3; 21 | $filter-heading: #fff; 22 | $schedule-color: $white; 23 | $event-color: $white; 24 | $head-color: $white; 25 | $room-color: $white; 26 | // Currently used for the filter search box. Matches the filter button borders (currently #ccc from Bootstrap's .btn-default) 27 | $filter-input-border-color: #ccc; 28 | $date-button:$gray-perfect; 29 | $text-color: $white; 30 | $navbar-color: #2b324a; 31 | $navbar-text-color: $white; 32 | $background: #333d5a; 33 | $background-shade: #333d5a; 34 | $white-classic-background: #23294a; 35 | $link-color: $light-blue; 36 | $hover-color: $light-blue; 37 | $speaker-name: $white; 38 | $span-background: #333d5a; 39 | $tracks-border-left: #f5f5f5; 40 | 41 | @import "../../application"; 42 | -------------------------------------------------------------------------------- /src/backend/_scss/_themes/_light-theme/_light.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @import "../../_base/config"; 3 | 4 | // 1.Overwrite stuff 5 | 6 | $corp-color: $gray-light; 7 | $corp-color-darken: darken($corp-color, 10%); 8 | $corp-color-second: $blue; 9 | $corp-color-second-dark: darken($corp-color-second, 10%); 10 | $base-font-size: 1.6; 11 | $base-font-family: Droid Sans, Georgia, Arial; 12 | $main-background: light; 13 | $base-border-radius: 0; 14 | $base-border-color: $gray-light; 15 | $main-background: $white; 16 | $schedule-color: #black; 17 | $event-color: $gray-dark; 18 | $head-color:$light-black; 19 | $room-color:$black; 20 | // Currently used for the filter search box. Matches the filter button borders (currently #ccc from Bootstrap's .btn-default) 21 | $filter-input-border-color: #ccc; 22 | $date-button:$gray-extra-light; 23 | $text-color: $gray-dark; 24 | $navbar-text-color: $black; 25 | $background: $white; 26 | 27 | @import "../../application"; 28 | -------------------------------------------------------------------------------- /src/backend/assets/dependencies/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/assets/dependencies/.gitignore -------------------------------------------------------------------------------- /src/backend/assets/dependencies/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/assets/dependencies/avatar.png -------------------------------------------------------------------------------- /src/backend/assets/dependencies/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/assets/dependencies/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /src/backend/assets/dependencies/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/assets/dependencies/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /src/backend/assets/dependencies/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/assets/dependencies/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/backend/assets/dependencies/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/assets/dependencies/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/backend/assets/dependencies/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/assets/dependencies/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/backend/assets/dependencies/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/assets/dependencies/loader.gif -------------------------------------------------------------------------------- /src/backend/assets/dependencies/loklak-fetcher.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * loklak-fetcher-client 3 | * by Yago González (C) 2016 - Under MIT license 4 | * Bugs? Questions? Don't know what's the meaning of life? 5 | * Take a look at: github.com/YagoGG/loklak-fetcher-client 6 | * Please, keep this header if you want to use this code. Thank you ;) 7 | ******************************************************************************/ 8 | 9 | window.loklakFetcher = (function() { 10 | var script = null; 11 | 12 | var loklakFetcher = { 13 | /** 14 | * Fetches tweets from the public loklak API, with the options provided 15 | * @param {object} options Object with allowed GET-attributes, see 16 | * loklak.org/api.html 17 | * @param {function} callback Function called after getting the results. 18 | * These are passed as first argument 19 | */ 20 | getTweets: function(options, callback) { 21 | if(typeof options === 'function') { // A callback has been provided as 2nd 22 | // argument (no options) 23 | callback = options; 24 | options = {}; 25 | } else if(callback === undefined) { // No callback has been provided, even 26 | // as 2nd argument 27 | throw new Error('[LOKLAK-FETCHER] No callback provided'); 28 | } 29 | 30 | var settings = [ 'count', 'source', 'fields', 'limit', 'tzOffset', 31 | 'minified' ]; // Field names for all the possible parameters 32 | var defaults = [ 100, 'cache', '', '', 0, true ]; // Default values 33 | 34 | // Check if no options have been provided 35 | if(typeof options === 'undefined') { 36 | options = {}; // Create 'options' to avoid ReferenceErrors later 37 | } 38 | 39 | //Check if there are any data elements set 40 | var tweetsEl = document.getElementById("tweets"); 41 | var dataset = tweetsEl.dataset; 42 | if(dataset.count) { 43 | options[settings[0]] = dataset.count; //count is index 0 44 | } 45 | 46 | var query; 47 | 48 | if(dataset.query) { 49 | query = dataset.query.replace(/\s/gi, '%20').replace(/#/gi, '%23').replace('_',""); 50 | //replace spaces and hashtags in URL 51 | } else { 52 | //query = "fossasia"; 53 | } 54 | 55 | if(dataset.start) { 56 | query = query + "&since:" + dataset.start; 57 | } 58 | 59 | if(dataset.end) { 60 | query = query + "&until:" + dataset.end; 61 | } 62 | 63 | if(dataset.from) { 64 | query = "from:" + dataset.from; 65 | } 66 | 67 | // Write unset options as their default 68 | for(var index in settings) { 69 | if(options[settings[index]] === undefined) { 70 | options[settings[index]] = defaults[index]; 71 | } 72 | } 73 | 74 | // Create the URL with all the parameters 75 | var url = 'https://api.loklak.org/api/search.json' + 76 | '?callback=loklakFetcher.handleData' + 77 | '&q=' + query + 78 | '&count=' + options.count + 79 | '&source=' + options.source + 80 | '&fields=' + options.fields + 81 | '&limit=' + options.limit + 82 | '&timezoneOffset=' + options.tzOffset + 83 | '&minified=' + options.minified ; 84 | // If the script element for JSONP already exists, remove it 85 | 86 | if(script !== null) { 87 | document.head.removeChild(script); 88 | } 89 | 90 | /** 91 | * Invokes the callback function, passing the data from the server as the 92 | * first and only argument. 93 | * @param {object} data JSON coming from loklak's API 94 | */ 95 | this.handleData = function(data) { 96 | callback(data); 97 | }; 98 | 99 | // Create the script tag for JSONP 100 | script = document.createElement("script"); 101 | script.src = url; 102 | document.head.appendChild(script); 103 | } 104 | }; 105 | 106 | return loklakFetcher; 107 | }()); 108 | -------------------------------------------------------------------------------- /src/backend/assets/dependencies/manifest.json: -------------------------------------------------------------------------------- 1 | "icons": [ 2 | { 3 | "src": "./images/logo.png", 4 | "type": "image/png", 5 | "sizes": "48x48" 6 | }, 7 | { 8 | "src": "./images/logo.png", 9 | "type": "image/png", 10 | "sizes": "96x96" 11 | }, 12 | { 13 | "src": "./images/logo.png", 14 | "type": "image/png", 15 | "sizes": "144x144" 16 | }, 17 | { 18 | "src": "./images/logo.png", 19 | "type": "image/png", 20 | "sizes": "256x256" 21 | }, 22 | { 23 | "src": "./images/logo.png", 24 | "type": "image/png", 25 | "sizes": "512x512" 26 | } 27 | ], 28 | "start_url": "index.html", 29 | "scope": ".", 30 | "display": "standalone", 31 | "orientation": "portrait-primary", 32 | "background_color": "#fff", 33 | "theme_color": "#3f51b5", 34 | "description": "Open Event Web Application Generator", 35 | "dir": "ltr", 36 | "lang": "en-US" 37 | } 38 | -------------------------------------------------------------------------------- /src/backend/assets/dependencies/offline.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Page Title 5 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |

Oops!

21 |

Page not cached

22 |
23 | You seem to be offline. Sorry, this page has not been cached yet. Other pages might be available! 24 |
25 |
26 |
27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /src/backend/assets/dependencies/smooth-scroll.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Smooth Scroll - v1.4.10 - 2013-03-02 3 | * https://github.com/kswedberg/jquery-smooth-scroll 4 | * Copyright (c) 2013 Karl Swedberg 5 | * Licensed MIT (https://github.com/kswedberg/jquery-smooth-scroll/blob/master/LICENSE-MIT) 6 | */ 7 | !function(l){function t(l){return l.replace(/(:|\.)/g,"\\$1")}var e="1.4.10",o={exclude:[],excludeWithin:[],offset:0,direction:"top",scrollElement:null,scrollTarget:null,beforeScroll:function(){},afterScroll:function(){},easing:"swing",speed:400,autoCoefficent:2},r=function(t){var e=[],o=!1,r=t.dir&&"left"==t.dir?"scrollLeft":"scrollTop";return this.each(function(){if(this!=document&&this!=window){var t=l(this);t[r]()>0?e.push(this):(t[r](1),o=t[r]()>0,o&&e.push(this),t[r](0))}}),e.length||this.each(function(){"BODY"===this.nodeName&&(e=[this])}),"first"===t.el&&e.length>1&&(e=[e[0]]),e};l.fn.extend({scrollable:function(l){var t=r.call(this,{dir:l});return this.pushStack(t)},firstScrollable:function(l){var t=r.call(this,{el:"first",dir:l});return this.pushStack(t)},smoothScroll:function(e){e=e||{};var o=l.extend({},l.fn.smoothScroll.defaults,e),r=l.smoothScroll.filterPath(location.pathname);return this.unbind("click.smoothscroll").bind("click.smoothscroll",function(e){var n=this,s=l(this),c=o.exclude,i=o.excludeWithin,a=0,f=0,h=!0,u={},d=location.hostname===n.hostname||!n.hostname,m=o.scrollTarget||(l.smoothScroll.filterPath(n.pathname)||r)===r,p=t(n.hash);if(o.scrollTarget||d&&m&&p){for(;h&&c.length>a;)s.is(t(c[a++]))&&(h=!1);for(;h&&i.length>f;)s.closest(i[f++]).length&&(h=!1)}else h=!1;h&&(e.preventDefault(),l.extend(u,o,{scrollTarget:o.scrollTarget||p,link:n}),l.smoothScroll(u))}),this}}),l.smoothScroll=function(t,e){var o,r,n,s,c=0,i="offset",a="scrollTop",f={},h={};"number"==typeof t?(o=l.fn.smoothScroll.defaults,n=t):(o=l.extend({},l.fn.smoothScroll.defaults,t||{}),o.scrollElement&&(i="position","static"==o.scrollElement.css("position")&&o.scrollElement.css("position","relative"))),o=l.extend({link:null},o),a="left"==o.direction?"scrollLeft":a,o.scrollElement?(r=o.scrollElement,c=r[a]()):r=l("html, body").firstScrollable(),o.beforeScroll.call(r,o),n="number"==typeof t?t:e||l(o.scrollTarget)[i]()&&l(o.scrollTarget)[i]()[o.direction]||0,f[a]=n+c+o.offset,s=o.speed,"auto"===s&&(s=f[a]||r.scrollTop(),s/=o.autoCoefficent),h={duration:s,easing:o.easing,complete:function(){o.afterScroll.call(o.link,o)}},o.step&&(h.step=o.step),r.length?r.stop().animate(f,h):o.afterScroll.call(o.link,o)},l.smoothScroll.version=e,l.smoothScroll.filterPath=function(l){return l.replace(/^\//,"").replace(/(index|default).[a-zA-Z]{3,4}$/,"").replace(/\/$/,"")},l.fn.smoothScroll.defaults=o}(jQuery); -------------------------------------------------------------------------------- /src/backend/assets/dependencies/timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/assets/dependencies/timeline.png -------------------------------------------------------------------------------- /src/backend/assets/dependencies/tweets.js: -------------------------------------------------------------------------------- 1 | var interval_id = null; 2 | var tweetP = document.getElementById('tweet'); 3 | var dateOfTweet = document.getElementById("dateTweeted"); 4 | var stuff = null; 5 | 6 | function interval() { 7 | if (interval_id !== null){ 8 | clearInterval(interval_id); 9 | interval_id = window.setInterval(nextTweet, 6600); //6.6 secs 10 | } else{ 11 | interval_id = window.setInterval(nextTweet, 6600); //6.6 secs 12 | } 13 | } 14 | 15 | var datafetcher = function () { 16 | if(tweetP === null) { 17 | return; 18 | } 19 | 20 | loklakFetcher.getTweets({}, datahandler); 21 | }; 22 | 23 | function datahandler(raw) { 24 | stuff = raw; // Makes the data available globally. 25 | parser(stuff); 26 | interval(); 27 | } 28 | 29 | var tweetNum = 0; 30 | 31 | function parseFunc(){ 32 | parser(stuff); 33 | } 34 | 35 | function nextTweet() { 36 | tweetNum += 1; 37 | var tweetsEl = document.getElementById('tweets'); 38 | //go back to the first tweet if it's greater than the amount of tweets available 39 | 40 | if(tweetNum == stuff.statuses.length) { 41 | tweetNum = 0; 42 | } 43 | interval(); 44 | tweetP.style.opacity = 0; 45 | dateOfTweet.style.opacity = 0; 46 | window.setTimeout(parseFunc, 560); 47 | } 48 | 49 | function lastTweet() { 50 | if (tweetNum > 0) { 51 | tweetNum -= 1; 52 | interval(); 53 | tweetP.style.opacity = 0; 54 | dateOfTweet.style.opacity = 0; 55 | window.setTimeout(parseFunc, 560); 56 | } 57 | } 58 | 59 | function timeSince(date) { 60 | 61 | var seconds = Math.floor((new Date() - date) / 1000); 62 | 63 | var interval = Math.floor(seconds / 31536000); 64 | 65 | if (interval > 1) { 66 | return interval + " years"; 67 | } 68 | interval = Math.floor(seconds / 2592000); 69 | if (interval > 1) { 70 | return interval + " months"; 71 | } 72 | interval = Math.floor(seconds / 86400); 73 | if (interval > 1) { 74 | return interval + " days"; 75 | } 76 | interval = Math.floor(seconds / 3600); 77 | if (interval > 1) { 78 | return interval + " hours"; 79 | } 80 | interval = Math.floor(seconds / 60); 81 | if (interval > 1) { 82 | return interval + " minutes"; 83 | } 84 | return Math.floor(seconds) + " seconds"; 85 | } 86 | 87 | function parser(data) { 88 | try{ 89 | var parsed = ""; 90 | var tweet = data.statuses[tweetNum].text; 91 | var words = tweet.split(" "); 92 | var loklakLinkCount = 0; 93 | for (var word in words) { 94 | if (words[word].startsWith("@")) { 95 | parsed += "" + words[word] + " "; 96 | } else if (words[word].startsWith("#")) { 97 | parsed += "" + words[word] + " "; 98 | } else if (words[word].startsWith("http")) { 99 | if (words[word].startsWith("http://loklak")) { 100 | parsed += "" + data.statuses[tweetNum].links[loklakLinkCount] + " "; 101 | loklakLinkCount += 1; 102 | } else { 103 | parsed += "" + words[word] + " "; 104 | } 105 | } else { 106 | parsed += words[word] + " "; 107 | } 108 | } 109 | tweetP.innerHTML = parsed; 110 | var user = data.statuses[tweetNum].user; 111 | var tweetDate = new Date(data.statuses[tweetNum].created_at); 112 | dateOfTweet.innerHTML = "Tweeted " + timeSince(tweetDate) + " ago"; 113 | tweetP.style.opacity = 1; 114 | dateOfTweet.style.opacity = 1; 115 | //document.getElementById("tweet-info").innerHTML = "Follow " + ""; 116 | }catch(err){ 117 | tweetP.innerHTML = "No Tweets Available"; 118 | tweetP.style.opacity = 1; 119 | } 120 | } 121 | 122 | window.datafetcher = datafetcher; 123 | -------------------------------------------------------------------------------- /src/backend/assets/js/FileSaver.js: -------------------------------------------------------------------------------- 1 | /* FileSaver.js 2 | * A saveAs() FileSaver implementation. 3 | * 1.3.2 4 | * 2016-06-16 18:25:19 5 | * 6 | * By Eli Grey, http://eligrey.com 7 | * License: MIT 8 | * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md 9 | */ 10 | 11 | /*global self */ 12 | /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ 13 | 14 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 15 | 16 | var saveAs = saveAs || (function(view) { 17 | "use strict"; 18 | // IE <10 is explicitly unsupported 19 | if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { 20 | return; 21 | } 22 | var 23 | doc = view.document 24 | // only get URL when necessary in case Blob.js hasn't overridden it yet 25 | , get_URL = function() { 26 | return view.URL || view.webkitURL || view; 27 | } 28 | , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") 29 | , can_use_save_link = "download" in save_link 30 | , click = function(node) { 31 | var event = new MouseEvent("click"); 32 | node.dispatchEvent(event); 33 | } 34 | , is_safari = /constructor/i.test(view.HTMLElement) || view.safari 35 | , is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent) 36 | , throw_outside = function(ex) { 37 | (view.setImmediate || view.setTimeout)(function() { 38 | throw ex; 39 | }, 0); 40 | } 41 | , force_saveable_type = "application/octet-stream" 42 | // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to 43 | , arbitrary_revoke_timeout = 1000 * 40 // in ms 44 | , revoke = function(file) { 45 | var revoker = function() { 46 | if (typeof file === "string") { // file is an object URL 47 | get_URL().revokeObjectURL(file); 48 | } else { // file is a File 49 | file.remove(); 50 | } 51 | }; 52 | setTimeout(revoker, arbitrary_revoke_timeout); 53 | } 54 | , dispatch = function(filesaver, event_types, event) { 55 | event_types = [].concat(event_types); 56 | var i = event_types.length; 57 | while (i--) { 58 | var listener = filesaver["on" + event_types[i]]; 59 | if (typeof listener === "function") { 60 | try { 61 | listener.call(filesaver, event || filesaver); 62 | } catch (ex) { 63 | throw_outside(ex); 64 | } 65 | } 66 | } 67 | } 68 | , auto_bom = function(blob) { 69 | // prepend BOM for UTF-8 XML and text/* types (including HTML) 70 | // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF 71 | if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { 72 | return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type}); 73 | } 74 | return blob; 75 | } 76 | , FileSaver = function(blob, name, no_auto_bom) { 77 | if (!no_auto_bom) { 78 | blob = auto_bom(blob); 79 | } 80 | // First try a.download, then web filesystem, then object URLs 81 | var 82 | filesaver = this 83 | , type = blob.type 84 | , force = type === force_saveable_type 85 | , object_url 86 | , dispatch_all = function() { 87 | dispatch(filesaver, "writestart progress write writeend".split(" ")); 88 | } 89 | // on any filesys errors revert to saving with object URLs 90 | , fs_error = function() { 91 | if ((is_chrome_ios || (force && is_safari)) && view.FileReader) { 92 | // Safari doesn't allow downloading of blob urls 93 | var reader = new FileReader(); 94 | reader.onloadend = function() { 95 | var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;'); 96 | var popup = view.open(url, '_blank'); 97 | if(!popup) view.location.href = url; 98 | url=undefined; // release reference before dispatching 99 | filesaver.readyState = filesaver.DONE; 100 | dispatch_all(); 101 | }; 102 | reader.readAsDataURL(blob); 103 | filesaver.readyState = filesaver.INIT; 104 | return; 105 | } 106 | // don't create more object URLs than needed 107 | if (!object_url) { 108 | object_url = get_URL().createObjectURL(blob); 109 | } 110 | if (force) { 111 | view.location.href = object_url; 112 | } else { 113 | var opened = view.open(object_url, "_blank"); 114 | if (!opened) { 115 | // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html 116 | view.location.href = object_url; 117 | } 118 | } 119 | filesaver.readyState = filesaver.DONE; 120 | dispatch_all(); 121 | revoke(object_url); 122 | } 123 | ; 124 | filesaver.readyState = filesaver.INIT; 125 | 126 | if (can_use_save_link) { 127 | object_url = get_URL().createObjectURL(blob); 128 | setTimeout(function() { 129 | save_link.href = object_url; 130 | save_link.download = name; 131 | click(save_link); 132 | dispatch_all(); 133 | revoke(object_url); 134 | filesaver.readyState = filesaver.DONE; 135 | }); 136 | return; 137 | } 138 | 139 | fs_error(); 140 | } 141 | , FS_proto = FileSaver.prototype 142 | , saveAs = function(blob, name, no_auto_bom) { 143 | return new FileSaver(blob, name || blob.name || "download", no_auto_bom); 144 | } 145 | ; 146 | // IE 10+ (native saveAs) 147 | if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { 148 | return function(blob, name, no_auto_bom) { 149 | name = name || blob.name || "download"; 150 | 151 | if (!no_auto_bom) { 152 | blob = auto_bom(blob); 153 | } 154 | return navigator.msSaveOrOpenBlob(blob, name); 155 | }; 156 | } 157 | 158 | FS_proto.abort = function(){}; 159 | FS_proto.readyState = FS_proto.INIT = 0; 160 | FS_proto.WRITING = 1; 161 | FS_proto.DONE = 2; 162 | 163 | FS_proto.error = 164 | FS_proto.onwritestart = 165 | FS_proto.onprogress = 166 | FS_proto.onwrite = 167 | FS_proto.onabort = 168 | FS_proto.onerror = 169 | FS_proto.onwriteend = 170 | null; 171 | 172 | return saveAs; 173 | }( 174 | typeof self !== "undefined" && self 175 | || typeof window !== "undefined" && window 176 | || this.content 177 | )); 178 | // `self` is undefined in Firefox for Android content script context 179 | // while `this` is nsIContentFrameMessageManager 180 | // with an attribute `content` that corresponds to the window 181 | 182 | if (typeof module !== "undefined" && module.exports) { 183 | module.exports.saveAs = saveAs; 184 | } else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) { 185 | define("FileSaver.js", function() { 186 | return saveAs; 187 | }); 188 | } 189 | 190 | window.saveAs = saveAs 191 | -------------------------------------------------------------------------------- /src/backend/assets/js/icsGen.js: -------------------------------------------------------------------------------- 1 | // (Non-JSDoc3 data): 2 | // icsGen, a generator for .ics files written in javascript with an optional php backend. 3 | // Edited by GameplayJDK (https://github.com/GameplayJDK); Repository can be found at https://github.com/GameplayJDK/icsGen. 4 | // Please report bugs or feature requests to https://github.com/GameplayJDK/icsGen/issues. 5 | // Forked from icsFormatter (https://github.com/matthiasanderer/icsFormatter) which was originally forked from ics.js (https://github.com/nwcell/ics.js). 6 | 7 | /** 8 | * icsGen, a generator for .ics files written in javascript with an optional php backend. 9 | * @see {@link https://github.com/GameplayJDK/icsGen/blob/master/README.md README.md} for a detailed description. 10 | * @file Holds the icsGen source code 11 | * @author GameplayJDK 12 | * @version 1.0 13 | * @todo (GameplayJDK): Add support for more stuff from the .ics spec? 14 | */ 15 | var icsGen = function () { 16 | 'use strict'; 17 | 18 | // IE is supported if the php backend is used, other wise, you should uncomment the 4 lines below: 19 | //if (navigator.userAgent.indexOf('MSIE') > -1 && navigator.userAgent.indexOf('MSIE 10') === -1) { 20 | // window.console.log('Unsupported Browser'); 21 | // return; 22 | //} 23 | 24 | /** 25 | * Generates a unique identifier (UID) 26 | * @return {string} UID 27 | */ 28 | var UID = function (length) { 29 | var chars = "abcdefghijklmnopqrstuvwxyz0123456789_", 30 | inString = "icsGen".toLowerCase(), 31 | outString = "", 32 | i; 33 | while (inString.length < length) { 34 | inString += inString; 35 | } 36 | for (i = 0; i < length; i += 1) { 37 | outString += chars.charAt(chars.indexOf(inString.charAt(i))); 38 | } 39 | return (outString); 40 | }, 41 | SEPARATOR = (navigator.appVersion.indexOf('Win') !== -1) ? '\r\n' : '\n', 42 | events = [], 43 | calendarEvents = [], 44 | calendarStart = [ 45 | 'BEGIN:VCALENDAR', 46 | 'VERSION:2.0' 47 | ].join(SEPARATOR), 48 | /** 49 | * @todo (GameplayJDK): Add support for timezones 50 | */ 51 | calendarTimezone = [ 52 | ], 53 | calendarEnd = 'END:VCALENDAR'; 54 | 55 | return { 56 | /** 57 | * Returns raw events array (raw) 58 | * @return {array} Raw events 59 | */ 60 | 'eventsRaw': function () { 61 | return calendarEvents; 62 | }, 63 | 64 | /** 65 | * Returns events array (object) 66 | * @return {array} Events 67 | */ 68 | 'events': function () { 69 | return events; 70 | }, 71 | 72 | 73 | /** 74 | * Returns calendar 75 | * @return {string} Calendar in iCalendar format 76 | */ 77 | 'calendar': function () { 78 | return [calendarStart, calendarTimezone, calendarEvents.join(SEPARATOR), calendarEnd].join(SEPARATOR); 79 | }, 80 | 81 | 'addEvent': function (session) { 82 | var calendarEvent = [ 83 | 'BEGIN:VEVENT', 84 | 'UID:' + session.uid, 85 | 'CLASS:PUBLIC', 86 | 'DESCRIPTION:' + session.description, 87 | 'DTSTART;VALUE=DATETIME:' + session.begin, 88 | 'DTEND;VALUE=DATE:' + session.stop, 89 | 'LOCATION:' + session.location, 90 | 'SUMMARY;LANGUAGE=en-us:' + session.subject, 91 | 'TRANSP:TRANSPARENT', 92 | 'END:VEVENT' 93 | ].join(SEPARATOR); 94 | 95 | var event = { 96 | "uid": session.uid, 97 | "description": session.description, 98 | "start": session.start, 99 | "end": session.end, 100 | "location": session.location, 101 | "subject": session.subject 102 | }; 103 | 104 | events.push(event); 105 | calendarEvents.push(calendarEvent); 106 | return calendarEvent; 107 | }, 108 | 109 | /** 110 | * Download calendar using dlh.php 111 | * @param {string} [filename=calendar] Filename 112 | * @param {string} [ext=js] Extention 113 | * @param {string} [dlh=./dlh.php] Path to the dlh.php file 114 | */ 115 | 'download': function (filename, ext, dlh) { 116 | if (calendarEvents.length < 1) { 117 | return false; 118 | } 119 | 120 | filename = (typeof filename !== 'undefined') ? filename : 'calendar'; 121 | ext = (typeof ext !== 'undefined') ? ext : '.ics'; 122 | dlh = (typeof dlh !== 'undefined') ? dlh : './dlh.php'; 123 | var calendar = [calendarStart, calendarTimezone, calendarEvents.join(SEPARATOR), calendarEnd].join(SEPARATOR); 124 | 125 | if (!dlh) { 126 | var blob = new Blob([calendar], {type: "data:text/calendar;charset=utf8"}); 127 | saveAs(blob, filename + ext); 128 | } else { 129 | window.location = encodeURI(dlh) + "?f=" + encodeURIComponent(filename + "." + ext) + "&t=" + encodeURIComponent(calendar); 130 | } 131 | } 132 | }; 133 | }; 134 | 135 | window.ics = icsGen; 136 | -------------------------------------------------------------------------------- /src/backend/assets/js/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function handleClientLoad() { 4 | gapi.load('client:auth2', main.initClient); 5 | } 6 | 7 | function initClient() { 8 | let id = document.getElementById('gcalendar-id').value; 9 | let key = document.getElementById('gcalendar-key').value; 10 | let CLIENT_ID = id; 11 | let API_KEY = key; 12 | let DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"]; 13 | let SCOPES = "https://www.googleapis.com/auth/calendar"; 14 | 15 | gapi.client.init({ 16 | apiKey: API_KEY, 17 | clientId: CLIENT_ID, 18 | discoveryDocs: DISCOVERY_DOCS, 19 | scope: SCOPES 20 | }) 21 | } 22 | 23 | function handleAuthClick(title, location, calendarStart, calendarEnd, timezone, description) { 24 | let isSignedIn = gapi.auth2.getAuthInstance().isSignedIn.get(); 25 | if (!isSignedIn) { 26 | gapi.auth2.getAuthInstance().signIn().then(function() { 27 | main.listUpcomingEvents(title, location, calendarStart, calendarEnd, timezone, description); 28 | }); 29 | } else { 30 | main.listUpcomingEvents(title, location, calendarStart, calendarEnd, timezone, description); 31 | } 32 | } 33 | 34 | function listUpcomingEvents(title, location, calendarStart, calendarEnd, timezone, description) { 35 | let event = { 36 | 'summary': title, 37 | 'location': location, 38 | 'description': description, 39 | 'start': { 40 | 'dateTime': calendarStart, 41 | 'timeZone': timezone 42 | }, 43 | 'end': { 44 | 'dateTime': calendarEnd, 45 | 'timeZone': timezone 46 | }, 47 | 'reminders': { 48 | 'useDefault': false, 49 | 'overrides': [{ 50 | 'method': 'email', 51 | 'minutes': 24 * 60 52 | }, 53 | { 54 | 'method': 'popup', 55 | 'minutes': 10 56 | } 57 | ] 58 | }, 59 | 'colorId': '5' 60 | }; 61 | 62 | let request = gapi.client.calendar.events.insert({ 63 | 'calendarId': 'primary', 64 | 'resource': event 65 | }); 66 | request.execute(function(event) { 67 | swal({ 68 | title: "Session added to your google calendar!", 69 | icon: "success", 70 | button: "OK!", 71 | }); 72 | }); 73 | } 74 | 75 | const loadVideoAndSlides = function(div, videoURL, slideURL) { 76 | const descriptionDiv = $('#desc-' + div); 77 | const speakerDiv = $('#speaker-' + div); 78 | 79 | if(videoURL !== null && videoURL !== '') { 80 | const isVideoDisplayed = descriptionDiv.hasClass('in'); 81 | let video = videoURL; 82 | const faviconDiv = $('#v' + div); 83 | 84 | if (videoURL.indexOf('v=') !== -1) { 85 | video = videoURL.split('v=')[1].replace(/[&#].*/, ''); 86 | } else if (videoURL.indexOf('https://youtu.be/') !== -1) { 87 | video = videoURL.split('https://youtu.be/')[1]; 88 | } 89 | 90 | if (!isVideoDisplayed && $('[id="video-' + div + '"]').length === 0) { 91 | faviconDiv.css('display', 'block'); 92 | speakerDiv.prepend(''); 93 | } else if(isVideoDisplayed) { 94 | faviconDiv.css('display', 'none'); 95 | $('#video-' + div).remove(); 96 | } 97 | } 98 | 99 | if(slideURL !== null && slideURL !== '') { 100 | const isSlideDisplayed = descriptionDiv.hasClass('in'); 101 | 102 | if (!isSlideDisplayed && $('[id="slide-' + div + '"]').length === 0) { 103 | if (slideURL.indexOf('pdf') !== -1) { 104 | speakerDiv.prepend(''); 105 | } else if (slideURL.indexOf('ppt') !== -1 || slideURL.indexOf('pptx') !== -1) { 106 | speakerDiv.prepend(''); 107 | } 108 | } 109 | else if(isSlideDisplayed) { 110 | $('#slide-' + div).remove(); 111 | } 112 | } 113 | }; 114 | 115 | $(document).ready(function () { 116 | const allFilter = { 117 | room: { 118 | dateFilter:'.date-filter', 119 | place:'.venue-filter', 120 | room:'.room-filter' 121 | }, 122 | 123 | track: { 124 | dateFilter:'.date-filter', 125 | place:'.track-filter', 126 | room:'.room-filter' 127 | }, 128 | 129 | schedule: { 130 | dateFilter:'.day-filter', 131 | calendarFilter: '.calendar', 132 | place:'.time-filter', 133 | room:'.schedule-track' 134 | } 135 | }; 136 | 137 | const showNoResult = function(filterType , calendarMode) { 138 | const filter = allFilter[filterType]; 139 | var search = false; 140 | $('.fossasia-filter').each(function() { 141 | if($(this).is(':visible') && $(this).val().length !== 0) { 142 | search = true; 143 | } 144 | }); 145 | var listFilterLength = $(filter.dateFilter+':visible').length; 146 | var calendarFilterLength = $('.room:visible').length; 147 | if ((calendarMode && calendarFilterLength == 0) || (!calendarMode && listFilterLength == 0)) { 148 | $('#no-results').remove(); 149 | const message = search ? 'No matching results found.' : 'No result found.'; 150 | $('.date-list').after("

"+message+"

"); 151 | } else { 152 | $('#no-results').remove(); 153 | } 154 | }; 155 | 156 | const trackRoomFilter = function (filterType, trackFilterMode, roomFilterMode, trackName, roomName, local_storage_events, mode) { 157 | let filterVal = ''; 158 | const filter = allFilter[filterType]; 159 | $('.fossasia-filter').each(function() { 160 | if($(this).is(':visible')) { 161 | filterVal = $(this).val(); 162 | } 163 | }); 164 | $(filter.dateFilter).each(function() { 165 | var temp = true; 166 | $(this).find(filter.place).each(function() { 167 | var flag = true; 168 | var venueName = filterType=='room' ? $(this).find('.text').text() : false; 169 | $(this).find(filter.room).each(function() { 170 | var id=$(this).attr('id'); 171 | if ($(this).find('.tip-description').text().toUpperCase().indexOf(filterVal.toUpperCase()) >= 0 || 172 | $(this).find('.session-speakers-list a span').text().toUpperCase().indexOf(filterVal.toUpperCase()) >= 0 || 173 | $(this).find('.session-speakers-more').text().toUpperCase().indexOf(filterVal.toUpperCase()) >= 0 || 174 | $(this).find('.event').text().toUpperCase().indexOf(filterVal.toUpperCase()) >= 0 || 175 | $(this).find('.speaker-name').text().toUpperCase().indexOf(filterVal.toUpperCase()) >= 0) { 176 | var trackVal = $(this).find('.title-inline .blacktext').text(); 177 | var roomVal = venueName ? venueName : $(this).find('#location').text(); 178 | if (mode && local_storage_events[id] != true) { 179 | $(this).hide(); 180 | } else if (trackFilterMode && trackVal != trackName) { 181 | $(this).hide(); 182 | } else if (roomFilterMode && roomVal != roomName) { 183 | $(this).hide(); 184 | } else { 185 | flag = false; 186 | $(this).show(); 187 | } 188 | } else { 189 | $(this).hide(); 190 | } 191 | }); 192 | if (flag == true) { 193 | $(this).hide(); 194 | } else { 195 | temp = false; 196 | $(this).show(); 197 | } 198 | }); 199 | if (temp == true) { 200 | $(this).hide(); 201 | } else { 202 | $(this).show(); 203 | } 204 | }); 205 | }; 206 | 207 | function viewsFilter(filterType, curView, date) { 208 | const filter = allFilter[filterType]; 209 | if(curView === 'list') { 210 | $(filter.dateFilter).each(function () { 211 | const showThing = date === 'all' || $(this).hasClass(date); 212 | $(this).toggleClass('hide', !showThing); 213 | }); 214 | } 215 | else if(curView === 'calendar') { 216 | $(filter.calendarFilter).each(function () { 217 | const showThing = date === 'all' || $(this).hasClass(date); 218 | $(this).toggleClass('hide', !showThing); 219 | }); 220 | } 221 | } 222 | 223 | window.main = { 224 | trackRoomFilter: trackRoomFilter, 225 | showNoResult: showNoResult, 226 | viewsFilter: viewsFilter, 227 | handleClientLoad: handleClientLoad, 228 | initClient: initClient, 229 | handleAuthClick: handleAuthClick, 230 | listUpcomingEvents: listUpcomingEvents, 231 | loadVideoAndSlides: loadVideoAndSlides 232 | } 233 | 234 | }); 235 | 236 | 237 | 238 | 239 | 240 | 241 | -------------------------------------------------------------------------------- /src/backend/assets/js/map.js: -------------------------------------------------------------------------------- 1 | 2 | let mapword = document.getElementById('mappos').value; 3 | let maparray = mapword.split(','); 4 | let latitude = parseFloat(maparray[0]); 5 | let longitude = parseFloat(maparray[1]); 6 | let myLatLng = {lat: latitude, lng:longitude}; 7 | let myLngLat = {lng: longitude, lat:latitude}; 8 | let map; 9 | let googleMarker; 10 | let osmMarker; 11 | const theme = parseInt(document.getElementById('theme').value); 12 | const mapType = parseInt(document.getElementById('mapType').value); 13 | 14 | // Selects the type of map - OSM OR Google maps 15 | if(mapType) 16 | { 17 | if(theme){ 18 | map = new google.maps.Map(document.getElementById('map'), { 19 | zoom: 16, 20 | center: myLatLng, 21 | styles: [ 22 | {elementType: 'geometry', stylers: [{color: '#242f3e'}]}, 23 | {elementType: 'labels.text.stroke', stylers: [{color: '#242f3e'}]}, 24 | {elementType: 'labels.text.fill', stylers: [{color: '#746855'}]}, 25 | { 26 | featureType: 'administrative.locality', 27 | elementType: 'labels.text.fill', 28 | stylers: [{color: '#d59563'}] 29 | }, 30 | { 31 | featureType: 'poi', 32 | elementType: 'labels.text.fill', 33 | stylers: [{color: '#d59563'}] 34 | }, 35 | { 36 | featureType: 'poi.park', 37 | elementType: 'geometry', 38 | stylers: [{color: '#263c3f'}] 39 | }, 40 | { 41 | featureType: 'poi.park', 42 | elementType: 'labels.text.fill', 43 | stylers: [{color: '#6b9a76'}] 44 | }, 45 | { 46 | featureType: 'road', 47 | elementType: 'geometry', 48 | stylers: [{color: '#38414e'}] 49 | }, 50 | { 51 | featureType: 'road', 52 | elementType: 'geometry.stroke', 53 | stylers: [{color: '#212a37'}] 54 | }, 55 | { 56 | featureType: 'road', 57 | elementType: 'labels.text.fill', 58 | stylers: [{color: '#9ca5b3'}] 59 | }, 60 | { 61 | featureType: 'road.highway', 62 | elementType: 'geometry', 63 | stylers: [{color: '#746855'}] 64 | }, 65 | { 66 | featureType: 'road.highway', 67 | elementType: 'geometry.stroke', 68 | stylers: [{color: '#1f2835'}] 69 | }, 70 | { 71 | featureType: 'road.highway', 72 | elementType: 'labels.text.fill', 73 | stylers: [{color: '#f3d19c'}] 74 | }, 75 | { 76 | featureType: 'transit', 77 | elementType: 'geometry', 78 | stylers: [{color: '#2f3948'}] 79 | }, 80 | { 81 | featureType: 'transit.station', 82 | elementType: 'labels.text.fill', 83 | stylers: [{color: '#d59563'}] 84 | }, 85 | { 86 | featureType: 'water', 87 | elementType: 'geometry', 88 | stylers: [{color: '#17263c'}] 89 | }, 90 | { 91 | featureType: 'water', 92 | elementType: 'labels.text.fill', 93 | stylers: [{color: '#515c6d'}] 94 | }, 95 | { 96 | featureType: 'water', 97 | elementType: 'labels.text.stroke', 98 | stylers: [{color: '#17263c'}] 99 | } 100 | ] 101 | }); 102 | } else{ 103 | map = new google.maps.Map(document.getElementById('map'), { 104 | zoom: 16, 105 | center: myLatLng 106 | }); 107 | } 108 | 109 | googleMarker = new google.maps.Marker({ 110 | position: myLatLng, 111 | map: map 112 | }); 113 | 114 | } else{ 115 | 116 | mapboxgl.accessToken = 'pk.eyJ1IjoiaGFyc2hrYXNoeWFwIiwiYSI6ImNqbjc0ZGRpcDAxZGIzcHA4MHduN3dkdDgifQ.YO4DvPlp5O7VTvlB0K4d0Q'; 117 | 118 | if(theme){ 119 | map = new mapboxgl.Map({ 120 | container: 'map', 121 | zoom: 16, 122 | center : myLngLat, 123 | scrollZoom : false, 124 | style: 'mapbox://styles/mapbox/navigation-preview-night-v4' 125 | }); 126 | } else{ 127 | map = new mapboxgl.Map({ 128 | container: 'map', 129 | zoom: 16, 130 | center : myLngLat, 131 | scrollZoom : false, 132 | // style: 'mapbox://styles/mapbox/streets-v10' 133 | style: 'mapbox://styles/mapbox/navigation-preview-day-v4' 134 | }); 135 | } 136 | 137 | osmMarker = new mapboxgl.Marker() 138 | .setLngLat(myLngLat) 139 | .addTo(map); 140 | 141 | var nav = new mapboxgl.NavigationControl(); 142 | map.addControl(nav, 'bottom-right'); 143 | map.addControl(new mapboxgl.FullscreenControl()); 144 | } -------------------------------------------------------------------------------- /src/backend/assets/js/navbar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by championswimmer on 27/08/16. 3 | */ 4 | $(function() { 5 | $('.nav.navbar-nav > li a').removeClass('active'); 6 | var linkUrl=window.location.href.split("/"); 7 | if(findMatch(linkUrl, "tracks.html")){ 8 | $("#trackslink").addClass('active'); 9 | } 10 | else if(findMatch(linkUrl, "rooms.html")){ 11 | $("#roomslink").addClass('active'); 12 | } 13 | else if(findMatch(linkUrl, "schedule.html")){ 14 | $("#schedulelink").addClass('active'); 15 | } 16 | else if(findMatch(linkUrl, "speakers.html")){ 17 | $("#speakerslink").addClass('active'); 18 | } 19 | else if(findMatch(linkUrl, "sessions.html")){ 20 | $("#sessionslink").addClass('active'); 21 | } 22 | else { 23 | $("#homelink").addClass('active'); 24 | } 25 | }); 26 | 27 | //The function below checks whether any of the entries of the array match against the 28 | //given pattern or not. 29 | 30 | function findMatch(arr, pattern){ 31 | // len stores the no. of elements checked so far and flag tells whether we found any 32 | // pattern or not. 33 | var len = 0, flag = 0; 34 | arr.forEach(function(val){ 35 | len += 1; 36 | if(val.indexOf(pattern) !== -1){ 37 | flag = 1; 38 | } 39 | }); 40 | 41 | // the check below makes sure that the function doesn't return any value before all 42 | // of the entries of the array are checked against the pattern. 43 | if(len === arr.length){ 44 | return flag; 45 | } 46 | } 47 | 48 | $(document).ready(function() { 49 | var sideslider = $('[data-toggle=collapse-side]'); 50 | var sel = sideslider.attr('data-target'); 51 | var top = $('header[role=banner]').outerHeight(); 52 | sideslider.click(function(event){ 53 | $(sel).css('top', top); 54 | $(sel).toggleClass('in'); 55 | }); 56 | }); 57 | 58 | 59 | // Making navbar translucent on scrolling down 60 | $(document).ready(function(){ 61 | try{ 62 | var navbar = document.getElementsByClassName('js-navbar')[0]; 63 | } catch(e){} 64 | 65 | window.addEventListener('scroll', function () { 66 | if(!navbar) return; 67 | if (window.scrollY > 0) { 68 | if (!navbar.classList.contains('navbar--translucent')) { 69 | navbar.classList.add('navbar--translucent'); 70 | } 71 | } else { 72 | if (navbar.classList.contains('navbar--translucent')) { 73 | navbar.classList.remove('navbar--translucent'); 74 | } 75 | } 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /src/backend/assets/js/scroll.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | $('a[href*="#"]:not([href="#"])').click(function() { 4 | if (location.pathname.replace(/^\//,'') === this.pathname.replace(/^\//,'') && location.hostname === this.hostname) { 5 | var href = $(this).attr('href'); 6 | var link = href.split('#')[1]; 7 | var selector = "a[id='" + link + "']"; 8 | var target = $(selector); 9 | target = target.length ? target : $('[name=' + this.hash.slice(1) +']'); 10 | if (target.length) { 11 | $('html, body').animate({ 12 | scrollTop: target.offset().top 13 | }, 500); 14 | return false; 15 | } 16 | } 17 | }); 18 | 19 | $('#down-button').hide(); 20 | $('#down-button').click(function() { 21 | $('html, body').animate({scrollTop: 0}, 500); 22 | $('#down-button').fadeOut(500); 23 | }); 24 | 25 | window.addEventListener('scroll', function() { 26 | if($(window).scrollTop() > 0) { 27 | $('#down-button').fadeIn(500); 28 | } 29 | if($(window).scrollTop() === 0) { 30 | $('#down-button').fadeOut(500); 31 | } 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/backend/assets/js/session.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | // eventInfo is an object defined in the script section inside the session template file 3 | var eventName = eventInfo.name; 4 | var sideslider = $('[data-toggle=collapse-side]'); 5 | var sel = sideslider.attr('data-target'); 6 | var top = $('header[role=banner]').outerHeight(); 7 | var downButton = $('#down-button'); 8 | var sessionElem = $('.single-session'); 9 | var sessionId = sessionElem.attr('id'); 10 | 11 | function init() { 12 | var temp = JSON.parse(localStorage[eventName] || '{}'); 13 | 14 | if (temp[sessionId] === 1) { 15 | sessionElem.find('.bookmark').addClass('starred'); 16 | } 17 | } 18 | 19 | sideslider.click(function() { 20 | $(sel).css('top', top); 21 | $(sel).toggleClass('in'); 22 | }); 23 | 24 | downButton.hide(); 25 | downButton.click(function() { 26 | $('html, body').animate({scrollTop: 0}, 500); 27 | downButton.fadeOut(500); 28 | }); 29 | 30 | window.addEventListener('scroll', function() { 31 | if ($(window).scrollTop() > 0) { 32 | downButton.fadeIn(500); 33 | } 34 | if ($(window).scrollTop() === 0) { 35 | downButton.fadeOut(500); 36 | } 37 | }); 38 | 39 | $('.bookmark').click(function() { 40 | var temp = JSON.parse(localStorage[eventName]); 41 | 42 | if ($(this).hasClass('starred')) { 43 | $(this).removeClass('starred'); 44 | temp[sessionId] = 0; 45 | } else { 46 | $(this).addClass('starred'); 47 | temp[sessionId] = 1; 48 | } 49 | 50 | localStorage[eventName] = JSON.stringify(temp); 51 | }); 52 | 53 | $('.session-lin').click(function(e) { 54 | var val = $(this).parent().parent().find('.speakers-inputbox').val(); 55 | 56 | $(this).parent().parent().find('div.social-buttons').toggle(); 57 | $(this).parent().parent().find('.speakers-inputbox').val(window.location.href.split('#')[0] + '#' + val.split('#').pop()); 58 | e.stopPropagation(); 59 | }); 60 | 61 | init(); 62 | }); 63 | -------------------------------------------------------------------------------- /src/backend/assets/js/social.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | $(document).ready(function() { 4 | $('.social-button').click(function() { 5 | var link = $(this).parent().parent().find('input.speakers-inputbox').val(); 6 | var source = $(this).attr('class').split(' ')[0].split('-')[0]; 7 | 8 | if (source === 'fb') { 9 | window.open('http://www.facebook.com/share.php?u=' + encodeURIComponent(link), 'facebook', 'height=360, width=580'); 10 | } else if (source === 'tw') { 11 | window.open('http://twitter.com/home?status=' + encodeURIComponent(link), 'twitter', 'height=360, width=580'); 12 | } else if (source === 'go') { 13 | window.open('https://plus.google.com/share?url=' + encodeURIComponent(link), 'google', 'height=360, width=580'); 14 | } else if (source === 'li') { 15 | window.open('http://www.linkedin.com/shareArticle?mini=true&url=' + encodeURIComponent(link), 'linkedin', 'height=360, width=580'); 16 | } 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/backend/assets/js/sw.js: -------------------------------------------------------------------------------- 1 | var urlsToCache = [ 2 | './css/bootstrap.min.css', 3 | './offline.html', 4 | './images/avatar.png' 5 | ]; 6 | 7 | self.addEventListener('install', function(event) { 8 | event.waitUntil( 9 | caches.open(CACHE_NAME).then(function(cache) { 10 | return cache.addAll(urlsToCache); 11 | }) 12 | ); 13 | }); 14 | 15 | self.addEventListener('fetch', function(event) { 16 | event.respondWith( 17 | caches.match(event.request).then(function(response) { 18 | // Cache hit - return response 19 | if (response) { 20 | return response; 21 | } 22 | 23 | var fetchRequest = event.request.clone(); 24 | 25 | return fetch(fetchRequest) 26 | .then(function(response) { 27 | // Check if we received a valid response 28 | if ( 29 | !response || 30 | response.status !== 200 || 31 | response.type !== 'basic' 32 | ) { 33 | return response; 34 | } 35 | 36 | var responseToCache = response.clone(); 37 | 38 | caches.open(CACHE_NAME).then(function(cache) { 39 | cache.put(event.request, responseToCache); 40 | }); 41 | 42 | return response; 43 | }) 44 | .catch(function(err) { 45 | if (event.request.headers.get('Accept').indexOf('text/html') !== -1) { 46 | return caches.match('./offline.html'); 47 | } else if (event.request.headers.get('Accept').indexOf('image') !== -1) { 48 | return caches.match('./images/avatar.png'); 49 | } else { 50 | console.log(err); 51 | } 52 | }); 53 | }) 54 | ); 55 | }); 56 | 57 | self.addEventListener('activate', function(event) { 58 | event.waitUntil( 59 | caches.keys().then(function(cacheNames) { 60 | return Promise.all( 61 | cacheNames.map(function(cacheName) { 62 | if (cacheName !== CACHE_NAME) { 63 | console.log('Deleting cache ' + cacheName); 64 | return caches.delete(cacheName); 65 | } 66 | }) 67 | ); 68 | }) 69 | ); 70 | }); 71 | 72 | -------------------------------------------------------------------------------- /src/backend/buildlogger.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | // eslint-disable-next-line no-var 5 | var exports = module.exports = {}; 6 | const buildLog = []; 7 | let obj = {}; 8 | let emit, largeMsg, message; 9 | 10 | exports.addLog = function(type, smallMessage, socket, largeMessage) { 11 | if (typeof largeMessage === 'undefined') { 12 | largeMsg = smallMessage; 13 | } 14 | 15 | buildLog.push({'type': type, 'smallMessage': smallMessage, 'largeMessage': largeMsg}); 16 | message = largeMsg.toString(); 17 | obj = {'type': type, 'smallMessage': smallMessage, 'largeMessage': message}; 18 | emit = false; 19 | 20 | if (socket.constructor.name === 'Socket') { 21 | emit = true; 22 | } 23 | if (emit) { 24 | socket.emit('buildLog', obj); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /src/backend/deploy.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const distHelper = require('./dist.js'); 5 | const fs = require('fs'); 6 | const Github = require('@octokit/rest'); 7 | const gh = new Github(); 8 | const async = require('async'); 9 | let results, bitmap, i, file, fullPath, eventName, repoName, total, counter, elem, fileName, sha; 10 | const Gemfile = __dirname + '/Gemfile'; 11 | const walk = function(dir, done) { 12 | results = []; 13 | fs.readdir(dir, function(err, list) { 14 | if (err) { 15 | return done(err); 16 | } 17 | i = 0; 18 | 19 | (function next() { 20 | file = list[i++]; 21 | 22 | if (!file) { 23 | return done(null, results); 24 | } 25 | file = dir + '/' + file; 26 | fs.stat(file, function(error_stat, stat) { 27 | if (stat && stat.isDirectory()) { 28 | walk(file, function(error, res) { 29 | results = results.concat(res); 30 | next(); 31 | }); 32 | } else { 33 | results.push(file); 34 | next(); 35 | } 36 | }); 37 | })(); 38 | }); 39 | }; 40 | 41 | function encode(file_name) { 42 | bitmap = fs.readFileSync(file_name); 43 | 44 | return new Buffer(bitmap).toString('base64'); 45 | } 46 | 47 | module.exports = function(accessToken, folder, user, socket, callback) { 48 | gh.authenticate({type: 'oauth', token: accessToken}); 49 | fullPath = distHelper.distPath + '/' + folder; 50 | eventName = folder.substr(folder.search('/') + 1); 51 | repoName = 'eventSiteWebApp'; 52 | 53 | async.series([ 54 | 55 | (done) => { 56 | socket.emit('started', 'Deleting previously existing repo of same name'); 57 | console.log('----------Deleting previously existing repo of same name -----------------'); 58 | 59 | gh.repos.delete({owner: user, repo: repoName}, function(err, res) { 60 | if (err) { 61 | console.log('Event Repo doesn\'t exist'); 62 | socket.emit('errorLog', 'Event Repo doesn\'t exist. Continuing further'); 63 | } 64 | if (socket.abortDeploy) { 65 | done('aborted'); 66 | return; 67 | } 68 | done(null, 'delete'); 69 | }); 70 | }, 71 | 72 | (done) => { 73 | socket.emit('started', 'Creating the eventSiteWebApp repo'); 74 | console.log('------------Creating the eventSiteWebApp repo ------------'); 75 | 76 | gh.repos.create({name: repoName, auto_init: 1}, function(err, response) { 77 | if (err) { 78 | console.log('Error happened while creating repository'); 79 | done(err, 'error'); 80 | socket.emit('errorLog', 'Error happened while creating repository. Can\'t continue further'); 81 | return; 82 | } 83 | if (socket.abortDeploy) { 84 | done('aborted'); 85 | return; 86 | } 87 | done(null, 'create'); 88 | }); 89 | }, 90 | 91 | (done) => { 92 | socket.emit('started', 'Creating Gemfile in the repository'); 93 | console.log('-------------Creating Gemfile in the eventsiteWebApp repository'); 94 | 95 | gh.repos.createFile({owner: user, repo: repoName, path: 'Gemfile', message: 'commit by web app', content: encode(Gemfile)}, 96 | function(err, res) { 97 | if (err) { 98 | console.log('Error occured in pushing Gemfile'); 99 | done(err, 'error'); 100 | socket.emit('errorLog', 'Error occured in pushing Gemfile. Can\'t continue further'); 101 | return; 102 | } 103 | if (socket.abortDeploy) { 104 | done('aborted'); 105 | return; 106 | } 107 | done(null, 'Gemfile'); 108 | }); 109 | }, 110 | 111 | (done) => { 112 | socket.emit('started', 'Creating a list of all files to be uploaded and committed to Github'); 113 | console.log('-------------Creating a list of all the files to be uploaded and committed to the github--------------'); 114 | 115 | walk(fullPath, function(err, resultsArray) { 116 | if (err) { 117 | console.log('Error happened while traversing the event site folder'); 118 | done(err, 'error'); 119 | socket.emit('errorLog', 'Error happened while traversing the event site folder. Can\'t continue further'); 120 | return; 121 | } 122 | 123 | total = resultsArray.length; 124 | counter = 0; 125 | 126 | function doOne() { 127 | if (resultsArray.length > 0) { 128 | elem = resultsArray.shift(); 129 | fileName = elem.substr(elem.search(eventName) + eventName.length + 1); 130 | 131 | console.log(fileName); 132 | setTimeout(function() { 133 | socket.emit('select', fileName + ' uploading'); 134 | gh.repos.createFile({owner: user, repo: repoName, path: fileName, message: 'commit by web app', content: encode(elem)}, 135 | function(error, res) { 136 | counter += 1; 137 | 138 | if (error) { 139 | console.log('Error occured while uploading ' + fileName); 140 | console.log(error); 141 | socket.emit('errorLog', 'Error happened while uploading ' + fileName + '. Ignoring'); 142 | } else { 143 | socket.emit('fileUpload', {file: fileName, percent: counter * 100 / total}); 144 | } 145 | 146 | if (socket.abortDeploy) { 147 | done('aborted'); 148 | return; 149 | } 150 | 151 | doOne(); 152 | }); 153 | }, 1000); 154 | } else { 155 | done(null, 'uploaded and committed'); 156 | } 157 | } 158 | doOne(); 159 | }); 160 | }, 161 | 162 | (done) => { 163 | socket.emit('progress', 'File upload done. Creating gh-pages branch'); 164 | console.log('-------------Creating gh-pages branch in the created repository--------------------'); 165 | 166 | gh.gitdata.getReference({owner: user, repo: repoName, ref: 'heads/master'}, function(err, res) { 167 | if (err) { 168 | console.log('Error happened when getting the sha of latest commit on master branch'); 169 | done(err, 'error'); 170 | socket.emit('errorLog', 'Error happened when getting the sha of latest commit on master branch. Can\'t continue further'); 171 | return; 172 | } 173 | if (socket.abortDeploy) { 174 | done('aborted'); 175 | return; 176 | } 177 | 178 | sha = res.data.object.sha; 179 | 180 | gh.gitdata.createReference({owner: user, repo: repoName, ref: 'refs/heads/gh-pages', sha: sha}, function(error, response) { 181 | if (error) { 182 | console.log('Error happened while creating gh-pages branch'); 183 | done(error, 'error'); 184 | socket.emit('errorLog', 'Error happened while creating gh-pages branch. Can\'t continue further'); 185 | return; 186 | } 187 | if (socket.abortDeploy) { 188 | done('aborted'); 189 | return; 190 | } 191 | 192 | socket.emit('progress', 'Gh-pages branch created'); 193 | console.log('Gh-pages branch created'); 194 | setTimeout(function() { 195 | socket.emit('finished', 'http://' + user + '.github.io/' + repoName); 196 | callback(); 197 | }, 10000); 198 | }); 199 | }); 200 | } 201 | ], 202 | 203 | function(err, result) { 204 | if (err) { 205 | if (err === 'aborted') { 206 | console.log('The process was aborted by the user'); 207 | socket.emit('abort', 'The process has been successfully aborted'); 208 | } else { 209 | console.log('The deployment process failed with an error'); 210 | console.log(err); 211 | } 212 | } 213 | }); 214 | }; 215 | -------------------------------------------------------------------------------- /src/backend/ftpdeploy.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const FtpDeploy = require('ftp-deploy'); 5 | const path = require('path'); 6 | 7 | function deploy(ftpDetails, appFolder, done) { 8 | const ftpDeploy = new FtpDeploy(); 9 | 10 | const config = { 11 | username: ftpDetails.user, 12 | password: ftpDetails.pass, // optional, prompted if none given 13 | host: ftpDetails.host, 14 | port: ftpDetails.port, 15 | localRoot: path.join(__dirname, '/../../dist', appFolder), 16 | remoteRoot: ftpDetails.path, 17 | exclude: ['.git', '.idea', 'tmp/*'], 18 | continueOnError: true 19 | }; 20 | 21 | ftpDeploy.on('upload-error', function(data) { 22 | console.log(data.err); // data will also include filename, relativePath, and other goodies 23 | }); 24 | 25 | ftpDeploy.on('uploaded', function(data) { 26 | console.log(data); // same data as uploading event 27 | }); 28 | ftpDeploy.on('uploading', function(data) { 29 | console.log(data); // same data as uploading event 30 | }); 31 | ftpDeploy.on('error', function(data) { 32 | console.log(data); // same data as uploading event 33 | }); 34 | 35 | ftpDeploy.deploy(config, function(err) { 36 | if (err) { 37 | console.log(err); 38 | } else { 39 | console.log('finished'); 40 | done(); 41 | } 42 | }); 43 | } 44 | 45 | module.exports = { 46 | deploy 47 | }; 48 | 49 | -------------------------------------------------------------------------------- /src/backend/gulpfile.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const gulp = require('gulp'); 5 | const concat = require('gulp-concat'); 6 | const del = require('del'); 7 | const esbuild = require('gulp-esbuild'); 8 | // eslint-disable-next-line no-var 9 | var exports = module.exports = {}; 10 | 11 | exports.minifyJs = function(path, cb) { 12 | const dir = path + '/js/'; 13 | 14 | function minifyPipeline(dist, src) { 15 | return gulp.src(src.map(file => dir + file)) 16 | .pipe(esbuild({ 17 | bundle: true, 18 | minify: true, 19 | format: 'iife', 20 | })) 21 | .pipe(concat(dist + '.min.js')) 22 | .pipe(gulp.dest(path + '/js/')); 23 | } 24 | 25 | function scheduleJs() { 26 | return minifyPipeline('schedule', [ 27 | 'FileSaver.js', 28 | 'social.js', 29 | 'scroll.js', 30 | 'navbar.js', 31 | 'popover.js', 32 | 'html2canvas.js', 33 | 'jquery.lazyload.js', 34 | 'icsGen.js' 35 | ]) 36 | } 37 | 38 | function tracksJs() { 39 | return minifyPipeline('tracks', ['social.js', 'scroll.js', 'navbar.js', 'jquery.lazyload.js']); 40 | } 41 | 42 | function eventJs() { 43 | return minifyPipeline('event', ['map.js', 'scroll.js', 'navbar.js', 'popover.js', 'loklak-fetcher.js', 'tweets.js', 'jquery.lazyload.js']); 44 | } 45 | 46 | function roomsJs() { 47 | return minifyPipeline('rooms', ['social.js', 'scroll.js', 'navbar.js', 'jquery.lazyload.js']); 48 | } 49 | 50 | function speakersJs() { 51 | return minifyPipeline('speakers', ['social.js', 'scroll.js', 'navbar.js', 'popover.js', 'jquery.lazyload.js']); 52 | } 53 | 54 | function sessionJs() { 55 | return minifyPipeline('session', ['session.js', 'social.js']); 56 | } 57 | 58 | function mainJs() { 59 | return minifyPipeline('main', ['main.js']); 60 | } 61 | 62 | gulp.task('minifyJs', gulp.series(gulp.parallel(speakersJs, roomsJs, scheduleJs, eventJs, tracksJs, sessionJs, mainJs), async function() { 63 | await del([dir + '*.js', '!' + dir + '*.min.js']); 64 | cb(); 65 | })); 66 | 67 | gulp.series('minifyJs')(); 68 | }; 69 | 70 | exports.minifyCss = function(path, cb) { 71 | // Minify all the css files of the web-app 72 | return gulp.src(path + '/css/*.css') 73 | .pipe(esbuild({ 74 | loader: {'.css': 'css'}, 75 | minify: true 76 | })) 77 | .pipe(gulp.dest(path + '/css')).on('end', function() { 78 | cb(); 79 | }); 80 | }; 81 | -------------------------------------------------------------------------------- /src/backend/mailer.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const config = require('../../config.json'); 5 | 6 | /** 7 | * Set these before requiring aws-sdk for all ENV vars to be loaded properly 8 | */ 9 | process.env.AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID || config.AWS_ACCESS_KEY_ID; 10 | process.env.AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY || config.AWS_SECRET_ACCESS_KEY; 11 | process.env.AWS_BUCKET = process.env.AWS_BUCKET || config.AWS_BUCKET; 12 | process.env.CLOUD_STORAGE = process.env.CLOUD_STORAGE || config.CLOUD_STORAGE; 13 | 14 | const promise = require('bluebird'); 15 | const helper = require('sendgrid').mail; 16 | const sg = require('sendgrid')(process.env.SENDGRID_API_KEY || config.SENDGRID_API_KEY); 17 | const distHelper = require('./dist.js'); 18 | const logger = require('./buildlogger.js'); 19 | const aws = require('aws-sdk'); 20 | const fs = require('fs'); 21 | const uuid = require('node-uuid'); 22 | const appUrl = process.env.HEROKU_URL || 'http://opev-webgen-dev.herokuapp.com/'; 23 | const nodemailer = require('nodemailer'); 24 | const smtpTransport = require('nodemailer-smtp-transport'); 25 | const moment = require('moment'); 26 | 27 | aws.config.setPromisesDependency(promise); 28 | 29 | let s3 = new aws.S3(); 30 | 31 | /** 32 | * Support Google Cloud Store too using the same AWS SDK via Google Cloud Storage interoperability keys 33 | */ 34 | if (process.env.CLOUD_STORAGE === 'google_cloud') { 35 | s3 = new aws.S3({endpoint: new aws.Endpoint('https://storage.googleapis.com')}); 36 | } 37 | 38 | process.env.DEFAULT_MAIL_STRATEGY = process.env.DEFAULT_MAIL_STRATEGY || config.DEFAULT_MAIL_STRATEGY; 39 | process.env.DEFAULT_FROM_EMAIL = process.env.DEFAULT_FROM_EMAIL || config.DEFAULT_FROM_EMAIL; 40 | 41 | function uploadToS3(file, fileName, socket) { 42 | const uploadParams = { 43 | Bucket: process.env.AWS_BUCKET, 44 | Key: fileName 45 | }; 46 | const fileStream = fs.createReadStream(file); 47 | 48 | fileStream.on('error', function(err) { 49 | console.log('File Error'); 50 | logger.addLog('Error', 'Error during upload to S3', socket, err); 51 | }); 52 | uploadParams.Body = fileStream; 53 | return s3.upload(uploadParams).promise(); 54 | } 55 | 56 | function emailSend(toEmail, url, appName) { 57 | const subject = 'Your webapp ' + appName + ' is Ready'; 58 | let downloadUrl = url; 59 | const previewUrl = appUrl + 'live/preview/' + toEmail + '/' + encodeURIComponent(appName); 60 | const currDate = new Date(); 61 | let previewExpiryDate = new Date(); 62 | let downloadLinkExpiryDate = new Date(); 63 | let mailSendStatus = 0; // boolean to indicate the success and failure of email send 64 | const chanChannelLink = 'https://gitter.im/fossasia/open-event-webapp'; 65 | const githubIssueLink = 'https://github.com/fossasia/open-event-webapp/issues'; 66 | let emailContent = ''; 67 | 68 | previewExpiryDate.setTime(currDate.getTime() + 7200000); // corresponds to current date + 2 hours 69 | previewExpiryDate = moment.utc(previewExpiryDate).format('dddd, h A') + ' (UTC)'; 70 | downloadLinkExpiryDate.setTime(currDate.getTime() + 259200000); // corresponds to current date + 3 days 71 | downloadLinkExpiryDate = moment.utc(downloadLinkExpiryDate).format('dddd, MMMM Do YYYY') + ' (UTC)'; 72 | 73 | const successMesg = `Hi !
Your webapp has been generated
You can preview it live on ${' link'.link(previewUrl)}. This link expires on ${previewExpiryDate}
You can download a zip of your website from ${' here'.link(downloadUrl)}. The download link for zip expires on ${downloadLinkExpiryDate}


Thank you for using Open Event Webapp Generator :)`; 74 | 75 | const errorMesg = 'Hi !
The cloud upload of the webapp failed. Please inform us about it on our ' + 'chat channel'.link(chanChannelLink) + ' or file an issue on our ' + 'Github repo'.link(githubIssueLink) + '. Sorry for the inconvenience :('; 76 | 77 | // The Cloud upload fails so download link point to the event folder on Heroku itself which will be purged in a few hours 78 | if (!url) { 79 | downloadUrl = appUrl + 'download/' + toEmail + '/' + appName; 80 | emailContent = errorMesg; 81 | } else { 82 | emailContent = successMesg; 83 | } 84 | 85 | if (process.env.DEFAULT_MAIL_STRATEGY === 'SMTP') { 86 | const smtpConfig = { 87 | host: process.env.SMTP_HOST || config.SMTP_HOST, 88 | port: process.env.SMTP_PORT || config.SMTP_PORT, 89 | auth: { 90 | user: process.env.SMTP_USERNAME || config.SMTP_USERNAME, 91 | pass: process.env.SMTP_PASSWORD || config.SMTP_PASSWORD 92 | } 93 | }; 94 | const transporter = nodemailer.createTransport(smtpTransport(smtpConfig)); 95 | 96 | return transporter.sendMail({ 97 | from: process.env.DEFAULT_FROM_EMAIL, 98 | to: toEmail, 99 | subject: subject, 100 | html: emailContent 101 | }).then((response) => { 102 | mailSendStatus = 1; 103 | console.log('Successfully sent Email'); 104 | console.log(response); 105 | return {'url': url, 'mail': mailSendStatus}; 106 | }).catch((err) => { 107 | console.log('Error sending Email', err); 108 | return {'url': url, 'mail': mailSendStatus}; 109 | }); 110 | } 111 | const fromEmail = new helper.Email(process.env.DEFAULT_FROM_EMAIL); 112 | const recipientEmail = new helper.Email(toEmail); 113 | const content = new helper.Content('text/html', emailContent); 114 | const mail = new helper.Mail(fromEmail, subject, recipientEmail, content); 115 | const requestBody = mail.toJSON(); 116 | const request = sg.emptyRequest(); 117 | 118 | request.host = 'api.sendgrid.com'; 119 | request.method = 'POST'; 120 | request.path = '/v3/mail/send'; 121 | request.body = requestBody; 122 | console.log(request); 123 | // eslint-disable-next-line new-cap 124 | return sg.API(request) 125 | .then((response) => { 126 | mailSendStatus = 1; 127 | console.log(response.statusCode); 128 | console.log(response.body); 129 | console.log(response.headers); 130 | return {'url': url, 'mail': mailSendStatus}; 131 | }) 132 | .catch((err) => { 133 | console.log('Error sending Email', err); 134 | return {'url': url, 'mail': mailSendStatus}; 135 | }); 136 | } 137 | 138 | function uploadAndsendMail(toEmail, appName, socket, done) { 139 | const file = distHelper.distPath + '/' + toEmail + '/event.zip'; 140 | 141 | const app_name = appName.split(' ').join('_'); 142 | const fileName = uuid.v4() + '/' + app_name + '.zip'; 143 | 144 | uploadToS3(file, fileName, socket) 145 | .then((data) => { 146 | logger.addLog('Success', 'Upload successful to s3', socket); 147 | data.Location = decodeURIComponent(data.Location); 148 | console.log('Upload Success', data.Location); 149 | return emailSend(toEmail, data.Location, app_name); 150 | }) 151 | .catch((err) => { 152 | console.log('Error', err); 153 | logger.addLog('Info', 'Failed while uploading the zip. No Amazon S3 keys found', socket); 154 | return emailSend(toEmail, null, app_name); 155 | }) 156 | .then((obj) => { 157 | return done(obj); 158 | }); 159 | } 160 | 161 | module.exports = { 162 | uploadAndsendMail 163 | }; 164 | -------------------------------------------------------------------------------- /src/backend/overviewSite/OTS18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/OTS18.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/PyCon17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/PyCon17.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/SparkSummit17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/SparkSummit17.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/droidcon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/droidcon.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/fa16small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/fa16small.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/fasmall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/fasmall.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/favicon.ico -------------------------------------------------------------------------------- /src/backend/overviewSite/fbsmall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/fbsmall.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/fossasia16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/fossasia16.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/fossasia2010.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/fossasia2010.JPG -------------------------------------------------------------------------------- /src/backend/overviewSite/fossasia2011.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/fossasia2011.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/googleIO.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/googleIO.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/mozilla2016.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/mozilla2016.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/mozilla_banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/mozilla_banner.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/nextcloud2017.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/nextcloud2017.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/nextcloud2018.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/nextcloud2018.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/oscal17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/oscal17.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/oscon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/oscon.png -------------------------------------------------------------------------------- /src/backend/overviewSite/ots16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/ots16.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/otssmall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/otssmall.jpg -------------------------------------------------------------------------------- /src/backend/overviewSite/redhat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/backend/overviewSite/redhat.jpg -------------------------------------------------------------------------------- /src/backend/templates/CoC.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | {{ apptitle }} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 37 | 38 | 39 | {{>navbar}} 40 |
41 |
42 |
43 |

44 | Code of Conduct 45 |

46 |
47 |
48 | 49 |
50 |
51 |
52 | {{{eventurls.codeOfConduct}}} 53 |
54 |
55 |
56 |
57 | {{>footer}} 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/backend/templates/partials/footer.hbs: -------------------------------------------------------------------------------- 1 | 2 | 87 | -------------------------------------------------------------------------------- /src/backend/templates/partials/googleanalytics.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{#if ganalyticsID}} 4 | 5 | 12 | {{/if}} 13 | -------------------------------------------------------------------------------- /src/backend/templates/partials/navbar.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 133 | -------------------------------------------------------------------------------- /src/backend/templates/partials/roomlist.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{#each roomsnames}} 3 |
4 | 5 | {{this}} 6 |
7 | {{/each}} 8 |
9 | -------------------------------------------------------------------------------- /src/backend/templates/partials/scroll.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/backend/templates/partials/social.hbs: -------------------------------------------------------------------------------- 1 | 4 | 7 | 10 | 13 | -------------------------------------------------------------------------------- /src/backend/templates/partials/tracklist.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{#tracknames}} 3 | {{#if title}} 4 |
5 | 6 | {{title}} 7 |
8 | {{/if}} 9 | {{/tracknames}} 10 |
11 | -------------------------------------------------------------------------------- /src/selenium/cocPage.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const BasePage = require('./basePage.js'); 5 | const By = require('selenium-webdriver').By; 6 | 7 | const cocPage = Object.create(BasePage); 8 | 9 | cocPage.checkCoCsection = function() { 10 | return this.find(By.className('coc')); 11 | }; 12 | 13 | module.exports = cocPage; 14 | -------------------------------------------------------------------------------- /src/selenium/eventPage.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const BasePage = require('./basePage.js'); 5 | const By = require('selenium-webdriver').By; 6 | 7 | const EventPage = Object.create(BasePage); 8 | 9 | EventPage.getEventName = function() { 10 | return this.find(By.css('h1')).getText().then(function(name) { 11 | return name; 12 | }); 13 | }; 14 | 15 | EventPage.checkTweetSection = function() { 16 | // This will return an error if the tweet section is not there 17 | return this.find(By.id('tweet')); 18 | }; 19 | 20 | EventPage.getNavbarFooterBrokenLinks = function() { 21 | // Both the promises return an array of links contained inside the container 22 | const navbarPromise = this.getAllLinks(By.className('navbar-default')); 23 | const footerPromise = this.getAllLinks(By.className('footer-container')); 24 | 25 | const promiseArr = []; 26 | 27 | promiseArr.push(navbarPromise); 28 | promiseArr.push(footerPromise); 29 | 30 | // Merges two arrays into one and remove duplicate elements 31 | function mergeUniqueArr(arr1, arr2) { 32 | return arr1.concat(arr2.filter(function(item) { 33 | return arr1.indexOf(item) === -1; 34 | })); 35 | } 36 | 37 | // Returns a promise which resolves to the unique list of elements in navbar and footer 38 | function getUniqueLinks() { 39 | return new Promise(function(resolve) { 40 | Promise.all(promiseArr).then(function(allLinksArr) { 41 | resolve(mergeUniqueArr(allLinksArr[0], allLinksArr[1])); 42 | }); 43 | }); 44 | } 45 | 46 | return getUniqueLinks().then(this.countBrokenLinks); 47 | }; 48 | 49 | EventPage.checkSponsorSection = function() { 50 | return this.find(By.className('sponsorscont')); 51 | }; 52 | 53 | EventPage.getSponsorsBrokenLinks = function() { 54 | const allLinks = this.getAllLinks(By.className('sponsorscont')); 55 | const brokenLinks = allLinks.then(this.countBrokenLinks); 56 | 57 | return brokenLinks; 58 | }; 59 | 60 | EventPage.checkTicketButton = function() { 61 | return this.find(By.id('ticket-button')); 62 | }; 63 | 64 | EventPage.checkTicketFunctionality = function() { 65 | const link = this.getAllLinks(By.className('ticket-button-container')); 66 | const brokenLinks = link.then(this.countBrokenLinks); 67 | 68 | return brokenLinks; 69 | }; 70 | module.exports = EventPage; 71 | -------------------------------------------------------------------------------- /src/selenium/generatorPage.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const By = require('selenium-webdriver').By; 5 | const until = require('selenium-webdriver').until; 6 | 7 | const GeneratorPage = { 8 | init: function(webdriver) { 9 | this.driver = webdriver; 10 | }, 11 | 12 | visit: function(url) { 13 | return this.driver.get(url); 14 | }, 15 | 16 | find: function(locator, timeout) { 17 | const waitTime = timeout || 20000; 18 | 19 | this.driver.wait(until.elementLocated(locator, waitTime)); 20 | return this.driver.findElement(locator); 21 | }, 22 | 23 | findAll: function(locator, timeout) { 24 | const waitTime = timeout || 20000; 25 | 26 | this.driver.wait(until.elementLocated(locator, waitTime)); 27 | return this.driver.findElements(locator); 28 | } 29 | }; 30 | 31 | // Checks if json upload section appears on selecting json-upload as a choice for input data 32 | 33 | GeneratorPage.checkJsonInput = function() { 34 | const self = this; 35 | const inputJsonId = 'jsonupload-input'; 36 | const promise = new Promise(function(resolve) { 37 | self.find(By.id('jsonupload')).click().then(self.driver.sleep(1000)).then(function() { 38 | resolve(self.find(By.id(inputJsonId)).isDisplayed()); 39 | }); 40 | }); 41 | 42 | return promise; 43 | }; 44 | 45 | // Checks if API endpoint section appears on selecting API-endpoint as a choice for input data 46 | 47 | GeneratorPage.checkAPIendpointInput = function() { 48 | const self = this; 49 | const inputAPIid = 'eventapi-input'; 50 | const promise = new Promise(function(resolve) { 51 | self.find(By.id('eventapi')).click().then(self.driver.sleep(1000)).then(function() { 52 | resolve(self.find(By.id(inputAPIid)).isDisplayed()); 53 | }); 54 | }); 55 | 56 | return promise; 57 | }; 58 | 59 | // Checks if ftp-details section appears on choosing ftp-upload. 60 | 61 | GeneratorPage.checkFTPinput = function() { 62 | const self = this; 63 | const inputFTPid = 'upload-ftp-details'; 64 | const promise = new Promise(function(resolve) { 65 | self.find(By.id('upload-ftp')).click().then(self.driver.sleep(1000)).then(function() { 66 | resolve(self.find(By.id(inputFTPid)).isDisplayed()); 67 | }); 68 | }); 69 | 70 | return promise; 71 | }; 72 | 73 | // Checks if logs are displayed on clicking the logs link. 74 | 75 | GeneratorPage.checkBuildLogs = function() { 76 | const self = this; 77 | const LogSectionId = 'buildLog'; 78 | const promiseArr = []; 79 | const promise = new Promise(function(resolve) { 80 | self.find(By.id('aLog')).click().then(self.driver.sleep(1000)).then(function() { 81 | promiseArr.push(self.find(By.id(LogSectionId)).isDisplayed()); 82 | }).then(function() { 83 | self.find(By.id('aLog')).click().then(self.driver.sleep(1000)).then(function() { 84 | promiseArr.push(self.find(By.id(LogSectionId)).isDisplayed()); 85 | resolve(Promise.all(promiseArr)); 86 | }); 87 | }); 88 | }); 89 | 90 | return promise; 91 | }; 92 | 93 | // Checks if the webapp menu appear on clicking the option to see sister projects. 94 | 95 | GeneratorPage.checkWebappMenu = function() { 96 | const self = this; 97 | const MenuClass = 'custom-menu-cont'; 98 | const promiseArr = []; 99 | const promise = new Promise(function(resolve) { 100 | self.find(By.className('custom-menubutton')).click().then(self.driver.sleep(1000)).then(function() { 101 | promiseArr.push(self.find(By.className(MenuClass)).isDisplayed()); 102 | }).then(function() { 103 | self.find(By.className('custom-menubutton')).click().then(self.driver.sleep(1000)).then(function() { 104 | promiseArr.push(self.find(By.className(MenuClass)).isDisplayed()); 105 | resolve(Promise.all(promiseArr)); 106 | }); 107 | }); 108 | }); 109 | 110 | return promise; 111 | }; 112 | 113 | module.exports = GeneratorPage; 114 | 115 | -------------------------------------------------------------------------------- /src/selenium/roomPage.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const BasePage = require('./basePage.js'); 5 | const By = require('selenium-webdriver').By; 6 | 7 | const RoomPage = Object.create(BasePage); 8 | 9 | RoomPage.checkIsolatedBookmark = function() { 10 | const self = this; 11 | const bookmarkSessionsIdsArr = ['3014']; 12 | const visibleCheckSessionsIdsArr = ['3014', '3015', '2918']; 13 | 14 | return self.bookmarkCheck(bookmarkSessionsIdsArr, visibleCheckSessionsIdsArr); 15 | }; 16 | 17 | RoomPage.toggleSessionElem = function() { 18 | const self = this; 19 | 20 | // Checking the toggle behaviour of session having id 3014 21 | const promise = new Promise(function(resolve) { 22 | self.find(By.id('title-3014')).then(self.click).then(self.driver.sleep(1000)).then(function() { 23 | const promiseArr = []; 24 | 25 | promiseArr.push(self.find(By.id('desc-3014')).isDisplayed()); 26 | promiseArr.push(self.find(By.id('desc2-3014')).isDisplayed()); 27 | resolve(Promise.all(promiseArr)); 28 | }); 29 | }); 30 | 31 | return promise; 32 | }; 33 | 34 | RoomPage.searchThenStarredMode = function() { 35 | const self = this; 36 | const idArr = ['3014', '2861', '3015']; 37 | const promiseArr = idArr.map(function(elem) { 38 | return self.find(By.id(elem)); 39 | }); 40 | 41 | return self.search('wel').then(self.toggleStarredButton.bind(self)).then(self.getElemsDisplayStatus.bind(null, promiseArr)); 42 | }; 43 | 44 | RoomPage.starredModeThenSearch = function() { 45 | const self = this; 46 | const idArr = ['3014', '2861', '3015']; 47 | const promiseArr = idArr.map(function(elem) { 48 | return self.find(By.id(elem)); 49 | }); 50 | 51 | return self.toggleStarredButton().then(self.search.bind(self, 'wel')).then(self.getElemsDisplayStatus.bind(null, promiseArr)); 52 | }; 53 | 54 | RoomPage.checkRoomFilterDirectLink = function() { 55 | const self = this; 56 | const roomIdArr = []; 57 | 58 | function pushId(roomElement) { 59 | roomElement.getAttribute('id').then(function(id) { 60 | roomIdArr.push(id); 61 | }); 62 | } 63 | 64 | return new Promise(function(resolve) { 65 | self.findAll(By.className('room-filter')).then(function(roomElems) { 66 | roomElems.forEach(function(roomElem) { 67 | roomElem.isDisplayed().then(function(val) { 68 | if (val === true) { 69 | pushId(roomElem); 70 | } 71 | }); 72 | }); 73 | }).then(function() { 74 | resolve(roomIdArr); 75 | }); 76 | }); 77 | }; 78 | 79 | RoomPage.checkFilterDynamicLink = function() { 80 | const self = this; 81 | const promiseArr = []; 82 | 83 | promiseArr.push(self.activeRooms()); 84 | promiseArr.push(self.activeTracks()); 85 | return Promise.all(promiseArr); 86 | }; 87 | 88 | RoomPage.checkVideo = function() { 89 | const self = this; 90 | 91 | return new Promise(function(resolve) { 92 | self.find(By.id('title-3015')).then(self.click).then(function() { 93 | self.find(By.id('video-3015')).then(function(elem) { 94 | elem.getAttribute('src').then(function(url) { 95 | resolve(self.isLinkBroken(url)); 96 | }); 97 | }); 98 | }); 99 | }); 100 | }; 101 | 102 | module.exports = RoomPage; 103 | -------------------------------------------------------------------------------- /src/selenium/schedulePage.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const BasePage = require('./basePage.js'); 5 | const By = require('selenium-webdriver').By; 6 | 7 | const SchedulePage = Object.create(BasePage); 8 | const datesId = ['2017-03-17', '2017-03-18', '2017-03-19']; 9 | 10 | SchedulePage.checkIsolatedBookmark = function() { 11 | const self = this; 12 | const bookmarkSessionsIdsArr = ['3015']; 13 | const visibleCheckSessionsIdsArr = ['3014', '3015', '2918']; 14 | 15 | return self.bookmarkCheck(bookmarkSessionsIdsArr, visibleCheckSessionsIdsArr); 16 | }; 17 | 18 | SchedulePage.toggleSessionElem = function() { 19 | const self = this; 20 | // Checking the toggle behaviour of session having id 3014 21 | const promise = new Promise(function(resolve) { 22 | self.find(By.id('title-3014')).then(self.click).then(self.driver.sleep(1000)).then(function() { 23 | resolve(self.find(By.id('desc-3014')).isDisplayed()); 24 | }); 25 | }); 26 | 27 | return promise; 28 | }; 29 | 30 | SchedulePage.getVisibleDates = function(mode) { 31 | const self = this; 32 | 33 | if (mode === 'list') { 34 | return self.find(By.className('list-view')).findElements(By.className('day-filter')).then(self.getElemsDisplayStatus); 35 | } else if (mode === 'calendar') { 36 | return self.find(By.className('calendar-view')).findElements(By.className('calendar')).then(self.getElemsDisplayStatus); 37 | } 38 | 39 | return null; 40 | }; 41 | 42 | SchedulePage.getCurrentView = function() { 43 | // Gives the current status about visibility of the date divs inside the list and the calendar container 44 | const promiseArr = []; 45 | 46 | promiseArr.push(this.getVisibleDates('list')); 47 | promiseArr.push(this.getVisibleDates('calendar')); 48 | return Promise.all(promiseArr); 49 | }; 50 | 51 | SchedulePage.changeDay = function(dayNo) { 52 | const self = this; 53 | const dateId = datesId[dayNo - 1]; 54 | 55 | return self.find(By.id(dateId)).then(self.click).then(self.getCurrentView.bind(self)); 56 | }; 57 | 58 | SchedulePage.toggleMode = function() { 59 | const self = this; 60 | const toggleButtonId = 'page-mode'; 61 | 62 | return self.find(By.id(toggleButtonId)).then(self.click).then(self.getCurrentView.bind(self)); 63 | }; 64 | 65 | SchedulePage.getDownloadDropdown = function() { 66 | const self = this; 67 | const promiseArr = []; 68 | 69 | const clickDropdownButton = function() { 70 | return self.find(By.css('.filter.dropdown .fa-download')).then(function(icon) { 71 | return icon.findElement(By.xpath('..')); 72 | }).then(function(button) { 73 | return button.click().then(self.driver.sleep(1000)); 74 | }); 75 | }; 76 | 77 | return Promise.resolve().then(function() { 78 | return clickDropdownButton(); 79 | }).then(function() { 80 | promiseArr.push(self.find(By.className('download-dropdown')).isDisplayed()); 81 | }).then(function() { 82 | return clickDropdownButton(); 83 | }).then(function() { 84 | promiseArr.push(self.find(By.className('download-dropdown')).isDisplayed()); 85 | }).then(function() { 86 | return Promise.all(promiseArr); 87 | }); 88 | }; 89 | 90 | SchedulePage.checkFilterDirectLink = function() { 91 | const self = this; 92 | const roomTrackIdArr = []; 93 | 94 | function pushId(roomTrackElem) { 95 | roomTrackElem.getAttribute('id').then(function(id) { 96 | roomTrackIdArr.push(id); 97 | }); 98 | } 99 | 100 | return new Promise(function(resolve) { 101 | self.findAll(By.className('schedule-track')).then(function(roomTrackElems) { 102 | roomTrackElems.forEach(function(roomTrackElem) { 103 | roomTrackElem.isDisplayed().then(function(val) { 104 | if (val === true) { 105 | pushId(roomTrackElem); 106 | } 107 | }); 108 | }); 109 | }).then(function() { 110 | resolve(roomTrackIdArr); 111 | }); 112 | }); 113 | }; 114 | 115 | SchedulePage.checkFilterDynamicLink = function() { 116 | const self = this; 117 | const promiseArr = []; 118 | 119 | promiseArr.push(self.activeRooms()); 120 | promiseArr.push(self.activeTracks()); 121 | return Promise.all(promiseArr); 122 | }; 123 | 124 | SchedulePage.checkVideo = function() { 125 | const self = this; 126 | 127 | return new Promise(function(resolve) { 128 | self.find(By.id('title-3015')).then(self.click).then(function() { 129 | self.find(By.id('video-3015')).then(function(elem) { 130 | elem.getAttribute('src').then(function(url) { 131 | resolve(self.isLinkBroken(url)); 132 | }); 133 | }); 134 | }); 135 | }); 136 | }; 137 | 138 | module.exports = SchedulePage; 139 | 140 | -------------------------------------------------------------------------------- /src/selenium/sessionPage.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const BasePage = require('./basePage.js'); 5 | const By = require('selenium-webdriver').By; 6 | 7 | const sessionPage = Object.create(BasePage); 8 | 9 | sessionPage.getSessionTitle = function() { 10 | const self = this; 11 | const titleId = 'title-1090'; 12 | 13 | const sessionPromise = new Promise(function(resolve) { 14 | const title = self.find(By.id(titleId)).getText(); 15 | 16 | resolve(title); 17 | }); 18 | 19 | return sessionPromise; 20 | }; 21 | 22 | sessionPage.getSessionBackgroundColor = function() { 23 | const self = this; 24 | const titleId = 'title-1090'; 25 | 26 | const sessionPromise = new Promise(function(resolve) { 27 | const backgroundColor = self.find(By.id(titleId)).getCssValue('background-color'); 28 | 29 | resolve(backgroundColor); 30 | }); 31 | 32 | return sessionPromise; 33 | }; 34 | 35 | sessionPage.getSpeakerName = function() { 36 | const self = this; 37 | const speaker = 'desc-speaker-name'; 38 | 39 | const sessionPromise = new Promise(function(resolve) { 40 | const title = self.find(By.className(speaker)).getText(); 41 | 42 | resolve(title); 43 | }); 44 | 45 | return sessionPromise; 46 | }; 47 | 48 | sessionPage.jumpToTrack = function() { 49 | const self = this; 50 | const trackClass = 'session-ul'; 51 | const pageVertScrollOffset = 'return window.scrollY'; 52 | 53 | const trackPromise = new Promise(function(resolve) { 54 | self.find(By.className(trackClass)).then(function(elem) { 55 | elem.findElement(By.css('a')).click().then(self.getPageUrl.bind(self)) 56 | .then(function(url) { 57 | self.driver.executeScript(pageVertScrollOffset).then(function(height) { 58 | resolve(height > 0 && url.search('tracks') !== -1); 59 | }); 60 | }); 61 | }); 62 | }); 63 | 64 | return trackPromise; 65 | }; 66 | 67 | sessionPage.jumpToSpeaker = function() { 68 | const self = this; 69 | const speakerClass = 'session-speakers-list'; 70 | const pageVertScrollOffset = 'return window.scrollY'; 71 | 72 | const speakerPromise = new Promise(function(resolve) { 73 | self.find(By.className(speakerClass)).then(function(elem) { 74 | elem.findElement(By.css('a')).click().then(self.getPageUrl.bind(self)) 75 | .then(function(url) { 76 | self.driver.executeScript(pageVertScrollOffset).then(function(height) { 77 | resolve(height > 0 && url.search('speakers') !== -1); 78 | }); 79 | }); 80 | }); 81 | }); 82 | 83 | return speakerPromise; 84 | }; 85 | 86 | sessionPage.jumpToRoom = function() { 87 | const self = this; 88 | const pageVertScrollOffset = 'return window.scrollY'; 89 | 90 | const roomPromise = new Promise(function(resolve) { 91 | self.find(By.css("a[href='../rooms.html#2017-06-30-Plaza_Room_B']")).then(function(elem) { 92 | elem.click().then(self.getPageUrl.bind(self)) 93 | .then(function(url) { 94 | self.driver.executeScript(pageVertScrollOffset).then(function(height) { 95 | resolve(height > 0 && url.search('rooms') !== -1); 96 | }); 97 | }); 98 | }); 99 | }); 100 | 101 | return roomPromise; 102 | }; 103 | 104 | module.exports = sessionPage; 105 | 106 | -------------------------------------------------------------------------------- /src/selenium/speakerPage.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const BasePage = require('./basePage.js'); 5 | const By = require('selenium-webdriver').By; 6 | 7 | const SpeakerPage = Object.create(BasePage); 8 | 9 | SpeakerPage.searchTest = function() { 10 | const idList = ['2330', '2240']; 11 | 12 | return this.commonSearchTest('Mario', idList); 13 | }; 14 | 15 | SpeakerPage.jumpToTrack = function() { 16 | const self = this; 17 | const speakerId = '2330'; 18 | const pageVertScrollOffset = 'return window.scrollY'; 19 | 20 | const trackPromise = new Promise(function(resolve) { 21 | self.find(By.id(speakerId)).then(function(elem) { 22 | self.driver.actions().mouseMove(elem).perform(); 23 | elem.findElement(By.className('sessions')).findElement(By.css('a')).click().then(self.getPageUrl.bind(self)) 24 | .then(function(url) { 25 | self.driver.executeScript(pageVertScrollOffset).then(function(height) { 26 | resolve(height > 0 && url.search('tracks') !== -1); 27 | }); 28 | }); 29 | }); 30 | }); 31 | 32 | return trackPromise; 33 | }; 34 | 35 | SpeakerPage.jumpToSession = function() { 36 | const self = this; 37 | const speakerId = '53'; 38 | const pageVertScrollOffset = 'return window.scrollY'; 39 | 40 | const sessionPromise = new Promise(function(resolve) { 41 | self.find(By.id(speakerId)).then(function(elem) { 42 | self.driver.actions().mouseMove(elem).perform(); 43 | elem.findElement(By.className('sessions')).findElement(By.css('a')).click().then(self.getPageUrl.bind(self)) 44 | .then(function(url) { 45 | self.driver.executeScript(pageVertScrollOffset).then(function() { 46 | resolve(url.search('session') !== -1); 47 | }); 48 | }); 49 | }); 50 | }); 51 | 52 | return sessionPromise; 53 | }; 54 | 55 | SpeakerPage.hoverOverSpeaker = function() { 56 | const self = this; 57 | const speaker = 'speaker'; 58 | const speakerDetailsDiv = 'speaker-social-icons'; 59 | 60 | const promise = new Promise(function(resolve) { 61 | self.find(By.className(speaker)).click().then(self.driver.sleep(1000)).then(function() { 62 | const socialLinkPromise = self.getAllLinks(By.id(speakerDetailsDiv)); 63 | 64 | socialLinkPromise.then(function(socialLinkArr) { 65 | const brokenLinks = self.countBrokenLinks(socialLinkArr.slice(0, 4)); 66 | 67 | resolve(brokenLinks); 68 | }); 69 | }); 70 | }); 71 | 72 | return promise; 73 | }; 74 | 75 | module.exports = SpeakerPage; 76 | -------------------------------------------------------------------------------- /src/selenium/trackPage.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | 4 | const BasePage = require('./basePage.js'); 5 | const By = require('selenium-webdriver').By; 6 | 7 | const TrackPage = Object.create(BasePage); 8 | 9 | // Get number of visible tracks on the page 10 | TrackPage.getNumTracksVisible = function() { 11 | const self = this; 12 | const numPromise = new Promise(function(resolve) { 13 | self.findAll(By.className('track-filter')).then(function(trackElems) { 14 | let counter = 0; 15 | const trackNameArr = []; 16 | 17 | trackElems.forEach(function(trackElem) { 18 | trackElem.isDisplayed().then(function(val) { 19 | trackElem.findElement(By.className('text')).getText().then(function(name) { 20 | if (val && trackNameArr.indexOf(name) === -1) { 21 | trackNameArr.push(name); 22 | } 23 | counter += 1; 24 | if (counter === trackElems.length) { 25 | resolve(trackNameArr.length); 26 | } 27 | }); 28 | }); 29 | }); 30 | }); 31 | }); 32 | 33 | return numPromise; 34 | }; 35 | 36 | TrackPage.checkSharableUrl = function() { 37 | const self = this; 38 | const speakerId = '3014'; 39 | 40 | const promise = new Promise(function(resolve) { 41 | self.find(By.id(speakerId)).click().then(function() { 42 | self.find(By.className('clickable-link')).click().then(self.driver.sleep(1000)).then(function() { 43 | const link = self.find(By.className('speakers-inputbox')).getAttribute('value'); 44 | 45 | self.find(By.id(speakerId)).click().then(self.driver.sleep(1000)).then(function() { 46 | resolve(link); 47 | }); 48 | }); 49 | }); 50 | }); 51 | 52 | return promise; 53 | }; 54 | 55 | TrackPage.checkIsolatedBookmark = function() { 56 | // Sample sessions having ids of 3014 and 3015 being checked for the bookmark feature 57 | const self = this; 58 | const bookmarkSessionsIdsArr = ['3014', '3015', '2907']; 59 | const visibleCheckSessionsIdsArr = ['3014', '3015', '2918', '2907']; 60 | 61 | return self.bookmarkCheck(bookmarkSessionsIdsArr, visibleCheckSessionsIdsArr); 62 | }; 63 | 64 | // Clicks on the Open Tech Track and then returns the number of visible tracks present on the page 65 | TrackPage.checkIsolatedTrackFilter = function() { 66 | const self = this; 67 | 68 | return self.find(By.className('track-room-names')).findElements(By.className('track-name')).then(function(elems) { 69 | // Clicking on the Open Tech Track 70 | return elems[16].click().then(self.getNumTracksVisible.bind(self)); 71 | }); 72 | }; 73 | 74 | TrackPage.toggleSessionElem = function() { 75 | const self = this; 76 | 77 | // Checking the toggle behaviour of session having id 3014 78 | const promise = new Promise(function(resolve) { 79 | self.find(By.id('title-3014')).then(self.click).then(self.driver.sleep(1000)).then(function() { 80 | const promiseArr = []; 81 | 82 | promiseArr.push(self.find(By.id('desc-3014')).isDisplayed()); 83 | promiseArr.push(self.find(By.id('desc2-3014')).isDisplayed()); 84 | resolve(Promise.all(promiseArr)); 85 | }); 86 | }); 87 | 88 | return promise; 89 | }; 90 | 91 | /* Below is the list of selected sessions which are to be tested for visiblity. Sessions having ids 3014, 3015, 3018, 2938 are 92 | of Open Tech Track. The former two are in bookmarked state. Session id 2907 is of Track Hardware and Making and the last session 93 | with id 2941 is of Database Track. */ 94 | 95 | const idArr = ['3014', '3015', '3018', '2938', '2907', '2941']; 96 | 97 | // Get the visibility status of the selected sessions on enabling and disabling the track filter. 98 | TrackPage.filterThenSessionStatus = function(choice) { 99 | const self = this; 100 | const promiseArr = idArr.map(function(elem) { 101 | return self.find(By.id(elem)); 102 | }); 103 | 104 | const statusPromise = new Promise(function(resolve) { 105 | if (choice === 'true') { 106 | // Applying track filter 107 | self.find(By.className('track-room-names')).findElements(By.className('track-name')).then(function(elems) { 108 | // Clicking on the Open Tech Track 109 | elems[16].click().then(self.getElemsDisplayStatus.bind(null, promiseArr)).then(function(ans) { 110 | self.driver.sleep(1000).then(function() { 111 | resolve(ans); 112 | }); 113 | }); 114 | }); 115 | } else { 116 | // Removing applied track filter 117 | self.find(By.id('TrackClearFilter')).click().then(self.getElemsDisplayStatus.bind(null, promiseArr)).then(function(ans) { 118 | self.driver.sleep(1000).then(function() { 119 | resolve(ans); 120 | }); 121 | }); 122 | } 123 | }); 124 | 125 | return statusPromise; 126 | }; 127 | 128 | // Get the visibility status of the selected sessions after search 129 | TrackPage.searchThenSessionStatus = function(text) { 130 | const self = this; 131 | const promiseArr = idArr.map(function(elem) { 132 | return self.find(By.id(elem)); 133 | }); 134 | 135 | return self.resetSearchBar().then(self.search.bind(self, text)).then(self.getElemsDisplayStatus.bind(null, promiseArr)); 136 | }; 137 | 138 | // Get the visibility status of the selected sessions after toggling the bookmark button 139 | TrackPage.starredThenSessionStatus = function() { 140 | const self = this; 141 | const promiseArr = idArr.map(function(elem) { 142 | return self.find(By.id(elem)); 143 | }); 144 | 145 | return self.toggleStarredButton().then(self.getElemsDisplayStatus.bind(null, promiseArr)); 146 | }; 147 | 148 | // Takes in an array of filters, apply them sequentially and send visibility results of selected sessions on each filter 149 | TrackPage.filterCombination = function(filtersArr) { 150 | const self = this; 151 | const filterObjectFunc = { 152 | 'trackselect': function() { 153 | return self.filterThenSessionStatus('true'); 154 | }, 155 | 156 | 'trackunselect': function() { 157 | return self.filterThenSessionStatus('false'); 158 | }, 159 | 160 | 'search': function() { 161 | return self.searchThenSessionStatus('wel'); 162 | }, 163 | 164 | 'unsearch': function() { 165 | return self.searchThenSessionStatus(''); 166 | }, 167 | 168 | 'starred': function() { 169 | return self.starredThenSessionStatus(); 170 | }, 171 | 172 | 'unstarred': function() { 173 | return self.starredThenSessionStatus(); 174 | } 175 | }; 176 | 177 | const serialPromise = function series(arrayOfPromises) { 178 | const results = []; 179 | 180 | return arrayOfPromises.reduce(function(seriesPromise, promise) { 181 | return seriesPromise.then(function() { 182 | return promise.then(function(result) { 183 | results.push(result); 184 | }); 185 | }); 186 | }, Promise.resolve()).then(function() { 187 | return results; 188 | }); 189 | }; 190 | 191 | let filtersArrProm = []; 192 | 193 | filtersArrProm = filtersArr.map(function(filter) { 194 | return filterObjectFunc[filter](); 195 | }); 196 | 197 | return serialPromise(filtersArrProm); 198 | }; 199 | 200 | TrackPage.checkTrackFilterDirectLink = function() { 201 | const self = this; 202 | const trackIdArr = []; 203 | 204 | function pushId(trackElem) { 205 | trackElem.getAttribute('id').then(function(id) { 206 | trackIdArr.push(id); 207 | }); 208 | } 209 | 210 | return new Promise(function(resolve) { 211 | self.findAll(By.className('room-filter')).then(function(trackElems) { 212 | trackElems.forEach(function(trackElem) { 213 | trackElem.isDisplayed().then(function(val) { 214 | if (val === true) { 215 | pushId(trackElem); 216 | } 217 | }); 218 | }); 219 | }).then(function() { 220 | resolve(trackIdArr); 221 | }); 222 | }); 223 | }; 224 | 225 | TrackPage.checkFilterDynamicLink = function() { 226 | const self = this; 227 | const promiseArr = []; 228 | 229 | promiseArr.push(self.activeRooms()); 230 | promiseArr.push(self.activeTracks()); 231 | return Promise.all(promiseArr); 232 | }; 233 | 234 | TrackPage.checkVideo = function() { 235 | const self = this; 236 | 237 | return new Promise(function(resolve) { 238 | self.find(By.id('title-3015')).then(self.click).then(function() { 239 | self.find(By.id('video-3015')).then(function(elem) { 240 | elem.getAttribute('src').then(function(url) { 241 | resolve(self.isLinkBroken(url)); 242 | }); 243 | }); 244 | }); 245 | }); 246 | }; 247 | 248 | module.exports = TrackPage; 249 | -------------------------------------------------------------------------------- /src/www/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 6 | 7 | 8 | 9 |
10 |
11 |
12 |
13 |

Page Not Found

14 |

Oops, the page you're looking for does not exist.

15 |

16 | You may want to head back to the homepage and restart your journey. 17 |

18 | 19 | Take Me Home 20 | 21 |
22 |
23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /src/www/css/main.css: -------------------------------------------------------------------------------- 1 | #btnLive { 2 | display: none; 3 | } 4 | 5 | #btnDownload { 6 | display: none; 7 | } 8 | 9 | input[type="file"] { 10 | display: block; 11 | height: inherit; 12 | } 13 | 14 | section, 15 | center{ 16 | margin-bottom: 20px; 17 | margin-top: 20px; 18 | } 19 | 20 | .upload-progress{ 21 | border-radius: 0; 22 | border: 1.1px solid #cecece; 23 | height: 12px; 24 | margin-top: 4px; 25 | } 26 | 27 | #upload-info{ 28 | background: rgb(237, 237, 237); 29 | border: 0.7px solid rgb(219, 219, 219); 30 | height: 30px; 31 | margin: 0; 32 | padding: 5px 10px; 33 | } 34 | 35 | .progressbar{ 36 | padding-left:10px; 37 | padding-right:10px; 38 | } 39 | 40 | .close{ 41 | line-height: 0.85; 42 | } 43 | 44 | pre#buildLog{ 45 | font-size: 12px; 46 | max-height: 400px; 47 | overflow-y: auto; 48 | text-align: left; 49 | word-break: unset; 50 | } 51 | 52 | #btnLive, #btnDownload, #deploy { 53 | margin-top : 1%; 54 | } 55 | 56 | div.form-div-board { 57 | background: #fffc; 58 | box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.3); 59 | color: #000; 60 | margin-bottom: 50px; 61 | margin-top: 40px; 62 | padding: 20px; 63 | } 64 | 65 | /* When a label appears next to an input, clicking on it should focus the input. */ 66 | li > label { 67 | color: red; 68 | } 69 | li > label[for] { 70 | color: black; 71 | font-weight: normal; 72 | } 73 | -------------------------------------------------------------------------------- /src/www/deploy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Webapp Generator 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |

Thanks for logging in to the github account. Press the button below to start the deployment process

22 |

23 | 24 | 30 |
31 |

32 |
33 | 36 |
37 |

38 |
39 | 40 |
41 |
42 |
43 |
44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/favicon.ico -------------------------------------------------------------------------------- /src/www/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /src/www/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /src/www/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/www/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/www/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/www/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /src/www/icons/Pslab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/icons/Pslab.png -------------------------------------------------------------------------------- /src/www/icons/blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/icons/blog.png -------------------------------------------------------------------------------- /src/www/icons/bug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/icons/bug.png -------------------------------------------------------------------------------- /src/www/icons/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/icons/code.png -------------------------------------------------------------------------------- /src/www/icons/eventyay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/icons/eventyay.png -------------------------------------------------------------------------------- /src/www/icons/fossasia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/icons/fossasia.png -------------------------------------------------------------------------------- /src/www/icons/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/icons/github.png -------------------------------------------------------------------------------- /src/www/icons/loklak.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/icons/loklak.png -------------------------------------------------------------------------------- /src/www/icons/phimp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/icons/phimp.png -------------------------------------------------------------------------------- /src/www/icons/susi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/icons/susi.png -------------------------------------------------------------------------------- /src/www/icons/susper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/open-event-wsgen/a6bb72bb489ea3537c88d66efa515949a65dc055/src/www/icons/susper.png -------------------------------------------------------------------------------- /src/www/js/deployProgress.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-empty-label */ 2 | 'use strict'; 3 | // eslint-disable-next-line no-undef 4 | const socket = io.connect('https://opev-webgen-dev.herokuapp.com/deploy'); 5 | const $deploy = $('#deploy'); 6 | const $abort = $('#abort'); 7 | const $msg = $('#msg'); 8 | const $link = $('#link'); 9 | const $error = $('#error'); 10 | const $progressBar = $('#upload-progress-bar'); 11 | const $progressVal = $('#upload-progress-val'); 12 | const $progressDiv = $('.progress'); 13 | const $title = $('#title'); 14 | 15 | function resetContents() { 16 | $error.html(''); 17 | $link.html(''); 18 | $msg.html(''); 19 | setProgressValues(0); 20 | } 21 | 22 | function showInfo() { 23 | $msg.show(); 24 | $link.show(); 25 | } 26 | 27 | function hideInfo() { 28 | $msg.hide(); 29 | $link.hide(); 30 | $progressDiv.hide(); 31 | } 32 | 33 | function setProgressValues(percent) { 34 | $progressBar.css('width', percent + '%'); 35 | $progressVal.html(percent + '%'); 36 | } 37 | 38 | function addInfoMessage(msg) { 39 | $msg.html(msg); 40 | } 41 | 42 | function addErrorMessage(msg) { 43 | const errorMsg = $("

" + msg + '

'); 44 | 45 | $error.append(errorMsg); 46 | } 47 | 48 | $deploy.click(function() { 49 | socket.emit('start', 'Kick Starting the deployment process'); 50 | resetContents(); 51 | showInfo(); 52 | $deploy.hide(); 53 | $abort.show(); 54 | $title.html('Press the button below to abort the deployment process'); 55 | }); 56 | 57 | $abort.click(function() { 58 | socket.emit('stop', 'Stop the deployment process'); 59 | $abort.hide(); 60 | $error.html(''); 61 | hideInfo(); 62 | addErrorMessage('The process is being aborted'); 63 | }); 64 | 65 | socket.on('progress', function(msg) { 66 | addInfoMessage(msg); 67 | }); 68 | 69 | socket.on('finished', function(msg) { 70 | const link = $(' Here is your deployed Event site. Thanks for using web app generator '); 71 | 72 | link.attr('href', msg); 73 | $link.append(link); 74 | setProgressValues(100); 75 | $abort.hide(); 76 | }); 77 | 78 | socket.on('errorLog', function(msg) { 79 | console.log(msg); 80 | addErrorMessage(msg); 81 | }); 82 | 83 | socket.on('select', function(msg) { 84 | addInfoMessage(msg); 85 | }); 86 | 87 | socket.on('started', function(msg) { 88 | addInfoMessage(msg); 89 | $progressDiv.show(); 90 | }); 91 | 92 | socket.on('fileUpload', function(msg) { 93 | const fileName = msg.file; 94 | const percent = msg.percent; 95 | 96 | addInfoMessage(fileName + ' uploaded'); 97 | setProgressValues(parseInt(percent, 10)); 98 | }); 99 | 100 | socket.on('abort', function(msg) { 101 | console.log(msg); 102 | $deploy.show(); 103 | $error.html(''); 104 | addErrorMessage(msg); 105 | $title.html('Press the button below to re-start the deployment process'); 106 | }); 107 | -------------------------------------------------------------------------------- /test/helper.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const webdriver = require('selenium-webdriver'); 3 | 4 | function getDriver() { 5 | const capabilities = { 6 | browserName: "chrome", 7 | chromeOptions: { 8 | prefs: { 9 | 'downloads': { 10 | 'prompt_for_download': false 11 | } 12 | }, 13 | args: [ 14 | '--window-size=1920,1080', 15 | '--start-maximized' 16 | ] 17 | } 18 | }; 19 | 20 | if (process.env.SAUCE_USERNAME !== undefined) { 21 | return new webdriver.Builder() 22 | .usingServer('http://' + process.env.SAUCE_USERNAME + ':' + process.env.SAUCE_ACCESS_KEY + '@ondemand.saucelabs.com:80/wd/hub') 23 | .withCapabilities({ 24 | 'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER, 25 | build: process.env.TRAVIS_BUILD_NUMBER, 26 | username: process.env.SAUCE_USERNAME, 27 | accessKey: process.env.SAUCE_ACCESS_KEY, 28 | ...capabilities 29 | }).build(); 30 | } else { 31 | return new webdriver.Builder() 32 | .withCapabilities(capabilities).build(); 33 | } 34 | } 35 | 36 | module.exports = { 37 | getDriver 38 | } 39 | -------------------------------------------------------------------------------- /test/sessionEventAndCoC.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | const assert = require('chai').assert; 5 | let generator = require('../src/backend/generator.js'); 6 | let app = require('../src/app'); 7 | const { getDriver } = require('./helper'); 8 | let sessionPage = require('../src/selenium/sessionPage.js'); 9 | let eventPage = require('../src/selenium/eventPage.js'); 10 | let cocPage = require('../src/selenium/cocPage.js'); 11 | 12 | describe('app', () => { 13 | describe('run', () => { 14 | it("should run app", () => { 15 | const expressApp = app.getApp(); 16 | assert.equal(expressApp.get('port'), (process.env.PORT || 3000)); 17 | }); 18 | }); 19 | 20 | }); 21 | 22 | describe('generate', function() { 23 | describe('.create different event sites and copy assets of overview site', function() { 24 | this.timeout(800000); 25 | 26 | it('should generate the FOSSASIA Summit 2017', function(done) { 27 | let data = {}; 28 | data.body = { 29 | "email": "a@a.com", 30 | "theme": "light", 31 | "name": "Open Event", 32 | "apiendpoint": "https://raw.githubusercontent.com/fossasia/open-event/master/sample/FOSSASIASummit2017/", 33 | "datasource": "eventapi", 34 | "assetmode": "download", 35 | }; 36 | generator.createDistDir(data, 'Socket', function(appFolder) { 37 | assert.equal(appFolder, "a@a.com/FOSSASIASummit2017"); 38 | done(); 39 | }); 40 | }); 41 | 42 | it('should generate the Mozilla All Hands 2017', function(done) { 43 | let data = {}; 44 | data.body = { 45 | "email": "a@a.com", 46 | "theme": "dark", 47 | "name": "Open Event", 48 | "apiendpoint": "https://raw.githubusercontent.com/fossasia/open-event/master/sample/MozillaAllHands17", 49 | "sessionMode": "single", 50 | "datasource": "eventapi", 51 | "assetmode": "download" 52 | }; 53 | generator.createDistDir(data, 'Socket', function(appFolder) { 54 | assert.equal(appFolder, "a@a.com/MozillaAllHands2017"); 55 | done(); 56 | }); 57 | }); 58 | 59 | }); 60 | }); 61 | 62 | describe("Running Selenium tests on Chrome Driver", function() { 63 | this.timeout(600000); 64 | let driver; 65 | 66 | before(function() { 67 | driver = getDriver(); 68 | }); 69 | 70 | after(function() { 71 | return driver.quit(); 72 | }); 73 | 74 | describe('Testing Session page', function() { 75 | before(function() { 76 | sessionPage.init(driver); 77 | sessionPage.visit('http://localhost:3000/live/preview/a@a.com/MozillaAllHands2017/sessions/session_1090.html'); 78 | }); 79 | 80 | it('Get the title of the session', function(done) { 81 | sessionPage.getSessionTitle().then(function(val) { 82 | assert.equal(val, 'IT All Hands (Session of 2 hours) | IT'); 83 | done(); 84 | }).catch(function(err) { 85 | done(err); 86 | }); 87 | }); 88 | 89 | it('Check the background color of the title', function(done) { 90 | sessionPage.getSessionBackgroundColor().then(function(val) { 91 | assert.equal(val, 'rgba(88, 214, 141, 1)'); 92 | done(); 93 | }).catch(function(err) { 94 | done(err); 95 | }); 96 | }); 97 | 98 | it('Get the speaker of the session', function(done) { 99 | sessionPage.getSpeakerName().then(function(val) { 100 | assert.equal(val, 'Alex Fridman'); 101 | done(); 102 | }).catch(function(err) { 103 | done(err); 104 | }); 105 | }); 106 | 107 | it('Jump to tracks page', function(done) { 108 | sessionPage.jumpToTrack().then(function(val) { 109 | assert.equal(val, true); 110 | done(); 111 | }).catch(function(err) { 112 | done(err); 113 | }); 114 | }); 115 | 116 | it('Jump to speakers page', function(done) { 117 | sessionPage.visit('http://localhost:3000/live/preview/a@a.com/MozillaAllHands2017/sessions/session_1090.html'); 118 | sessionPage.jumpToSpeaker().then(function(val) { 119 | assert.equal(val, true); 120 | done(); 121 | }).catch(function(err) { 122 | done(err); 123 | }); 124 | }); 125 | 126 | it('Jump to rooms page', function(done) { 127 | sessionPage.visit('http://localhost:3000/live/preview/a@a.com/MozillaAllHands2017/sessions/session_1090.html'); 128 | sessionPage.jumpToRoom().then(function(val) { 129 | assert.equal(val, true); 130 | done(); 131 | }).catch(function(err) { 132 | done(err); 133 | }); 134 | }); 135 | }); 136 | 137 | describe('Testing event page', function() { 138 | before(function() { 139 | eventPage.init(driver); 140 | eventPage.visit('http://localhost:3000/live/preview/a@a.com/FOSSASIASummit2017'); 141 | }); 142 | 143 | it('Check for Scrollbars', function(done) { 144 | let sizesArr = [ 145 | [300, 600], 146 | [720, 600] 147 | ]; 148 | eventPage.getScrollbarVisibility(sizesArr).then(function(statusArr) { 149 | eventPage.driver.manage().window().maximize(); 150 | assert.deepEqual(statusArr, [false, false]); 151 | done(); 152 | }).catch(function(err) { 153 | done(err); 154 | }); 155 | }); 156 | 157 | it('Checking the title of the page', function(done) { 158 | eventPage.getEventName().then(function(eventName) { 159 | assert.equal(eventName, "FOSSASIA Summit 2017"); 160 | done(); 161 | }).catch(function(err) { 162 | done(err); 163 | }); 164 | }); 165 | 166 | it('Checking the presence of tweet section', function(done) { 167 | eventPage.checkTweetSection().then(function() { 168 | done(); 169 | }).catch(function(err) { 170 | done(err); 171 | }); 172 | }); 173 | 174 | it('Check whether the down button is working or not', function(done) { 175 | eventPage.checkDownButton().then(function(offset) { 176 | assert.equal(offset, 0); 177 | done(); 178 | }).catch(function(err) { 179 | done(err); 180 | }); 181 | }); 182 | 183 | it('Checking the presence of Sponsors section', function(done) { 184 | eventPage.checkSponsorSection().then(function() { 185 | done(); 186 | }).catch(function(err) { 187 | done(err); 188 | }); 189 | }); 190 | 191 | it('Checking the presence of ticket button', function(done) { 192 | eventPage.checkTicketButton().then(function() { 193 | done(); 194 | }).catch(function(err) { 195 | done(err); 196 | }); 197 | }); 198 | 199 | it('Checking the functionality of ticket button', function(done) { 200 | eventPage.checkTicketFunctionality().then(function(brokenLinksCount) { 201 | assert.equal(brokenLinksCount, 0); 202 | done(); 203 | }).catch(function(err) { 204 | done(err); 205 | }); 206 | }); 207 | 208 | it('Checking the background colors for dark theme', function (done) { 209 | eventPage.visit('http://localhost:3000/live/preview/a@a.com/MozillaAllHands2017/index.html'); 210 | eventPage.getBackgroundColor('event').then(function(bgcolorArr) { 211 | assert.deepEqual(bgcolorArr, ['rgba(51, 61, 90, 1)', 'rgba(35, 41, 58, 1)']); 212 | done(); 213 | }).catch(function(err) { 214 | done(err); 215 | }); 216 | }); 217 | 218 | it('Checking broken links in of Sponsors section', function(done) { 219 | eventPage.getSponsorsBrokenLinks().then(function(brokenLinksCount) { 220 | assert.equal(brokenLinksCount, 0); 221 | done(); 222 | }).catch(function(err) { 223 | done(err); 224 | }); 225 | }); 226 | }); 227 | 228 | describe('Testing Code of Conduct page', function(){ 229 | before(function() { 230 | cocPage.init(driver); 231 | cocPage.visit('http://localhost:3000/live/preview/a@a.com/FOSSASIASummit2017/CoC.html') 232 | }); 233 | 234 | it('Checking the presence of Code of Conduct section', function(done) { 235 | cocPage.checkCoCsection().then(function () { 236 | done(); 237 | }).catch(function (err) { 238 | done(err); 239 | }) 240 | }); 241 | 242 | }); 243 | }); 244 | --------------------------------------------------------------------------------