diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..439b9cf Binary files /dev/null and b/.DS_Store differ diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 0000000..beb7358 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory" : "client/bower_components" +} \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index f0cc37b..c7101bb 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,7 +12,7 @@ module.exports = function (grunt) { bower: { dest: 'client/dist/bower.js', src: ['client/bower_components/jquery/jquery.js', - 'client/bower_components/lodash/lodash.compat.js', + 'client/bower_components/lodash/dist/lodash.compat.js', 'client/bower_components/eventEmitter/EventEmitter.js', 'client/bower_components/get-style-property/get-style-property.js', 'client/bower_components/get-size/get-size.js', @@ -24,7 +24,7 @@ module.exports = function (grunt) { 'client/bower_components/masonry/masonry.js', 'client/bower_components/imagesloaded/imagesloaded.js', 'client/bower_components/angular/angular.js', - 'client/bower_components/angular-ui-router/angular-ui-router.js', + 'client/bower_components/angular-ui-router/release/angular-ui-router.min.js', 'client/bower_components/angular-masonry/angular-masonry.js', 'client/bower_components/angular-strap/dist/angular-strap.min.js', 'client/bower_components/angular-strap/dist/angular-strap.tpl.min.js', @@ -118,10 +118,10 @@ module.exports = function (grunt) { nodemon.stdout.pipe(process.stdout); nodemon.stderr.pipe(process.stderr); - grunt.task.run(['clean', 'concat:bower', 'concat:client', 'stylus', 'uglify:dev', 'watch']); + grunt.task.run(['clean', 'concat:bower', 'concat:client', 'stylus', 'uglify:dev' , 'watch']); }); - grunt.registerTask('build', ['clean', 'bower', 'concat:bower', 'concat:client', 'stylus', 'uglify:build']); + grunt.registerTask('build', ['clean', 'bower', 'concat:bower', 'concat:client', 'stylus','uglify:build']); grunt.registerTask('test', ['mochaTest']); }; diff --git a/bower.json b/bower.json index 4ae0b16..ca278e1 100644 --- a/bower.json +++ b/bower.json @@ -18,11 +18,15 @@ "tests" ], "dependencies": { + "angular": "~1.3", "angular-masonry": "~0.9.0", - "angular": "~1.2.22", "jquery": "~2.1.1", "lodash": "~2.4.1", "angular-ui-router": "~0.2.10", - "angular-strap": "~2.1.1" + "angular-strap": "~2.1.1", + "angular-socket-io": "~0.6.0" + }, + "resolutions": { + "angular": "~1.3" } } diff --git a/client/app/app.js b/client/app/app.js index 85343be..4e1b4f5 100644 --- a/client/app/app.js +++ b/client/app/app.js @@ -1,7 +1,11 @@ +// The applcations states are created using ui-router . +//Here the controller,templateURL that each state uses are specified too. + (function(){ -'use strict'; +'use strict'; var WaddleConfig = function ($stateProvider, $urlRouterProvider) { + //creates an application state $stateProvider .state('frontpage', { url: '/', @@ -36,8 +40,31 @@ var WaddleConfig = function ($stateProvider, $urlRouterProvider) { }) .state('map.feed', { url: '/feed', - templateUrl: '../app/modules/pages/map/feed.html', - controller: 'FeedController as mapFeed' + views: { + '': { + templateUrl: '../app/modules/pages/map/feed.html', + controller: 'FeedController as mapFeed' + }, + 'profile': { + templateUrl: '../app/modules/pages/map/profile.html', + controller: 'ProfileController' + } + }, + }) + .state('map.feed.checkin', { + url: '/checkin', + templateUrl: '../app/modules/pages/map/checkin.html', + controller: 'CheckinController' + }) + .state('map.feed.checkin.post', { + url: '/:venue', + templateUrl: '../app/modules/pages/map/checkinpost.html', + controller: 'CheckinController' + }) + .state('map.feed.checkin.post.photoupload', { + url: '/photoupload', + templateUrl: '../app/modules/pages/map/photoupload.html', + controller: 'CheckinController' }) .state('map.feed.footprint', { url: '/:footprint', @@ -46,12 +73,13 @@ var WaddleConfig = function ($stateProvider, $urlRouterProvider) { .state('map.footprints', { url: '/footprints', templateUrl: '../app/modules/pages/map/footprints.html', - controller: 'FeedController as mapFootprints' + controller: 'FeedController as mapFeed' }) - +//when none of the above state match the URL then redirect the page to state represented by '/' $urlRouterProvider.otherwise('/'); }; +//All the depenedent modules in the app are registered . Through config method application states are configired . angular.module('waddle', [ 'waddle.controllers', 'waddle.directives', @@ -61,7 +89,8 @@ angular.module('waddle', [ 'mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.dropdown', - 'ngSanitize' + 'ngSanitize', + 'btford.socket-io' ]).config(['$stateProvider', '$urlRouterProvider', WaddleConfig]); // angular.module('mgcrea.ngStrap') diff --git a/client/app/modules/controllers.js b/client/app/modules/controllers.js index 0996f61..ce030df 100644 --- a/client/app/modules/controllers.js +++ b/client/app/modules/controllers.js @@ -1,3 +1,3 @@ (function() { -angular.module('waddle.controllers', ['waddle.frontpage', 'waddle.map', 'waddle.feed', 'waddle.friends', 'waddle.navbar']); +angular.module('waddle.controllers', ['waddle.frontpage', 'waddle.map', 'waddle.feed', 'waddle.profile', 'waddle.friends', 'waddle.navbar', 'waddle.checkin']); })(); \ No newline at end of file diff --git a/client/app/modules/pages/frontpage/frontpage.html b/client/app/modules/pages/frontpage/frontpage.html index f2fd741..97ae508 100644 --- a/client/app/modules/pages/frontpage/frontpage.html +++ b/client/app/modules/pages/frontpage/frontpage.html @@ -9,6 +9,7 @@

Waddle

Your world. Your footprints.

+
diff --git a/client/app/modules/pages/frontpage/frontpage.js b/client/app/modules/pages/frontpage/frontpage.js index 8dc6354..c490a45 100644 --- a/client/app/modules/pages/frontpage/frontpage.js +++ b/client/app/modules/pages/frontpage/frontpage.js @@ -1,3 +1,4 @@ + (function(){ var FrontpageController = function (UserRequests, $scope, $state) { @@ -11,6 +12,7 @@ var FrontpageController = function (UserRequests, $scope, $state) { }); }; + var sendUserDataToServer = function(fbToken, fbData){ window.sessionStorage.userFbID = fbData.id; @@ -19,16 +21,18 @@ var FrontpageController = function (UserRequests, $scope, $state) { name: fbData.name, fbToken: fbToken }; - +//when sucessfully connected to fb account , loading screen is made active $state.go('loading'); UserRequests.sendUserData(userData) .then(function(storedUserData){ UserRequests.allData = storedUserData.data + //Here map state is set to active $state.go('map'); }); }; +//gets login status of the facebook account openFB.getLoginStatus(function (response){ if (response.status === 'connected'){ console.log('connected'); @@ -38,6 +42,7 @@ var FrontpageController = function (UserRequests, $scope, $state) { } }); +//when user clicks lets waddle this function is invoked which calls facebook login function in return $scope.login = function(){ openFB.login(function (response) { if(response.status === 'connected') { @@ -47,11 +52,13 @@ var FrontpageController = function (UserRequests, $scope, $state) { alert('Facebook login failed: ' + response.error); } }, { + //to tell fb that these information of the user will be accessed scope: 'user_friends, user_tagged_places, user_photos, read_stream' }); }; }; +//Injects the services needed by the controller FrontpageController.$inject = ['UserRequests', '$scope', '$state'] //Start creating Angular module diff --git a/client/app/modules/pages/map/checkin-post.html b/client/app/modules/pages/map/checkin-post.html new file mode 100644 index 0000000..3867200 --- /dev/null +++ b/client/app/modules/pages/map/checkin-post.html @@ -0,0 +1,5 @@ + +

HOOBITY HOOBIty HOO

+ \ No newline at end of file diff --git a/client/app/modules/pages/map/checkin.html b/client/app/modules/pages/map/checkin.html new file mode 100644 index 0000000..eaaa5ee --- /dev/null +++ b/client/app/modules/pages/map/checkin.html @@ -0,0 +1,21 @@ +
+
+ +



+
+
+
+

{{venue.name}}

+
+

{{venue.location.formattedAddress[0]}} {{venue.location.formattedAddress[1]}}

+
+
+
+
+ diff --git a/client/app/modules/pages/map/checkin.js b/client/app/modules/pages/map/checkin.js new file mode 100644 index 0000000..611c062 --- /dev/null +++ b/client/app/modules/pages/map/checkin.js @@ -0,0 +1,46 @@ +(function(){ + +var CheckinController = function ($scope, NativeCheckin){ + $scope.venues = null; + + + $scope.venueData = {}; + + $scope.s3Upload = NativeCheckin.s3_upload; + + $scope.passSelectedVenueInfoToPostModal = function (venueInfo) { + $scope.venue = venueInfo; + } + + $scope.sendCheckinDataToServer = function(venueInfo) { + venueInfo.facebookID = window.sessionStorage.userFbID; + venueInfo.footprintCaption = $scope.footprintCaption; + NativeCheckin.s3_upload() + .then(function (public_url) { + venueInfo.photo = public_url; + console.log('venueInfo: ' + JSON.stringify(venueInfo)); + NativeCheckin.sendCheckinDataToServer(venueInfo) + }) + .then(function (data) { + console.log(data); + }) + } + + $scope.getAndParseUserInput = function () { + var venueQuery = $scope.venueQuery.replace(" ", "%20"); + var locationQuery = $scope.locationQuery.replace(" ", "%20"); + NativeCheckin.searchFoursquareVenues({near: locationQuery, query: venueQuery}) + .then(function (results) { + console.log(results); + $scope.venues = results.data.response.venues; + }) + } +} +// Inject all the depependent services needed by the controller +CheckinController.$inject = ['$scope', 'NativeCheckin']; + +//Start creating Angular module +angular.module('waddle.checkin', []) + .controller('CheckinController', CheckinController); + +})(); \ No newline at end of file diff --git a/client/app/modules/pages/map/checkinpost.html b/client/app/modules/pages/map/checkinpost.html new file mode 100644 index 0000000..5d28c38 --- /dev/null +++ b/client/app/modules/pages/map/checkinpost.html @@ -0,0 +1,18 @@ + +
+
+ +

{{venue.name}}

+ +
+
+ +
\ No newline at end of file diff --git a/client/app/modules/pages/map/feed.html b/client/app/modules/pages/map/feed.html index 49c477f..a91288e 100644 --- a/client/app/modules/pages/map/feed.html +++ b/client/app/modules/pages/map/feed.html @@ -1,22 +1,46 @@
-
-

- {{footprint.place.name}} -

- - +
+

Feed

+ +
+
+

{{footprint.user.name}}

+ + + {{footprint.checkin.checkinTime | date : shortDate}}
- {{footprint.checkin.checkinTime | date : shortDate}} -
- +

+ {{footprint.place.name}} +

+
+ +

{{footprint.checkin.caption}}

+
+
+ +
+
+
-
- +
+

"{{footprint.checkin.caption}}"

-
-

"{{footprint.checkin.caption}}"

+
+ +

{{comment.commenter.name}}

+ {{comment.comment.time | date : shortDate}}
+

{{comment.comment.text}}

+
120 Character Max diff --git a/client/app/modules/pages/map/feed.js b/client/app/modules/pages/map/feed.js index 4c09a43..ace854f 100644 --- a/client/app/modules/pages/map/feed.js +++ b/client/app/modules/pages/map/feed.js @@ -1,6 +1,6 @@ (function(){ -var FeedController = function (MapFactory, FootprintRequests, Auth, $scope, $rootScope, $state) { +var FeedController = function (MapFactory, FootprintRequests, UserRequests, Auth, $scope, $rootScope, $state, Socket) { Auth.checkLogin() .then( function (){ // Finds all points on the map that are within the bottom left and top right @@ -17,9 +17,57 @@ var FeedController = function (MapFactory, FootprintRequests, Auth, $scope, $roo $scope.$apply(function(){ MapFactory.filterFeedByBounds($scope.currentMap.getBounds()) }); + }); } + $scope.feedDisplay = function (photo, caption) { + if(photo === 'null' && caption === 'null') { + return "bothNull"; + } else if(photo !== 'null' && caption !== 'null') { + return "bothTrue"; + } else if (photo === 'null' && caption !== 'null'){ + return "captionTrue"; + } else { + return "photoTrue"; + } + } + + $scope.search = {query: null}; + + $scope.$on('displayFootprint', function (event, footprintNotification) { + console.log('footprintNotification', footprintNotification); + $scope.getFootprint(footprintNotification); + event.stopPropagation(); + }); + + $scope.filterMap = function () { + console.log($scope.search.query); + MapFactory.searchMarkersByPlaceName($scope.search.query); + }; + + Socket.on('notification', function(data) { + console.log('notify moi' + data); + }); + + $scope.socketTest = function() { + Socket.emit('hi', 'hello my socket'); + Socket.forward('news', $scope); + $scope.$on('Socket:news', function(ev, data) { + console.log(data); + $scope.theData = data; + }) + } + Socket.on('hi', function(data) { + console.log('client says: ' + data); + }) + + // $scope.footprintsCount = UserRequests.allData.allCheckins.length; + + $scope.removeComment = function() { + console.log('reached remove comment'); + } + $scope.addPropsToCheckin = function (footprint){ var propsData = { @@ -39,7 +87,7 @@ var FeedController = function (MapFactory, FootprintRequests, Auth, $scope, $roo }); }; - $scope.addCheckinToBucketlist = function (footprint){ + $scope.addCheckinToBucketList = function (footprint){ var bucketListData = { facebookID: window.sessionStorage.userFbID, checkinID: footprint.checkin.checkinID @@ -53,6 +101,18 @@ var FeedController = function (MapFactory, FootprintRequests, Auth, $scope, $roo }); }; + $scope.removeCheckinFromBucketList = function (footprint){ + console.log('removed?'); + var bucketListData = { + facebookID: window.sessionStorage.userFbID, + checkinID: footprint.checkin.checkinID + }; + FootprintRequests.removeFromBucketList(bucketListData) + .then(function (data){ + MapFactory.markerQuadTree.addPropertyToCheckin(footprint, 'bucketed', false); + }); + }; + $scope.selectedFootprintInteractions = null; // Send request to database for user props and comments data @@ -83,14 +143,34 @@ var FeedController = function (MapFactory, FootprintRequests, Auth, $scope, $roo $scope.selectedFootprintInteractions.comments = data.data.comments; }); }; +// $scope.removeCommenttest = function() + // { + // console.log("del reached"); + //} + + $scope.removeComment = function (footprint, comment){ + console.log(footprint); + console.log(comment); + var commentData = { + facebookID: comment.commenter.facebookID, + checkinID: footprint.checkin.checkinID, + commentID : comment.comment.commentID + }; + console.log(commentData); + FootprintRequests.removeComment(commentData) + .then(function (data){ + console.log("success"); + //MapFactory.markerQuadTree.addPropertyToCheckin(footprint, 'bucketed', false); + }); + }; }); } -FeedController.$inject = ['MapFactory', 'FootprintRequests', 'Auth', '$scope', '$rootScope', '$state']; +FeedController.$inject = ['MapFactory', 'FootprintRequests', 'UserRequests', 'Auth', '$scope', '$rootScope', '$state', 'Socket']; // Custom Submit will avoid binding data to multiple fields in ng-repeat and allow custom on submit processing -var CustomSubmitDirective = function(FootprintRequests) { +var CustomSubmitDirective = function(FootprintRequests, Socket) { return { restrict: 'A', link: function( scope , element , attributes ){ @@ -135,19 +215,20 @@ var CustomSubmitDirective = function(FootprintRequests) { var commentData = { clickerID: window.sessionStorage.userFbID, checkinID: scope.footprint.checkin.checkinID, + commentID: scope.footprint.comments[0], text: scope.comment } FootprintRequests.addComment(commentData) - .then(function (data){ - + .then(function (data) { + Socket.emit('comment posted', commentData); if (FootprintRequests.openFootprint){ scope.updateFootprint(FootprintRequests.openFootprint) } scope.data.currentComment = '' //$element[0][0].value = '' }) - console.log(commentData) + console.log(commentData); scope.comment = "" scope.$apply(); }); @@ -155,7 +236,7 @@ var CustomSubmitDirective = function(FootprintRequests) { }; }; -CustomSubmitDirective.$inject = ['FootprintRequests']; +CustomSubmitDirective.$inject = ['FootprintRequests', 'Socket']; //Start creating Angular module angular.module('waddle.feed', []) diff --git a/client/app/modules/pages/map/footprint.html b/client/app/modules/pages/map/footprint.html index 3f1adfb..c02874a 100644 --- a/client/app/modules/pages/map/footprint.html +++ b/client/app/modules/pages/map/footprint.html @@ -1,29 +1,40 @@ -
- X -

{{footprint.place.name}}

-

"{{footprint.checkin.caption}}"

- - -
- - - - -

{{selectedFootprintInteractions.props}}

-
-
-

Be the first to comment!

- - - 120 Character Max - -
-
-
- +
+
+ +
+ + +
+
+
+ +

{{footprint.user.name}}

+ + +

{{footprint.place.name}}

+

"{{footprint.checkin.caption}}"

+ +
+
+
+
+ +
+

{{comment.commenter.name}}

+ {{comment.comment.time | date : shortDate}}
+

{{comment.comment.text}}


+ +
+
+

Be the first to comment!

+
+ + 120 Character Max +
+
+
-

{{comment.comment.text}}

- {{comment.comment.time | date : shortDate}} -

{{comment.commenter.name}}

-
+
\ No newline at end of file diff --git a/client/app/modules/pages/map/friends.html b/client/app/modules/pages/map/friends.html index 15e4e04..3f41c97 100644 --- a/client/app/modules/pages/map/friends.html +++ b/client/app/modules/pages/map/friends.html @@ -1,10 +1,9 @@
-
+
-

- {{friend.name}} -

+

{{friend.name}}

+

{{friend.footprintsCount}} footprints

-
+
\ No newline at end of file diff --git a/client/app/modules/pages/map/friends.js b/client/app/modules/pages/map/friends.js index f4ac9d7..27ba9ff 100644 --- a/client/app/modules/pages/map/friends.js +++ b/client/app/modules/pages/map/friends.js @@ -1,24 +1,29 @@ (function(){ -var FriendsController = function ($scope, $state, UserRequests, MapFactory) { +var FriendsController = function ($scope, $state, UserRequests, MapFactory, $rootScope) { if(UserRequests.allData) { $scope.allUserFriends = UserRequests.allData.friends; - console.log($scope.allUserFriends); } + //sets profile info; if friend data not provided, defaults to logged in user's profile + +//gets friend data and builds quadtree representing friend data on the map $scope.clickFriend = function (friend) { var viewer = window.sessionStorage.userFbID; UserRequests.getUserData(friend, viewer) .then(function (data){ - MapFactory.markerQuadTree = MapFactory.handleUserCheckinData(data.data); + MapFactory.markerQuadTree = MapFactory.handleUserCheckinData(data.data.footprints); + $rootScope.$broadcast("displayFriendInfo", data.data.user); $state.go('map.feed') }); }; }; -FriendsController.$inject = ['$scope', '$state', 'UserRequests', 'MapFactory']; +//Injects all the dependencies needed by FriendController +FriendsController.$inject = ['$scope', '$state', 'UserRequests', 'MapFactory', '$rootScope']; +//Creates module waddle.friends and registers the controller function to it angular.module('waddle.friends', []) .controller('FriendsController', FriendsController); diff --git a/client/app/modules/pages/map/map.html b/client/app/modules/pages/map/map.html index e3fb771..a9440e8 100644 --- a/client/app/modules/pages/map/map.html +++ b/client/app/modules/pages/map/map.html @@ -1,3 +1,3 @@ -
+
\ No newline at end of file diff --git a/client/app/modules/pages/map/map.js b/client/app/modules/pages/map/map.js index 41b70b7..5e1ebbe 100644 --- a/client/app/modules/pages/map/map.js +++ b/client/app/modules/pages/map/map.js @@ -11,6 +11,7 @@ var MapController = function (Auth, UserRequests, MapFactory, $scope, $state, $s } }); + $scope.data = {}; Auth.checkLogin() @@ -18,7 +19,7 @@ var MapController = function (Auth, UserRequests, MapFactory, $scope, $state, $s if(UserRequests.allData) { $scope.currentMap = MapFactory.initializeMap(); - MapFactory.currentMap = $scope.currentMap; + // MapFactory.currentMap = $scope.currentMap; MapFactory.markerQuadTree = MapFactory.handleUserCheckinData(UserRequests.allData.allCheckins); $state.go('map.feed'); } else { @@ -27,6 +28,7 @@ var MapController = function (Auth, UserRequests, MapFactory, $scope, $state, $s }); } +// Inject all the depependent services needed by the controller MapController.$inject = ['Auth', 'UserRequests', 'MapFactory', '$scope', '$state', '$stateParams', '$rootScope']; //Start creating Angular module diff --git a/client/app/modules/pages/map/photoupload.html b/client/app/modules/pages/map/photoupload.html new file mode 100644 index 0000000..6a6ff5b --- /dev/null +++ b/client/app/modules/pages/map/photoupload.html @@ -0,0 +1,14 @@ +
















+
+ +

Please select a file

+
+ +
+ +
+

+ +
+
+ diff --git a/client/app/modules/pages/map/profile.html b/client/app/modules/pages/map/profile.html new file mode 100644 index 0000000..4ee1acc --- /dev/null +++ b/client/app/modules/pages/map/profile.html @@ -0,0 +1,10 @@ + +
+ +
+

{{username}}


+ Professional Waddler
+

{{footprintsCount}} footprints

+
+
diff --git a/client/app/modules/pages/map/profile.js b/client/app/modules/pages/map/profile.js new file mode 100644 index 0000000..bd8af32 --- /dev/null +++ b/client/app/modules/pages/map/profile.js @@ -0,0 +1,29 @@ +(function(){ + +var ProfileController = function ($scope, $state, UserRequests){ + + + if(UserRequests.allData) { + console.log('Profile Controller: ', UserRequests.allData); + $scope.username = UserRequests.allData.name; + $scope.picture = UserRequests.allData.fbProfilePicture + $scope.footprintsCount = UserRequests.allData.footprintsCount; + } + + $scope.$on('displayFriendInfo', function (event, friendProfileData) { + console.log('friendProfileData: ', friendProfileData); + $scope.username = friendProfileData.name; + $scope.picture = friendProfileData.fbProfilePicture + $scope.footprintsCount = friendProfileData.footprintsCount; + }); + + +} +// Inject all the depependent services needed by the controller +ProfileController.$inject = ['$scope', '$state', 'UserRequests']; + +//Start creating Angular module +angular.module('waddle.profile', []) + .controller('ProfileController', ProfileController); + +})(); diff --git a/client/app/modules/pages/partials/navbar.html b/client/app/modules/pages/partials/navbar.html index 52e1a99..91d4fac 100644 --- a/client/app/modules/pages/partials/navbar.html +++ b/client/app/modules/pages/partials/navbar.html @@ -1,4 +1,63 @@ -
- XX + X
\ No newline at end of file diff --git a/client/app/modules/services.js b/client/app/modules/services.js index de90683..608fc16 100644 --- a/client/app/modules/services.js +++ b/client/app/modules/services.js @@ -1,3 +1,4 @@ +//create module and configure all the services of the application (function() { -angular.module('waddle.services', ['waddle.services.auth', 'waddle.services.mapFactory', 'waddle.services.userRequestsFactory', 'waddle.services.footprintRequestsFactory']); +angular.module('waddle.services', ['waddle.services.auth', 'waddle.services.mapFactory', 'waddle.services.userRequestsFactory', 'waddle.services.footprintRequestsFactory', 'waddle.services.socket', 'waddle.services.nativeCheckinFactory']); })(); diff --git a/client/app/modules/services/auth.js b/client/app/modules/services/auth.js index f0b07e8..6eb0363 100644 --- a/client/app/modules/services/auth.js +++ b/client/app/modules/services/auth.js @@ -23,8 +23,9 @@ var Auth = function ($q, $state){ window.sessionStorage.clear(); window.localStorage.clear(); + - $state.go('frontpage'); + $state.go('frontpage',{},{reload: true}); }; return { diff --git a/client/app/modules/services/footprintRequestsFactory.js b/client/app/modules/services/footprintRequestsFactory.js index 55b140c..03cf24c 100644 --- a/client/app/modules/services/footprintRequestsFactory.js +++ b/client/app/modules/services/footprintRequestsFactory.js @@ -20,6 +20,16 @@ var FootprintRequests = function ($http){ } }, + removeFromBucketList: function (data) { + if (data) { + return $http({ + method: 'POST', + data: data, + url: 'api/checkins/removebucket' + }); + } + }, + addComment: function (data) { if (data && data.text) { return $http({ @@ -30,6 +40,16 @@ var FootprintRequests = function ($http){ } }, + removeComment : function(data) { + if (data) { + return $http({ + method : 'POST', + data : data , + url : 'api/checkins/removecomment' + }); + } + }, + giveProps: function (data) { if (data) { return $http({ diff --git a/client/app/modules/services/mapFactory.js b/client/app/modules/services/mapFactory.js index 8f001b5..9342f28 100644 --- a/client/app/modules/services/mapFactory.js +++ b/client/app/modules/services/mapFactory.js @@ -107,7 +107,7 @@ var MapFactory = function (){ var mapFactoryVars = { // Markers in bounds are stored on factory to be accessible from any state markerQuadTree: null, - currentMap: currentMap, + // currentMap: currentMap, // Share data points in bounds accross different views. // Mainly added to account for navbar's need for inbounds data currentInBounds: currentInBounds, @@ -171,6 +171,19 @@ var MapFactory = function (){ aggregatedMarkers.addLayer(marker); }, + searchMarkersByPlaceName: function (searchQuery) { + var processedSearchQuery = searchQuery.toLowerCase(); + function checkPlaceName (marker) { + console.log(marker.title); + return marker.title + .toLowerCase() + .indexOf(processedSearchQuery) !== -1; + + } + aggregatedMarkers.setFilter(checkPlaceName); + + }, + handleUserCheckinData: function (allFootprints) { aggregatedMarkers.clearLayers(); diff --git a/client/app/modules/services/nativeCheckinFactory.js b/client/app/modules/services/nativeCheckinFactory.js new file mode 100644 index 0000000..4a3be28 --- /dev/null +++ b/client/app/modules/services/nativeCheckinFactory.js @@ -0,0 +1,66 @@ +(function(){ + +var NativeCheckin = function ($http, $q){ + + return { + + searchFoursquareVenues: function (params) { + if (params) { + return $http({ + method: 'GET', + url: 'https://api.foursquare.com/v2/venues/search?' + + 'client_id=' + globals.WADDLE_FOURSQUARE_CLIENT_ID + + '&client_secret=' + globals.WADDLE_FOURSQUARE_CLIENT_SECRET + + '&v=20141027' + + '&near=' + params.near + '&query=' + params.query + }); + } + }, + + sendCheckinDataToServer: function (checkinData) { + if (checkinData) { + return $http({ + method: 'POST', + data: checkinData, + url: '/api/checkins/nativecheckin/' + }); + } + }, + + s3_upload: function() { + var deferred = $q.defer(); + var status_elem = document.getElementById("status"); + var preview_elem = document.getElementById("preview"); + console.log('status: ' + status_elem + 'preview: ' + preview_elem); + + var s3upload = new S3Upload({ + file_dom_selector: 'files', + s3_sign_put_url: 'api/checkins/sign_s3', + onProgress: function(percent, message) { + status_elem.innerHTML = 'Upload progress: ' + percent + '% ' + message; + }, + onFinishS3Put: function(public_url) { + console.log(public_url) + status_elem.innerHTML = 'Upload completed. Uploaded to: ' + public_url; + // Store this url in mongodb + // self.saveStache(newStache); + preview_elem.innerHTML = ''; + deferred.resolve(public_url); + }, + onError: function(status) { + status_elem.innerHTML = 'Upload error: ' + status; + } + }); + return deferred.promise; + } + + }; +}; + +NativeCheckin.$inject = ['$http', '$q']; + +//Start creating Angular module +angular.module('waddle.services.nativeCheckinFactory', []) + .factory('NativeCheckin', NativeCheckin); + +})(); diff --git a/client/app/modules/services/socketFactory.js b/client/app/modules/services/socketFactory.js new file mode 100644 index 0000000..9e919a1 --- /dev/null +++ b/client/app/modules/services/socketFactory.js @@ -0,0 +1,7 @@ +angular.module('waddle.services.socket', []) + .factory('Socket', function (socketFactory) { + var Socket = socketFactory(); + Socket.forward('error'); + return Socket; + }); + diff --git a/client/app/modules/services/userRequestsFactory.js b/client/app/modules/services/userRequestsFactory.js index 3d03f0e..bf38425 100644 --- a/client/app/modules/services/userRequestsFactory.js +++ b/client/app/modules/services/userRequestsFactory.js @@ -19,9 +19,21 @@ var UserRequests = function ($http){ } }, + getUserInfo: function (userFbID) { + console.log(userFbID); + if (userFbID) { + return $http({ + method: 'GET', + url: '/api/users/userinfo/' + userFbID + }); + } + + }, + // Grab existing user's checkins/data // Pass in the viewerID so that there is a context to the data returned // this allows the viewer to see whether they have liked another user's checkin + getUserData: function (userFbID, viewerID) { if (userFbID) { return $http({ @@ -31,6 +43,15 @@ var UserRequests = function ($http){ } }, + getAggregatedFeedData:function (userFbID) { + if (userFbID) { + return $http({ + method: 'GET', + url: '/api/users/aggregatefeed/' + userFbID + }); + } + }, + getBucketList: function (userFbID) { if (userFbID) { return $http({ @@ -38,6 +59,16 @@ var UserRequests = function ($http){ url: '/api/users/bucketlist/' + userFbID }); } + }, + + fetchNotifications: function (userFbID) { + if (userFbID) { + return $http({ + method: 'GET', + url: '/api/users/notifications/' + userFbID + }) + } + } }; }; diff --git a/client/index.html b/client/index.html index 44bbb82..3e27e97 100644 --- a/client/index.html +++ b/client/index.html @@ -9,14 +9,21 @@ + + +
-
+
+
+
- + + + \ No newline at end of file diff --git a/client/styles/styles.styl b/client/styles/styles.styl index 47f9fae..0593435 100644 --- a/client/styles/styles.styl +++ b/client/styles/styles.styl @@ -2,43 +2,53 @@ font-family: 'Lobster'; font-style: normal; font-weight: 400; - src: local('Lobster'), url(http://themes.googleusercontent.com/static/fonts/lobster/v6/MWVf-Rwh4GLQVBEwbyI61Q.woff) format('woff'); + src: local('Lobster'), url(https://themes.googleusercontent.com/static/fonts/lobster/v6/MWVf-Rwh4GLQVBEwbyI61Q.woff) format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), url(http://themes.googleusercontent.com/static/fonts/opensans/v8/DXI1ORHCpsQm3Vp6mXoaTXhCUOGz7vYGh680lGh-uXM.woff) format('woff'); + src: local('Open Sans Light'), local('OpenSans-Light'), url(https://themes.googleusercontent.com/static/fonts/opensans/v8/DXI1ORHCpsQm3Vp6mXoaTXhCUOGz7vYGh680lGh-uXM.woff) format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url(http://themes.googleusercontent.com/static/fonts/opensans/v8/cJZKeOuBrn4kERxqtaUH3T8E0i7KZn-EPnyo3HZu7kw.woff) format('woff'); + src: local('Open Sans'), local('OpenSans'), url(https://themes.googleusercontent.com/static/fonts/opensans/v8/cJZKeOuBrn4kERxqtaUH3T8E0i7KZn-EPnyo3HZu7kw.woff) format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 600; - src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(http://themes.googleusercontent.com/static/fonts/opensans/v8/MTP_ySUJH_bn48VBG8sNSnhCUOGz7vYGh680lGh-uXM.woff) format('woff'); + src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(https://themes.googleusercontent.com/static/fonts/opensans/v8/MTP_ySUJH_bn48VBG8sNSnhCUOGz7vYGh680lGh-uXM.woff) format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 700; - src: local('Open Sans Bold'), local('OpenSans-Bold'), url(http://themes.googleusercontent.com/static/fonts/opensans/v8/k3k702ZOKiLJc3WVjuplzHhCUOGz7vYGh680lGh-uXM.woff) format('woff'); + src: local('Open Sans Bold'), local('OpenSans-Bold'), url(https://themes.googleusercontent.com/static/fonts/opensans/v8/k3k702ZOKiLJc3WVjuplzHhCUOGz7vYGh680lGh-uXM.woff) format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 800; - src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url(http://themes.googleusercontent.com/static/fonts/opensans/v8/EInbV5DfGHOiMmvb1Xr-hnhCUOGz7vYGh680lGh-uXM.woff) format('woff'); + src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url(https://themes.googleusercontent.com/static/fonts/opensans/v8/EInbV5DfGHOiMmvb1Xr-hnhCUOGz7vYGh680lGh-uXM.woff) format('woff'); } @font-face { font-family: 'Open Sans'; font-style: italic; font-weight: 400; - src: local('Open Sans Italic'), local('OpenSans-Italic'), url(http://themes.googleusercontent.com/static/fonts/opensans/v8/xjAJXh38I15wypJXxuGMBobN6UDyHWBl620a-IRfuBk.woff) format('woff'); + src: local('Open Sans Italic'), local('OpenSans-Italic'), url(https://themes.googleusercontent.com/static/fonts/opensans/v8/xjAJXh38I15wypJXxuGMBobN6UDyHWBl620a-IRfuBk.woff) format('woff'); +} + +.white{ + color: #ffffff; + border: 0px; + background: rgba(0, 0, 0, 0); + margin: 6px; + padding: 4px; + text-align: center; + text-decoration: none; } .col-md-4 { @@ -49,6 +59,10 @@ color: #FFF; } +.aboveerrything { + z-index: 10; +} + #welcome{ width:900px; height:100%; @@ -139,6 +153,11 @@ div{ margin:0px; } +a{ + cursor: pointer; + cursor: hand; +} + h1{ font-family:'Open Sans', san-serif; font-style: bold; @@ -163,7 +182,7 @@ h3{ font-style: none; font-weight:100; font-size:16px; - color:#555555; + color: rgba(0, 192, 161, 1); line-height:180%; margin:0px; padding:0px; @@ -203,6 +222,13 @@ h8{ display:inline; font-size:10px; } +h9{ + font-family:'Open Sans', san-serif; + color:#FFF; + display:inline; + font-weight: 100; + font-size:12px; + } p{ display:inline; font-size:12px; @@ -240,34 +266,36 @@ li{ opacity: 0.2; } -.centered { - position: fixed; - top: 50%; - left: 50%; - margin-top: -300px; - margin-left: -350px; -} - #account_connect_bg { background-color:rgba(0,0,0, 0.8); position:fixed; top:0; left:0; width:100%; height:100%; - z-index: 1; + z-index: 2; } .cancel { position: absolute; - top: 144px; - left: 753px; opacity: 0; cursor: pointer; background-color: #505050 + z-index: 5; +} + +.loading{ + text-align: center; +} + +.loadingimg{ + margin-top: auto; + margin-bottom: auto; + margin-right: auto; + margin-left: auto; } .waddlelogo { - margin:5px; + margin: 0px; width:25px; height:auto; } @@ -305,6 +333,30 @@ li{ opacity: 0.2; } +#venuelist{ + display: block; +} + +.venueitem{ + background: #FFF; + margin-left: 10px; + margin-right: 100px; + margin-bottom: 10px; + padding: 5px; + border-radius: 5px; +} + +.block{ + display: block; +} + +.inline{ + display: inline; +} + +.nomargin{ + margin: 0px; +} .divhack{ position:absolute; @@ -343,6 +395,10 @@ li{ float: left; } +.floatleft{ + float:left; +} + .navigation li a { width: 100px; height: 10px; @@ -362,29 +418,68 @@ li{ background-color: #ccc; } +#profilebox{ + float: left; + padding: 10px; + margin-top: 10px; + margin-left: 10px; + border-radius: 10px; + background: rgba(255, 255, 255, 0.8); +} + +.profileboxinfo{ + display: inline-block; + margin-left:5px; +} + +.profileboxfootprints{ + margin-left: 42px; +} + .navbarprofile { float: right; - margin-right: 10px; + margin-top: auto; + margin-bottom: auto; +} + +.dropstyle { + background-color: rgba(0, 0, 0, 0); } .navbarprofile img { border-radius: 5px; overflow: hidden; - max-width: 25px; - height: 25px; + width: 25px; + max-height: 25px; + text-align: center; +} + +.navbar-default { + background-color: rgba(0,192,161,0.8); + border-color: rgba(0, 150, 130, 0.8); + border-radius: 0px; +} + +.active { + opacity: 0.8; + border-radius: 5px; } .waddlefeed { - margin-top: 40px; + margin-top: 10px; margin-right: 10px; height: 50em; width: 275px; float: right; border-radius:5px; - background-color:rgba(255,255,255,0.9); + background-color:rgba(255,255,255,0.5); overflow-y: scroll; } +.feedtitle { + margin-left: 10px; +} + .defaultpeng { -webkit-filter: grayscale(50%); -moz-filter: grayscale(80%); @@ -408,13 +503,25 @@ li{ overflow: hidden; } +.feedcomment { + margin-bottom: 10px; +} + .feeditemname { - display: inline-block; - white-space: nowrap; + display: inline; + white-space: normal; width: 77%; overflow: hidden; text-overflow: ellipsis; cursor: pointer; + font-weight: 400; + margin: 0px; + padding: 0px; +} + +.checkindate{ + float: right; + margin-right: 10px; } .feedphoto { @@ -425,8 +532,9 @@ li{ text-align:center; cursor: pointer; background-position: center; - border-radius: 5px; - padding: 5px; + border: 1px solid #e6e6e6; + border-radius: 10px; + margin-bottom: 10px; } .footprintbrick { @@ -438,12 +546,25 @@ li{ height: 17%; background-color: #fff; margin: 5px; + width: auto; + border-radius: 10px; +} + +.waddlefeedfriend:hover { + cursor: pointer; } .friendname { + display: block; + cursor:pointer; position: relative; - left: 130px; - top: -67px; + top: 50%; + transform: translateY(-50%); +} + +.footprintnumber { + margin-top: 40px; + display: block; cursor:pointer; } @@ -451,16 +572,6 @@ li{ color: Teal; } -.friendphoto { - cursor: pointer; - display: inline; - margin: 5px; - border-radius: 3px; - overflow: hidden; - width: 95px; - max-height: 95px; -} - .footprints { margin-top: 60px; margin-left: 50px; @@ -470,30 +581,92 @@ li{ overflow-y: scroll; } - .footprintitem { - top: 50px; - margin: 10px; + top: 84px; + margin-right: auto; + margin-left: auto; padding: 5px; min-height: 300px; min-width: 300px; max-height: 750px; - border-radius: 5px; + max-width: 1100px; + border-radius: 10px; overflow-y: scroll; - position: absolute; + position: fixed; background-color: rgba(255,255,255,0.9); z-index: 1; + margin-left: 50px; +} + +.checkinpost{ + margin-right: auto; + margin-left: auto; + padding: 5px; + min-height: 300px; + min-width: 300px; + max-height: 750px; + max-width: 1100px; + border-radius: 10px; + overflow-y: scroll; + position: fixed; + background-color: rgba(255,255,255,0.9); + z-index: 2; +} + +.postcheckin{ + padding: 5px; + min-height: 300px; + min-width:300px; + max-width:550px; + max-height:550px; + border-radius: 10px; + overflow-y: scroll; + background-color: #ffffff; + position: fixed; + top:50%; + left: 50%; + display: block; +} + +.form-control{ + max-height: 350px; + max-width:350px; +} + +.centered { + position: fixed; + top: 50%; + left: 50%; + margin-top: -300px; + margin-left: -200px; +} + +.fullwidth{ + width: auto; +} + +.footprintpicture{ + max-width: 700px; + max-height: 700px; + margin-left: auto; + margin-right: auto; +} + +.footprint-pic-bg{ + background-color: #808080; + border-radius: 10px + text-align: center; } .closefootprint { - font-family:'Open Sans', san-serif; - float:right; - cursor:pointer; - color: #a6a6a6; - font-size: 25px; - display: inline-block; - line-height: 0px; - padding: 11px 3px; + font-family:'Open Sans', san-serif; + float:right; + cursor:pointer; + color: #a6a6a6; + font-size: 25px; + display: inline-block; + line-height: 0px; + padding: 11px 3px; } .footprintcommentpiccontainer { @@ -504,9 +677,63 @@ li{ .footprintcommentpic { width: 70px; + border-radius: 10px; height: auto; } +/* .footprintcommentsmain{ + background: #D9D9D9; + border-radius: 5px; + padding: 1px; +} */ + +.footprintcomments{ + margin: 5px 0px; + background: #FFF; + border-radius: 5px; + padding: 4px; +} + +.deletecomment { + background: rgba(0, 0, 0, 0,); + border: 0; + color: #BFBFBF; + margin: 0; + padding: 0; +} + +.deletecomment:hover { + color: #5BAAEB; +} + +.footprintprofpic { + width: 40px; + height: 40px; + border-radius: 10px; + margin-left: auto; + margin-right: auto; + overflow: hidden; +} + +.footprintprofpicframe { + display: inline; + width: 40px; + height: 40px; + border-radius: 10px; + text-align: center; + overflow: hidden; +} + +.friendphoto { + float: left; + width: 95px; + height: 95px; + border-radius: 10px; + overflow: hidden; + display: inline; + margin: 12px; +} + .commentername { display: block; } @@ -552,11 +779,11 @@ li{ .comment_form input { position: relative; - height:24px; - width:245px; + height:26px; + width: 100%; padding:5px; - box-shadow: 0px 0px 3px #ccc, 0 10px 15px #eee inset; - border-radius: 3px; + box-shadow: 0px 0px 3px #ccc inset; + border-radius: 5px; border: none; } @@ -570,7 +797,3 @@ li{ font-size: 13px; } -.mapuiview { - -} - diff --git a/client/utils/s3upload.js b/client/utils/s3upload.js new file mode 100644 index 0000000..b6466a9 --- /dev/null +++ b/client/utils/s3upload.js @@ -0,0 +1,124 @@ +(function() { + + window.S3Upload = (function() { + + S3Upload.prototype.s3_object_name = 'default_name'; + + S3Upload.prototype.s3_sign_put_url = '/signS3put'; + + S3Upload.prototype.file_dom_selector = 'file_upload'; + + S3Upload.prototype.onFinishS3Put = function(public_url) { + return console.log('base.onFinishS3Put()', public_url); + }; + + S3Upload.prototype.onProgress = function(percent, status) { + return console.log('base.onProgress()', percent, status); + }; + + S3Upload.prototype.onError = function(status) { + return console.log('base.onError()', status); + }; + + function S3Upload(options) { + if (options == null) options = {}; + for (option in options) { + this[option] = options[option]; + } + this.handleFileSelect(document.getElementById(this.file_dom_selector)); + } + + S3Upload.prototype.handleFileSelect = function(file_element) { + var f, files, output, _i, _len, _results; + this.onProgress(0, 'Upload started.'); + files = file_element.files; + output = []; + _results = []; + for (_i = 0, _len = files.length; _i < _len; _i++) { + f = files[_i]; + _results.push(this.uploadFile(f)); + } + return _results; + }; + + S3Upload.prototype.createCORSRequest = function(method, url) { + var xhr; + xhr = new XMLHttpRequest(); + if (xhr.withCredentials != null) { + xhr.open(method, url, true); + } else if (typeof XDomainRequest !== "undefined") { + xhr = new XDomainRequest(); + xhr.open(method, url); + } else { + xhr = null; + } + return xhr; + }; + + S3Upload.prototype.executeOnSignedUrl = function(file, callback) { + var this_s3upload, xhr; + this_s3upload = this; + xhr = new XMLHttpRequest(); + xhr.open('GET', this.s3_sign_put_url + '?s3_object_type=' + file.type + '&s3_object_name=' + this.s3_object_name, true); + xhr.overrideMimeType('text/plain; charset=x-user-defined'); + xhr.onreadystatechange = function(e) { + var result; + if (this.readyState === 4 && this.status === 200) { + try { + result = JSON.parse(this.responseText); + } catch (error) { + this_s3upload.onError('Signing server returned some ugly/empty JSON: "' + this.responseText + '"'); + return false; + } + return callback(result.signed_request, result.url); + } else if (this.readyState === 4 && this.status !== 200) { + return this_s3upload.onError('Could not contact request signing server. Status = ' + this.status); + } + }; + return xhr.send(); + }; + + S3Upload.prototype.uploadToS3 = function(file, url, public_url) { + var this_s3upload, xhr; + this_s3upload = this; + xhr = this.createCORSRequest('PUT', url); + if (!xhr) { + this.onError('CORS not supported'); + } else { + xhr.onload = function() { + if (xhr.status === 200) { + this_s3upload.onProgress(100, 'Upload completed.'); + return this_s3upload.onFinishS3Put(public_url); + } else { + return this_s3upload.onError('Upload error: ' + xhr.status); + } + }; + xhr.onerror = function() { + return this_s3upload.onError('XHR error.'); + }; + xhr.upload.onprogress = function(e) { + var percentLoaded; + if (e.lengthComputable) { + percentLoaded = Math.round((e.loaded / e.total) * 100); + return this_s3upload.onProgress(percentLoaded, percentLoaded === 100 ? 'Finalizing.' : 'Uploading.'); + } + }; + } + xhr.setRequestHeader('Content-Type', file.type); + xhr.setRequestHeader('x-amz-acl', 'public-read'); + return xhr.send(file); + }; + + S3Upload.prototype.uploadFile = function(file) { + var this_s3upload; + this_s3upload = this; + return this.executeOnSignedUrl(file, function(signedURL, publicURL) { + return this_s3upload.uploadToS3(file, signedURL, publicURL); + }); + }; + + return S3Upload; + + })(); + +}).call(this); \ No newline at end of file diff --git a/package.json b/package.json index 1b55921..2bb3677 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "test": "karma start test/karma.conf.js" }, "dependencies": { - "angular": "~1.2.19", + "angular": "~1.3.0", "angular-ui-router": "~0.2.10", "body-parser": "~1.5.2", "browserify": "~5.9.1", @@ -43,7 +43,10 @@ "supertest": "^0.13.0", "request": "~2.40.0", "bower": "~1.3.9", - "grunt-bower-task": "~0.4.0" + "grunt-bower-task": "~0.4.0", + "socket.io": "~1.1.0", + "node-uuid":"1.4.1", + "aws-sdk": "*" }, "devDependencies": { "grunt-contrib-copy": "~0.5.0", diff --git a/server/api/checkins/checkinController.js b/server/api/checkins/checkinController.js index 253d93f..76d88f2 100644 --- a/server/api/checkins/checkinController.js +++ b/server/api/checkins/checkinController.js @@ -1,5 +1,7 @@ var Q = require('q'); var _ = require('lodash'); +var aws = require('aws-sdk'); +var uuid = require('node-uuid') var Checkin = require('./checkinModel.js'); var User = require('../users/userModel.js'); @@ -10,6 +12,30 @@ var facebookUtils = require('../../utils/facebookUtils.js'); var checkinController = {}; +checkinController.handleNativeCheckin = function (req, res) { + var user; + var nativeCheckin = req.body + var facebookID = req.body.facebookID + + User.find({facebookID: facebookID}) + .then(function (userNode) { + user = userNode; + return foursquareUtils.parseNativeCheckin(nativeCheckin); + }) + .then(function (parsedCheckin) { + console.log('parsedCheckin: ' + JSON.stringify(parsedCheckin)); + return user.addCheckins([parsedCheckin]); + }) + .then(function (data) { + console.log(data); + }) + .catch(function (err) { + console.log(err); + }); + + res.status(200).end(); +}; + checkinController.instagramHubChallenge = function (req, res) { res.status(200).send(req.query['hub.challenge']); }; @@ -128,6 +154,21 @@ checkinController.addToBucketList = function (req, res){ }); }; +checkinController.removeFromBucketList = function (req, res){ + var checkinID = req.body.checkinID; + var facebookID = req.body.facebookID; + + Checkin.removeFromBucketList(facebookID, checkinID) + .then(function (data){ + res.json(data); + res.status(201).end(); + }) + .catch(function(err) { + console.log(err); + res.status(500).end(); + }); +} + checkinController.addComment = function (req, res){ var clickerID = req.body.clickerID; var checkinID = req.body.checkinID; @@ -149,6 +190,22 @@ checkinController.addComment = function (req, res){ }); }; +checkinController.removeComment = function (req, res){ + var checkinID = req.body.checkinID; + var facebookID = req.body.facebookID; + var commentID = req.body.commentID ; + console.log(req.body); + Checkin.removeComment(facebookID, checkinID , commentID) + .then(function (data){ + res.json(data); + res.status(201).end(); + }) + .catch(function(err) { + console.log(err); + res.status(500).end(); + }); +} + checkinController.giveProps = function (req, res){ var clickerID = req.body.clickerID; var checkinID = req.body.checkinID; @@ -165,6 +222,7 @@ checkinController.giveProps = function (req, res){ }); }; + checkinController.getPropsAndComments = function (req, res){ var checkinID = req.params.checkinid; var data = {} @@ -203,4 +261,30 @@ checkinController.getPropsAndComments = function (req, res){ }); }; +checkinController.sign_s3 = function (req, res) { + aws.config.update({accessKeyId: process.env.AWS_ACCESS_KEY, secretAccessKey: process.env.AWS_SECRET_KEY}); + var s3 = new aws.S3(); + var aws_uuid = uuid.v4(); + var s3_params = { + Bucket: process.env.S3_BUCKET, + Key: aws_uuid, + Expires: 60, + ContentType: req.query.s3_object_type, + ACL: 'public-read' + }; + s3.getSignedUrl('putObject', s3_params, function(err, data){ + if(err){ + console.log(err); + } + else{ + var return_data = { + signed_request: data, + url: 'https://' + process.env.S3_BUCKET + '.s3.amazonaws.com/' + aws_uuid + }; + res.write(JSON.stringify(return_data)); + res.end(); + } + }); +} + module.exports = checkinController; diff --git a/server/api/checkins/checkinModel.js b/server/api/checkins/checkinModel.js index d06a94e..db0e122 100644 --- a/server/api/checkins/checkinModel.js +++ b/server/api/checkins/checkinModel.js @@ -1,6 +1,7 @@ var neo4j = require('neo4j'); var Q = require('q'); var _ = require('lodash'); +var uuid = require('node-uuid'); var db = new neo4j.GraphDatabase(process.env['WADDLE_GRAPHENEDB_URL'] || 'http://localhost:7474'); @@ -40,15 +41,46 @@ Checkin.addToBucketList = function(facebookID, checkinID){ 'RETURN checkin' ].join('\n'); + + var params = { + facebookID: facebookID, + checkinID: checkinID + }; + + console.log(params); + db.query(query, params, function (err, results) { + if (err) { deferred.reject(err); } + else { + deferred.resolve(results); + } + }); + + return deferred.promise; +}; + +Checkin.removeFromBucketList = function(facebookID, checkinID){ + var deferred = Q.defer(); + + var query = [ + // 'MATCH (user:User {facebookID: {facebookID}})', + // 'MATCH (checkin:Checkin {checkinID: {checkinID}})', + // 'MATCH (user)-[rel:hasBucket]->(checkin)', + // 'DELETE rel' + 'match (user:User {facebookID: {facebookID}})-[rel:hasBucket]->(checkin:Checkin {checkinID: {checkinID}})delete rel' + ].join('\n'); + + var params = { facebookID: facebookID, checkinID: checkinID }; + console.log(params); db.query(query, params, function (err, results) { if (err) { deferred.reject(err); } else { deferred.resolve(results); + console.log('query executed!') } }); @@ -58,19 +90,20 @@ Checkin.addToBucketList = function(facebookID, checkinID){ Checkin.addComment = function (clickerID, checkinID, text){ var deferred = Q.defer(); - + var commentID = uuid.v4(); var query = [ 'MATCH (clicker:User {facebookID: {facebookID}})', - 'MATCH (checkin:Checkin {checkinID: {checkinID}})', - 'MERGE (clicker)-[:madeComment]->(comment:Comment {text: {text}, time: timestamp()})' + + 'MATCH (commentReceiver:User)-[:hasCheckin]->(checkin:Checkin {checkinID: {checkinID}})', + 'MERGE (clicker)-[:madeComment]->(comment:Comment {text: {text}, commentID : {commentID}, time: timestamp() })' + '-[:gotComment]->(checkin)', + 'MERGE (commentReceiver)-[:hasUnreadNotification]->(comment)', 'RETURN comment' ].join('\n'); - var params = { 'facebookID': clickerID, 'checkinID': checkinID, - 'text': text + 'text': text, + 'commentID' : commentID }; console.log(params); @@ -85,6 +118,44 @@ Checkin.addComment = function (clickerID, checkinID, text){ return deferred.promise; }; +Checkin.removeComment = function(facebookID, checkinID, commentID){ + var deferred = Q.defer(); + + var query = [ + // 'MATCH (user:User {facebookID: {facebookID}})', + // 'MATCH (checkin:Checkin {checkinID: {checkinID}})', + // 'MATCH (user)-[rel:hasBucket]->(checkin)', + // 'DELETE rel' + //'match (user:User {facebookID: {facebookID}})-[rel:hasBucket]->(checkin:Checkin {checkinID: {checkinID}})delete rel' + //].join('\n'); + 'match (clicker:User{facebookID: {facebookID}})-[rel1:madeComment]->(comment:Comment {commentID: {commentID}})-[rel2:gotComment]->(checkin:Checkin {checkinID: {checkinID}})delete rel1,rel2,comment' + ].join('\n'); +/*var query = [ + 'MATCH (clicker:User {facebookID: {facebookID}})', + 'MATCH (checkin:Checkin {checkinID: {checkinID}})', + 'MERGE (clicker)-[:madeComment]->(comment:Comment {text: {text}, commentID : {commentID}, time: timestamp() })' + + '-[:gotComment]->(checkin)', + 'RETURN comment' + ].join('\n'); + */ + var params = { + facebookID: facebookID, + checkinID: checkinID , + commentID : commentID + }; + console.log(params); + + db.query(query, params, function (err, results) { + if (err) { deferred.reject(err); } + else { + deferred.resolve(results); + console.log('query executed!') + } + }); + + return deferred.promise; +}; + Checkin.giveProps = function (clickerID, checkinID){ var deferred = Q.defer(); diff --git a/server/api/checkins/checkinRoutes.js b/server/api/checkins/checkinRoutes.js index 6eab550..8243430 100644 --- a/server/api/checkins/checkinRoutes.js +++ b/server/api/checkins/checkinRoutes.js @@ -1,8 +1,9 @@ var checkinController = require('./checkinController.js'); module.exports = function (app) { + app.post('/nativecheckin', checkinController.handleNativeCheckin); + app.get('/sign_s3', checkinController.sign_s3); app.post('/realtimefsqdata', checkinController.realtimeFoursquareData); - app.get('/realtimeinstagram', checkinController.instagramHubChallenge); app.post('/realtimeinstagram', checkinController.handleIGPost); app.get('/realtimefacebook', checkinController.facebookHubChallenge); @@ -10,7 +11,9 @@ module.exports = function (app) { //Routes for user actions app.post('/bucketlist', checkinController.addToBucketList); + app.post('/removebucket', checkinController.removeFromBucketList); app.post('/comment', checkinController.addComment); + app.post('/removecomment', checkinController.removeComment); app.post('/props', checkinController.giveProps); app.get('/interactions/:checkinid', checkinController.getPropsAndComments); }; diff --git a/server/api/places/placeModel.js b/server/api/places/placeModel.js index aed9972..9e28e7c 100644 --- a/server/api/places/placeModel.js +++ b/server/api/places/placeModel.js @@ -72,4 +72,34 @@ Place.find = function (data){ return deferred.promise; }; +Place.findByCheckinID = function (checkinID) { + + var deferred = Q.defer(); + + var query = [ + 'MATCH (checkin:Checkin {checkinID: {checkinID}})-[]->(place:Place)', + 'RETURN place', + ].join('\n'); + + var params = { + checkinID: checkinID + }; + + db.query(query, params, function (err, results) { + if (err) { deferred.reject(err); } + else { + console.log('results' + JSON.stringify(results[0].user.data)) + if (results && results[0] && results[0]['place']) { + console.log(results) + deferred.resolve(new User(results[0]['place'])); + } + else { + deferred.reject(new Error('user does not exist')); + } + } + }); + + return deferred.promise; +}; + module.exports = Place; diff --git a/server/api/users/userController.js b/server/api/users/userController.js index 697627b..b793f17 100644 --- a/server/api/users/userController.js +++ b/server/api/users/userController.js @@ -54,6 +54,7 @@ userController.userLogin = function (req, res) { // console.log('fb checkins: ', checkinsAlreadyStored.length); // For existing users if (checkinsAlreadyStored.length) { + user.setProperty('footprintsCount', checkinsAlreadyStored.length); user.findAllFriends() .then(function (neoUserData){ var allData = { @@ -123,17 +124,18 @@ userController.userLogin = function (req, res) { userFBPhotoData = fbParsedPhotoData; combinedFBCheckins = userFBTaggedPostsData.concat(userFBPhotoData); //get statuses posted by user - return facebookUtils.getFBStatuses(user); - }) - .then(function (fbRawStatusList) { - return facebookUtils.parseFBData(user, fbRawStatusList); - }) - .then(function (fbParsedStatusesData) { - userFBStatusesData = fbParsedStatusesData; - combinedFBCheckins = combinedFBCheckins.concat(userFBStatusesData); - console.log("combinedCheckins: " + combinedFBCheckins); + // return facebookUtils.getFBStatuses(user); return user.addCheckins(combinedFBCheckins); }) + // .then(function (fbRawStatusList) { + // return facebookUtils.parseFBData(user, fbRawStatusList); + // }) + // .then(function (fbParsedStatusesData) { + // userFBStatusesData = fbParsedStatusesData; + // combinedFBCheckins = combinedFBCheckins.concat(userFBStatusesData); + // console.log("combinedCheckins: " + combinedFBCheckins); + // return user.addCheckins(combinedFBCheckins); + // }) .then(function (data) { return user.findAllCheckins(userData.facebookID); }) @@ -229,20 +231,23 @@ userController.addInstagramData = function (req, res) { }; -// +//uses facebook ID to grab friend data when user navigates to friend page userController.getUserData = function (req, res){ var userData = { facebookID: req.params.friend }; + var userInfo = {}; var viewer = req.params.viewer; User.find(userData) .then(function (friend) { + userInfo.user = friend.node._data.data; return friend.findAllCheckins(viewer); }) .then(function (checkins) { // console.log("checkins: ", checkins.length) - res.json(checkins); + userInfo.footprints = checkins; + res.json(userInfo); res.status(200).end(); }) .catch(function (err) { @@ -251,6 +256,77 @@ userController.getUserData = function (req, res){ }); }; +userController.getAggregatedListOfCheckins = function (req, res){ + // var users = req.params.userlist; + var user; + var params = {}; + var aggregatedFootprints = []; + // var friendCheckins; + params.facebookID = req.params.user; + + User.find(params) + .then(function (userNode) { + user = userNode; + return user.getAggregatedFootprintList(params.facebookID); + }) + .then(function (aggregatedFootprintsFromFriends) { + aggregatedFootprints.push(aggregatedFootprintsFromFriends); + return user.findAllCheckins(params.facebookID); + }) + .then(function (userFootprints) { + aggregatedFootprints.push(userFootprints); + + console.log(aggregatedFootprints); + res.json(_.flatten(aggregatedFootprints)); + res.status(200).end(); + }) + .catch(function (err) { + console.log(err); + res.status(500).end(); + }); +}; + +userController.getNotifications = function (req, res) { + var user; + var params = {} + params.facebookID = req.params.user; + + User.find(params) + .then(function (userNode) { + user = userNode; + return user.getNotifications(); + }) + .then(function (notifications) { + res.json(notifications); + res.status(200).end(); + }) + .catch(function (err) { + console.log(err); + res.status(500).end(); + }) +} + +userController.getUserInfo = function (req, res) { + console.log('in the controller') + var params = {}; + params.facebookID = req.params.user; + console.log('dis be ma params' + JSON.stringify(req.params)) + + User.find(params) + .then(function (userInfo) { + console.log('userInfo' + JSON.stringify(userInfo.node._data.data)); + res.json(userInfo.node._data.data); + res.status(200).end(); + }) + .catch(function (err) { + console.log(err); + res.status(500).end(); + }); + + + +} + // Takes a facebookID and returns a footprint object with // checkin and place keys, containing checkin and place data userController.getBucketList = function (req, res){ diff --git a/server/api/users/userModel.js b/server/api/users/userModel.js index 0158384..409d9e0 100644 --- a/server/api/users/userModel.js +++ b/server/api/users/userModel.js @@ -158,8 +158,10 @@ User.prototype.addCheckins = function(combinedCheckins){ 'ON MATCH SET checkin.checkinTime = {checkinTime}, checkin.likes = {likes}, checkin.photoSmall = {photoSmall}, checkin.photoLarge = {photoLarge}, checkin.caption = {caption}, checkin.source = {source}', //change to merge on foursquareID only 'MERGE (place:Place {name: {name}, lat: {lat}, lng: {lng}, country: {country}, category: {category}, foursquareID: {foursquareID}})', - 'MERGE (user)-[:hasCheckin]->(checkin)-[:hasPlace]->(place)', - 'RETURN user, checkin, place', + 'MERGE (country:Country {name: {country}})', + 'MERGE (city:City {name: {city}})', + 'MERGE (user)-[:hasCheckin]->(checkin)-[:hasPlace]->(place)-[:hasCity]->(city)-[:hasCountry]->(country)', + 'RETURN user, checkin, place, city, country', ].join('\n'); // Map over the friends and return a list of objects @@ -232,10 +234,11 @@ User.prototype.findAllCheckins = function (viewer) { var deferred = Q.defer(); var query = [ - 'MATCH (user:User {facebookID: {facebookID}})-[:hasCheckin]->(checkin:Checkin)-[:hasPlace]->(p:Place)', - (viewer ? 'OPTIONAL MATCH (liker:User {facebookID: {viewerID}})-[connection:givesProps]->(checkin)' + + 'MATCH (user:User {facebookID: {facebookID}})-[:hasCheckin]->(checkin:Checkin)-[:hasPlace]->(place:Place)', + 'OPTIONAL MATCH (checkin)<-[]-(comment:Comment)<-[]-(commenter:User)', + (viewer ? 'OPTIONAL MATCH (liker:User {facebookID: {viewerID}})-[:givesProps]->(checkin)' + 'OPTIONAL MATCH (bucketer:User {facebookID: {viewerID}})-[:hasBucket]->(checkin)' : ""), - 'RETURN checkin, p' + (viewer ? ', liker, bucketer' : "") + 'RETURN user, checkin, place, collect(comment), collect(commenter)' + (viewer ? ', liker, bucketer' : "") ].join('\n'); var params = { @@ -250,10 +253,26 @@ User.prototype.findAllCheckins = function (viewer) { if (err) { deferred.reject(err); } else { var parsedResults = _.map(results, function (item) { + var singleResult = { + "user": item.user.data, "checkin": item.checkin.data, - "place": item.p.data + "place": item.place.data, + "comments": null + } + + if(item['collect(comment)'].length && item['collect(commenter)'].length) { + var commentsArray = []; + for(var i = 0; i < item['collect(comment)'].length; i++) { + var commentData = { + comment: item['collect(comment)'][i].data, + commenter: item['collect(commenter)'][i].data + } + commentsArray.push(commentData); + } + singleResult.comments = commentsArray; } + if (item.liker){ singleResult.checkin.liked = true; } @@ -270,6 +289,98 @@ User.prototype.findAllCheckins = function (viewer) { return deferred.promise; }; +//TO-DO: implement query to get all footprints associated with a user and their friends + +// User.getAggregatedFootprintList = function (viewer) { +// var deferred = Q.defer(); + +// var query = [ +// 'M' +// ] +// + +User.prototype.getAggregatedFootprintList = function (facebookID) { + var deferred = Q.defer(); + + var query = [ + // 'MATCH (user:User {facebookID: {facebookID}})-[:hasCheckin]->(checkin:Checkin)-[:hasPlace]->(place:Place)', + 'MATCH (user:User {facebookID: {facebookID}})-[:hasFriend]->(friend:User)-[:hasCheckin]->(checkin:Checkin)-[:hasPlace]->(place:Place)', + 'OPTIONAL MATCH (checkin)<-[]-(comment:Comment)<-[]-(commenter:User)', + 'RETURN user, friend, checkin, place, collect(comment), collect(commenter)' + ].join('\n'); + + var params = { + facebookID: this.getProperty('facebookID') + }; + + db.query(query, params, function (err, results) { + if (err) { deferred.reject(err); } + else { + var parsedResults = _.map(results, function (item) { + var singleResult = { + "user": item.user.data, + "checkin": item.checkin.data, + "place": item.place.data, + } + + if(item['collect(comment)'].length && item['collect(commenter)'].length) { + var commentsArray = []; + for(var i = 0; i < item['collect(comment)'].length; i++) { + var commentData = { + comment: item['collect(comment)'][i].data, + commenter: item['collect(commenter)'][i].data + } + commentsArray.push(commentData); + } + singleResult.comments = commentsArray; + } + + if(item.friend) { + singleResult["user"] = item.friend.data; + } + + return singleResult; + }); + + deferred.resolve(parsedResults); + } + }); + + return deferred.promise; +} + +User.prototype.getNotifications = function () { + var deferred = Q.defer(); + + var query = [ + 'MATCH (user:User {facebookID: {facebookID}})-[:hasUnreadNotification]->(comment:Comment)-[]->(checkin:Checkin)-[]->(place:Place)', + 'MATCH (commenter:User)-[:madeComment]->(comment)', + 'RETURN user, comment, checkin, place, commenter' + ].join('\n'); + + var params = { + facebookID: this.getProperty('facebookID') + }; + + db.query(query, params, function (err, results) { + if (err) { deferred.reject(err); } + else { + var parsedResults = _.map(results, function (item) { + var singleResult = { + "user": item.user.data, + "comment": item.comment.data, + "commenter": item.commenter.data, + "checkin": item.checkin.data, + "place": item.place.data + } + return singleResult; + }); + deferred.resolve(parsedResults); + } + }); + return deferred.promise; +} + // Find all bucketList items for a user // Takes a facebookID and returns a footprint object with // checkin and place keys, containing checkin and place data @@ -297,7 +408,6 @@ User.getBucketList = function (facebookID){ if (singleResult.checkin.likes.length){ singleResult.checkin.liked = true; } - console.log(item.checkin.data) return singleResult; }) @@ -325,6 +435,7 @@ User.find = function (data) { if (err) { deferred.reject(err); } else { if (results && results[0] && results[0]['user']) { + console.log(results) deferred.resolve(new User(results[0]['user'])); } else { @@ -393,4 +504,50 @@ User.findByInstagramID = function (instagramID) { return deferred.promise; }; +User.findByFootprintCheckinID = function (checkinID) { + var deferred = Q.defer(); + + var query = [ + 'MATCH (checkin:Checkin{checkinID: {checkinID}})<-[]-(user:User)', + 'RETURN user' + ].join('\n'); + + var params = { + checkinID: checkinID + }; + + db.query(query, params, function (err, results) { + if (err) { deferred.reject(err); } + else { + deferred.resolve(new User(results[0]['user'])); + } + }); + return deferred.promise; +} + +User.findLatestCommenterAndCommentOnCheckinByCheckinID = function (checkinID) { + var deferred = Q.defer(); + + var query = [ + 'MATCH (user:User)-[]->(checkin:Checkin {checkinID:{checkinID}})<-[]-(comment:Comment)<-[]-(commenter:User)', + 'OPTIONAL MATCH (checkin)-[]->(place:Place)', + 'RETURN user, commenter, checkin, comment, place', + 'ORDER BY -comment.time', + 'LIMIT 1' + ].join('\n'); + + var params = { + checkinID: checkinID + }; + + db.query(query, params, function (err, results) { + if (err) { deferred.reject(err); } + else { + deferred.resolve(results[0]); + } + }); + return deferred.promise; +} + + module.exports = User; \ No newline at end of file diff --git a/server/api/users/userRoutes.js b/server/api/users/userRoutes.js index 85755ca..a93c076 100644 --- a/server/api/users/userRoutes.js +++ b/server/api/users/userRoutes.js @@ -4,6 +4,10 @@ module.exports = function(app){ app.post('/userdata', userController.userLogin); app.post('/userfoursquarecode', userController.addFoursquareData); app.post('/userinstagramcode', userController.addInstagramData); - app.get('/bucketlist/:user', userController.getBucketList) + app.get('/bucketlist/:user', userController.getBucketList); + app.get('/aggregatefeed/:user', userController.getAggregatedListOfCheckins); + app.get('/notifications/:user', userController.getNotifications); + app.get('/userinfo/:user', userController.getUserInfo) + //the next line must be listed last because it catches all paths app.get('/:friend/:viewer', userController.getUserData); }; diff --git a/server/middleware.js b/server/middleware.js index faf2ddb..794dfb8 100644 --- a/server/middleware.js +++ b/server/middleware.js @@ -3,6 +3,7 @@ var morgan = require('morgan'); var path = require('path'); var errorhandlers = require('./errorhandlers.js'); + module.exports = function (app, express) { var userRouter = express.Router(); var checkinRouter = express.Router(); diff --git a/server/server.js b/server/server.js index 52e768f..3d8afd9 100644 --- a/server/server.js +++ b/server/server.js @@ -1,12 +1,32 @@ var express = require('express'); var app = express(); +var server=require('http').Server(app); +var io = require('socket.io')(server); +var User = require('./api/users/userModel.js'); +var Place = require('./api/places/placeModel.js'); require('./middleware.js')(app, express); + var port = process.env.PORT || 8080; -app.listen(port, function () { +server.listen(port, function () { console.log('Listening on port ' + this.address().port); }); +io.sockets.on('connection', function (socket) { + console.log('socket connected!'); + + socket.on('comment posted', function(commentData) { + var commenterName, receiverUserID, footprintPlaceName; + User.findLatestCommenterAndCommentOnCheckinByCheckinID(commentData.checkinID) + .then(function(commentData) { + commenterName = commentData.commenter.data.name; + footprintPlaceName = commentData.place.data.name; + console.log(commenterName + ' left a comment on your footprint at ' + footprintPlaceName); + socket.emit('notification', commentData) + }) + }) +}); + module.exports.app = app; \ No newline at end of file diff --git a/server/socket.js b/server/socket.js new file mode 100644 index 0000000..e69de29 diff --git a/server/utils/facebookUtils.js b/server/utils/facebookUtils.js index aa44dfb..bb06bec 100644 --- a/server/utils/facebookUtils.js +++ b/server/utils/facebookUtils.js @@ -101,7 +101,7 @@ utils.makeFBPaginatedRequest = function (queryPath, container) { var dataObj = JSON.parse(data); container.push(dataObj.data) - console.log("container: " + JSON.stringify(container)); + console.log("makeFBPaginatedRequest container: " + JSON.stringify(container)); if (! dataObj.paging) { deferred.resolve(_.flatten(container, true)); @@ -147,7 +147,7 @@ utils.getFBStatuses = function (user) { var queryPath = 'https://graph.facebook.com/'+fbID+'/statuses?' + qs.stringify(query); - var statusContainer = []; + var statusContainer = ['BROUHAHA']; deferred.resolve(utils.makeFBPaginatedRequest(queryPath, statusContainer)); diff --git a/server/utils/foursquareUtils.js b/server/utils/foursquareUtils.js index aa0d7d2..2eb00f3 100644 --- a/server/utils/foursquareUtils.js +++ b/server/utils/foursquareUtils.js @@ -4,6 +4,8 @@ var qs = require('querystring'); var Q = require('q'); var _ = require('lodash'); +var uuid = require('node-uuid'); + var helpers = require('./helpers.js'); var User = require('../api/users/userModel.js'); @@ -122,6 +124,65 @@ utils.parseFoursquareCheckins = function(foursquareCheckinArray) { }); }; +utils.parseNativeCheckin = function (venue) { + var deferred = Q.defer(); + + var formattedCheckin = { + 'checkinID': uuid.v4(), + 'name': venue.name, + 'lat': venue.location.lat, + 'lng': venue.location.lng, + 'checkinTime': new Date().getTime(), + 'likes': 'null', + 'photoSmall': 'null', + 'photoLarge': 'null', + 'caption': 'null', + 'foursquareID': venue.id, + 'address': 'null', + 'city': 'null', + 'country': venue.location.country, + 'postalCode': 'null', + 'category': 'null', + 'source': 'waddle' + }; + + if (venue.categories[0]) { + formattedCheckin.category = venue.categories[0].name; + } + + if (venue.location.address) { + formattedCheckin.address = venue.location.address; + } + + if (venue.location.postalCode) { + formattedCheckin.postalCode = venue.location.postalCode; + } + + if (venue.footprintCaption) { + formattedCheckin.caption = venue.footprintCaption; + } + + //TODO: figure out how to generate different size images from AWS url + + if (venue.photo) { + formattedCheckin.photoLarge = venue.photo; + } + + if (venue.location.city) { + formattedCheckin.city = venue.location.city; + deferred.resolve(formattedCheckin); + } + else { + helpers.findCityByReverseGeocoding(formattedCheckin.lat, formattedCheckin.lng) + .then(function (geocodeData) { + console.log(geocodeData); + formattedCheckin.city = geocodeData.features[0].place_name; + deferred.resolve(formattedCheckin); + }) + } + return deferred.promise; +} + utils.parseCheckin = function (checkin) { var formattedCheckin = { 'checkinID': checkin.id, @@ -134,7 +195,10 @@ utils.parseCheckin = function (checkin) { 'photoLarge': 'null', 'caption': 'null', 'foursquareID': checkin.venue.id, + 'address': 'null', + 'city': checkin.venue.location.city, 'country': checkin.venue.location.country, + 'postalCode': 'null', 'category': 'null', 'source': 'foursquare' }; @@ -143,6 +207,14 @@ utils.parseCheckin = function (checkin) { formattedCheckin.category = checkin.venue.categories[0].name; } + if (checkin.venue.location.address) { + formattedCheckin.address = checkin.venue.location.address; + } + + if (checkin.venue.location.postalCode) { + formattedCheckin.postalCode = checkin.venue.location.postalCode; + } + if (checkin.photos && checkin.photos.count > 0) { formattedCheckin.photoSmall = checkin.photos.items[0].prefix + 'cap300' + checkin.photos.items[0].suffix; formattedCheckin.photoLarge = checkin.photos.items[0].prefix + 'original' + checkin.photos.items[0].suffix; diff --git a/server/utils/helpers.js b/server/utils/helpers.js index 3ccd549..7c76e3a 100644 --- a/server/utils/helpers.js +++ b/server/utils/helpers.js @@ -22,4 +22,22 @@ helpers.httpsGet = function (queryPath) { return deferred.promise; }; +helpers.findCityByReverseGeocoding = function (lat, lng) { + var deferred = Q.defer(); + var geocodingQueryPath = 'https://api.tiles.mapbox.com/v4/geocode/mapbox.places-city-v1/' + + lng + ',' + lat + '.json?access_token=pk.eyJ1Ijoid2FkZGxldXNlciIsImEiOiItQWlwaU5JIn0.mTIpotbZXv5KVgP4pkcYrA'; + console.log(geocodingQueryPath); + + helpers.httpsGet(geocodingQueryPath) + .then(function (data) { + console.log(data) + deferred.resolve(JSON.parse(data)) + }) + .catch(function (err) { + deferred.reject(err); + }); + + return deferred.promise +} + module.exports = helpers;