diff --git a/lab-khalid/.babelrc b/lab-khalid/.babelrc
new file mode 100644
index 0000000..2dcde76
--- /dev/null
+++ b/lab-khalid/.babelrc
@@ -0,0 +1,3 @@
+{
+ "presets": "es2015"
+}
\ No newline at end of file
diff --git a/lab-khalid/.eslintrc b/lab-khalid/.eslintrc
new file mode 100644
index 0000000..b663d77
--- /dev/null
+++ b/lab-khalid/.eslintrc
@@ -0,0 +1,21 @@
+{
+ "rules": {
+ "no-console": "off",
+ "indent": [ "error", 2 ],
+ "quotes": [ "error", "single" ],
+ "semi": ["error", "always"],
+ "linebreak-style": [ "error", "unix" ]
+ },
+ "env": {
+ "es6": true,
+ "node": true,
+ "mocha": true,
+ "jasmine": true
+ },
+ "ecmaFeatures": {
+ "modules": true,
+ "experimentalObjectRestSpread": true,
+ "impliedStrict": true
+ },
+ "extends": "eslint:recommended"
+}
\ No newline at end of file
diff --git a/lab-khalid/.gitignore b/lab-khalid/.gitignore
new file mode 100644
index 0000000..d571c04
--- /dev/null
+++ b/lab-khalid/.gitignore
@@ -0,0 +1,33 @@
+# Created by https://www.gitignore.io/api/node,vim,macos,linux,windows
+.DS_Store
+node_modules/
+.env
+### Node ###
+# Logs
+logs
+*.log
+npm-debug.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+
+.env
\ No newline at end of file
diff --git a/lab-khalid/app/component/gallery/create-gallery/_create-gallery.scss b/lab-khalid/app/component/gallery/create-gallery/_create-gallery.scss
new file mode 100644
index 0000000..e69de29
diff --git a/lab-khalid/app/component/gallery/create-gallery/create-gallery.html b/lab-khalid/app/component/gallery/create-gallery/create-gallery.html
new file mode 100644
index 0000000..33780ed
--- /dev/null
+++ b/lab-khalid/app/component/gallery/create-gallery/create-gallery.html
@@ -0,0 +1,17 @@
+
\ No newline at end of file
diff --git a/lab-khalid/app/component/gallery/create-gallery/create-gallery.js b/lab-khalid/app/component/gallery/create-gallery/create-gallery.js
new file mode 100644
index 0000000..92e3eda
--- /dev/null
+++ b/lab-khalid/app/component/gallery/create-gallery/create-gallery.js
@@ -0,0 +1,22 @@
+'use strict';
+
+module.exports = {
+ template: require('./create-gallery.html'),
+ controller: ['$log', 'galleryService', CreateGalleryController],
+ controllerAs: 'createGalleryCtrl'
+};
+
+
+function CreateGalleryController($log, galleryService){
+ $log.debug('CreateGalleryController');
+
+ this.gallery = {};
+
+ this.createGallery = function() {
+ galleryService.createGallery(this.gallery)
+ .then( () => {
+ this.gallery.name = null;
+ this.gallery.desc = null;
+ });
+ };
+}
\ No newline at end of file
diff --git a/lab-khalid/app/component/gallery/edit-gallery/_edit-gallery.scss b/lab-khalid/app/component/gallery/edit-gallery/_edit-gallery.scss
new file mode 100644
index 0000000..e69de29
diff --git a/lab-khalid/app/component/gallery/edit-gallery/edit-gallery.html b/lab-khalid/app/component/gallery/edit-gallery/edit-gallery.html
new file mode 100644
index 0000000..d62a358
--- /dev/null
+++ b/lab-khalid/app/component/gallery/edit-gallery/edit-gallery.html
@@ -0,0 +1,16 @@
+
\ No newline at end of file
diff --git a/lab-khalid/app/component/gallery/edit-gallery/edit-gallery.js b/lab-khalid/app/component/gallery/edit-gallery/edit-gallery.js
new file mode 100644
index 0000000..10b1848
--- /dev/null
+++ b/lab-khalid/app/component/gallery/edit-gallery/edit-gallery.js
@@ -0,0 +1,19 @@
+'use strict';
+
+module.exports = {
+ template: require('./edit-gallery.html'),
+ controller: ['$log', 'galleryService', EditGalleryController],
+ controllerAs: 'editGalleryCtrl',
+ bindings: {
+ gallery:'<'
+ }
+};
+
+function EditGalleryController($log, galleryService){
+ $log.debug('EditGalleryController');
+
+ this.updateGallery = function(){
+ $log.debug('EditGalleryController.updateGallery');
+ galleryService.updateGallery(this.gallery._id, this.gallery);
+ };
+}
\ No newline at end of file
diff --git a/lab-khalid/app/component/gallery/gallery-item/_gallery-item.scss b/lab-khalid/app/component/gallery/gallery-item/_gallery-item.scss
new file mode 100644
index 0000000..a883dfb
--- /dev/null
+++ b/lab-khalid/app/component/gallery/gallery-item/_gallery-item.scss
@@ -0,0 +1,3 @@
+.gallery-item{
+ background-color: crimson;
+}
\ No newline at end of file
diff --git a/lab-khalid/app/component/gallery/gallery-item/gallery-item.html b/lab-khalid/app/component/gallery/gallery-item/gallery-item.html
new file mode 100644
index 0000000..e6cfb72
--- /dev/null
+++ b/lab-khalid/app/component/gallery/gallery-item/gallery-item.html
@@ -0,0 +1,21 @@
+
+
+
+ name:
+ {{ galleryItemCtrl.gallery.name }}
+
+
+
+ description:
+ {{ galleryItemCtrl.gallery.desc }}
+
+
+
+
+
+
+ edit
+
+ delete
+
\ No newline at end of file
diff --git a/lab-khalid/app/component/gallery/gallery-item/gallery-item.js b/lab-khalid/app/component/gallery/gallery-item/gallery-item.js
new file mode 100644
index 0000000..cc866f8
--- /dev/null
+++ b/lab-khalid/app/component/gallery/gallery-item/gallery-item.js
@@ -0,0 +1,22 @@
+'use strict';
+
+require('./_gallery-item.scss');
+
+module.exports = {
+ template: require('./gallery-item.html'),
+ controller: ['$log', 'galleryService', GalleryItemController],
+ controllerAs: 'galleryItemCtrl',
+ bindings: {
+ gallery: '<'
+ }
+};
+
+function GalleryItemController($log, galleryService){
+ $log.debug('GalleryItemController');
+
+ this.showEditGallery = false;
+
+ this.deleteGallery = function(){
+ galleryService.deleteGallery(this.gallery._id);
+ };
+}
\ No newline at end of file
diff --git a/lab-khalid/app/component/gallery/thumbnail-container/_thumbnail-container.scss b/lab-khalid/app/component/gallery/thumbnail-container/_thumbnail-container.scss
new file mode 100644
index 0000000..e69de29
diff --git a/lab-khalid/app/component/gallery/thumbnail-container/thumbnail-container.html b/lab-khalid/app/component/gallery/thumbnail-container/thumbnail-container.html
new file mode 100644
index 0000000..ee327be
--- /dev/null
+++ b/lab-khalid/app/component/gallery/thumbnail-container/thumbnail-container.html
@@ -0,0 +1,8 @@
+
+ {{ thumbnailContainerCtrl.gallery.name }}
+
+
+
+
+
+
diff --git a/lab-khalid/app/component/gallery/thumbnail-container/thumbnail-container.js b/lab-khalid/app/component/gallery/thumbnail-container/thumbnail-container.js
new file mode 100644
index 0000000..f3f9a27
--- /dev/null
+++ b/lab-khalid/app/component/gallery/thumbnail-container/thumbnail-container.js
@@ -0,0 +1,13 @@
+'use strict';
+
+require('./_thumbnail-container.scss');
+
+module.exports = {
+ template: require('./thumbnail-container.html'),
+ controllerAs: 'thumbnailContainerCtrl',
+ bindings: {
+ gallery: '<'
+ }
+};
+
+//finish maybe
\ No newline at end of file
diff --git a/lab-khalid/app/component/gallery/thumbnail/_thumbnail.scss b/lab-khalid/app/component/gallery/thumbnail/_thumbnail.scss
new file mode 100644
index 0000000..e69de29
diff --git a/lab-khalid/app/component/gallery/thumbnail/thumbnail.html b/lab-khalid/app/component/gallery/thumbnail/thumbnail.html
new file mode 100644
index 0000000..a520c1f
--- /dev/null
+++ b/lab-khalid/app/component/gallery/thumbnail/thumbnail.html
@@ -0,0 +1,5 @@
+
+
![{thumbnailCtrl.pic.desc}]()
+
delete
+
+
\ No newline at end of file
diff --git a/lab-khalid/app/component/gallery/thumbnail/thumbnail.js b/lab-khalid/app/component/gallery/thumbnail/thumbnail.js
new file mode 100644
index 0000000..c2cd240
--- /dev/null
+++ b/lab-khalid/app/component/gallery/thumbnail/thumbnail.js
@@ -0,0 +1,24 @@
+'use strict';
+
+
+require('./_thumbnail.scss');
+
+module.exports = {
+ template: require('./thumbnail.html'),
+ controller: ['$log', 'picService', ThumbnailController],
+ controllerAs: 'thumbnailCtrl',
+ bindings: {
+ pic: '<'
+ }
+};
+
+function ThumbnailController($log, picService){
+ $log.debug('ThumbnailController');
+
+ this.deletePic = function(){
+ $log.debug('thumbnailCtrl.deletePic');
+ };
+
+}
+
+//finish
\ No newline at end of file
diff --git a/lab-khalid/app/component/gallery/upload-pic/_upload-pic.scss b/lab-khalid/app/component/gallery/upload-pic/_upload-pic.scss
new file mode 100644
index 0000000..e69de29
diff --git a/lab-khalid/app/component/gallery/upload-pic/upload-pic.html b/lab-khalid/app/component/gallery/upload-pic/upload-pic.html
new file mode 100644
index 0000000..0838e0b
--- /dev/null
+++ b/lab-khalid/app/component/gallery/upload-pic/upload-pic.html
@@ -0,0 +1,25 @@
+
\ No newline at end of file
diff --git a/lab-khalid/app/component/gallery/upload-pic/upload-pic.js b/lab-khalid/app/component/gallery/upload-pic/upload-pic.js
new file mode 100644
index 0000000..c88a0c3
--- /dev/null
+++ b/lab-khalid/app/component/gallery/upload-pic/upload-pic.js
@@ -0,0 +1,29 @@
+'use sthis.pic.name = null;rict';
+
+require('./_upload-pic.scss');
+
+module.exports = {
+ template: require('./upload-pic.html'),
+ controller: [ '$log', 'picService', UploadPicController],
+ controllerAs: 'uploadPicCtrl',
+ bindings: {
+ gallery: '<'
+ }
+};
+
+
+function UploadPicController($log, picService){
+ $log.debug('uploadPicController');
+
+ this.pic = {};
+
+ this.uploadPic = function(){
+ picService.uploadGalleryPic(this.gallery, this.pic)
+ .then( () => {
+ this.pic.name = null;
+ this.pic.desc = null;
+ this.pic.file = null;
+ });
+ };
+
+}
\ No newline at end of file
diff --git a/lab-khalid/app/component/landing/login/_login.scss b/lab-khalid/app/component/landing/login/_login.scss
new file mode 100644
index 0000000..e69de29
diff --git a/lab-khalid/app/component/landing/login/login.html b/lab-khalid/app/component/landing/login/login.html
new file mode 100644
index 0000000..2ce5219
--- /dev/null
+++ b/lab-khalid/app/component/landing/login/login.html
@@ -0,0 +1,26 @@
+
\ No newline at end of file
diff --git a/lab-khalid/app/component/landing/login/login.js b/lab-khalid/app/component/landing/login/login.js
new file mode 100644
index 0000000..040f152
--- /dev/null
+++ b/lab-khalid/app/component/landing/login/login.js
@@ -0,0 +1,27 @@
+'use strict';
+
+require('./_login.scss');
+
+module.exports = {
+ template: require('./login.html'),
+ controller: ['$log', '$location', 'authService', LoginController],
+ controllerAs: 'loginCtrl'
+};
+
+function LoginController($log, $location, authService){
+ $log.debug('LoginController');
+
+ authService.getToken()
+ .then( () => {
+ $location.url('/home');
+ });
+
+ this.login = function() {
+ $log.debug('loginCtrl.login');
+
+ authService.login(this.user)
+ .then( () => {
+ $location.url('/home');
+ });
+ };
+}
\ No newline at end of file
diff --git a/lab-khalid/app/component/landing/signup/_signup.scss b/lab-khalid/app/component/landing/signup/_signup.scss
new file mode 100644
index 0000000..872d99c
--- /dev/null
+++ b/lab-khalid/app/component/landing/signup/_signup.scss
@@ -0,0 +1,35 @@
+$space: 20px;
+$primary-color: #404040;
+$secondary-color: lightgrey;
+
+form {
+ display: block;
+ margin: $space auto;
+ width: 40%;
+ legend{
+ font-size: 20px;
+ font-family: Arial, Helvetica, sans-serif;
+ }
+ input{
+ display: block;
+ width: 80%;
+ height: 30px;
+ margin-top: $space;
+ font-size: 15px;
+ // margin:10px auto;
+ padding: 5px;
+ border-radius: 1px;
+ border: none;
+ // margin: auto;
+ }
+ button {
+ width: 30%;
+ height: 30px;
+ font-size: 15px;
+ margin-top: $space;
+ margin-left: 52%;
+ background-color: $primary-color;
+ color: $secondary-color;
+ border: none;
+ }
+}
\ No newline at end of file
diff --git a/lab-khalid/app/component/landing/signup/signup.html b/lab-khalid/app/component/landing/signup/signup.html
new file mode 100644
index 0000000..880316b
--- /dev/null
+++ b/lab-khalid/app/component/landing/signup/signup.html
@@ -0,0 +1,10 @@
+
+
diff --git a/lab-khalid/app/component/landing/signup/signup.js b/lab-khalid/app/component/landing/signup/signup.js
new file mode 100644
index 0000000..43d7d9c
--- /dev/null
+++ b/lab-khalid/app/component/landing/signup/signup.js
@@ -0,0 +1,26 @@
+'use strict';
+require('./_signup.scss');
+
+module.exports = {
+ template: require('./signup.html'),
+ controller: ['$log', '$location', 'authService', SignupController],
+ controllerAs: 'signupCtrl'
+};
+
+function SignupController($log, $location, authService){
+ $log.debug('SignupController');
+
+ authService.getToken()
+ .then( () => {
+ $location.url('/home');
+ });
+
+ this.signup = function(user){
+ $log.debug('signupCtrl.signup');
+
+ authService.signup(user)
+ .then( () => {
+ $location.url('/home');
+ });
+ };
+}
\ No newline at end of file
diff --git a/lab-khalid/app/component/navbar/_navbar.scss b/lab-khalid/app/component/navbar/_navbar.scss
new file mode 100644
index 0000000..df0b61a
--- /dev/null
+++ b/lab-khalid/app/component/navbar/_navbar.scss
@@ -0,0 +1,8 @@
+.navbar {
+ button {
+ width: 60px;
+ height: 30px;
+ border-radius: 6px;
+ border: none;
+ }
+}
\ No newline at end of file
diff --git a/lab-khalid/app/component/navbar/navbar.html b/lab-khalid/app/component/navbar/navbar.html
new file mode 100644
index 0000000..1989d33
--- /dev/null
+++ b/lab-khalid/app/component/navbar/navbar.html
@@ -0,0 +1,14 @@
+
+
+
+
\ No newline at end of file
diff --git a/lab-khalid/app/component/navbar/navbar.js b/lab-khalid/app/component/navbar/navbar.js
new file mode 100644
index 0000000..372880b
--- /dev/null
+++ b/lab-khalid/app/component/navbar/navbar.js
@@ -0,0 +1,43 @@
+'use strict';
+
+require('./_navbar.scss');
+
+module.exports = {
+ template: require('./navbar.html'),
+ controller: ['$log', '$location', '$rootScope', 'authService', NavbarController],
+ controllerAs: 'navbarCtrl'
+};
+
+function NavbarController($log, $location, $rootScope, authService){
+ $log.debug('NavbarController');
+
+ this.checkPath = function(){
+ let path = $location.path;
+ if(path === '/join'){
+ this.hideButtons = true;
+ }
+
+ if(path !== '/join'){
+ this.hideButtons = false;
+ authService.getToken()
+ .catch( () => {
+ $location.url('/join#login');
+ });
+ }
+ };
+
+ this.checkPath();
+
+ $rootScope.$on('$locationChangeSuccess', () => {
+ this.checkPath();
+ });
+
+ this.logout = function () {
+ $log.log('navbarCtrl.logout');
+ this.hideButtons = true;
+ authService.logout()
+ .then( () => {
+ $location.url('/');
+ });
+ };
+}
\ No newline at end of file
diff --git a/lab-khalid/app/config/log-config.js b/lab-khalid/app/config/log-config.js
new file mode 100644
index 0000000..9ffc30a
--- /dev/null
+++ b/lab-khalid/app/config/log-config.js
@@ -0,0 +1,7 @@
+'use strict';
+
+module.exports = ['$logProvider', logConfig];
+
+function logConfig($logProvider){
+ $logProvider.debugEnabled(__DEBUG__);
+}
\ No newline at end of file
diff --git a/lab-khalid/app/config/router-config.js b/lab-khalid/app/config/router-config.js
new file mode 100644
index 0000000..4777210
--- /dev/null
+++ b/lab-khalid/app/config/router-config.js
@@ -0,0 +1,31 @@
+'use strict';
+
+module.exports = ['$stateProvider', '$urlRouterProvider', routerConfig];
+
+function routerConfig($stateProvider, $urlRouterProvider){
+ $urlRouterProvider.when('', '/join#signup');
+ $urlRouterProvider.when('/', '/join#signup');
+ $urlRouterProvider.when('/signup', '/join#signup');
+ $urlRouterProvider.when('/login', '/join#login');
+
+ let states = [
+ {
+ name: 'home',
+ url: '/home',
+ template: require('../view/home/home.html'),
+ controller: 'HomeController',
+ controllerAs: 'homeCtrl'
+ },
+ {
+ name: 'landing',
+ url: '/join',
+ template: require('../view/landing/landing.html'),
+ controller: 'LandingController',
+ controllerAs: 'landingCtrl'
+ }
+ ];
+
+ states.forEach( state => {
+ $stateProvider.state(state);
+ });
+}
\ No newline at end of file
diff --git a/lab-khalid/app/entry.js b/lab-khalid/app/entry.js
new file mode 100644
index 0000000..87d5aa4
--- /dev/null
+++ b/lab-khalid/app/entry.js
@@ -0,0 +1,48 @@
+'use strict';
+
+require('./scss/main.scss');
+
+const
+ path = require('path'),
+ angular = require('angular'),
+ camelcase = require('camelcase'),
+ pascalcase = require('pascalcase'),
+ uiRouter = require('angular-ui-router'),
+ ngTouch = require('angular-touch'),
+ ngAnimate = require('angular-animate'),
+ ngFileUpload = require('ng-file-upload'),
+
+ cfgram = angular.module('cfgram', [ngTouch, ngAnimate, uiRouter, ngFileUpload]);
+
+let context = require.context('./config/', true, /\.js$/);
+// console.log('CONTEXT', context);
+context.keys().forEach( key => {
+ // console.log('k',key);
+ cfgram.config(context(key));
+});
+
+context = require.context('./view/', true, /\.js$/);
+// console.log('CONTEXT2', context);
+context.keys().forEach( key => {
+ // console.log('k',key);
+ let name = pascalcase(path.basename(key, '.js'));
+ let module = context(key);
+ cfgram.controller(name, module);
+});
+
+context = require.context('./service/', true, /\.js$/);
+context.keys().forEach(key => {
+ // console.log('k',key);
+ let name = camelcase(path.basename(key, '.js'));
+ let module = context(key);
+ cfgram.service(name, module);
+});
+
+context = require.context('./component', true, /\.js$/);
+context.keys().forEach( key => {
+ // console.log('k',key);
+ let name = camelcase(path.basename(key, '.js'));
+ let module = context(key);
+ cfgram.component(name, module);
+});
+
diff --git a/lab-khalid/app/index.html b/lab-khalid/app/index.html
new file mode 100644
index 0000000..98dfca3
--- /dev/null
+++ b/lab-khalid/app/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ cfgram
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab-khalid/app/scss/lib/header/_reset.scss b/lab-khalid/app/scss/lib/header/_reset.scss
new file mode 100644
index 0000000..af94440
--- /dev/null
+++ b/lab-khalid/app/scss/lib/header/_reset.scss
@@ -0,0 +1,48 @@
+/* http://meyerweb.com/eric/tools/css/reset/
+ v2.0 | 20110126
+ License: none (public domain)
+*/
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+body {
+ line-height: 1;
+}
+ol, ul {
+ list-style: none;
+}
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: '';
+ content: none;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
\ No newline at end of file
diff --git a/lab-khalid/app/scss/lib/header/header.scss b/lab-khalid/app/scss/lib/header/header.scss
new file mode 100644
index 0000000..82bf067
--- /dev/null
+++ b/lab-khalid/app/scss/lib/header/header.scss
@@ -0,0 +1,28 @@
+header {
+ width: 100%;
+ height: 6vw;
+ background-color: black;
+ color: lightgrey;
+
+ h1 {
+ display: inline;
+ font-size: 30px;
+ font-family: Arial, sans-serif;
+ // margin: 5% 10%;
+ margin: 5%;
+ padding: 10px;
+ font-weight: lighter;
+ }
+
+ ul{
+ margin-left: 10%;
+ padding-top: 5px;
+
+ }
+ li{
+ display: inline-block;
+ &:last-child{
+ margin-left: 90%;
+ }
+ }
+}
\ No newline at end of file
diff --git a/lab-khalid/app/scss/main.scss b/lab-khalid/app/scss/main.scss
new file mode 100644
index 0000000..8b6d844
--- /dev/null
+++ b/lab-khalid/app/scss/main.scss
@@ -0,0 +1,6 @@
+@import './lib/header/header.scss';
+@import './lib/header/_reset.scss';
+@import '../component/landing/signup/_signup.scss';
+body {
+ background-color: $secondary-color;
+}
\ No newline at end of file
diff --git a/lab-khalid/app/service/auth-service.js b/lab-khalid/app/service/auth-service.js
new file mode 100644
index 0000000..2df638c
--- /dev/null
+++ b/lab-khalid/app/service/auth-service.js
@@ -0,0 +1,89 @@
+'use strict';
+
+module.exports = ['$q', '$log', '$http', '$window', authService];
+
+function authService($q, $log, $http, $window){
+ $log.debug('authService');
+
+ let service = {};
+ let token = null;
+
+ function setToken(_token){
+ $log.debug('authService.setToken');
+
+ if(! _token) {
+ return $q.reject(new Error('no token'));
+ }
+
+ $window.localStorage.setItem('token', _token);
+ console.log('Ma TOKEEEEEEN>>>>>', _token);
+ token = _token;
+ return $q.resolve(token);
+ }
+
+ service.getToken = function() {
+ $log.debug('authService.getToken');
+
+ if(token){
+ return $q.resolve(token);
+ }
+
+ token = $window.localStorage.getItem('token');
+ if(token) return $q.resolve(token);
+ return $q.reject(new Error('token not found'));
+ };
+
+ service.signup = function(user){
+ $log.debug('authService.signup');
+
+ let url = `${__API_URL__}/api/signup`;
+ let config = {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'
+ }
+ };
+ console.log('LOOK AT ME NOW!');
+ return $http.post(url, user, config)
+ .then( res => {
+ $log.log('+++++++++++++++success ', res);
+ return setToken(res.data);
+ })
+ .catch( err => {
+ $log.error('failure:', err.message);
+ return $q.reject(err);
+ });
+ };
+
+ service.logout = function(){
+ $log.debug('authService.logout');
+
+ $window.localStorage.removeItem('token');
+ token = null;
+ return $q.resolve();
+ };
+
+ service.login = function(user){
+ $log.debug('authService.login');
+
+ let url = `${__API_URL__}/api/login`;
+ let base64 = $window.btoa(`${user.username}:${user.password}`);
+ let config = {
+ headers: {
+ Accept: 'application/json',
+ Authorization: `Basic ${base64}`
+ }
+ };
+
+ return $http.get(url, config)
+ .then( res => {
+ $log.log('success: ', res.data);
+ return setToken(res.data);
+ })
+ .catch( err => {
+ $log.log('failure: ', err.message);
+ return $q.reject(err);
+ });
+ };
+ return service;
+}
\ No newline at end of file
diff --git a/lab-khalid/app/service/gallery-service.js b/lab-khalid/app/service/gallery-service.js
new file mode 100644
index 0000000..c2da2cc
--- /dev/null
+++ b/lab-khalid/app/service/gallery-service.js
@@ -0,0 +1,149 @@
+'use strict';
+
+module.exports = ['$q', '$log', '$http', 'authService', galleryService];
+
+function galleryService($q, $log, $http, authService){
+ $log.debug('galleryService');
+
+ let service = {};
+ service.galleries = [];
+ console.log("SERVICE>GALLAERIES :::::::::::::", service.galleries);
+
+ service.createGallery = function(gallery){
+ $log.debug('createGallery');
+
+ console.log('888888888888888888888888888888888887')
+
+ return authService.getToken()
+ .then( token => {
+ let url = `${__API_URL__}/api/gallery`;
+ let config = {
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${token}`
+ }
+ };
+
+ return $http.post(url, gallery, config);
+ })
+ .then( res => {
+ $log.log('gallery created');
+ let gallery = res.data;
+ service.galleries.unshift(gallery);
+ return gallery;
+ })
+ .catch( err => {
+ $log.error(err.message);
+ return $q.reject(err);
+ });
+ };
+
+ // service.deleteGalleries = function(galleryID){
+ // $log.debug('galleryService.deleteGallery');
+
+ // return authService.getToken()
+ // .then( token => {
+ // let url = `${__API_URL__}/api/gallery/${galleryID}`;
+ // let config = {
+ // headers : {
+ // Accept: 'application/json',
+ // Authorization: `Bearer ${token}`
+ // }
+ // };
+
+ // //TODO create $http.delete request
+
+ // });
+ // };
+
+ service.fetchGalleries = function(){
+ $log.debug('service.fetchgalleries');
+
+ return authService.getToken()
+ .then( token => {
+ let url = `${__API_URL__}/api/gallery`;
+ let config = {
+ headers: {
+ Accept: 'application/json',
+ Authorization: `Bearer ${token}`,
+ }
+ };
+ return $http.get(url, config);
+ })
+ .then( res => {
+ $log.log('galleries retrieved');
+
+ service.galleries = res.data;
+ return service.galleries;
+ })
+ .catch( err => {
+ $log.error(err.message);
+ return $q.reject(err);
+ });
+ };
+
+ service.updateGallery = function(galleryID, galleryData){
+ $log.debug('galleryService.updateGallery');
+
+ return authService.getToken()
+ .then( token => {
+ let url = `${__API_URL__}/api/gallery/${galleryID}`;
+ let config = {
+ headers: {
+ Accept: 'application/json',
+ Authorization: `Bearer ${token}`,
+ 'Content-Type': 'application/json'
+ }
+ };
+ return $http.put(url ,galleryData, config);
+ })
+ .then( res => {
+ for( var i = 0; i < service.galleries.length; i++){
+ let current = service.galleries[i];
+ if(current._id === galleryID){
+ service.galleries[i] = res.data;
+ break;
+ }
+ }
+
+ return res.data;
+ })
+ .catch( err => {
+ $log.error(err.message);
+ $q.reject(err);
+
+ });
+ };
+
+ service.deleteGallery = function(galleryID){
+ $log.debug('galleryService.deleteGallery');
+
+ return authService.getToken()
+ .then( token => {
+ let url = `${__API_URL__}/api/gallery/${galleryID}`;
+ let config = {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ }
+ };
+
+ return $http.delete(url, config);
+ })
+ .then( res => {
+ for (let i = 0; i < service.galleries.length; i++){
+ let current = service.galleries[i];
+ if( current._id === galleryID){
+ service.galleries.splice(i, 1);
+ break;
+ }
+ }
+ })
+ .catch( err => {
+ $log.error(err.message);
+ return $q.reject(err);
+ });
+ };
+
+ return service;
+}
\ No newline at end of file
diff --git a/lab-khalid/app/service/pic-service.js b/lab-khalid/app/service/pic-service.js
new file mode 100644
index 0000000..8a130ca
--- /dev/null
+++ b/lab-khalid/app/service/pic-service.js
@@ -0,0 +1,43 @@
+'use strict';
+
+module.exports = ['$q', '$log', '$http', 'Upload', 'authService', picService];
+
+function picService($q, $log, $http, Upload, authService){
+ $log.debug('picService');
+
+ let service = {};
+
+ service.uploadGalleryPic = function(galleryData, picData){
+ $log.debug('service.uploadGalleryPic');
+
+ return authService.getToken()
+ .then( token => {
+ let url = `${API_URL}/api/gallery/${galleryData._id}/pic`;
+ let headers = {
+ Authorization: `Bearer ${token}`,
+ Accept: 'application/json'
+ };
+
+ return Upload.upload({
+ url,
+ headers,
+ method: 'POST',
+ data:{
+ name: picData.name,
+ desc: picData.desc,
+ file: picData.file
+ }
+ });
+ })
+ .then( res => {
+ galleryData.pics.unshift(res.data);
+ return res.data;
+ })
+ .catch(err => {
+ $log.error(err.message);
+ return $q.reject(err);
+ });
+ };
+
+ return service;
+}
diff --git a/lab-khalid/app/view/home/_home.scss b/lab-khalid/app/view/home/_home.scss
new file mode 100644
index 0000000..e69de29
diff --git a/lab-khalid/app/view/home/home-controller.js b/lab-khalid/app/view/home/home-controller.js
new file mode 100644
index 0000000..c5b33c5
--- /dev/null
+++ b/lab-khalid/app/view/home/home-controller.js
@@ -0,0 +1,31 @@
+'use strict';
+
+require('./_home.scss');
+
+module.exports = ['$log','$rootScope','galleryService', HomeController];
+
+function HomeController($log, $rootScope, galleryService){
+ $log.debug('HomeController');
+
+ this.galleries = [];
+ console.log('THIS>GALLERIES', this.galleries);
+ console.log('*************', galleryService);
+
+ this.fetchGalleries = function(){
+ galleryService.fetchGalleries()
+ .then( galleries => {
+ this.galleries = galleries;
+ this.currentGallery = galleries[0];
+ });
+ };
+
+ this.galleryDeleteDone = function(gallery){
+ if(this.currentGallery._id === gallery._id){
+ this.currentGallery = null;
+ }
+ };
+
+ this.fetchGalleries();
+
+ $rootScope.$on('$locationChangeSuccess', () => this.fetchGalleries());
+}
\ No newline at end of file
diff --git a/lab-khalid/app/view/home/home.html b/lab-khalid/app/view/home/home.html
new file mode 100644
index 0000000..cf9edc0
--- /dev/null
+++ b/lab-khalid/app/view/home/home.html
@@ -0,0 +1,12 @@
+
diff --git a/lab-khalid/app/view/landing/_landing.scss b/lab-khalid/app/view/landing/_landing.scss
new file mode 100644
index 0000000..c5a6da6
--- /dev/null
+++ b/lab-khalid/app/view/landing/_landing.scss
@@ -0,0 +1,14 @@
+.landing {
+ p {
+ font-family: Arial, Helvetica, sans-serif;
+ display: inline;
+ margin-left: 44%;
+ padding: 0 10px;
+ }
+ a {
+ text-decoration: none;
+ font-family: Arial, Helvetica, sans-serif;
+ font-weight: 900;
+ color: black;
+ }
+}
\ No newline at end of file
diff --git a/lab-khalid/app/view/landing/landing-controller.js b/lab-khalid/app/view/landing/landing-controller.js
new file mode 100644
index 0000000..f78ad6f
--- /dev/null
+++ b/lab-khalid/app/view/landing/landing-controller.js
@@ -0,0 +1,11 @@
+'use strict';
+
+require('./_landing.scss');
+
+module.exports = ['$log', '$location', '$rootScope', 'authService', LandingController];
+
+function LandingController($log, $location, authService){
+ $log.log('LandingController');
+ let url = $location.url();
+ this.showSignup = url === '/join#signup' || url === '/join';
+}
\ No newline at end of file
diff --git a/lab-khalid/app/view/landing/landing.html b/lab-khalid/app/view/landing/landing.html
new file mode 100644
index 0000000..362435e
--- /dev/null
+++ b/lab-khalid/app/view/landing/landing.html
@@ -0,0 +1,17 @@
+
\ No newline at end of file
diff --git a/lab-khalid/karma.conf.js b/lab-khalid/karma.conf.js
new file mode 100644
index 0000000..9f781df
--- /dev/null
+++ b/lab-khalid/karma.conf.js
@@ -0,0 +1,77 @@
+// Karma configuration
+// Generated on Tue Apr 04 2017 14:24:45 GMT-0700 (PDT)
+
+const webpack = require('./webpack.config.js');
+
+delete webpack.entry;
+
+module.exports = function(config) {
+ config.set({
+ webpack,
+ // 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: ['jasmine'],
+
+
+ // list of files / patterns to load in the browser
+ files: [
+ 'app/entry.js',
+ 'test/**/*-test.js',
+ 'node_modules/angular-mocks/angular-mocks.js'
+ ],
+
+
+ // 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: {
+ 'test/**/*-test.js': ['webpack'],
+ 'app/entry.js': ['webpack']
+ },
+
+
+ // test results reporter to use
+ // possible values: 'dots', 'progress'
+ // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+ reporters: ['mocha'],
+
+
+ // 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: ['Chrome'],
+
+
+ // Continuous Integration mode
+ // if true, Karma captures browsers, runs the tests and exits
+ singleRun: false,
+
+ // Concurrency level
+ // how many browser should be started simultaneous
+ concurrency: Infinity
+ });
+};
\ No newline at end of file
diff --git a/lab-khalid/package.json b/lab-khalid/package.json
new file mode 100644
index 0000000..dd38119
--- /dev/null
+++ b/lab-khalid/package.json
@@ -0,0 +1,53 @@
+{
+ "name": "cfgram-auth",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "build": "./node_modules/webpack/bin/webpack.js",
+ "watch": "./node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot",
+ "test-watch": "./node_modules/karma/bin/karma start ",
+ "test": "./node_modules/karma/bin/karma start --single-run"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "angular": "^1.6.3",
+ "angular-animate": "^1.6.3",
+ "angular-route": "^1.6.3",
+ "angular-touch": "^1.6.3",
+ "angular-ui-router": "^0.4.2",
+ "babel-core": "^6.24.0",
+ "babel-loader": "^6.4.1",
+ "babel-preset-es2015": "^6.24.0",
+ "camelcase": "^4.0.0",
+ "clean-webpack-plugin": "^0.1.16",
+ "css-loader": "^0.27.3",
+ "dotenv": "^4.0.0",
+ "extract-text-webpack-plugin": "^2.1.0",
+ "file-loader": "^0.10.1",
+ "html-loader": "^0.4.5",
+ "html-webpack-plugin": "^2.28.0",
+ "ng-file-upload": "^12.2.13",
+ "node-sass": "^4.5.1",
+ "pascalcase": "^0.1.1",
+ "resolve-url-loader": "^2.0.2",
+ "sass-loader": "^6.0.3",
+ "style-loader": "^0.16.1",
+ "ui-router": "^1.0.0-alpha.3",
+ "url-loader": "^0.5.8",
+ "webpack": "^2.3.2"
+ },
+ "devDependencies": {
+ "angular-mocks": "^1.6.4",
+ "jasmine-core": "^2.5.2",
+ "karma": "^1.5.0",
+ "karma-chrome-launcher": "^2.0.0",
+ "karma-jasmine": "^1.1.0",
+ "karma-mocha-reporter": "^2.2.3",
+ "karma-phantomjs-launcher": "^1.0.4",
+ "karma-webpack": "^2.0.3",
+ "webpack-dev-server": "^2.4.2"
+ }
+}
diff --git a/lab-khalid/test/auth-service-test.js b/lab-khalid/test/auth-service-test.js
new file mode 100644
index 0000000..b06b494
--- /dev/null
+++ b/lab-khalid/test/auth-service-test.js
@@ -0,0 +1,31 @@
+'use strict';
+
+describe('Auth Service', function() {
+
+ beforeEach(() => {
+ angular.mock.module('cfgram');
+ angular.mock.inject(($rootScope, authService, $window, $httpBackend) => {
+ this.$window = $window;
+ this.$rootScope = $rootScope;
+ this.authService = authService;
+ this.$httpBackend = $httpBackend;
+ });
+ });
+
+ describe('authService.getToken', () => {
+ it('should return a token', () => {
+ this.authService.token = null;
+ this.$window.localStorage.setItem('token', 'test token');
+
+ this.authService.getToken()
+ .then( token => {
+ expect(token).toEqual('test token');
+ })
+ .catch( err => {
+ expect(err).toEqual(null);
+ });
+
+ this.$rootScope.$apply();
+ });
+ });
+});
diff --git a/lab-khalid/test/edit-gallery-test.js b/lab-khalid/test/edit-gallery-test.js
new file mode 100644
index 0000000..a0682dc
--- /dev/null
+++ b/lab-khalid/test/edit-gallery-test.js
@@ -0,0 +1,62 @@
+'use strict';
+
+describe( 'Edit gallery component test', function(){
+
+ beforeEach( () => {
+ angular.mock.module('cfgram');
+ angular.mock.inject(($rootScope, $componentController, $httpBackend, authService) => {
+ this.$rootScope = $rootScope;
+ this.$componentController = $componentController;
+ this.$httpBackend = $httpBackend;
+ this.authService = authService;
+ });
+ });
+
+ it('should contain the proper component binding', () => {
+ let mockBinding = {
+ gallery: {
+ name: 'test name gallery',
+ desc: 'test gallery description'
+ }
+ };
+
+ let editGalleryCtrl = this.$componentController('editGallery', null, mockBinding);
+ expect(editGalleryCtrl.gallery.name).toEqual(mockBinding.gallery.name);
+ expect(editGalleryCtrl.gallery.desc).toEqual(mockBinding.gallery.desc);
+
+ this.$rootScope.$apply();
+ });
+
+ describe('editGalleryController.updateGallery', () => {
+ it('should make a valid put request', ()=> {
+ let url = 'http://localhost:8088/api/gallery/12345';
+ let headers = {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ Authorization: 'Bearer test token'
+ };
+
+ this.$httpBackend.expectPUT(url, {
+ _id: '12345',
+ name: 'updated name',
+ desc: 'updated desc'
+ }, headers).respond(200);
+
+ let mockBinding = {
+ gallery: {
+ _id: '12345',
+ name: 'updated name',
+ desc: 'updated description'
+ }
+ };
+
+ let editGalleryCtrl = this.$componentController('editGallery', null, mockBinding);
+ editGalleryCtrl.gallery.name = 'updated name';
+ editGalleryCtrl.gallery.desc = 'updated desc';
+ editGalleryCtrl.updateGallery();
+ this.$httpBackend.flush();
+ this.$rootScope.$apply();
+
+ });
+ });
+});
diff --git a/lab-khalid/test/example-test.js b/lab-khalid/test/example-test.js
new file mode 100644
index 0000000..01b00f2
--- /dev/null
+++ b/lab-khalid/test/example-test.js
@@ -0,0 +1,7 @@
+'use strict';
+
+describe('Example Test', function() {
+ it('should pass this test', () => {
+ expect(true).toEqual(true);
+ });
+});
\ No newline at end of file
diff --git a/lab-khalid/test/gallery-item-component-test.js b/lab-khalid/test/gallery-item-component-test.js
new file mode 100644
index 0000000..2e8d52c
--- /dev/null
+++ b/lab-khalid/test/gallery-item-component-test.js
@@ -0,0 +1,65 @@
+'use strict';
+
+describe('Gallery Item Component', function(){
+
+ beforeEach( () => {
+ angular.mock.module('cfgram');
+ angular.mock.inject(($rootScope, $componentController, $httpBackend, authService) => {
+ this.$rootScope = $rootScope;
+ this.$componentController = $componentController;
+ this.$httpBackend = $httpBackend;
+ this.authService = authService;
+ });
+ });
+
+ describe('galleryItemCtrl.deleteDone', () => {
+ it('should call deleteDone', () => {
+ let mockBinding = {
+ gallery: {
+ _id: '12345',
+ name: 'test name',
+ desc: 'test description',
+ pics: []
+ },
+ deleteDone: function(data){
+ expect(data.galleryData._id).toEqual('12345');
+ }
+ };
+
+ let galleryItemCtrl = this.$componentController('galleryItem', null, mockBinding);
+ galleryItemCtrl.deleteDone({galleryData: galleryItemCtrl.gallery});
+ this.$rootScope.$apply();
+ });
+ });
+
+ it('should call deleteDone with gallery after galleryDelete', () => {
+ let url = 'http://localhost:8088/api/gallery/12345';
+ let headers = {
+ Authorization: 'Bearer test token',
+ Accept: 'application/json, text/plain, */*'
+ };
+
+ let mockBindings = {
+ gallery: {
+ _id: '12345',
+ name: 'test name',
+ desc: 'test description',
+ pics: []
+ },
+ deleteDone: function(data){
+ expect(data.galleryData._id).toEqual(mockBindings.gallery._id);
+ }
+ };
+
+ this.$httpBackend.expectDELETE(url, headers).respond(204);
+
+ let galleryItemCtrl = this.$componentController('galleryItem', null, mockBindings);
+ galleryItemCtrl.deleteGallery();
+
+ this.$httpBackend.flush();
+ this.$rootScope.$apply();
+ });
+
+});
+
+//finish
\ No newline at end of file
diff --git a/lab-khalid/test/gallery-service-test.js b/lab-khalid/test/gallery-service-test.js
new file mode 100644
index 0000000..5989cd9
--- /dev/null
+++ b/lab-khalid/test/gallery-service-test.js
@@ -0,0 +1,70 @@
+'use strict';
+
+describe('Gallery Service', function() {
+
+ beforeEach(() => {
+ angular.mock.module('cfgram');
+ angular.mock.inject(($rootScope, authService, galleryService, $window, $httpBackend) => {
+ this.$window = $window;
+ this.$rootScope = $rootScope;
+ this.authService = authService;
+ this.galleryService = galleryService;
+ this.$httpBackend = $httpBackend;
+ });
+ });
+
+ describe('galleryService.createGallery', () => {
+ it('should create a new gallery', () => {
+ let galleryData = {
+ name: 'example gallery',
+ desc: 'example description'
+ };
+
+ let headers = {
+ 'Content-Type': 'application/json',
+ Accept: 'application/json',
+ Authorization: 'Bearer test token'
+ };
+
+ this.$httpBackend.expectPOST('http://localhost:8088/api/gallery', galleryData, headers)
+ .respond(200, {
+ _id: '1234',
+ username: 'testuser',
+ name: galleryData.name,
+ desc: galleryData.desc,
+ pics: []
+ });
+
+ this.galleryService.createGallery(galleryData);
+ this.$httpBackend.flush();
+ this.$rootScope.$apply();
+ });
+ });
+
+ // TODO: create another test for deleting a gallery
+
+ describe('galleryService.deleteGallery', () => {
+ it('should delete a gallery', () => {
+ let galleryData = {
+ name: 'example gallery',
+ desc: 'example description'
+ };
+
+ let headers = {
+ 'Content-Type': 'application/json',
+ Accept: 'application/json',
+ Authorization: 'Bearer test token'
+ };
+
+ this.$httpBackend.expectPOST('http://localhost:8088/api/gallery', galleryData, headers)
+ .respond(200, {
+ _id: '1234',
+ username: 'testuser',
+ name: galleryData.name,
+ desc: galleryData.desc,
+ pics: []
+ });
+ });
+ });
+
+});
\ No newline at end of file
diff --git a/lab-khalid/webpack.config.js b/lab-khalid/webpack.config.js
new file mode 100644
index 0000000..92eeaf5
--- /dev/null
+++ b/lab-khalid/webpack.config.js
@@ -0,0 +1,47 @@
+'use strict';
+
+
+const
+ HTMLPlugin = require('html-webpack-plugin'),
+ ExtractTextPlugin = require('extract-text-webpack-plugin'),
+ webpack = require('webpack'),
+ production = process.env.NODE_ENV === 'production',
+ dotenv = require('dotenv');
+
+dotenv.load();
+
+module.exports = {
+ devtool: 'eval',
+ entry: `${__dirname}/app/entry.js`,
+ output: {
+ filename: 'bundle.js',
+ path: `${__dirname}/build`
+ },
+ plugins:[
+ new HTMLPlugin({
+ template: `${__dirname}/app/index.html`
+ }),
+ new ExtractTextPlugin('bundle.css'),
+ new webpack.DefinePlugin({
+ __API_URL__: JSON.stringify(process.env.API_URL),
+ __DEBUG__: JSON.stringify(!production)
+ })
+ ],
+ module:{
+ rules:[
+ {
+ test: /\.js$/,
+ exclude: /node_modules/,
+ loader: 'babel-loader'
+ },
+ {
+ test: /\.scss$/,
+ loader: ExtractTextPlugin.extract(['css-loader', 'sass-loader'])
+ },
+ {
+ test: /\.html$/,
+ loader: 'html-loader'
+ }
+ ]
+ }
+};