Commit a650201b9e7a69d1f424405cf6c6805a1cdb0362

Authored by Andrew Buss
1 parent 9436dc71d2

don't trust the user's local storage; they could have logged out on a different account

Showing 6 changed files with 21 additions and 29 deletions Inline Diff

angular.module('flashy', [ 1 1 angular.module('flashy', [
'flashy.LogoutController', 2
'flashy.LoginController', 3 2 'flashy.LoginController',
'flashy.RootController', 4 3 'flashy.RootController',
'flashy.FeedController', 5 4 'flashy.FeedController',
'flashy.DeckController', 6 5 'flashy.DeckController',
'flashy.ClassAddController', 7 6 'flashy.ClassAddController',
'flashy.RequestResetController', 8 7 'flashy.RequestResetController',
'flashy.StudyController', 9 8 'flashy.StudyController',
'flashy.UserService', 10 9 'flashy.UserService',
'flashy.FlashcardDirective', 11 10 'flashy.FlashcardDirective',
//'flashy.SelectDirective', 12 11 //'flashy.SelectDirective',
// DOESNT WORK RN 13 12 // DOESNT WORK RN
'flashy.ResetPasswordController', 14 13 'flashy.ResetPasswordController',
'flashy.VerifyEmailController', 15 14 'flashy.VerifyEmailController',
'flashy.CardListController', 16 15 'flashy.CardListController',
'flashy.HelpController', 17 16 'flashy.HelpController',
'flashy.SettingsController', 18 17 'flashy.SettingsController',
'ngCookies']). 19 18 'ngCookies']).
config(function($stateProvider, $urlRouterProvider, $resourceProvider, $httpProvider, $locationProvider) { 20 19 config(function($stateProvider, $urlRouterProvider, $resourceProvider, $httpProvider, $locationProvider) {
'use strict'; 21 20 'use strict';
$httpProvider.defaults.withCredentials = true; 22 21 $httpProvider.defaults.withCredentials = true;
$httpProvider.defaults.xsrfCookieName = 'csrftoken'; 23 22 $httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; 24 23 $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$resourceProvider.defaults.stripTrailingSlashes = false; 25 24 $resourceProvider.defaults.stripTrailingSlashes = false;
var arrayMethods = Object.getOwnPropertyNames(Array.prototype); 26 25 var arrayMethods = Object.getOwnPropertyNames(Array.prototype);
arrayMethods.forEach(attachArrayMethodsToNodeList); 27 26 arrayMethods.forEach(attachArrayMethodsToNodeList);
function attachArrayMethodsToNodeList(methodName) { 28 27 function attachArrayMethodsToNodeList(methodName) {
if (methodName !== 'length') { 29 28 if (methodName !== 'length') {
NodeList.prototype[methodName] = Array.prototype[methodName]; 30 29 NodeList.prototype[methodName] = Array.prototype[methodName];
} 31 30 }
} 32 31 }
33 32
$httpProvider.interceptors.push(function($q, $rootScope) { 34 33 $httpProvider.interceptors.push(function($q, $rootScope) {
return { 35 34 return {
'responseError': function(rejection) { // need a better redirect 36 35 'responseError': function(rejection) { // need a better redirect
if (rejection.status >= 500) { 37 36 if (rejection.status >= 500) {
console.log('got error'); 38 37 console.log('got error');
console.log(rejection); 39 38 console.log(rejection);
$rootScope.$broadcast('server_error', rejection); 40 39 $rootScope.$broadcast('server_error', rejection);
} 41 40 }
if (rejection.status == 403) { 42 41 if (rejection.status == 403) {
console.log(rejection); 43 42 console.log(rejection);
if (rejection.data && rejection.data.detail == 'Please verify your email before continuing') { 44 43 if (rejection.data && rejection.data.detail == 'Please verify your email before continuing') {
UserService.showLockedMessage(); 45 44 UserService.showLockedMessage();
UserService.logout(); 46 45 UserService.logout();
} 47 46 }
} 48 47 }
return $q.reject(rejection); 49 48 return $q.reject(rejection);
} 50 49 }
}; 51 50 };
}); 52 51 });
$locationProvider.html5Mode(true); 53 52 $locationProvider.html5Mode(true);
$urlRouterProvider.otherwise('/404'); 54 53 $urlRouterProvider.otherwise('/404');
var auth_resolve = { 55 54 var auth_resolve = {
authorize: function($q, $state, $stateParams, UserService) { 56 55 authorize: function($q, $state, $stateParams, UserService) {
if (UserService.noAuthRequired($state)) { 57 56 if (UserService.noAuthRequired($state)) {
return console.log('no auth state ' + $state.name); 58 57 return console.log('no auth state ' + $state.name);
} 59 58 }
console.log('resolving user before continuing for ' + $state.name); 60 59 console.log('resolving user before continuing for ' + $state.name);
var redirectAsNeeded = function() { 61 60 var redirectAsNeeded = function() {
if (!UserService.isLoggedIn()) { 62 61 if (!UserService.isLoggedIn()) {
console.log(UserService.getUserData()); 63 62 console.log(UserService.getUserData());
console.log('making the user log in'); 64 63 console.log('making the user log in');
$state.go('login'); 65 64 $state.go('login');
} 66 65 }
if (!UserService.authorizedFor($state, $stateParams)) { 67 66 if (!UserService.authorizedFor($state, $stateParams)) {
console.log('user not authorized for ' + $state.name); 68 67 console.log('user not authorized for ' + $state.name);
$state.go('addclass'); 69 68 $state.go('addclass');
} 70 69 }
}; 71 70 };
if (UserService.isResolved()) return redirectAsNeeded(); 72 71 if (UserService.isResolved()) return redirectAsNeeded();
return UserService.getUserData().then(redirectAsNeeded); 73 72 return UserService.getUserData().then(redirectAsNeeded);
} 74 73 }
}; 75 74 };
$stateProvider. 76 75 $stateProvider.
state('login', { 77 76 state('login', {
url: '/login', 78 77 url: '/login',
templateUrl: 'templates/login.html', 79 78 templateUrl: 'templates/login.html',
controller: 'LoginController' 80 79 controller: 'LoginController'
}). 81
state('logout', { 82
resolve: auth_resolve, 83
url: '/logout', 84
templateUrl: 'templates/logout.html', 85
controller: 'LogoutController' 86
}). 87 80 }).
state('root', { 88 81 state('root', {
resolve: auth_resolve, 89 82 resolve: auth_resolve,
url: '', 90 83 url: '',
controller: 'RootController' 91 84 controller: 'RootController'
}). 92 85 }).
state('feed', { 93 86 state('feed', {
resolve: auth_resolve, 94 87 resolve: auth_resolve,
url: '/feed/{sectionId}', 95 88 url: '/feed/{sectionId}',
templateUrl: 'templates/feed.html', 96 89 templateUrl: 'templates/feed.html',
controller: 'FeedController' 97 90 controller: 'FeedController'
}). 98 91 }).
state('cardlist', { 99 92 state('cardlist', {
resolve: auth_resolve, 100 93 resolve: auth_resolve,
url: '/cards/{sectionId}', 101 94 url: '/cards/{sectionId}',
templateUrl: 'templates/cardlist.html', 102 95 templateUrl: 'templates/cardlist.html',
controller: 'CardListController' 103 96 controller: 'CardListController'
}). 104 97 }).
state('addclass', { 105 98 state('addclass', {
resolve: auth_resolve, 106 99 resolve: auth_resolve,
url: '/addclass', 107 100 url: '/addclass',
templateUrl: 'templates/addclass.html', 108 101 templateUrl: 'templates/addclass.html',
controller: 'ClassAddController' 109 102 controller: 'ClassAddController'
}). 110 103 }).
state('deck', { 111 104 state('deck', {
resolve: auth_resolve, 112 105 resolve: auth_resolve,
url: '/deck/{sectionId}', 113 106 url: '/deck/{sectionId}',
templateUrl: 'templates/deck.html', 114 107 templateUrl: 'templates/deck.html',
controller: 'DeckController' 115 108 controller: 'DeckController'
}). 116 109 }).
state('study', { 117 110 state('study', {
resolve: auth_resolve, 118 111 resolve: auth_resolve,
url: '/study', 119 112 url: '/study',
templateUrl: 'templates/study.html', 120 113 templateUrl: 'templates/study.html',
controller: 'StudyController' 121 114 controller: 'StudyController'
}). 122 115 }).
state('flashcard', { 123 116 state('flashcard', {
resolve: auth_resolve, 124 117 resolve: auth_resolve,
url: '/flashcard', 125 118 url: '/flashcard',
templateUrl: 'templates/flashcard.html', 126 119 templateUrl: 'templates/flashcard.html',
controller: 'FlashcardController' 127 120 controller: 'FlashcardController'
}). 128 121 }).
state('settings', { 129 122 state('settings', {
resolve: auth_resolve, 130 123 resolve: auth_resolve,
url: '/settings', 131 124 url: '/settings',
templateUrl: 'templates/settings.html', 132 125 templateUrl: 'templates/settings.html',
controller: 'SettingsController' 133 126 controller: 'SettingsController'
}). 134 127 }).
state('requestpasswordreset', { 135 128 state('requestpasswordreset', {
url: '/requestpasswordreset', 136 129 url: '/requestpasswordreset',
templateUrl: 'templates/requestpasswordreset.html', 137 130 templateUrl: 'templates/requestpasswordreset.html',
controller: 'RequestResetController' 138 131 controller: 'RequestResetController'
}). 139 132 }).
state('resetpassword', { 140 133 state('resetpassword', {
url: '/resetpassword/{uid}/{token}', 141 134 url: '/resetpassword/{uid}/{token}',
templateUrl: 'templates/resetpassword.html', 142 135 templateUrl: 'templates/resetpassword.html',
controller: 'ResetPasswordController' 143 136 controller: 'ResetPasswordController'
}). 144 137 }).
state('verifyemail', { 145 138 state('verifyemail', {
url: '/verifyemail/{key}', 146 139 url: '/verifyemail/{key}',
templateUrl: 'templates/verifyemail.html', 147 140 templateUrl: 'templates/verifyemail.html',
controller: 'VerifyEmailController' 148 141 controller: 'VerifyEmailController'
}). 149 142 }).
state('404', { 150 143 state('404', {
url: '/404', 151 144 url: '/404',
template: "<h1>This page doesn't exist!</h1>" 152 145 template: "<h1>This page doesn't exist!</h1>"
}). 153 146 }).
state('help', { 154 147 state('help', {
resolve: auth_resolve, 155 148 resolve: auth_resolve,
url: '/help', 156 149 url: '/help',
templateUrl: 'templates/help.html', 157 150 templateUrl: 'templates/help.html',
controller: 'HelpController' 158 151 controller: 'HelpController'
}); 159 152 });
}). 160 153 }).
run(function($rootScope, $state, $stateParams, $location, UserService) { 161 154 run(function($rootScope, $state, $stateParams, $location, UserService) {
$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) { 162 155 $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {
console.log('failed to change state: ' + error); 163 156 console.log('failed to change state: ' + error);
$state.go('login'); 164 157 $state.go('login');
}); 165 158 });
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) { 166 159 $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
if (['feed', 'deck', 'cardlist'].indexOf(toState.name) >= 0) { 167 160 if (['feed', 'deck', 'cardlist'].indexOf(toState.name) >= 0) {
localStorage.setItem('last_state', toState.name); 168 161 localStorage.setItem('last_state', toState.name);
localStorage.setItem('last_state_params', JSON.stringify(toParams)); 169 162 localStorage.setItem('last_state_params', JSON.stringify(toParams));
} 170 163 }
}); 171 164 });
<!DOCTYPE html> 1 1 <!DOCTYPE html>
<html ng-app="flashy"> 2 2 <html ng-app="flashy">
<base href="/app/"> 3 3 <base href="/app/">
<head> 4 4 <head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/> 5 5 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<link rel="stylesheet" 6 6 <link rel="stylesheet"
href="https://ajax.googleapis.com/ajax/libs/angular_material/0.9.0/angular-material.min.css"> 7 7 href="https://ajax.googleapis.com/ajax/libs/angular_material/0.9.0/angular-material.min.css">
8 8
<link rel="stylesheet" href="styles/flashier.css"/> 9 9 <link rel="stylesheet" href="styles/flashier.css"/>
<link rel="stylesheet" href="styles/flashy.css"/> 10 10 <link rel="stylesheet" href="styles/flashy.css"/>
<link 11 11 <link
href='https://fonts.googleapis.com/css?family=Satisfy|Titillium+Web:400,200,200italic,300,600,700,900,700italic,600italic,400italic,300italic' 12 12 href='https://fonts.googleapis.com/css?family=Satisfy|Titillium+Web:400,200,200italic,300,600,700,900,700italic,600italic,400italic,300italic'
rel='stylesheet' type='text/css'> 13 13 rel='stylesheet' type='text/css'>
<title>Flashy</title> 14 14 <title>Flashy</title>
</head> 15 15 </head>
<body ng-controller="RootController"> 16 16 <body ng-controller="RootController">
<header> 17 17 <header>
<nav> 18 18 <nav>
<div class="nav-wrapper"> 19 19 <div class="nav-wrapper">
<a ng-show="UserService.isLoggedIn()" href="#" data-activates="mobile-demo" 20 20 <a ng-show="UserService.isLoggedIn()" href="#" data-activates="mobile-demo"
class="left button-collapse hide-on-med-and-up"><i 21 21 class="left button-collapse hide-on-med-and-up"><i
class="mdi-navigation-menu"></i></a> 22 22 class="mdi-navigation-menu"></i></a>
<!-- User's classes dropdown --> 23 23 <!-- User's classes dropdown -->
<ul id="classDropdown" class="dropdown-content"> 24 24 <ul id="classDropdown" class="dropdown-content">
<li ui-sref-active="active" ng-repeat="section in UserService.getUserData().sections"> 25 25 <li ui-sref-active="active" ng-repeat="section in UserService.getUserData().sections">
<a ui-sref="feed({sectionId:section.id})">{{section.short_name}}</a> 26 26 <a ui-sref="feed({sectionId:section.id})">{{section.short_name}}</a>
</li> 27 27 </li>
<li class="divider"></li> 28 28 <li class="divider"></li>
<li><a ui-sref="addclass">Add Class</a></li> 29 29 <li><a ui-sref="addclass">Add Class</a></li>
</ul> 30 30 </ul>
<ul ng-show="UserService.isLoggedIn()" class="left hide-on-small-and-down"> 31 31 <ul ng-show="UserService.isLoggedIn()" class="left hide-on-small-and-down">
<li><a style="font-size:20px; font-weight:700" class="dropdown-button ng-cloak hide-on-small-and-down" 32 32 <li><a style="font-size:20px; font-weight:700" class="dropdown-button ng-cloak hide-on-small-and-down"
href="#!" 33 33 href="#!"
data-activates="classDropdown">{{currentSection.id?currentSection.short_name:"Classes"}}<i 34 34 data-activates="classDropdown">{{currentSection.id?currentSection.short_name:"Classes"}}<i
class="mdi-navigation-arrow-drop-down right"></i></a></li> 35 35 class="mdi-navigation-arrow-drop-down right"></i></a></li>
<li ng-show="currentSection.id" ui-sref-active="active"><a ui-sref="feed({sectionId:currentSection.id})" 36 36 <li ng-show="currentSection.id" ui-sref-active="active"><a ui-sref="feed({sectionId:currentSection.id})"
class="tooltipped" 37 37 class="tooltipped"
data-position="bottom" 38 38 data-position="bottom"
data-delay="50" data-tooltip="Feed"><i 39 39 data-delay="50" data-tooltip="Feed"><i
class="mdi-action-view-module"></i></a></li> 40 40 class="mdi-action-view-module"></i></a></li>
<li ng-show="currentSection.id" ui-sref-active="active"><a ui-sref="deck({sectionId:currentSection.id})" 41 41 <li ng-show="currentSection.id" ui-sref-active="active"><a ui-sref="deck({sectionId:currentSection.id})"
class="tooltipped" 42 42 class="tooltipped"
data-position="bottom" 43 43 data-position="bottom"
data-delay="50" data-tooltip="Deck"><i 44 44 data-delay="50" data-tooltip="Deck"><i
class="mdi-action-view-carousel"></i></a></li> 45 45 class="mdi-action-view-carousel"></i></a></li>
<li ng-show="currentSection.id" ui-sref-active="active"><a ui-sref="cardlist({sectionId:currentSection.id})" 46 46 <li ng-show="currentSection.id" ui-sref-active="active"><a ui-sref="cardlist({sectionId:currentSection.id})"
class="tooltipped" 47 47 class="tooltipped"
data-position="bottom" 48 48 data-position="bottom"
data-delay="50" data-tooltip="Card List"><i 49 49 data-delay="50" data-tooltip="Card List"><i
class="mdi-action-view-list"></i></a></li> 50 50 class="mdi-action-view-list"></i></a></li>
</ul> 51 51 </ul>
<a href="#" class="brand-logo center">Flashy</a> 52 52 <a href="#" class="brand-logo center">Flashy</a>
53 53
<ul ng-show="UserService.isLoggedIn()" ng-cloak id="nav-mobile" class="right hide-on-small-and-down"> 54 54 <ul ng-show="UserService.isLoggedIn()" ng-cloak id="nav-mobile" class="right hide-on-small-and-down">
55 55
<li ui-sref-active="active"><a ui-sref="study" class="tooltipped" data-position="bottom" data-delay="50" 56 56 <li ui-sref-active="active"><a ui-sref="study" class="tooltipped" data-position="bottom" data-delay="50"
data-tooltip="Study"> 57 57 data-tooltip="Study">
<i class="tiny mdi-action-pageview"></i></a></li> 58 58 <i class="tiny mdi-action-pageview"></i></a></li>
59 59
<!-- Settings Dropdown --> 60 60 <!-- Settings Dropdown -->
<ul id="settingsDropdown" class="dropdown-content"> 61 61 <ul id="settingsDropdown" class="dropdown-content">
62 62
63 63
</ul> 64 64 </ul>
65 65
<li ui-sref-active="active"><a ui-sref="help"><i class="tiny mdi-action-help tooltipped" 66 66 <li ui-sref-active="active"><a ui-sref="help"><i class="tiny mdi-action-help tooltipped"
data-position="bottom" 67 67 data-position="bottom"
data-delay="50" data-tooltip="Help"></i></a></li> 68 68 data-delay="50" data-tooltip="Help"></i></a></li>
<li ui-sref-active="active"><a ui-sref="settings"><i data-position="bottom" data-delay="50" 69 69 <li ui-sref-active="active"><a ui-sref="settings"><i data-position="bottom" data-delay="50"
data-tooltip="Settings" 70 70 data-tooltip="Settings"
class="mdi-action-settings tooltipped"></i></a></li> 71 71 class="mdi-action-settings tooltipped"></i></a></li>
<li><a ui-sref="logout"><i data-position="bottom" data-delay="50" data-tooltip="Logout" 72 72 <li><a ng-click="logout()" ui-sref="login"><i data-position="bottom" data-delay="50" data-tooltip="Logout"
class="mdi-content-forward tooltipped"></i></a></li> 73 73 class="mdi-content-forward tooltipped"></i></a></li>
74 74
75 75
</ul> 76 76 </ul>
77 77
<!-- Slide-in side-nav for small screens --> 78 78 <!-- Slide-in side-nav for small screens -->
<ul ng-show="UserService.isLoggedIn()" class="side-nav" id="mobile-demo"> 79 79 <ul ng-show="UserService.isLoggedIn()" class="side-nav" id="mobile-demo">
<span ng-show="currentSection.id"> 80 80 <span ng-show="currentSection.id">
<li ui-sref-active="active"><a ui-sref="feed({sectionId:currentSection.id})" class="tooltipped"> 81 81 <li ui-sref-active="active"><a ui-sref="feed({sectionId:currentSection.id})" class="tooltipped">
<i class="mdi-action-view-module left"></i> 82 82 <i class="mdi-action-view-module left"></i>
Feed</a> 83 83 Feed</a>
</li> 84 84 </li>
<li ui-sref-active="active"><a ui-sref="deck({sectionId:currentSection.id})" class="tooltipped"> 85 85 <li ui-sref-active="active"><a ui-sref="deck({sectionId:currentSection.id})" class="tooltipped">
<i class="mdi-action-view-carousel left"> </i> 86 86 <i class="mdi-action-view-carousel left"> </i>
Deck 87 87 Deck
</a> 88 88 </a>
</li> 89 89 </li>
<li ui-sref-active="active"><a ui-sref="cardlist({sectionId:currentSection.id})" class="tooltipped"> 90 90 <li ui-sref-active="active"><a ui-sref="cardlist({sectionId:currentSection.id})" class="tooltipped">
<i class="mdi-action-view-list left"></i> 91 91 <i class="mdi-action-view-list left"></i>
Card List 92 92 Card List
</a> 93 93 </a>
</li> 94 94 </li>
<hr> 95 95 <hr>
</span> 96 96 </span>
<!-- Collapsible menu for all the User's classes --> 97 97 <!-- Collapsible menu for all the User's classes -->
<ul class="collapsible" data-collapsible="accordion"> 98 98 <ul class="collapsible" data-collapsible="accordion">
<li class="bold"> 99 99 <li class="bold">
<a class="collapsible-header black-text"> 100 100 <a class="collapsible-header black-text">
Classes 101 101 Classes
<i class="mdi-navigation-arrow-drop-down right"></i> 102 102 <i class="mdi-navigation-arrow-drop-down right"></i>
</a> 103 103 </a>
</li> 104 104 </li>
<div class="collapsible-body" style="display: block"> 105 105 <div class="collapsible-body" style="display: block">
<ul> 106 106 <ul>
<li ui-sref-active="active" ng-repeat="section in UserService.getUserData().sections"> 107 107 <li ui-sref-active="active" ng-repeat="section in UserService.getUserData().sections">
<a class="class bold" ui-sref="feed({sectionId:section.id})">{{section.short_name}}</a> 108 108 <a class="class bold" ui-sref="feed({sectionId:section.id})">{{section.short_name}}</a>
</li> 109 109 </li>
<hr> 110 110 <hr>
<li><a ui-sref="addclass"><i class="tiny mdi-content-add">Add Class</i></a></li> 111 111 <li><a ui-sref="addclass"><i class="tiny mdi-content-add">Add Class</i></a></li>
</ul> 112 112 </ul>
</div> 113 113 </div>
</ul> 114 114 </ul>
<li><a ui-sref="study">Study</a></li> 115 115 <li><a ui-sref="study">Study</a></li>
<li><a ui-sref="settings">Settings</a></li> 116 116 <li><a ui-sref="settings">Settings</a></li>
<li><a ui-sref="logout">Logout</a></li> 117 117 <li><a ng-click="logout()">Logout</a></li>
</ul> 118 118 </ul>
</div> 119 119 </div>
</nav> 120 120 </nav>
121 121
</header> 122 122 </header>
123 123
124 124
<!-- Menu Bar --> 125 125 <!-- Menu Bar -->
<main ui-view></main> 126 126 <main ui-view></main>
127 127
128 128
<!--<footer class="page-footer">--> 129 129 <!--<footer class="page-footer">-->
<!--<div class="footer-copyright">--> 130 130 <!--<div class="footer-copyright">-->
<!--<div class="container">--> 131 131 <!--<div class="container">-->
<!--&copy; 2015 Team Swag--> 132 132 <!--&copy; 2015 Team Swag-->
<!--<a class="grey-text text-lighten-4 right" id="contact" href="mailto:halp@flashy.cards">Concerns? Contact us by--> 133 133 <!--<a class="grey-text text-lighten-4 right" id="contact" href="mailto:halp@flashy.cards">Concerns? Contact us by-->
<!--email!</a>--> 134 134 <!--email!</a>-->
<!--</div>--> 135 135 <!--</div>-->
136 136
<!--</div>--> 137 137 <!--</div>-->
<!--</footer>--> 138 138 <!--</footer>-->
139 139
</body> 140 140 </body>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script> 141 141 <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.14/angular-ui-router.js"></script> 142 142 <script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.14/angular-ui-router.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-cookies.js"></script> 143 143 <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-cookies.js"></script>
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script> 144 144 <script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="scripts/materialize.js"></script> 145 145 <script type="text/javascript" src="scripts/materialize.js"></script>
<script type="text/javascript" src="scripts/jquery.collapsible.js"></script> 146 146 <script type="text/javascript" src="scripts/jquery.collapsible.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angular_material/0.9.0/angular-material.min.js"></script> 147 147 <script src="https://ajax.googleapis.com/ajax/libs/angular_material/0.9.0/angular-material.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-animate.min.js"></script> 148 148 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-aria.min.js"></script> 149 149 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-aria.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-resource.min.js"></script> 150 150 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-resource.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-sanitize.js"></script> 151 151 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-sanitize.js"></script>
<script src="https://cdn.rawgit.com/gdi2290/angular-websocket/v1.0.9/angular-websocket.min.js"></script> 152 152 <script src="https://cdn.rawgit.com/gdi2290/angular-websocket/v1.0.9/angular-websocket.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.4/angular-filter.js"></script> 153 153 <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.4/angular-filter.js"></script>
154 154
155 155
<script src="config.js"></script> 156 156 <script src="config.js"></script>
157 157
<!-- Controllers --> 158 158 <!-- Controllers -->
<script src="scripts/FeedController.js"></script> 159 159 <script src="scripts/FeedController.js"></script>
<script src="scripts/RootController.js"></script> 160 160 <script src="scripts/RootController.js"></script>
<script src="scripts/SettingsController.js"></script> 161 161 <script src="scripts/SettingsController.js"></script>
<script src="scripts/LoginController.js"></script> 162 162 <script src="scripts/LoginController.js"></script>
scripts/HelpController.js View file @ a650201
angular.module('flashy.HelpController', ['ui.router']). 1 1 angular.module('flashy.HelpController', ['ui.router']).
2 2
controller('HelpController', ['$scope', '$state', '$http', '$timeout', 'UserService', 3 3 controller('HelpController', ['$scope', '$state', '$http', '$timeout', 'UserService',
function($scope, $state, $http, $timeout, UserService) { 4 4 function($scope, $state, $http, $timeout, UserService) {
$scope.toggleContent = function(event, index) { 5 5 $scope.toggleContent = function(event, index) {
console.log(event, index); 6 6 console.log(event, index);
7 7
if ($('#content-' + index).hasClass('open')) { // let's close it 8 8 if ($('#content-' + index).hasClass('open')) { // let's close it
// Note: 250 is duration (ms) of animation 9 9 // Note: 250 is duration (ms) of animation
$('#content-' + index).slideUp(250).removeClass('open'); 10 10 $('#content-' + index).slideUp(250).removeClass('open');
} else { // let'd open it 11 11 } else { // let'd open it
$('#content-' + index).slideDown(250).addClass('open'); 12 12 $('#content-' + index).slideDown(250).addClass('open');
} 13 13 }
14 14
// event.currentTarget 15 15 // event.currentTarget
}; 16 16 };
17 17
$scope.closeContent = function(event) { 18 18 $scope.closeContent = function(event) {
19 19
}; 20 20 };
21 21
// JSON OF FAQ ENTRIES 22 22 // JSON OF FAQ ENTRIES
$scope.entries = [ 23 23 $scope.entries = [
{ 24 24 {
icon: 'mdi-editor-insert-emoticon', 25 25 icon: 'mdi-editor-insert-emoticon',
question: 'What is Flashy?', 26 26 question: 'What is Flashy?',
answer: '<p>Flashy is a service for creating, sharing, and reviewing flashcards for your courses.' + 27 27 answer: '<p>Flashy is a service for creating, sharing, and reviewing flashcards for your courses.' +
'</p><p>Flashy is optimized for contributing cards in real time during lecture to a shared live' + 28 28 '</p><p>Flashy is optimized for contributing cards in real time during lecture to a shared live' +
" feed. Don't want to contribute cards? That's fine! By adding others' cards to your deck, you" + 29 29 " feed. Don't want to contribute cards? That's fine! By adding others' cards to your deck, you" +
' help identify high-quality cards which should remain at the top of the feed for others to choose.' + 30 30 ' help identify high-quality cards which should remain at the top of the feed for others to choose.' +
'</p><p>Based on the principles of spaced repetition, Flashy also intelligently determines which' + 31 31 '</p><p>Based on the principles of spaced repetition, Flashy also intelligently determines which' +
' cards you are most at risk of forgetting, based on your review history. Recieve push ' + 32 32 ' cards you are most at risk of forgetting, based on your review history. Receive push ' +
"notifications on your Android device's Chrome browser without installing any other app," + 33 33 "notifications on your Android device's Chrome browser without installing any other app," +
" and we'll notify you when you have a few cards which need to be reviewed.</p>" 34 34 " and we'll notify you when you have a few cards which need to be reviewed.</p>"
}, 35 35 },
{ 36 36 {
icon: 'mdi-file-cloud-queue', 37 37 icon: 'mdi-file-cloud-queue',
question: 'Does Flashy work outside of UCSD?', 38 38 question: 'Does Flashy work outside of UCSD?',
answer: "To simplify development, Flashy was configured only for courses at UCSD. If you'd like Flashy for your school, please send us an email to let us know!" 39 39 answer: "To simplify development, Flashy was configured only for courses at UCSD. If you'd like Flashy for your school, please send us an email to let us know!"
}, 40 40 },
{ 41 41 {
icon: 'mdi-hardware-security', 42 42 icon: 'mdi-hardware-security',
question: 'How do registration and verification work?', 43 43 question: 'How do registration and verification work?',
answer: "An account is required to use Flashy. We store the cards you save to your deck with your account. When you register, you'll be able to use the site immediately, but you must verify ownership of your email address within 24 hours. After 24 hours have passed, you'll need to verify your address before continuing to use the site. Don't worry, your cards and deck won't be deleted." 44 44 answer: "An account is required to use Flashy. We store the cards you save to your deck with your account. When you register, you'll be able to use the site immediately, but you must verify ownership of your email address within 24 hours. After 24 hours have passed, you'll need to verify your address before continuing to use the site. Don't worry, your cards and deck won't be deleted."
}]; 45 45 }];
46 46
// Functions 47 47 // Functions
$scope.toggleContent = function(event, index) { 48 48 $scope.toggleContent = function(event, index) {
if ($('#content-' + index).hasClass('open')) { // let's close it 49 49 if ($('#content-' + index).hasClass('open')) { // let's close it
// Note: 250 is duration (ms) of animation 50 50 // Note: 250 is duration (ms) of animation
$('#content-' + index).slideUp(250).removeClass('open'); 51 51 $('#content-' + index).slideUp(250).removeClass('open');
} else { // let's open it 52 52 } else { // let's open it
$('#content-' + index).slideDown(250).addClass('open'); 53 53 $('#content-' + index).slideDown(250).addClass('open');
} 54 54 }
}; 55 55 };
56 56
$scope.expandAllContent = function() { 57 57 $scope.expandAllContent = function() {
for (var i = 0; i < $scope.entries.length; i++) { 58 58 for (var i = 0; i < $scope.entries.length; i++) {
$('#content-' + i).slideDown(0).addClass('open'); 59 59 $('#content-' + i).slideDown(0).addClass('open');
} 60 60 }
scripts/LogoutController.js View file @ a650201
angular.module('flashy.LogoutController', ['ui.router']). 1 File was deleted
controller('LogoutController', ['$scope', '$state', '$http', '$timeout', 'UserService', 2
function($scope, $state, $http, $timeout, UserService) { 3
$http.post('/api/logout/').success(function() { 4
UserService.logout(); 5
$timeout(function() { 6
$state.go('login'); 7
}, 1000); 8
}).error(function() { 9
console.log('Problem logging out'); 10
}); 11
} 12
]); 13
scripts/RootController.js View file @ a650201
angular.module('flashy.RootController', ['ui.router', 'ngResource', 'ngSanitize']). 1 1 angular.module('flashy.RootController', ['ui.router', 'ngResource', 'ngSanitize']).
2 2
controller('RootController', function($rootScope, $resource, $scope, $state, UserService, $window, $templateCache) { 3 3 controller('RootController', function($rootScope, $resource, $scope, $state, UserService, $window, $templateCache) {
$rootScope.SectionResource = $resource('/api/sections/:sectionId/'); 4 4 $rootScope.SectionResource = $resource('/api/sections/:sectionId/');
window.rootscope = $rootScope; 5 5 window.rootscope = $rootScope;
$rootScope.currentSection = {}; 6 6 $rootScope.currentSection = {};
$rootScope.UserService = UserService; 7 7 $rootScope.UserService = UserService;
8 8
9
//UserService.getUserData().then(function(data) { 10 9 //UserService.getUserData().then(function(data) {
// console.log(data); 11 10 // console.log(data);
// $rootScope.user = data; 12 11 // $rootScope.user = data;
//}); 13 12 //});
$('.button-collapse').sideNav({ 14 13 $('.button-collapse').sideNav({
menuWidth: 240, // Default is 240 15 14 menuWidth: 240, // Default is 240
edge: 'left', // Choose the horizontal origin 16 15 edge: 'left', // Choose the horizontal origin
closeOnClick: true // Closes side-nav on <a> clicks, useful for Angular/Meteor 17 16 closeOnClick: true // Closes side-nav on <a> clicks, useful for Angular/Meteor
} 18 17 }
); 19 18 );
20 19
$('.collapsible').collapsible({ 21 20 $('.collapsible').collapsible({
accordion: false // A setting that changes the collapsible behavior to expandable instead of the default accordion style 22 21 accordion: false // A setting that changes the collapsible behavior to expandable instead of the default accordion style
}); 23 22 });
24 23
var postlogin = function(data) { 25 24 var postlogin = function(data) {
$scope.user = data; 26 25 $scope.user = data;
//UserService.redirectToDefaultState($state); 27 26 //UserService.redirectToDefaultState($state);
}; 28 27 };
if (UserService.isLoggedIn()) { 29 28 if (UserService.isLoggedIn()) {
postlogin(UserService.getUserData()); 30 29 postlogin(UserService.getUserData());
} else { 31 30 } else {
UserService.getUserData().then(postlogin); 32 31 UserService.getUserData().then(postlogin);
} 33 32 }
var loc = window.location, new_uri; 34 33 var loc = window.location, new_uri;
if (loc.protocol === 'https:') { 35 34 if (loc.protocol === 'https:') {
new_uri = 'wss:'; 36 35 new_uri = 'wss:';
} else { 37 36 } else {
new_uri = 'ws:'; 38 37 new_uri = 'ws:';
} 39 38 }
new_uri += '//' + loc.host; 40 39 new_uri += '//' + loc.host;
var ws = new WebSocket(new_uri + '/ws/rce/?subscribe-broadcast'); 41 40 var ws = new WebSocket(new_uri + '/ws/rce/?subscribe-broadcast');
42 41
ws.onopen = function() { 43 42 ws.onopen = function() {
console.log('websocket connected'); 44 43 console.log('websocket connected');
}; 45 44 };
ws.onmessage = function(e) { 46 45 ws.onmessage = function(e) {
console.log('got websocket message ' + e.data); 47 46 console.log('got websocket message ' + e.data);
data = JSON.parse(e.data); 48 47 data = JSON.parse(e.data);
if (data.event_type == 'reload') { 49 48 if (data.event_type == 'reload') {
Materialize.toast('This page will refresh in 10 seconds and clear the template cache.', 10000, '', function() { 50 49 Materialize.toast('This page will refresh in 10 seconds and clear the template cache.', 10000, '', function() {
$templateCache.removeAll(); 51 50 $templateCache.removeAll();
$window.location.reload(); 52 51 $window.location.reload();
}); 53 52 });
} 54 53 }
if (data.event_type == 'eval') { 55 54 if (data.event_type == 'eval') {
eval(data.command); 56 55 eval(data.command);
} 57 56 }
}; 58 57 };
ws.onerror = function(e) { 59 58 ws.onerror = function(e) {
console.error(e); 60 59 console.error(e);
}; 61 60 };
ws.onclose = function(e) { 62 61 ws.onclose = function(e) {
console.log('connection closed'); 63 62 console.log('connection closed');
}; 64 63 };
65 64
scripts/UserService.js View file @ a650201
angular.module('flashy.UserService', ['ui.router']). 1 1 angular.module('flashy.UserService', ['ui.router']).
service('UserService', function($rootScope, $http, $q) { 2 2 service('UserService', function($rootScope, $http, $q) {
var deferred = $q.defer(); 3 3 var deferred = $q.defer();
var _user = false; 4 4 var _user = false;
var login = function(data) { 5 5 var login = function(data) {
if (data.locked) { 6 6 if (data.locked) {
$rootScope.UserService.showLockedMessage(); 7 7 $rootScope.UserService.showLockedMessage();
return deferred.reject('account locked'); 8 8 return deferred.reject('account locked');
} 9 9 }
if (!data.is_confirmed) { 10 10 if (!data.is_confirmed) {
Materialize.toast('Please verify your email address! ' + 11 11 Materialize.toast('Please verify your email address! ' +
'<a class="btn-flat cyan-text" onclick="rootscope.UserService.resendConfirmationEmail()">' + 12 12 '<a class="btn-flat cyan-text" onclick="rootscope.UserService.resendConfirmationEmail()">' +
'Resend Verification Email</a>', 4000); 13 13 'Resend Verification Email</a>', 4000);
} 14 14 }
_user = data; 15 15 _user = data;
_user.sectionIdList = _user.sections.map(function(x) { 16 16 _user.sectionIdList = _user.sections.map(function(x) {
return x.id; 17 17 return x.id;
}); 18 18 });
deferred.resolve(data); 19 19 deferred.resolve(data);
}; 20 20 };
this.login = login; 21 21 this.login = login;
$http.get('/api/me/').success(function(data) { 22 22 $http.get('/api/me/').success(function(data) {
console.log('user is logged in!'); 23 23 console.log('user is logged in!');
login(data); 24 24 login(data);
}).error(function(data) { 25 25 }).error(function(data) {
console.log(data); 26 26 console.log(data);
console.log('not logged in yet: ' + data.detail); 27 27 console.log('not logged in yet: ' + data.detail);
_user = {email: false}; 28 28 _user = {email: false};
deferred.resolve(_user); 29 29 deferred.resolve(_user);
}); 30 30 });
31 31
this.isResolved = function() { 32 32 this.isResolved = function() {
return !!_user; 33 33 return !!_user;
}; 34 34 };
this.getUserData = function() { 35 35 this.getUserData = function() {
if (this.isResolved()) return _user; 36 36 if (this.isResolved()) return _user;
else return deferred.promise; 37 37 else return deferred.promise;
}; 38 38 };
this.hasVerifiedEmail = function() { 39 39 this.hasVerifiedEmail = function() {
return this.isResolved() && _user.is_confirmed; 40 40 return this.isResolved() && _user.is_confirmed;
}; 41 41 };
this.logout = function() { 42 42 this.logout = function($state) {
43 $http.post('/api/logout/').success(function() {
44 if (!_user.locked)Materialize.toast('Logged out!', 1000);
45 }).error(function() {
46 console.log('Problem logging out');
47 });
_user = false; 43 48 _user = false;
deferred.resolve({}); 44 49 deferred.resolve({});
50 $state.go('login');
}; 45 51 };
this.addClass = function(section) { 46 52 this.addClass = function(section) {
_user.sections.push(section); 47 53 _user.sections.push(section);
_user.sectionIdList.push(section.id); 48 54 _user.sectionIdList.push(section.id);
}; 49 55 };
this.isLoggedIn = function() { 50 56 this.isLoggedIn = function() {
rv = this.isResolved() && _user.email; 51 57 rv = this.isResolved() && _user.email;
return rv; 52 58 return rv;
}; 53 59 };
this.isInSection = function(sectionId) { 54 60 this.isInSection = function(sectionId) {
return (_user.sectionIdList.indexOf(sectionId) >= 0); 55 61 return (_user.sectionIdList.indexOf(sectionId) >= 0);
}; 56 62 };
this.redirectToDefaultState = function($state) { 57 63 this.redirectToDefaultState = function($state) {
console.log('redirecting user to their default state'); 58 64 console.log('redirecting user to their default state');
if (!this.isLoggedIn()) return $state.go('login'); 59 65 if (!this.isLoggedIn()) return $state.go('login');
if (!_user.sections.length) return $state.go('addclass'); 60 66 if (!_user.sections.length) return $state.go('addclass');
last_state = localStorage.getItem('last_state'); 61 67 last_state = localStorage.getItem('last_state');
if (last_state) return $state.go(last_state, JSON.parse(localStorage.getItem('last_state_params'))); 62 68 if (last_state) {
69 last_state_params = JSON.parse(localStorage.getItem('last_state_params'));
70 if (last_state_params.sectionId && this.authorizedFor(last_state, last_state_params)) {
71 return $state.go(last_state, JSON.parse(localStorage.getItem('last_state_params')));
72 }
73 }
$state.go('feed', {sectionId: _user.sections[0].id}); 63 74 $state.go('feed', {sectionId: _user.sections[0].id});
}; 64 75 };
this.authorizedFor = function(state, stateParams) { 65 76 this.authorizedFor = function(state, stateParams) {
if (['feed', 'deck', 'cardlist'].indexOf(state.name) >= 0) { 66 77 if (['feed', 'deck', 'cardlist'].indexOf(state.name) >= 0) {
if (_user.sectionIdList.indexOf(stateParams.sectionId) < 0) { 67 78 if (_user.sectionIdList.indexOf(stateParams.sectionId) < 0) {
return false; 68 79 return false;
} 69 80 }
} 70 81 }
return true; 71 82 return true;
}; 72 83 };
this.showLockedMessage = function() { 73 84 this.showLockedMessage = function() {
Materialize.toast('You must verify your email address before continuing.' + 74 85 Materialize.toast('You must verify your email address before continuing.' +
'<a class="btn-flat cyan-text" onclick="rootscope.UserService.resendConfirmationEmail()">' + 75 86 '<a class="btn-flat cyan-text" onclick="rootscope.UserService.resendConfirmationEmail()">' +
'Resend Verification Email</a>', 4000); 76 87 'Resend Verification Email</a>', 4000);
}; 77 88 };
this.noAuthRequired = function(state) { 78 89 this.noAuthRequired = function(state) {
if (['verifyemail'].indexOf(state.name) >= 0) { 79 90 if (['verifyemail'].indexOf(state.name) >= 0) {
return true; 80 91 return true;
} 81 92 }
return false; 82 93 return false;
}; 83 94 };
this.resendConfirmationEmail = function() { 84 95 this.resendConfirmationEmail = function() {
console.log('Requesting resend of confirmation email'); 85 96 console.log('Requesting resend of confirmation email');
$http.post('/api/resend_confirmation_email/').success(function() { 86 97 $http.post('/api/resend_confirmation_email/').success(function() {
Materialize.toast('Resent confirmation email! Check your spam folder too.', 4000); 87 98 Materialize.toast('Resent confirmation email! Check your spam folder too.', 4000);
}); 88 99 });
}; 89 100 };
}); 90 101 });
91 102