diff --git a/.coveralls.yml b/.coveralls.yml index 9431f11..98b88c5 100644 --- a/.coveralls.yml +++ b/.coveralls.yml @@ -1 +1,2 @@ +service_name: travis-ci repo_token: HdilFXSOLhCFVMjD8SRRhsTj7oRpciOuM \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2ac7755..1b276a1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,13 @@ bower_components c4h_keys.txt .env .idea/ +.coverdata +coverage +Procfile +.coverrun +.vscode +gruntfile.js +debug public/lib .vscode npm-debug.log diff --git a/.karma.conf.js b/.karma.conf.js new file mode 100644 index 0000000..1157d67 --- /dev/null +++ b/.karma.conf.js @@ -0,0 +1,83 @@ +// Karma configuration +// Generated on Fri Jan 27 2017 10:42:09 GMT+0100 (WAT) + +module.exports = function (config) { + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['mocha'], + + + // list of files / patterns to load in the browser + files: [ + 'server.js', + './test/user/model.js', + './test/game/game.js', + './app/models/user.js' + ], + + coverageReporter: { + type: 'lcov', + dir: 'coverage/' + }, + + // list of files to exclude + exclude: [], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + './app/models/user.js': ['coverage'] + }, + + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress', 'coverage', 'coveralls'], + + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: process.env.TRAVIS ? ['Chrome_travis_ci'] : ['Chrome'], + + // Custom launchers for travis. + customLaunchers: { + Chrome_travis_ci: { + base: 'Chrome', + flags: ['--no-sandbox'] + } + }, + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: true, + + // Concurrency level + // how many browser should be started simultaneous + concurrency: Infinity + }) +} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 31ecf34..a2d9401 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,75 @@ +sudo: required +dist: trusty language: node_js node_js: - "6" - "6.1" - "5.11" - - "4.5" - - "4.4" +env: + - DB_URL=mongodb://localhost:27017 /cfh +# global: +# - secure: "Nquwxpu+qT9YS1ZE/6SewrL6/v2V/9EXvSavGsX6kCPmbBCJnsi0eVtPZultU+kNsrfTzMzzgCoqfhDDZRgQOlGct1Hd3c850Pcq+5NsRtsd8mqS2gYc+2iXh +# Ucnuossre/bYBWVVZEmOjiObQpEHaHXST/UO+D8gyezsz4GLo6YTzRqR/1jIZ9crJpHRmApk1JJ0mujKgzXNG1RuJYhVYwYzA44Mrshehop3VAIxO0xY/mehPuF7EDMsuEKl +# 29wS/ck1MW1SXKuirgIKXWwUCuaA1lhispjgJU6KtRw5OC+ETAMMoyz0ryTep6GLpRYmZgcEd/LvXw4F5agacyC5o9bjaI1U5X3a9+4DXN+t1GDj3o9DtlE18aBtY5ERkZRv +# 18eSoGhira4a4akwGrnOrJIkf8U85fETyRLoQLRbzUXI1yLRlotQk7kwltcMYsa/tYI7ro2b8I9rTX6AK0QhSRH++syWDaqIXJLibL90X3pL83bw20D5VSaaysAnVxfDrync +# r6Oi7vGen44OhtWfaN91yugqLH0LZWuW++cZcFSru+WtHkb1q/chLDOlyruIgH62oHVWlgjn8OYTKfl7ugfqY7R336puxe/D+5XpTSCOlFpmgFCgBOhYFaKXaKzrakEUtLwT +# ftpgRBXQzz4vN2dkWEcPClQL2aU5NTY8CM=" +# - secure: "b/8Whcs0xqcMnYQuARw9WdzrjVhiZkuo7H/wrHlYn1I4FuteYJy+gKX2cbaeS5G/wpaCAhoCz5CqUMLPgleFMSiN2KxMpdgp8vewcrRF199tEEtSY+RF9j8ot +# h4tBeHOe1dBrzxWSKmY2Z5Ic5bBrqo4UKSPbzP6RaPC51H5yCmOPA5b8I+LfPjeh8hBDYeXOG2kqwjWJR5TB0qbyBwIU1ptx8FxFej7EgYSmHKvu6amgfOWO7ZDL9gct2BzQ +# zR2uGTK4F5K+axcmm6du495RQkVnNbDZh78HkFXB4vIwbNzmRIs2HvoE/+8t/BeE/lBoR0X8UTmH23yrUHNWgoh+SxHPNPG1Flmk8Y/e0AZbLtsBXjUFXApt584+ptnf0k38 +# ThKDnSbP+dKLI9Dnmqzm/5Vx7jtWJS1hfvs5F6sjc5I5R1gyCKcCYyU0ICCCyBB8dDFz4tyyFVW5fvE6KniF+pD2NZuEOrty38+EmE9TkhTtUdcdHW2udtvSvpYDk5ymVW9G +# 80F/DrRjDfauw/ZG78s9d5LfRn/KwNIM+4oNowu02GYabKSGJiPIWTChurMWcrwleWSOGqaVB1lrLoXJw1aN4cjAdfl9x/PIH33f1W/77xRYpsqz6/N4g6BxU055sEWNWnGA +# WuABYuHdnfnyFFVi8a0uvgoPfvyPva44U8=" +# - secure: "lj9TEajslbTYoHOVNJ9+b3ourAYHi+VJkRvN2qeH61gzOcriwgRKyixIDeL3mNk2KkNyDWmJ19WmhyufydUDOL9loA/zRgSBv1uKbzAv/pe1wxGjF/eLDkuQn +# JdArPoN5TaD2Uxg3AuSphGmdT7atGJ+jXa+lj5WLDL9nK21GUbhpS/HwlzrvXCdUu60qQMIgzQcC95Vv52ZjjBVNioFVfcw6jkvbtTEFrsexeWkMkhNCJmWOv1+/YEPotsFY +# SYYxp4LF8KhRjgnZI8BRTCnJoBzsZL+DPpKpMlaq4pmdP1l2JtxatC2Ew1iT2KrI+f8IN9j0IyceaZ90HfBLbzCHyD1hnSB4kUq26AIt7V0QgSryLQueJujI9LizQoM0HEid +# MVZkIwvPtFZPCR680yu+Rg96LDiIPS/0dbzeILmlzKnFgw3Tpc6q/NUG/a8a4/MAA+xbZVtLdUzszB8gLMBCBmma1WbDjqcyat1a7GwGVBwXKezRNqTbC3B8fdhsf61yIP4m +# gelUuFkDuOQIkf44xdxsM4Oe6ePua/h/IQ9u3/L7noe7de3rIsWVfWyFP3kKTT1GCinW6QuOAVGMFXf6rPiMS1mvliXFVhwqEv1UwMUVUgm0PAyb0w0PuRE/uh1d7+/4fVzp +# YUIj3oJjvJgjhvG5MgrIb40KZJNW4M0cp0=" +# - secure: "r+hFiyVTmbJNtMA0lDArvOVlHyZ7qJ4w8R+xU6HoXolFu7TQA2wOj3lyZ5RLmf62+JvRBBXNRQ46sF7jCg+IWPx/Oxtf+skLtiYAMFmXjyD2qY4ztiqp2+VKW +# Ljx5hcp0dKee7LlljN2g1akJp4Y5Ikl8slFAbZerhkdSPiA4SOah7GCH32HL1p42UyK8gkMtJ01pxqKOEaMgURCEqOP56GVuhc64izHpuIdVCQn81xISIARXiPjl3hig1kTf +# O1+yEZIn+8vW3QHK7bRAKX3Y0wpTuiArMW+kMOekOzSWmPaL9wwW6C98/fVmqnNsOcUL24Xk1vlP1QWjQqiACqz7Z/xVcNgZIkzQQ9gZWq5pbbXV+ZiPxDWD0I3E/YLpjFXr +# vRDXqbUTiRIbkxGFLjz1whUtU/UepQMUASo2r4mGM+EgtZk+Gq/+Aay5yo5j95O90bYmHF+C/OMNt2lV92yR1MGktPPmsEhnKcHP9V6HBacogWTwDHz9NsjH1ZJx1vMh/4pA +# J1Y0JXgca1q+Vj7SHi5zk+q2ENXlVfQJYn0+X5vJjZL1JN8ojoEBuOKNmUd9a0+KXxPlCF0AiokSGKyrQelR7KKd/G49VPNrjBDkNLHVdZ45rI7IRS/gahHTXh90b6LCPoEU +# qbkk5J0s3rWI7Bp1Gdkz625UOXctpC0RsM=" +# - secure: "nFO5ZXoWuUiHGlFNMV1cE581B436otj1MQjKlr1s/FTsZXmtXTitGNkKfVe8ehvslh6JylRz2UPvSwatVe6Juber7NqNyNs1BJSLiGeaV0yHUOrDjNP/PL7va +# jWomnQy4TH814RCFjsr1YjmVsCxOPnwIh5Y6HzbUpRj4UMT602/xHSiLwpn93CByr9a5VlG13bOWxNbCa3EcBkolhYSjlzm0mw6YUPr/VKrHlxF+87R4lPWVk+5bznMlj/Gj +# 22mAOMeqNj0j6V0YWkSufD6LiX719JsTC+YdkCDKOWIXlCMpUnNjqRNosaNDKweimkOL02g43IWeLpw9ERAUMkqlQb21OA9dHSDZSc1jPuS9Eh4/m3wUdI8+wzHSolr59nIB +# ITu/0jhYTr6YfJppTxQHre/lICwRf2VtdwJMF/1lyzMeBu6qM/GS9sKcb4MeTKMQ0hWUS0Tv9qoGScyzY38GAk1wULB5fV3erQHVWdTvuXvpGCGVYCOyZ8T99oofNw1yvFi7 +# NqILgkJ0M8T0rJ/FN+JlzN1c82DBywOgpD4tKUYTZa7Lrn238iie9qrEoFQ8diti7DuX3K/MxPtfIUIvTpRZPXl6adghtBj/LSAdVbomJnFwj/rF5HvlMz8oDAn58pUlFuB5 +# B24XcBYYYqJSCumG5y6Pj33yp84BbfUjU0=" +# - secure: "vRWcV+yh/3R+/rFqbsRdBx+OJzQuKU0x4uVofAm5F1wp83LGRegCcCEi/107QeSPoF78FD9xRenvLYq0Moy/L5b1jgDp/j/AqZlKRP9ASMYXF9xz1foKMtS32 +# 5FQOtG8gU7G8MvoHuQ59X5Z4z/xEN+sMXaTVkk6Z/qz5zofCouMqDCz2gWe40MHCwR5PNXef1XQzRItcHf4QC91H7X5U66yuAj9hgQriVT22AzXHU5L62lXeAaQsV/dMthRv +# 5WwJGztb3L/qCqQXJ1H8afPpTeOdFp0xdjBAGFayIqFWReCnrBgZeKukOz04R+l2uleD94jGLS2nCnF/YYy7kCT7rnbTOZQSFRP4QC2zoPjeXhK4pJIT2rI7NBFRwXdoUxN0 +# xTzSUbM8JHv2JQNnP4gT46C8rygPsxSj1Dy4BJ07p97SdqxgzJ09uJln8as//7YnT+2gr4/EeOYVUqtJW9fas7x0cN5nxJJVxQw1UKF2MS1q1V/72hrYSDk1Ezh+XlIAcVdV +# WJ/nAiALeQPEk7d6W8EggCVZYYec4k2UAPHYE5S6LFb8brh1A5Uv2CTscwh43inN2eusUuincv7BX+uVhxoD5DEWCI4/vIzuOfqy4JS/ufQ6uISYLWlFW4NmtV3c+V59s7IY +# xfTRiVzufv1XKodrC8aKI4hCerpxpbsD8k=" +# - secure: "YqRg6QJX5SNPLS325ojzspwt2oioYp8cHT46JzjXvnBbrCSMUww8OFUZGXh+sVkrjDXR8CrgmyvvAP1srl2UeLsQhmxZHWYQrM3qytEneHr/ZGQ4XZrd6c+Hr +# Jvg7Jrf0HzTcaoSY/Pbd6yfbv3FsyC44EhiYUDP5cSHYOlBE+G0F2UBR0hf0CTDehQuP9ASmTH6nPGdmFNeaZ857uheBImtWAw0zh9cYvAez2aZyRQ5n2R3nPFl4xZYrwvxT +# Y/GpvY6XdjYHrP71rP8BOVTlJa+39kyGhCcTz0zs332ZJhHYAxr45klVctikak968K9su/hh66oBn/ERtDBzQtFenZVK2c7WfOcLTPrla8pKx+mP94ZlyI7dosCYFTAvA006 +# UNpF3FBStt9pPogPv6RI/2SnnieLi3dF5GDcv0loM5TUoQ+zMcnl3qKU8606Lqtdyj4h65UdZcyHILE+wR6BwFcuvc4qyHDD8Z5NOlhh6KPAL6/wmVWHMb5+BneGH1gNM3CI +# Iq+HafNCXdTp+Pb7xLcGHBtAHIjRs/BtUJQBG+Nue0DHiqsutU2DOcuNXeuuHdnlEkia4Z4l6VPNgsgZSKSklf4hdpDiFPaVLorUxk3/zUGRd6BTxw3Wu9tYOFcwWNZVOjXQ +# J2ftcdloLeiMBnGW+tKWbkZPiDJs15KBv4=" +# - secure: "kLMe5MAGSePtQEVhAsJ0/L+a8aLYWn2TaG0G2Ap/iyounn5nSPaTe3a+NzIGBvB/8ncsfR5Xde/9u1DBNdBkk2mkEPRVE6tDP6gG0oDYhJgsDWcNPhwGzcSyZ +# ji7C17v0ntNcWQTc8y3xlZq85SEm+u/7twQx3sOXbZTWUWlJ8D2m6AoKIVfBI15O0f22QjcqBDbE5udWAh3bpJywdfgiMMpW+2ZZqk0Cb4n+oJp4UVIPaUyg6qcUVJQiTVzY +# G7E5pRAl22zkoqud0NJ8bO1RWeMNiJ2tRHEXvL0pQ4ps74WZ033VukIFm2E4+9yGSMlc2+hhVo7ib/nhRUgLum/EBgHvkrDOFpbj53dfyutuFNWyVfgCGBirG1ve/QPPgfKk +# E0EAAFiPNHKK63JvH+YiDlWNY/YbHGrigT/ASL5WGNAMl4Ogq4hZT3f1MHhZyTo6jDbyqGTIlw8Jmqz/YbculHQfWcUb0cgrrdtEBU5bcnpI99kowOvnm9ZNx+ZWpbqfvnAf +# p9a/VIOkI02pAhM+g3GjehzHz98AQtVAA9G2l4rQAm6Ls0Wa8xd8pl8qJInd00WXMBeyr3eHp3+/ex2A3ezV3yl7qJdY/w+Ybhj+o7z6Lz/6myPZc4YQjr5+FyvERTJaD/LC +# EtxcRJ4Rv8KnceLtMwJMX0FMLZJSk0pDco=" +# - secure: "fa/i5q8f6rJxIYreAdAgmqnW/VF5t1914Y3zspimq0ZAmdX+g+nftPJed8MTNgg2o0LfxUmYmxwEQQHtHBSGMXUvRSTv66Mo0UoWaKzjFvQ8/hMc9hn3XZKQk +# LBW/F0Nqr+lkU4RvRYWelhgySuGO5AP1qkNPYKs1NUSegglPXJeSsJcEyvR+X6mSwfl2MCziJsr/XniJ4tdHPNn6zNFHZBMv+2lLwahe6C5diasmOUdp6oDqOe+iCs/Ewvqm +# AEJj3yr9BLob8UUz5OqE0UQyg1BvL6tzsQej3Hr2uZGReAxXWkP9uvExGS3kx4/EAtbfUJWA7Qk7ZV6uvrTrqqkEo4oBgO2cwMOVzPydiv2DtimTSy/430zw8c1BHjeGXUKc +# kkj7Vt73TcyeP3uswTtMl2IvAghcJrF1e7mZIdQQWNkDiAKP59ljW6XZqjvTLN3eEGtiWbWl4zj2ov0Bkjcw+N3vsL1v+u3kt/tdG/HApIJX/AI5PRVaLueQvzdG0STWem46 +# rw1zqIm/JF+7apcXNXgXC7ZXbtqo/i08AYAdvO6NSAsnvUHywUY+pqELQNJyOJAaq8a+aC4ZbHa8T/y5+xZVopVtUwFfj1DJklpP0hsNTvL7BmP3AGx61bAz7c0S3oJuZCFe +# hcOHDm7nxxWxB0bf5Efm/uZaHvzTV6h/Sc=" +# - secure: "oBUUFmccgsCi6RpH6wi/cnYVhqC0eUaoNrpYhc53mF2Iazgm/GWsRw9v1v1idLeCyv4vKTJdrBcD4dL2fgC0vjEyqzD7emRnu0kLwTum6/zCzrAVe2OfUZFep +# 0nzwIdFNXH4HBJvizxghHk18Jv4lqd/0EMHq/uvfhrG0LeNx0or7LpB1GzxNMC9Ekzp46QwMbAqFs/tpfdyy0IbTFRZ4TbwosAR+bciGuX5RNMJsb8r0i8Xpcd7bbIyCHQO+ +# rSfJBirCVWEhbzapjSFxzW4RoKSCMj9TjkrLHnrCVkGBqcCSNqMNjqdtqVZR1L0mtKHOV4PBZRduosgsrcUaLEyxeJkbDCaWJ2DzcpdlJHuSX8wRLtrdkkL8D95EjQtf2UuU +# bQ5a1LA4KhPmKTQR2DBzzAS1B6//5WJyqN1E0PCdfIberZT7INKR+bF0Tu/IjDjvEVl99l5kKgfV/hvlq7tgJrOhHqUKqoTYgNdSg4KuEwPVJMwIrmF3Br5z4kVP1UBkJBzL +# QNNoXiYOu6OrP3z77iyrwl+YBXm65L/55y7sL5fmzcbCOZ72hbi0Bkih4DlTihfdFKNOWzHO4L4ZK6OuPJhHUl1ZxmiHBC85qv4uNRXmoPoROpXU/rzIcvAjEFoomWz5arC5 +# UXZvRI91c6Q8fRCItsApdE0RTnQFq08gbI=" +services: + - mongodb before_script: - - npm install grunt-cli -g \ No newline at end of file + - npm install +after_script: cat ./coverage/**/lcov.info | ./node_modules/.bin/coveralls \ No newline at end of file diff --git a/README.md b/README.md index 11201fc..91e5cb4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Coverage Status](https://coveralls.io/repos/github/andela/project-jiayou-cfh/badge.svg?branch=master)](https://coveralls.io/github/andela/project-jiayou-cfh?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/andela/project-jiayou-cfh/badge.svg?branch=setup%2Fintegrate-coveralls-code-coverage-service-137138317)](https://coveralls.io/github/andela/project-jiayou-cfh?branch=setup%2Fintegrate-coveralls-code-coverage-service-137138317) ![](https://travis-ci.org/andela/project-jiayou-cfh.svg?branch=feature%2Fcreate-travisCI-badge-137138309) diff --git a/app/controllers/users.js b/app/controllers/users.js index 5d58b34..e00ac7b 100755 --- a/app/controllers/users.js +++ b/app/controllers/users.js @@ -21,6 +21,7 @@ exports.signin = function (req, res) { if (!req.user) { res.redirect('/#!/signin?error=invalid'); } else { + console.log(req); res.redirect('/#!/app'); } }; @@ -40,8 +41,10 @@ exports.signup = function (req, res) { * Logout */ exports.signout = function (req, res) { - req.logout(); - res.redirect('/'); + req.logOut(); + req.session.destroy(function (err) { + res.redirect('/'); + }); }; /** diff --git a/app/views/includes/foot.jade b/app/views/includes/foot.jade index ba013bd..24bba05 100755 --- a/app/views/includes/foot.jade +++ b/app/views/includes/foot.jade @@ -10,6 +10,7 @@ script(type='text/javascript', src='/lib/underscore/underscore-min.js') //Bootstrap script(type='text/javascript', src='/lib/bootstrap/dist/js/bootstrap.js') + //AngularJS script(type='text/javascript', src='https://code.angularjs.org/1.5.6/angular.js') script(type='text/javascript', src='https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-animate.min.js') @@ -22,7 +23,8 @@ script(type='text/javascript', src='https://code.angularjs.org/1.1.5/angular-coo script(type='text/javascript', src='https://cdnjs.cloudflare.com/ajax/libs/angular-sanitize/1.6.2/angular-sanitize.js') -//MAterialize + +//Materialize script(type='text/javascript', src='https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js') script(type='text/javascript', src='https://cdn.gitcdn.link/cdn/angular/bower-material/v1.1.3/angular-material.js') diff --git a/app/views/includes/head.jade b/app/views/includes/head.jade index de4521e..9d8f814 100755 --- a/app/views/includes/head.jade +++ b/app/views/includes/head.jade @@ -28,6 +28,7 @@ head meta(property='fb:admins', content='APP_ADMIN') link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.css') + link(rel='stylesheet', href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic') link(rel='stylesheet', href='https://cdn.gitcdn.link/cdn/angular/bower-material/v1.1.3/angular-material.css') link(rel='stylesheet', href='https://material.angularjs.org/1.1.3/docs.css') diff --git a/config/passport.js b/config/passport.js index 20a185b..ff6814e 100755 --- a/config/passport.js +++ b/config/passport.js @@ -92,7 +92,9 @@ module.exports = function (passport) { passport.use(new FacebookStrategy({ clientID: process.env.FB_CLIENT_ID, clientSecret: process.env.FB_CLIENT_SECRET, - callbackURL: process.env.FB_CALLBACK_URL + callbackURL: process.env.FB_CALLBACK_URL, + profileFields: ['id', 'email', 'gender', 'link', 'locale', 'name', 'timezone', 'updated_time', 'verified'], + enableProof: true }, function (accessToken, refreshToken, profile, done) { User.findOne({ @@ -113,6 +115,7 @@ module.exports = function (passport) { user.save(function (err) { if (err) console.log(err); user.facebook = null; + console.log(user); return done(err, user); }); } else { diff --git a/config/routes.js b/config/routes.js index 08984bb..1a9dc45 100755 --- a/config/routes.js +++ b/config/routes.js @@ -11,7 +11,6 @@ module.exports = function(app, passport, auth) { var index = require('../app/controllers/index'); var games = require('../app/controllers/games'); - var signup = require('../app/controllers/signup'); var invite = require('../app/controllers/invite'); // Route for sign-in app.post('/api/auth/login', signin.userAuth); diff --git a/config/socket/game.js b/config/socket/game.js index 122d918..5bd62ea 100644 --- a/config/socket/game.js +++ b/config/socket/game.js @@ -37,6 +37,8 @@ function Game(gameID, io) { this.timeLimits = { stateChoosing: 21, stateJudging: 16, + // time limit for czar to draw cards + stateDrawCards: 11, stateResults: 6 }; // setTimeout ID that triggers the czar judging state @@ -48,6 +50,7 @@ function Game(gameID, io) { // Gets cleared if czar finishes judging before time limit. this.judgingTimeout = 0; this.resultsTimeout = 0; + this.drawCardsTimeout = 0; this.guestNames = guestNames.slice(); } @@ -135,14 +138,24 @@ Game.prototype.startGame = function() { console.log(this.gameID, this.state); this.shuffleCards(this.questions); this.shuffleCards(this.answers); + // my code + // this.stateDrawCards(this); this.stateChoosing(this); }; -Game.prototype.sendUpdate = function() { +Game.prototype.sendUpdate = function () { this.io.sockets.in(this.gameID).emit('gameUpdate', this.payload()); }; -Game.prototype.stateChoosing = function(self) { +Game.prototype.stateDrawCards = function (self) { + self.state = 'waiting for czar to draw cards'; + self.sendUpdate(); + self.drawCardsTimeout = setTimeout(function () { + self.stateChoosing(self); + }, self.timeLimits.stateDrawCards * 1000); +}; + +Game.prototype.stateChoosing = function (self) { self.state = "waiting for players to pick"; // console.log(self.gameID,self.state); self.table = []; @@ -178,9 +191,10 @@ Game.prototype.selectFirst = function() { this.players[winnerIndex].points++; this.winnerAutopicked = true; this.stateResults(this); + this.sendNotification(this.players[winnerIndex].username+' has won the round!'); } else { // console.log(this.gameID,'no cards were picked!'); - this.stateChoosing(this); + this.stateDrawCards(this); } }; @@ -215,7 +229,7 @@ Game.prototype.stateResults = function(self) { if (winner !== -1) { self.stateEndGame(winner); } else { - self.stateChoosing(self); + self.stateDrawCards(self); } }, self.timeLimits.stateResults * 1000); }; @@ -421,6 +435,12 @@ Game.prototype.killGame = function() { clearTimeout(this.resultsTimeout); clearTimeout(this.choosingTimeout); clearTimeout(this.judgingTimeout); + clearTimeout(this.drawCardsTimeout); +}; + +Game.prototype.drawCard = function () { + clearTimeout(this.drawCardsTimeout); + this.stateChoosing(this); }; module.exports = Game; \ No newline at end of file diff --git a/config/socket/socket.js b/config/socket/socket.js index 29f8f2f..78b790d 100644 --- a/config/socket/socket.js +++ b/config/socket/socket.js @@ -18,6 +18,7 @@ module.exports = function (io) { io.sockets.on('connection', function (socket) { console.log(socket.id + ' Connected'); + socket.emit('id', { id: socket.id }); @@ -83,6 +84,12 @@ module.exports = function (io) { exitGame(socket); // return { gameDBId: socket.gameDBId, newGameId: socket.gameID, playerLeft: numberOfPlayersLeft }; }); + + socket.on('drawCard', function () { + if (allGames[socket.gameID]) { + allGames[socket.gameID].drawCard(); + } + }); }); var joinGame = function (socket, data) { @@ -106,6 +113,7 @@ module.exports = function (io) { player.premium = user.premium || 0; player.avatar = user.avatar || avatars[Math.floor(Math.random() * 4) + 12]; } + getGame(player, socket, data.room, data.gameDBId, data.createPrivate); }); } else { @@ -193,6 +201,7 @@ module.exports = function (io) { } }; + var createGameWithFriends = function (player, socket, gameDBId) { var isUniqueRoom = false; var uniqueRoom = ''; diff --git a/gulpfile.js b/gulpfile.js index f5a7502..864989d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,94 +1,109 @@ var gulp = require('gulp'); var browserSync = require('browser-sync'); -var mocha = require('gulp-mocha'); +var coveralls = require('gulp-coveralls'); +var jasmine = require('gulp-jasmine'); +var cover = require('gulp-coverage'); var jshint = require('gulp-jshint'); var nodemon = require('gulp-nodemon'); var bower = require('gulp-bower'); var sass = require('gulp-sass'); - +var istanbul = require('gulp-istanbul'); require('dotenv').config(); - // Configuration +// Configuration gulp.task('watch', function () { - gulp.watch(['public/css/common.scss', - 'public/css/views/articles.scss'], ['sass']); + gulp.watch(['public/css/common.scss', + 'public/css/views/articles.scss' + ], ['sass']); - gulp.watch(['public/js/**', 'app/**/*.js'], ['jshint']) - .on('change', browserSync.reload); + gulp.watch(['public/js/**', 'app/**/*.js'], ['jshint']) + .on('change', browserSync.reload); - gulp.watch('public/views/**').on('change', browserSync.reload); + gulp.watch('public/views/**').on('change', browserSync.reload); - gulp.watch('public/css/**', ['sass']) - .on('change', browserSync.reload); + gulp.watch('public/css/**', ['sass']) + .on('change', browserSync.reload); - gulp.watch('app/views/**', ['jade']) - .on('change', browserSync.reload); + gulp.watch('app/views/**', ['jade']) + .on('change', browserSync.reload); }); - //setup jshint +//setup jshint gulp.task('jshint', function () { - return gulp.src([ - 'gulpfile.js', - 'app/**/*.js', - 'test/**/*.js', - 'public/js/**/*.js']) + return gulp.src([ + 'gulpfile.js', + 'app/**/*.js', + 'test/**/*.js', + 'public/js/**/*.js' + ]) .pipe(jshint()) .pipe(jshint.reporter('jshint-stylish')); }); //setup nodemon gulp.task('nodemon', function (done) { - var started = false; - return nodemon({ - script: 'server.js', - ext: 'js', - }).on('start', function(){ - if(!started){ - done(); - started = true; - } - }); + var started = false; + return nodemon({ + script: 'server.js', + ext: 'js', + }).on('start', function () { + if (!started) { + done(); + started = true; + } + }); }); //setup server gulp.task('server', ['nodemon'], function () { - browserSync.init({ - proxy: 'http://localhost:'+process.env.PORT || 5000, - port: 3000, - ui:{ - port: 3001 - }, - reloadOnRestart: true - }); + browserSync.init({ + proxy: 'http://localhost:' + process.env.PORT || 5000, + port: 3000, + ui: { + port: 3001 + }, + reloadOnRestart: true + }); +}); + +gulp.task('coveralls', ['coverage'], function () { + gulp.src('coverage/lcov.info') + .pipe(coveralls()); +}); + + +gulp.task('pre-test', function () { + return gulp.src('./app/**/*.js') + .pipe(istanbul()) + .pipe(istanbul.hookRequire()); + }); -//setup mocha -gulp.task('mochaTest', function () { - gulp.src('test/**/*.js', {read: false}) - // gulp-mocha needs filepaths so you can't have any plugins before it - .pipe(mocha({ reporter: 'spec' })); +gulp.task('coverage', ['pre-test'], function () { + return gulp.src('test/**/*.js') + .pipe(jasmine()) + .pipe(istanbul.writeReports()) + .pipe(istanbul.enforceThresholds({ thresholds: { global: 90 } })); }); //setup sass gulp.task('sass', function () { - return gulp.src('public/css/common.scss') - .pipe(sass()) - .pipe(gulp.dest('public/css/')); + return gulp.src('public/css/common.scss') + .pipe(sass()) + .pipe(gulp.dest('public/css/')); }); - //install bower gulp.task('install', function () { - return bower('./bower_components') - .pipe(gulp.dest('./public/lib')); + return bower('./bower_components') + .pipe(gulp.dest('./public/lib')); }); //Default task(s). -gulp.task('default', ['install','jshint', 'server', 'watch', 'sass'], function (done) { - done(); +gulp.task('default', ['install', 'jshint', 'server', 'watch', 'sass'], function (done) { + done(); }); -//Test task. -gulp.task('test', ['mochaTest'], function (done) { - done(); +gulp.task('test', ['coveralls'], function (done) { + done(); }); diff --git a/package.json b/package.json index 76f5d89..43ed901 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ }, "scripts": { "start": "node node_modules/gulp-cli/bin/gulp", - "test": "echo \"Error: no test specified\"", + "test": "npm run coverage", + "coverage": "node_modules/.bin/istanbul cover jasmine test/**/*.js spec/ && cat ./coverage/lcov.info | node_modules/.bin/coveralls", "postinstall": "node node_modules/gulp-cli/bin/gulp install", "coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls" }, @@ -29,6 +30,7 @@ "connect-flash": "~0.1.1", "connect-mongo": "^1.3.2", "console-stamp": "~0.1.1", + "coveralls": "^2.11.15", "dotenv": "^4.0.0", "express": "~3.4.0", "forever": "latest", @@ -38,6 +40,7 @@ "gulp": "^3.9.1", "gulp-bower": "0.0.13", "gulp-cli": "^1.2.2", + "gulp-istanbul": "^1.1.1", "gulp-jshint": "^2.0.4", "gulp-mocha": "^3.0.1", "gulp-nodemon": "^2.2.1", @@ -46,6 +49,7 @@ "jshint": "^2.9.4", "jshint-stylish": "^2.2.1", "jsonwebtoken": "^7.2.1", + "karma-chrome-launcher": "^2.0.0", "mean-logger": "~0.0.1", "moment": "^2.17.1", "mongodb": "^2.2.19", @@ -78,7 +82,14 @@ "grunt-mocha-test": "~0.7.0", "grunt-nodemon": "~0.1.1", "gulp": "^3.9.1", + "gulp-coverage": "^0.3.38", + "gulp-coveralls": "^0.1.4", + "gulp-istanbul": "^1.1.1", + "gulp-jasmine": "^2.4.2", "gulp-jshint": "^2.0.4", + "gulp-mocha": "^3.0.1", + "gulp-plumber": "^1.1.0", + "instrumentjs": "0.0.3", "jshint": "^2.9.4", "should": "~1.3.0", "supertest": "~0.8.0", @@ -89,4 +100,4 @@ "express-session": "~1.7.6", "ejs": "~1.0.0" } -} +} \ No newline at end of file diff --git a/public/css/common.css b/public/css/common.css index 0176569..6e096c2 100644 --- a/public/css/common.css +++ b/public/css/common.css @@ -865,6 +865,82 @@ body { .gradientButton .donateNow { border-top: 0px solid black !important; } +/*---------------------------- +Card flipping animation start +----------------------------*/ +.back { + -webkit-transition: all 0.5s ease-in-out; + transition: all 0.5s ease-in-out; + position: absolute; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + +.front { + -webkit-transition: all 0.5s ease-in-out; + transition: all 0.5s ease-in-out; + position: absolute; } + +#axis .back.flipped { + -webkit-transform: translate(300px, 5px) rotateX(180deg) rotateY(180deg) scale(1.15, 1.2); + transform: translate(300px, 5px) rotateX(180deg) rotateY(0deg) scale(1.15, 1.2); } + +#axis .front.flipped { + transform: translate(300px, 5px) rotateX(0deg) rotateY(20deg) scale(1.15, 1.2); + -webkit-transform: translate(300px, 5px) rotateX(0deg) rotateY(20deg) scale(1.15, 1.2); + -moz-transform: translate(300px, 5px) rotateX(0deg) rotateY(20deg) scale(1.15, 1.2); } + +#outer { + position: relative; + margin-left: 20px; + margin-right: 40px; + -webkit-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); + box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); + -webkit-transform: rotateX(180deg); + -moz-transform: rotateX(180deg); + -ms-transform: rotateX(180deg); + transform: rotateX(180deg); + cursor: pointer; + background-color: #fff; + background-repeat: no-repeat; + background-size: contain; + background-position: right bottom; + opacity: 50; + width: 250px; } + +.inner { + -ms-transform: rotate(0deg); + /* IE 9 */ + -webkit-transform: rotate(0deg); + /* Chrome, Safari, Opera */ + transform: rotate(0deg); + padding-left: 20px; + padding-top: 20px; } + +#backface { + margin-left: 10px; + width: 260px; + height: 217px; + border-radius: 9.5px; + background-color: #e8eaef; + -webkit-transform: rotate(-2deg); + -moz-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + cursor: pointer; } + +.preload * { + -webkit-transition: 0s !important; + -moz-transition: 0s !important; + -ms-transition: 0s !important; + transition: 0s !important; } + +.czar-click { + padding-top: 70px; } + +/*-------------------------- +Card flipping animation end +---------------------------*/ .chat { width: 300px; height: 80vh; diff --git a/public/css/common.scss b/public/css/common.scss index 8cc4df1..1ccaf4b 100644 --- a/public/css/common.scss +++ b/public/css/common.scss @@ -348,7 +348,7 @@ background-image: linear-gradient(to bottom right, #0B394E 0%, #ABCE8D 100%); &.smallest { font-size: .98em; font-family: 'ubuntu', cursive; - + @include mobile-only{ font-size: 10px; //play with later @@ -389,7 +389,7 @@ html, body, .main-container, .cont, #first-section, #inner-container{ } html{ - + background-attachment: fixed; background-repeat: no-repeat; position: relative; @@ -487,7 +487,7 @@ body{ padding: 0.65em 20px; width: 140px; cursor: pointer; - + @include mobile-only{ font-size: 0.7rem; @@ -498,7 +498,7 @@ body{ } @media only screen and (min-width : 1025) { position: relative; - + } } @@ -871,6 +871,7 @@ body{ #question-container-inner{ width: 100%; height: 100%; + .card{ width: 100%; margin: 0px auto; @@ -982,6 +983,9 @@ body{ } } } + // #question-container-inner:hover .card, .question-container-inner.hover .card { + // transform: rotateY(180deg); + // } } } #info-container{ @@ -1326,6 +1330,89 @@ body{ } } +/*---------------------------- +Card flipping animation start +----------------------------*/ + +.back { + -webkit-transition: all 0.5s ease-in-out; + transition: all 0.5s ease-in-out; + position: absolute; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; +} + +.front { + -webkit-transition: all 0.5s ease-in-out; + transition: all 0.5s ease-in-out; + position: absolute; +} + +#axis .back.flipped { + -webkit-transform: translate(300px, 5px) rotateX(180deg) rotateY(180deg) scale(1.15, 1.20); + transform: translate(300px, 5px) rotateX(180deg) rotateY(0deg) scale(1.15, 1.20); +} + +#axis .front.flipped { + transform: translate(300px, 5px) rotateX(0deg) rotateY(20deg) scale(1.15, 1.20); + -webkit-transform: translate(300px, 5px) rotateX(0deg) rotateY(20deg) scale(1.15, 1.20); + -moz-transform: translate(300px, 5px) rotateX(0deg) rotateY(20deg) scale(1.15, 1.20); +} + +#outer { + position: relative; + margin-left: 20px; + margin-right: 40px; + -webkit-box-shadow: 2px 2px 5px rgba(0,0,0,0.3); + -moz-box-shadow: 2px 2px 5px rgba(0,0,0,0.3); + box-shadow: 2px 2px 5px rgba(0,0,0,0.3); + -webkit-transform: rotateX(180deg); + -moz-transform: rotateX(180deg); + -ms-transform: rotateX(180deg); + transform: rotateX(180deg); + cursor: pointer; + background-color: #fff; + background-repeat: no-repeat; + background-size: contain; + background-position: right bottom; + opacity: 50; + width: 250px; +} + +.inner { + -ms-transform: rotate(0deg); /* IE 9 */ + -webkit-transform: rotate(0deg); /* Chrome, Safari, Opera */ + transform: rotate(0deg); + padding-left: 20px; + padding-top: 20px +} + +#backface { + margin-left: 10px; + width:260px; + height:217px; + border-radius: 9.5px; + background-color: #e8eaef; + -webkit-transform: rotate(-2deg); + -moz-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + cursor: pointer; +} + +.preload * { + -webkit-transition: 0s !important; + -moz-transition: 0s !important; + -ms-transition: 0s !important; + transition: 0s !important; +} + +.czar-click { + padding-top: 70px; +} +/*-------------------------- +Card flipping animation end +---------------------------*/ @mixin ball { // @include right; @@ -1371,20 +1458,20 @@ Chat Title text-transform: uppercase; text-align: left; padding: 10px 10px 10px 50px; - + h1, h2 { font-weight: normal; font-size: 10px; margin: 0; padding: 0; } - + h2 { color: rgba(255, 255, 255, .5); font-size: 8px; letter-spacing: 1px; } - + .avatar { position: absolute; z-index: 1; @@ -1397,7 +1484,7 @@ Chat Title margin: 0; padding: 0; border: 2px solid rgba(255, 255, 255, 0.24); - + img { width: 100%; height: auto; @@ -1415,7 +1502,7 @@ Messages overflow: hidden; position: relative; width: 100%; - + & .messages-content { position: absolute; top: 0; @@ -1424,7 +1511,7 @@ Messages width: 100%; } - + .message { clear: both; float: left; @@ -1437,14 +1524,14 @@ Messages margin-left: 35px; position: relative; text-shadow: 0 1px 1px rgba(0, 0, 0, .2); - + .timestamp { position: absolute; bottom: -15px; font-size: 9px; color: rgba(255, 255, 255, .3); } - + &::before { content: ''; position: absolute; @@ -1453,7 +1540,7 @@ Messages left: 0; border-right: 7px solid transparent; } - + .avatar { position: absolute; z-index: 1; @@ -1472,14 +1559,14 @@ Messages height: auto; } } - + &.message-personal { float: right; color: #fff; text-align: right; background: linear-gradient(120deg, #248A52, #257287); border-radius: 10px 10px 0 10px; - + &::before { left: auto; right: 0; @@ -1489,17 +1576,17 @@ Messages bottom: -4px; } } - + &:last-child { margin-bottom: 30px; } - + &.new { transform: scale(0); transform-origin: 0 0; animation: bounce 500ms linear both; } - + &.loading { &::before { @@ -1527,7 +1614,7 @@ Messages } } } - + } } @@ -1542,7 +1629,7 @@ Message Box padding: 10px; position: relative; opacity: 2; - + & .message-input { background: none; border: none; @@ -1555,11 +1642,11 @@ Message Box padding-right: 20px; width: 265px; } - + textarea:focus:-webkit-placeholder{ color: transparent; } - + & .message-submit { position: absolute; z-index: 1; @@ -1571,11 +1658,11 @@ Message Box font-size: 10px; text-transform: uppercase; line-height: 1; - padding: 6px 10px; + padding: 6px 10px; border-radius: 10px; outline: none!important; transition: background .2s ease; - + &:hover { background: #fff; } @@ -1613,13 +1700,13 @@ Message Box } .player-chip{ - background-image: url(../img/11.png); - background-size: 15px; - width: 15px; - height: 15px; - position: absolute; - z-index: 100; - top: -2px; + background-image: url(../img/11.png); + background-size: 15px; + width: 15px; + height: 15px; + position: absolute; + z-index: 100; + top: -2px; right: 50px } @@ -1635,7 +1722,7 @@ Message Box } .player-card{ background-color: whitesmoke; - + } .is-czar { @@ -1652,18 +1739,18 @@ Message Box .question-top { justify-content: center; - margin-bottom: 20px; + margin-bottom: 20px; margin-top:10px; } #question-container { - font-family: ubuntu; - text-align: center; + font-family: ubuntu; + text-align: center; padding-top: 15px; } .questions { - margin-left: unset; + margin-left: unset; margin-right: auto; } @@ -1672,13 +1759,13 @@ Message Box } #waiting-for-players { - padding-left: 17px; + padding-left: 17px; font-size: 15px; font-family: ubuntu; } #cfh-icon { - font-size: 30px; - font-family: ubuntu; + font-size: 30px; + font-family: ubuntu; padding-left: 70px; -} \ No newline at end of file +} diff --git a/public/css/style.css b/public/css/style.css index e5ec995..44bef8b 100755 --- a/public/css/style.css +++ b/public/css/style.css @@ -446,6 +446,19 @@ padding-right: 10px; } + .draw-card-icon{ + background-image:url('../img/deck-card.jpg'); + background-repeat:no-repeat; + background-size:contain; + background-position:center; + height: 200px; + cursor: pointer; +} + +.text-center { + text-align: center; +} + #login-buttons { text-align: center; } diff --git a/public/img/deck-card.jpg b/public/img/deck-card.jpg new file mode 100644 index 0000000..3d02ada Binary files /dev/null and b/public/img/deck-card.jpg differ diff --git a/public/js/controllers/game.js b/public/js/controllers/game.js index c1b00d8..da7c1ce 100644 --- a/public/js/controllers/game.js +++ b/public/js/controllers/game.js @@ -1,14 +1,17 @@ angular.module('mean.system') .controller('GameController', ['$scope', 'game', '$timeout', '$location', 'MakeAWishFactsService', '$http', '$dialog', 'gameModals', function ($scope, game, $timeout, $location, MakeAWishFactsService, $http, $dialog, gameModals) { - $scope.hasPickedCards = false; - $scope.winningCardPicked = false; - $scope.showTable = false; - $scope.modalShown = false; - $scope.game = game; - $scope.pickedCards = []; - var makeAWishFacts = MakeAWishFactsService.getMakeAWishFacts(); - $scope.makeAWishFact = makeAWishFacts.pop(); - + Materialize.toast('Welcome!', 4000); + $scope.hasPickedCards = false; + $scope.winningCardPicked = false; + $scope.showTable = false; + $scope.modalShown = false; + // boolean that tracks if the card deck has been clicked + $scope.cardDeckClicked = false; + $scope.game = game; + $scope.pickedCards = []; + var makeAWishFacts = MakeAWishFactsService.getMakeAWishFacts(); + $scope.makeAWishFact = makeAWishFacts.pop(); + $scope.pickCard = function (card) { if (!$scope.hasPickedCards) { if ($scope.pickedCards.indexOf(card.id) < 0) { @@ -19,168 +22,193 @@ angular.module('mean.system') } else if (game.curQuestion.numAnswers === 2 && $scope.pickedCards.length === 2) { // delay and send - $scope.hasPickedCards = true; - $timeout($scope.sendPickedCards, 300); + $scope.hasPickedCards = true; + $timeout($scope.sendPickedCards, 300); + } } } - } - }; - $scope.pointerCursorStyle = function () { - if ($scope.isCzar() && $scope.game.state === 'waiting for czar to decide') { - return { - 'cursor': 'pointer' - }; - } else { - $scope.pickedCards.pop(); - } - }; - - $scope.getEmail = function () { - $scope.canSend = false; - $http({ - method: 'GET', - url: '/api/userEmail' - }).then(function successCallback(response) { - var data = response.data; - $scope.emails = data; - }, function errorCallback(response) { - }); - }; + $scope.pointerCursorStyle = function () { + if ($scope.isCzar() && $scope.game.state === 'waiting for czar to decide') { + return { cursor: 'pointer' }; + } + return {}; + }; + + $scope.getEmail = function () { + $scope.canSend = false; + $http({ + method: 'GET', + url: '/api/userEmail' + }).then(function successCallback(response) { + var data = response.data; + $scope.emails = data; + }, function errorCallback(response) { + }); + }; - $scope.checkAll = function () { - $scope.selected = angular.copy($scope.emails); - }; + $scope.checkAll = function () { + $scope.selected = angular.copy($scope.emails); + }; - $scope.uncheckAll = function () { - $scope.selected = angular.copy([]); - }; + $scope.uncheckAll = function () { + $scope.selected = angular.copy([]); + }; + + $scope.sentEmails = []; + $scope.canSend = false; + $scope.cantSend = []; - $scope.sentEmails = []; - $scope.canSend = false; - $scope.cantSend = []; - $scope.sendInvite = function () { - array = []; - var selectedEmail = document.getElementById('select').value; - var currentUser = localStorage.getItem('Email'); - if (currentUser !== selectedEmail) { - array.push({ email: selectedEmail }); - if ($scope.sentEmails.indexOf(selectedEmail) === -1) { - $scope.sentEmails.push(selectedEmail); + $scope.sendInvite = function () { + array = []; + var selectedEmail = document.getElementById('select').value; + var currentUser = localStorage.getItem('Email'); + if (currentUser !== selectedEmail) { + array.push({ email: selectedEmail }); + if ($scope.sentEmails.indexOf(selectedEmail) === -1) { + $scope.sentEmails.push(selectedEmail); + } else { + $scope.cantSend.push(selectedEmail); + } + if ($scope.sentEmails.length > 11) { + $scope.canSend = false; + } else { + $scope.canSend = true; + } + if ($scope.canSend) { + $http.post('/api/search/users', { emailArray: array }).success(function (res) { + if (res.statusCode === 202) { + $scope.showSuccessAlert = true; + $scope.timer(5000); + } else { + $location.path('/#!/signup'); + } + }); + } else { + $scope.showAlert2 = true; + $scope.timer(4000); + } } else { - $scope.cantSend.push(selectedEmail); + $scope.showWarningAlert = true; + $scope.timer(5000); } - if ($scope.sentEmails.length > 11) { - $scope.canSend = false; - } else { - $scope.canSend = true; + document.getElementById('select').value = ''; + }; + + $scope.timer = function (howLong) { + $timeout(function () { + $scope.showSuccessAlert = false; + $scope.showWarningAlert = false; + $scope.showAlert2 = false; + }, howLong); + }; + $scope.checkFirst = function () { + $scope.user.emails.splice(0, $scope.user.roles.length); + $scope.user.emails.push('guest'); + }; + + $scope.sendPickedCards = function () { + game.pickCards($scope.pickedCards); + $scope.showTable = true; + }; + + $scope.cardIsFirstSelected = function (card) { + if (game.curQuestion.numAnswers > 1) { + return card === $scope.pickedCards[0]; } - if ($scope.canSend) { - $http.post('/api/search/users', { emailArray: array }).success(function (res) { - if (res.statusCode === 202) { - $scope.showSuccessAlert = true; - $scope.timer(5000); - } else { - $location.path('/#!/signup'); - } - }); - } else { - $scope.showAlert2 = true; - $scope.timer(4000); + return false; + }; + + $scope.cardIsSecondSelected = function (card) { + if (game.curQuestion.numAnswers > 1) { + return card === $scope.pickedCards[1]; } - } else { - $scope.showWarningAlert = true; - $scope.timer(5000); - } - document.getElementById('select').value = ''; - }; + return false; + }; - $scope.timer = function (howLong) { - $timeout(function () { - $scope.showSuccessAlert = false; - $scope.showWarningAlert = false; - $scope.showAlert2 = false; - }, howLong); - }; - $scope.checkFirst = function () { - $scope.user.emails.splice(0, $scope.user.roles.length); - $scope.user.emails.push('guest'); - }; + $scope.firstAnswer = function ($index) { + if ($index % 2 === 0 && game.curQuestion.numAnswers > 1) { + return true; + } + return false; + }; - $scope.sendPickedCards = function () { - game.pickCards($scope.pickedCards); - $scope.showTable = true; - }; + $scope.secondAnswer = function ($index) { + if ($index % 2 === 1 && game.curQuestion.numAnswers > 1) { + return true; + } + return false; + }; - $scope.cardIsFirstSelected = function (card) { - if (game.curQuestion.numAnswers > 1) { - return card === $scope.pickedCards[0]; - } - return false; - }; + $scope.showFirst = function (card) { + return game.curQuestion.numAnswers > 1 && $scope.pickedCards[0] === card.id; + }; - $scope.cardIsSecondSelected = function (card) { - if (game.curQuestion.numAnswers > 1) { - return card === $scope.pickedCards[1]; - } - return false; - }; + $scope.showSecond = function (card) { + return game.curQuestion.numAnswers > 1 && $scope.pickedCards[1] === card.id; + }; - $scope.firstAnswer = function ($index) { - if ($index % 2 === 0 && game.curQuestion.numAnswers > 1) { - return true; - } - return false; - }; + $scope.isCzar = function () { + return game.czar === game.playerIndex; + }; - $scope.secondAnswer = function ($index) { - if ($index % 2 === 1 && game.curQuestion.numAnswers > 1) { - return true; - } - return false; - }; + $scope.isPlayer = function ($index) { + return $index === game.playerIndex; + }; - $scope.showFirst = function (card) { - return game.curQuestion.numAnswers > 1 && $scope.pickedCards[0] === card.id; - }; + $scope.isCustomGame = function () { + return !(/^\d+$/).test(game.gameID) && game.state === 'awaiting players'; + }; - $scope.showSecond = function (card) { - return game.curQuestion.numAnswers > 1 && $scope.pickedCards[1] === card.id; - }; + $scope.isPremium = function ($index) { + return game.players[$index].premium; + }; - $scope.isCzar = function () { - return game.czar === game.playerIndex; - }; + $scope.currentCzar = function ($index) { + return $index === game.czar; + }; - $scope.isPlayer = function ($index) { - return $index === game.playerIndex; - }; + $scope.winningColor = function ($index) { + if (game.winningCardPlayer !== -1 && $index === game.winningCard) { + return $scope.colors[game.players[game.winningCardPlayer].color]; + } + return '#f9f9f9'; + }; - $scope.isCustomGame = function () { - return !(/^\d+$/).test(game.gameID) && game.state === 'awaiting players'; - }; + $scope.pickWinning = function (winningSet) { + if ($scope.isCzar()) { + game.pickWinning(winningSet.card[0]); + $scope.winningCardPicked = true; + } + }; - $scope.isPremium = function ($index) { - return game.players[$index].premium; - }; + $scope.winnerPicked = function () { + return game.winningCard !== -1; + }; - $scope.currentCzar = function ($index) { - return $index === game.czar; - }; + $scope.startGame = function () { + game.startGame(); + }; - $scope.winningColor = function ($index) { - if (game.winningCardPlayer !== -1 && $index === game.winningCard) { - return $scope.colors[game.players[game.winningCardPlayer].color]; - } - return '#f9f9f9'; - }; + $scope.abandonGame = function () { + // sessionStorage.clear(); + sessionStorage.removeItem('guest'); + game.leaveGame(); + $location.path('/'); + }; - $scope.pickWinning = function (winningSet) { - if ($scope.isCzar()) { - game.pickWinning(winningSet.card[0]); - $scope.winningCardPicked = true; - } - }; + $scope.gameState = { + awaitingPlayers: function () { + return $scope.game.state === 'awaiting players'; + }, + + ended: function () { + return $scope.game.state === 'game ended'; + }, + + dissolved: function () { + return $scope.game.state === 'game dissolved'; + }, $scope.abandonGame = function (event) { var dialogDetails = { title: "Exit Game", @@ -211,70 +239,98 @@ angular.module('mean.system') }).error(function (err) { // $scope.startGameStatus = false; // $scope.showDialog(); - }); - $location.path('/'); - } - }; + }); + $location.path('/'); + } + }; + awaitingCzar: function () { + return $scope.game.state === 'waiting for czar to decide'; + }, - $scope.winnerPicked = function () { - return game.winningCard !== -1; - }; + winnerChosen: function () { + return $scope.game.state === 'winner has been chosen'; + }, - $scope.startGame = function () { - game.startGame(); - }; + noWinner: function () { + return game.gameWinner === -1; + }, + userWon: function () { + return game.gameWinner === game.playerIndex; + }, + userLost: function () { + return game.gameWinner !== game.playerIndex; + }, + awaitingDrawCard: function () { + return $scope.game.state === 'waiting for czar to draw cards'; + } + }; // Catches changes to round to update when no players pick card // (because game.state remains the same) - $scope.$watch('game.round', function () { - $scope.hasPickedCards = false; - $scope.showTable = false; - $scope.winningCardPicked = false; - $scope.makeAWishFact = makeAWishFacts.pop(); - if (!makeAWishFacts.length) { - makeAWishFacts = MakeAWishFactsService.getMakeAWishFacts(); - } - $scope.pickedCards = []; - }); + $scope.$watch('game.round', function () { + $scope.hasPickedCards = false; + $scope.showTable = false; + $scope.winningCardPicked = false; + $scope.makeAWishFact = makeAWishFacts.pop(); + if (!makeAWishFacts.length) { + makeAWishFacts = MakeAWishFactsService.getMakeAWishFacts(); + } + $scope.pickedCards = []; + }); // In case player doesn't pick a card in time, show the table - $scope.$watch('game.state', function () { - if (game.state === 'waiting for czar to decide' && $scope.showTable === false) { - $scope.showTable = true; - } - }); + $scope.$watch('game.state', function () { + if (game.state === 'waiting for czar to decide' && $scope.showTable === false) { + $scope.showTable = true; + } + }); - $scope.$watch('game.gameID', function () { - if (game.gameID && game.state === 'awaiting players') { - if (!$scope.isCustomGame() && $location.search().game) { + $scope.$watch('game.gameID', function () { + if (game.gameID && game.state === 'awaiting players') { + if (!$scope.isCustomGame() && $location.search().game) { // If the player didn't successfully enter the request room, // reset the URL so they don't think they're in the requested room. - $location.search({}); - } else if ($scope.isCustomGame() && !$location.search().game) { + $location.search({}); + } else if ($scope.isCustomGame() && !$location.search().game) { // Once the game ID is set, update the URL if this is a game with friends, // where the link is meant to be shared. + $location.search({ game: game.gameID }); + if (!$scope.modalShown) { + setTimeout(function () { + var link = document.URL; + var txt = 'Give the following link to your friends so they can join your game: '; + $('#lobby-how-to-play').text(txt); - $location.search({ game: game.gameID }); - if (!$scope.modalShown) { - setTimeout(function () { - var link = document.URL; - var txt = 'Give the following link to your friends so they can join your game: '; - $('#lobby-how-to-play').text(txt); - $('#oh-el').css({ 'text-align': 'center', 'font-size': '22px', 'background': 'white', 'color': 'black' }).text(link); - }, 200); - $scope.modalShown = true; + $('#oh-el').css({ 'text-align': 'center', 'font-size': '22px', 'background': 'white', 'color': 'black' }).text(link); + }, 200); + $scope.modalShown = true; + } } } + }); + + if ($location.search().game && !(/^\d+$/).test($location.search().game)) { + game.joinGame('joinGame', $location.search().game); + } else if ($location.search().custom) { + var gameDBId = localStorage.getItem("gameDBId"); + game.joinGame('joinGame', null, gameDBId, true); + } else { + game.joinGame(); } - }); - - if ($location.search().game && !(/^\d+$/).test($location.search().game)) { - game.joinGame('joinGame', $location.search().game); - } else if ($location.search().custom) { - var gameDBId = localStorage.getItem("gameDBId"); - game.joinGame('joinGame', null, gameDBId, true); - } else { - game.joinGame(); - } -}]); + $scope.drawCard = () => { + if (game.state === 'waiting for czar to draw cards' && !$scope.isCzar()) { + Materialize.toast('You are not the czar!'); + } else if (game.state === 'waiting for czar to draw cards' && $scope.isCzar()) { + // Ensure only card czar choose question for next round + game.drawCard(); + /** + * Flip cards. First set cardDeckClicked to true only when czar clicks + * the card deck + */ + $scope.cardDeckClicked = true; + } else { + Materialize.toast('Wait for czar to choose next question!', 4000); + } + }; + }]); diff --git a/public/js/controllers/index.js b/public/js/controllers/index.js index ce4552f..0cf7d93 100644 --- a/public/js/controllers/index.js +++ b/public/js/controllers/index.js @@ -97,7 +97,12 @@ angular.module('mean.system') var signInFailure = function (err) { $scope.userActive = false; }; - + + $scope.userLogin = function () { + authService.signIn($scope.credentials.userEmail, $scope.credentials.userPassword).then(signInSuccess, signInFailure); + }; + + var signUpSuccess = function (res) { if (res.success) { // Write token to local storage diff --git a/public/js/directives.js b/public/js/directives.js index 3711a81..594850c 100644 --- a/public/js/directives.js +++ b/public/js/directives.js @@ -72,12 +72,32 @@ angular.module('mean.directives', []) scope.showOptions = true; scope.showNavBar = true; scope.signOut = false; - + if ((localStorage.getItem('JWT') && localStorage.getItem('Email')) || localStorage.getItem('jwtToken') || localStorage.getItem('sign_in')) { scope.showNavBar = false; scope.signOut = true; } + if (sessionStorage.getItem('socialPlayer')) { + // when user logs in with social media, hide sign in button + scope.showNavBar = false; + scope.signOut = true; + } else if (sessionStorage.getItem('guestPlayer')) { + scope.showNavBar = true; + } + scope.playAsGuest = function () { + sessionStorage.setItem('guestPlayer', 'true'); + }; + + /** + * function that gets called when a user signs in with a social + * media account + * @returns {undefined} + */ + scope.socialPlayer = function () { + sessionStorage.setItem('socialPlayer', 'true'); + }; + if (localStorage.getItem('JWT')) { // Fix ?? // set alert message to true for 4000ms @@ -87,11 +107,8 @@ angular.module('mean.directives', []) } scope.userLogout = function () { // remove the JWT, email and expDate on logout - localStorage.removeItem('JWT'); - localStorage.removeItem('Email'); - localStorage.removeItem('expDate'); - localStorage.removeItem('jwtToken'); - localStorage.removeItem('sign_in'); + localStorage.clear(); + sessionStorage.removeItem('socialPlayer'); }; } }; diff --git a/public/js/services/game.js b/public/js/services/game.js index fd1a395..564d457 100644 --- a/public/js/services/game.js +++ b/public/js/services/game.js @@ -91,6 +91,9 @@ angular.module('mean.system') data.state !== 'game ended' && data.state !== 'game dissolved') { game.time = game.timeLimits.stateChoosing - 1; timeSetViaUpdate = true; + } else if (newState && data.state === 'waiting for czar to draw cards') { + game.time = game.timeLimits.stateDrawCards - 1; + timeSetViaUpdate = true; } else if (newState && data.state === 'waiting for czar to decide') { game.time = game.timeLimits.stateJudging - 1; timeSetViaUpdate = true; @@ -161,6 +164,22 @@ angular.module('mean.system') } else { addToNotificationQueue('Select TWO answers!'); } + } else if (data.state === 'waiting for czar to draw cards') { + if (game.czar === game.playerIndex) { + // addToNotificationQueue('Click to Draw the Cards!'); + } else { + // addToNotificationQueue('The czar is drawing the cards...'); + } + } else if (data.state === 'winner has been chosen' && + game.curQuestion.text.indexOf('') > -1) { + game.curQuestion = data.curQuestion; + } else if (data.state === 'awaiting players') { + joinOverrideTimeout = $timeout(function () { + game.joinOverride = true; + }, 15000); + } else if (data.state === 'game dissolved' || data.state === 'game ended') { + game.players[game.playerIndex].hand = []; + game.time = 0; } }); @@ -188,6 +207,10 @@ angular.module('mean.system') game.pickWinning = function(card) { socket.emit('pickWinning',{card: card.id}); }; - decrementTime(); + +game.drawCard = function() { + socket.emit('drawCard'); + }; + decrementTime(); return game; }]); diff --git a/public/views/answers.html b/public/views/answers.html index 61fccbd..c51332b 100644 --- a/public/views/answers.html +++ b/public/views/answers.html @@ -1,174 +1,120 @@ -
-
-
-
-
- -
-
-

- 1 - 2 -
-
+
+
+
+
+
+ +
+
+

+ 1 + 2
- +
+
+
-
- - 1 - 2 +
+ + 1 + 2
-
-
-
-
    -
  • -

    How To Play

    -
  • -
    - -
  • - Each player begins with, and will always have, 10 white answer cards. -
  • -
    -
  • -
    For each round, one player is randomly chosen as the Card Czar.
    -
  • -
    -
  • -
    Everyone else answers the black question card by clicking on the answer card they want to use.
    -
  • -
    -
  • -
    The Card Czar then picks a favorite answer, and whoever played that answer wins the round.
    -
  • -
    -
  • -
    *Want to adorn your avatar with a glorious crown? Donate to charity after the game!
    -
  • -
  • - -
  • -
-
- - Donate Now -
- - +
+
    +
  • +

    How To Play

    +
  • +
    + +
  • + Each player begins with, and will always have, 10 white answer cards. +
  • +
    +
  • +
    For each round, one player is randomly chosen as the Card Czar.
    +
  • +
    +
  • +
    Everyone else answers the black question card by clicking on the answer card + they want to use.
    +
  • +
    +
  • +
    The Card Czar then picks a favorite answer, and whoever played that answer + wins the round.
    +
  • +
    +
  • +
    *Want to adorn your avatar with a glorious crown? Donate to charity after the + game! +
    +
  • +
+
-
-
-

What would you like to do now?

- You might consider donating to charity to atone for the horrifying answers you've submitted. Donating will also place a lovely - crown on your avatar's head. -
-
-

What would you like to do now?

- Help yourself to another game or help a child in need? Donating will also place a lovely crown on your avatar's head. +
+
+

What would you like to do now?

+ You might consider donating to charity to atone for the horrifying answers you've + submitted. Donating will also place a lovely crown on your avatar's head. +
+
+

What would you like to do now?

+ Help yourself to another game or help a child in need? Donating will also place a + lovely crown on your avatar's head. +
+ +
-
- You are the Card Czar.
- Players are choosing their answers. Prepare to select a winner. +
+ You are the Card Czar.
+ Players are choosing their answers. Prepare to select a winner. +
+
+
Did you know?
+
+ {{ makeAWishFact }}
-
-
Did you know?
-
- {{ makeAWishFact }} -
-
- -
+
+
+
- \ No newline at end of file diff --git a/public/views/app.html b/public/views/app.html index 9cde6b4..324a41e 100644 --- a/public/views/app.html +++ b/public/views/app.html @@ -4,24 +4,31 @@
CFH
-
+ -
-
+
+
+
+
+
+
+
+
+
+
+
+ +
+
{{game.notification}}
-
- - -
-
-
+
+
-
-
- +
+

Click to draw the next question

CARD DECK
@@ -29,39 +36,55 @@
-
-
- - - - +
+

Wait for Czar to draw next question

+
+
+ + +
+
+
+
-
-
+
+
+
+ -
-
+
+
-
-
-
-
-
- - -
+
+
+
+
+
+ +
- +
\ No newline at end of file + + setTimeout(function () { + $('div').removeClass("preload"); + }, 500); + + diff --git a/public/views/header.html b/public/views/header.html index a4945c7..7a8af75 100644 --- a/public/views/header.html +++ b/public/views/header.html @@ -1,4 +1,5 @@ - + - \ No newline at end of file + diff --git a/public/views/index.html b/public/views/index.html index 41d8a30..e7b6738 100644 --- a/public/views/index.html +++ b/public/views/index.html @@ -7,19 +7,23 @@ -

Cards for Humanity

-

Cards for Humanity is a fast-paced online version of the popular card game, Cards Against Humanity, that gives you the opportunity to donate to children in need - all while remaining as despicable and awkward as you naturally are. -

- +

Cards for Humanity is a fast-paced online version of the popular card game, + Cards Against Humanity, that gives you the opportunity to donate to children + in need - all while remaining as despicable and awkward as you naturally + are.

@@ -62,18 +66,20 @@

HOW TO PLAY

var span = document.getElementsByClassName("close")[0]; // When the user clicks the button, open the modal - btn.onclick = function() { + btn.onclick = function () { modal.style.display = "block"; }; // When the user clicks on (x), close the modal - span.onclick = function() { + span.onclick = function () { modal.style.display = "none"; }; // When the user clicks anywhere outside of the modal, close it - window.onclick = function(event) { + window.onclick = function (event) { if (event.target === modal) { modal.style.display = "none"; } }; - \ No newline at end of file + + + diff --git a/public/views/question.html b/public/views/question.html index f021f23..7db3390 100644 --- a/public/views/question.html +++ b/public/views/question.html @@ -1,44 +1,30 @@ - -
+ + +
+
+
+
+

Finding Players

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
{{game.players.length}} / 6
+
Players
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -60,28 +46,31 @@

Finding Players

-
-
-
-
-
- -
-
-
What the!? The game ended because too many people left!
- Our sincere apologies. -
-
-
Congratulations! You won the game, {{game.players[game.playerIndex].username | upperFirstLetter}}!
We hope you feel special. If you'd like to share that special feeling with the world, consider donating to charity. Or just horde it all for - youself. -
-
-
Aw, shucks! {{game.players[game.gameWinner].username | upperFirstLetter }} won the game!
- That makes you a loser, unfortunately. + +
+
+
What the!? The game ended because too many people left!
+ Our sincere apologies. +
+
+
Congratulations! You won the game, {{game.players[game.playerIndex].username + | upperFirstLetter}}!
We hope you feel special. If you'd like to share + that special feeling with the world, consider donating to charity. Or just + horde it all for youself. +
+
+
Aw, shucks! {{game.players[game.gameWinner].username | upperFirstLetter }} + won the game!
+ That makes you a loser, unfortunately. +
-
\ No newline at end of file + +
diff --git a/public/views/signin.html b/public/views/signin.html index b0ae4d3..837f709 100644 --- a/public/views/signin.html +++ b/public/views/signin.html @@ -3,7 +3,6 @@ -
@@ -45,14 +44,18 @@

SIGN IN

...or sign in with:
Don't have an account yet? Sign up
+ +
+
+
@@ -60,4 +63,4 @@
Don't have an account yet? Si - \ No newline at end of file + diff --git a/public/views/timer.html b/public/views/timer.html index 81a31c6..cf22c95 100644 --- a/public/views/timer.html +++ b/public/views/timer.html @@ -1,6 +1,7 @@
Time Remaining Next Round In - Czar Choosing + Czar Choosing
-
\ No newline at end of file +
+ diff --git a/test/game/game.js b/test/game/game.js index c0c3ce7..ab9869d 100644 --- a/test/game/game.js +++ b/test/game/game.js @@ -16,12 +16,13 @@ describe("Game Server",function(){ it('Should accept requests to joinGame', function(done) { var client1 = io.connect(socketURL, options); + var disconnect = function() { client1.disconnect(); done(); }; client1.on('connect', function(data){ - client1.emit('joinGame',{userID:'unauthenticated',room: '', createPrivate: false}); + client1.emit('joinGame',{userID:'unauthenticated',room: '', createPrivate: true}); setTimeout(disconnect,200); }); }); @@ -43,7 +44,7 @@ describe("Game Server",function(){ it('Should announce new user to all users', function(done){ var client1 = io.connect(socketURL, options); - var client2; + var client2, client3; var disconnect = function() { client1.disconnect(); client2.disconnect(); @@ -52,12 +53,22 @@ describe("Game Server",function(){ client1.on('connect', function(data){ client1.emit('joinGame',{userID:'unauthenticated',room: '', createPrivate: false}); client2 = io.connect(socketURL, options); + client3 = io.connect(socketURL, options); client2.on('connect', function(data) { client2.emit('joinGame',{userID:'unauthenticated',room: '', createPrivate: false}); client1.on('notification', function(data) { data.notification.should.match(/ has joined the game\!/); }); }); + client3.on('connect', function(data) { + client3.emit('joinGame',{userID:'unauthenticated',room: '', createPrivate: false}); + client1.on('notification', function(data) { + data.notification.should.match(/ has joined the game\!/); + }); + client2.on('notification', function(data) { + data.notification.should.match(/ has joined the game\!/); + }); + }); setTimeout(disconnect,200); }); }); @@ -164,4 +175,4 @@ describe("Game Server",function(){ }); }); }); -}); +}); \ No newline at end of file diff --git a/test/user/model.js b/test/user/model.js index 4919b7b..9944b55 100644 --- a/test/user/model.js +++ b/test/user/model.js @@ -12,7 +12,7 @@ var user; //The tests describe('', function() { describe('Model User:', function() { - before(function(done) { + beforeEach(function(done) { user = new User({ name: 'Full name', email: 'test@test.com', @@ -40,7 +40,7 @@ describe('', function() { }); }); - after(function(done) { + afterAll(function(done) { done(); }); });