├── .gitignore ├── .idea ├── .name ├── encodings.xml ├── jsLibraryMappings.xml ├── libraries │ └── redditClient_node_modules.xml ├── misc.xml ├── modules.xml ├── redditClient.iml ├── scopes │ └── scope_settings.xml ├── vcs.xml └── workspace.xml ├── .travis.yml ├── CONTRIBUTING ├── Gruntfile.js ├── LICENSE ├── README.md ├── comment.js ├── link.js ├── package.json ├── public ├── app.js ├── client.css ├── controllers │ ├── newRedditButtonController.js │ ├── newRedditController.js │ ├── redditListController.js │ └── userController.js ├── directives │ └── reddit │ │ ├── controller.js │ │ └── template.html ├── i18n │ └── ng-translate.js ├── images │ ├── 404.png │ ├── 404_mobile.png │ ├── caret-bottom.svg │ ├── caret-top.svg │ ├── favicon.ico │ └── reddit.png ├── index.html ├── old │ ├── NewReddit.xhtml │ ├── RedditTable.xhtml │ ├── RedditView.xhtml │ ├── base.xhtml │ ├── commentEntry.xhtml │ ├── css │ │ ├── base.css │ │ ├── layout.css │ │ └── modules.css │ └── redditEntry.xhtml ├── services │ ├── loginService.js │ └── socketService.js └── view │ ├── 404.html │ ├── newReddit.html │ └── table.html ├── rating.js ├── screenshot.png ├── server.js └── user.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.swp 3 | *.log 4 | .idea/ 5 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | redditClient -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/libraries/redditClient_node_modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/redditClient.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 114 | 115 | 116 | 117 | 118 | $PROJECT_DIR$/Gruntfile.js 119 | 120 | 121 | false 122 | 123 | 124 | true 125 | 126 | 127 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 162 | 163 | 164 | 165 | 168 | 169 | 172 | 173 | 174 | 175 | 178 | 179 | 182 | 183 | 186 | 187 | 188 | 189 | 192 | 193 | 196 | 197 | 200 | 201 | 204 | 205 | 206 | 207 | 210 | 211 | 214 | 215 | 218 | 219 | 222 | 223 | 224 | 225 | 228 | 229 | 232 | 233 | 236 | 237 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 307 | 308 | 309 | 310 | 311 | true 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 1415286432284 336 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 390 | 393 | 394 | 395 | 397 | 398 | 401 | 402 | 403 | 404 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | - 0.11 5 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | Samuel Kurath @Murthy10 2 | Severin Bühler @Sebubu 3 | Lukas Martinelli @lukasmartinelli 4 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.initConfig({ 4 | pkg: grunt.file.readJSON('package.json'), 5 | qunit: { 6 | files: ['test/**/*.html'] 7 | }, 8 | jshint: { 9 | files: ['Gruntfile.js', 'public/**/*.js', 'test/**/*.js'], 10 | options: { 11 | // options here to override JSHint defaults 12 | globals: { 13 | jQuery: true, 14 | console: true, 15 | module: true, 16 | document: true 17 | } 18 | } 19 | }, 20 | watch: { 21 | files: ['<%= jshint.files %>'], 22 | tasks: ['jshint', 'qunit'] 23 | } 24 | }); 25 | 26 | grunt.loadNpmTasks('grunt-contrib-jshint'); 27 | grunt.loadNpmTasks('grunt-contrib-qunit'); 28 | grunt.loadNpmTasks('grunt-contrib-watch'); 29 | 30 | grunt.registerTask('test', ['jshint', 'qunit']); 31 | grunt.registerTask('default', ['jshint', 'qunit']); 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Lukas Martinelli 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Reddit Clone ![stability-deprecated](https://img.shields.io/badge/stability-deprecated-red.svg) [![Build Status](https://travis-ci.org/lukasmartinelli/reddit-clone-js.svg)](https://travis-ci.org/lukasmartinelli/reddit-clone-js) 2 | 3 | > :warning: This repository is no longer maintained by Lukas Martinelli. 4 | 5 | This is a Single Page App built with AngularJs on the client side 6 | and Node on the server side. 7 | The same Project has been [realized in JSF](https://github.com/lukasmartinelli/reddit-clone). 8 | It is a mini project created after the specifications given 9 | in the [Internet Technologies](http://studien.hsr.ch/allModules/23331_M_IntTe.html) lecture. 10 | 11 | ![Screenshot](screenshot.png?raw=true "Screenshot of Reddit Clone") 12 | 13 | ## Requirements 14 | 15 | You should have NodeJS and npm installed. 16 | For testing and linting the project you need Grunt. 17 | 18 | ## Run Project 19 | 20 | ``` 21 | npm install 22 | node server.js 23 | ``` 24 | 25 | Now visit `http://localhost:4730/index.html`. 26 | 27 | # Test Project 28 | 29 | ``` 30 | grunt test 31 | ``` 32 | -------------------------------------------------------------------------------- /comment.js: -------------------------------------------------------------------------------- 1 | var Rating = require('./rating.js'); 2 | 3 | module.exports = function Comment(id, text, author) { 4 | this.id = id; 5 | this.text = text; 6 | this.author = author; 7 | this.createTime = new Date(); 8 | this.createTimeDisplay = this.createTime.toLocaleDateString() + " : " + this.createTime.toLocaleTimeString(); 9 | this.rating = new Rating(); 10 | this.comments = []; 11 | }; 12 | 13 | -------------------------------------------------------------------------------- /link.js: -------------------------------------------------------------------------------- 1 | var Rating = require('./rating.js'); 2 | 3 | module.exports = function Link(id, title, author, url) { 4 | this.id = id; 5 | this.title = title; 6 | this.author = author; 7 | this.url = url; 8 | this.createTime = new Date(); 9 | this.createTimeDisplay = this.createTime.toLocaleDateString() + " : " + this.createTime.toLocaleTimeString(); 10 | this.rating = new Rating(); 11 | this.comments = []; 12 | this.voters = []; 13 | }; 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "IntTeTestat", 3 | "description": "Testat Server", 4 | "version": "0.0.1", 5 | "private": true, 6 | "dependencies": { 7 | "express": "3.4.1", 8 | "socket.io": "latest" 9 | }, 10 | "devDependencies": { 11 | "grunt": "^0.4.5", 12 | "grunt-contrib-jshint": "^0.10.0", 13 | "grunt-contrib-qunit": "^0.5.2", 14 | "grunt-contrib-watch": "^0.6.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /public/app.js: -------------------------------------------------------------------------------- 1 | var redditclone = angular.module('redditclone', ['ngRoute','pascalprecht.translate']); 2 | 3 | redditclone.config(['$routeProvider', function($routeProvider) { 4 | $routeProvider. 5 | when('/', { 6 | templateUrl: 'view/table.html', 7 | controller: 'redditListController', 8 | }). 9 | when('/new', { 10 | templateUrl: 'view/new.html' 11 | // controller: 'AddOrderController' 12 | }). 13 | when('/entry', { 14 | templateUrl: 'view/entry.html' 15 | // controller: 'ShowOrdersController' 16 | }). 17 | when('/newReddit', { 18 | templateUrl: 'view/newReddit.html' 19 | // controller: 'ShowOrdersController' 20 | }). 21 | when('/404', { 22 | templateUrl: 'view/404.html' 23 | // controller: 'ShowOrdersController' 24 | }). 25 | otherwise({ 26 | redirectTo: '/404' 27 | }); 28 | }]); 29 | -------------------------------------------------------------------------------- /public/client.css: -------------------------------------------------------------------------------- 1 | /* ===NAVBAR=== */ 2 | .navbar h1 { 3 | display: inline; 4 | } 5 | 6 | .navbar-brand { 7 | padding-top: 8px; 8 | } 9 | 10 | .navbar-brand > img { 11 | margin-top: -10px; 12 | display: inline; 13 | height: 40px; 14 | } 15 | 16 | /* ===REDDITS=== */ 17 | .reddit { 18 | position: relative; 19 | display:block; 20 | min-height: 5rem; 21 | margin-bottom: 2rem; 22 | } 23 | 24 | form.comment-form { 25 | max-width:56rem; 26 | } 27 | 28 | .reddit .reddit-wrapper { 29 | padding-left: 6rem; 30 | } 31 | 32 | .reddit .votebuttons { 33 | position: absolute; 34 | z-index: 2; 35 | } 36 | 37 | .redditComments .votebuttons { 38 | } 39 | 40 | .commentText { 41 | min-height: 5rem; 42 | padding-left: 5rem; 43 | margin-bottom: 3em; 44 | } 45 | 46 | /* ===VOTE BUTTONS=== */ 47 | .votebuttons { 48 | text-align: center; 49 | width: 5rem; 50 | } 51 | 52 | .votebuttons img { 53 | width: 2rem; 54 | height: 2rem; 55 | fill: #4F4A4A; 56 | } 57 | 58 | .votebuttons img:hover { 59 | cursor: pointer; 60 | cursor: hand; 61 | } 62 | 63 | .votebuttons .upvote:hover, .votebuttons .upvote.active { 64 | fill: #4BC35F; 65 | } 66 | 67 | .votebuttons .downvote:hover, .votebuttons .downvote.active { 68 | fill: #C15044; 69 | } 70 | 71 | .votebuttons .vote_sum { 72 | font-size: 3.6rem; 73 | font-family: "Droid Sans", sans-serif; 74 | } 75 | -------------------------------------------------------------------------------- /public/controllers/newRedditButtonController.js: -------------------------------------------------------------------------------- 1 | 2 | redditclone.controller('newRedditButtonController', ['$scope', '$translate', 'loginService', function($scope, $translate, loginService) { 3 | $scope.isLoggedIn = function() { 4 | return loginService.loggedIn; 5 | }; 6 | }]); 7 | 8 | -------------------------------------------------------------------------------- /public/controllers/newRedditController.js: -------------------------------------------------------------------------------- 1 | redditclone.controller('newRedditController', ['$scope', '$http', '$location', 'loginService', function($scope, $http, $location, loginService) { 2 | $scope.title = ""; 3 | $scope.loggedIn = loginService.loggedIn; 4 | 5 | $scope.newReddit = function() { 6 | if(loginService.loggedIn) { 7 | $http.post('/entry', {"title": $scope.title, 8 | "url": $scope.link, 9 | "username": loginService.user.username}) 10 | .success(function (data, status, headers, config) { 11 | $location.path('/'); 12 | //$scope.loggedIn = true; 13 | }) 14 | .error(function (data, status, headers, config) { 15 | //$scope.loggedIn = false; 16 | }); 17 | } 18 | }; 19 | 20 | }]); 21 | -------------------------------------------------------------------------------- /public/controllers/redditListController.js: -------------------------------------------------------------------------------- 1 | 2 | redditclone.controller('redditListController', ['$scope', '$http', 'socketService', 'loginService', function($scope, $http, socketService, loginService) { 3 | $scope.reddits = []; 4 | $scope.commentAddedID = -1; 5 | $scope.isLoggedIn = function() { 6 | return loginService.loggedIn; 7 | }; 8 | function extendReddit(entry) { 9 | entry.areCommentsVisible = false; 10 | entry.setCommentsVisible = function (){ 11 | if(loginService.loggedIn === true) { 12 | this.areCommentsVisible = true; 13 | } 14 | }; 15 | entry.newCommentText = ""; 16 | entry.submitNewComment = function() { 17 | $scope.commentAddedID = entry.id; 18 | $http.post("/entry/" + entry.id + "/comment",{text:entry.newCommentText}).success(function(data, status, headers, config) { 19 | console.log("comment added successfully: " + entry.newCommentText); 20 | }) 21 | }; 22 | }; 23 | $scope.update = function() { 24 | $http.get('/entries').success(function(data, status, headers, config) { 25 | data.forEach(function(entry) { 26 | extendReddit(entry); 27 | if(entry.id === $scope.commentAddedID) { 28 | entry.setCommentsVisible(); 29 | $scope.commentAddedID = -1; 30 | } 31 | }); 32 | $scope.reddits = data; 33 | console.log("Loaded " + data.length + " reddits"); 34 | }); 35 | 36 | }; 37 | 38 | $scope.upEntry = function(entryId) { 39 | if(loginService.loggedIn) { 40 | socketService.emit('upEntry', {eId: entryId, uId: loginService.user.username}); 41 | } 42 | }; 43 | 44 | $scope.downEntry = function(entryId) { 45 | if(loginService.loggedIn) { 46 | socketService.emit('downEntry', {eId: entryId, uId: loginService.user.username}); 47 | } 48 | }; 49 | 50 | $scope.upComment = function(commentId, redditId) { 51 | if(loginService.loggedIn) { 52 | socketService.emit('upComment', {cId: commentId, eId: redditId, uId: loginService.user.username}); 53 | } 54 | }; 55 | 56 | $scope.downComment = function(commentId, redditId) { 57 | if(loginService.loggedIn) { 58 | socketService.emit('downComment', {cId: commentId, eId: redditId, uId: loginService.user.username}); 59 | } 60 | }; 61 | 62 | socketService.on('voteEntryState', function(reddit){ 63 | extendReddit(reddit); 64 | reddit.setCommentsVisible(); 65 | $scope.reddits[reddit.id] = reddit; 66 | }); 67 | $scope.update(); 68 | }]); 69 | 70 | -------------------------------------------------------------------------------- /public/controllers/userController.js: -------------------------------------------------------------------------------- 1 | redditclone.controller('userController', ['$scope', '$http', 'loginService', 2 | function($scope, $http, loginService) { 3 | $scope.loggedIn = false; 4 | 5 | $scope.logout = function() { 6 | loginService.logout(); 7 | $scope.loggedIn = false; 8 | }; 9 | 10 | $scope.login = function() { 11 | loginService.login($scope.username, $scope.password, function() { 12 | $scope.loggedIn = loginService.loggedIn; 13 | }); 14 | }; 15 | 16 | $scope.register = function() { 17 | loginService.register($scope.username, $scope.password, function() { 18 | $scope.loggedIn = loginService.loggedIn; 19 | }); 20 | }; 21 | 22 | if(sessionStorage.username) { 23 | $scope.username = sessionStorage.username; 24 | $scope.password = sessionStorage.password; 25 | $scope.login(); 26 | } 27 | }]); 28 | -------------------------------------------------------------------------------- /public/directives/reddit/controller.js: -------------------------------------------------------------------------------- 1 | redditclone.controller('redditEntryController', ['$scope', function($scope) { 2 | $scope.title = "Dorfmarkt knackt Umsatzrekord"; 3 | $scope.votesCount = 103; 4 | $scope.author = "Piter Sommerlat"; 5 | $scope.commentsCount = 63; 6 | $scope.timeAgo = "2 days ago"; 7 | $scope.url = "http://www.20min.ch"; 8 | }]) 9 | .directive('redditentry', function() { 10 | return { 11 | templateUrl: 'directives/reddit/template.html' 12 | }; 13 | }); 14 | -------------------------------------------------------------------------------- /public/directives/reddit/template.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
5 | 6 | 7 | 8 | {{votesCount}} 9 | 10 | 11 | 12 |
13 |
14 | 15 |

{{title}}

16 |
17 | 18 |

19 | {{timeAgo}} by {{author}} 20 |

21 | 22 |

23 | 24 | 25 |

{{commentsCount}} comments

26 | 27 | 28 |

29 |
30 |
31 |
-------------------------------------------------------------------------------- /public/i18n/ng-translate.js: -------------------------------------------------------------------------------- 1 | 2 | redditclone.config(function($translateProvider) { 3 | $translateProvider.translations('en', { 4 | newRedditButton: 'New Reddit!' 5 | }) 6 | .translations('de', { 7 | newRedditButton: 'Neuer Reddit!' 8 | }); 9 | $translateProvider.preferredLanguage('en'); 10 | }); 11 | 12 | 13 | redditclone.controller('i18nController', ['$scope', '$translate', function($scope, $translate) { 14 | $scope.setLanguageDE = function () { 15 | $translate.use('de'); 16 | console.log("Language is set to DE"); 17 | }; 18 | $scope.setLanguageEN = function () { 19 | $translate.use('en'); 20 | console.log("Language is set to EN"); 21 | }; 22 | }]); -------------------------------------------------------------------------------- /public/images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukasmartinelli-alt/reddit-clone-js/e67d1e44cd25bfec2c7a98b1c7b7861e994bd0c8/public/images/404.png -------------------------------------------------------------------------------- /public/images/404_mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukasmartinelli-alt/reddit-clone-js/e67d1e44cd25bfec2c7a98b1c7b7861e994bd0c8/public/images/404_mobile.png -------------------------------------------------------------------------------- /public/images/caret-bottom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /public/images/caret-top.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukasmartinelli-alt/reddit-clone-js/e67d1e44cd25bfec2c7a98b1c7b7861e994bd0c8/public/images/favicon.ico -------------------------------------------------------------------------------- /public/images/reddit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukasmartinelli-alt/reddit-clone-js/e67d1e44cd25bfec2c7a98b1c7b7861e994bd0c8/public/images/reddit.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | InTeTestat 5 | 6 | 7 | 8 | 9 | 10 | 44 | 45 | 46 | 47 | 48 |
49 |
50 | 51 | 52 |
53 |
54 | 55 | 56 | 57 | 58 |
59 | 60 | 61 |
62 |
63 | 70 |
71 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /public/old/NewReddit.xhtml: -------------------------------------------------------------------------------- 1 | 7 | Create new Reddit 8 | 9 |
10 |

Submit a new Link

11 | 12 | 13 | 14 |
15 | 16 |
17 | 18 |
19 |
20 |
21 |
-------------------------------------------------------------------------------- /public/old/RedditTable.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 11 | Reddit Table 12 | 13 |
14 |

Entries

15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 |
-------------------------------------------------------------------------------- /public/old/RedditView.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 11 | Reddit Comments 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | add comment 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 |
29 | 30 | 31 |
32 | 33 | 34 | 35 |
36 |
37 |
38 |
39 |
40 |
41 | 42 | 43 | 44 |
-------------------------------------------------------------------------------- /public/old/base.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | <ui:insert name="title">Reddit Clone</ui:insert> 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 | 22 |

23 | 24 | redditclone 25 |

26 |
27 |
28 | 38 | 39 | 40 | 41 |
42 | 43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 |
52 | 53 | 54 | 58 |
59 |
60 | 61 | -------------------------------------------------------------------------------- /public/old/commentEntry.xhtml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 |
19 | 20 | 23 | 24 | 25 | #{cc.comment.votes.votesCount} 26 | 27 | 30 | 31 | 32 |
33 |
34 |
35 |
36 |

37 | #{cc.timeAgo} #{cc.comment.author.name} 38 |

39 |

40 | #{cc.comment.text} 41 |

42 | 43 | add comment 44 | 45 | 46 | 47 | 48 | 49 |
50 |
51 |
52 |
-------------------------------------------------------------------------------- /public/old/css/base.css: -------------------------------------------------------------------------------- 1 | /* ===RESET=== */ 2 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, 3 | blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, 4 | em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, 5 | b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, 6 | table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, 7 | details, embed, figure, figcaption, footer, header, hgroup, menu, nav, 8 | output, ruby, section, summary, time, mark, audio, video { 9 | margin: 0; 10 | padding: 0; 11 | border: 0; 12 | font: inherit; 13 | font-size: 100%; 14 | vertical-align: baseline; 15 | } 16 | 17 | html { 18 | line-height: 1; 19 | } 20 | 21 | ol, ul { 22 | list-style: none; 23 | } 24 | 25 | table { 26 | border-collapse: collapse; 27 | border-spacing: 0; 28 | } 29 | 30 | caption, th, td { 31 | text-align: left; 32 | font-weight: normal; 33 | vertical-align: middle; 34 | } 35 | 36 | q, blockquote { 37 | quotes: none; 38 | } 39 | 40 | q:before, q:after, blockquote:before, blockquote:after { 41 | content: ""; 42 | content: none; 43 | } 44 | 45 | a img { 46 | border: none; 47 | } 48 | 49 | article, aside, details, figcaption, figure, footer, header, hgroup, 50 | main, menu, nav, section, summary { 51 | display: block; 52 | } 53 | 54 | html { 55 | box-sizing: border-box; 56 | } 57 | 58 | *, *:before, *:after { 59 | box-sizing: inherit; 60 | } 61 | 62 | /* ===TYPOGRAPHY=== */ 63 | html { 64 | font-size: 62.5%; 65 | } 66 | 67 | body { 68 | background: #fff; 69 | font-size: 1.6rem; 70 | line-height: 1.82rem; 71 | font-family: 'Istok Web', sans-serif; 72 | color: #333; 73 | } 74 | 75 | h1, h2, h3, h4, h5, h6, nav a { 76 | font-family: 'Istok Web', sans-serif; 77 | } 78 | 79 | h1 { 80 | font-size: 4.8rem; 81 | font-weight: 400; 82 | color: #155183; 83 | line-height: 1em; 84 | margin-bottom: 2rem; 85 | } 86 | 87 | h2 { 88 | font-size: 3.6rem; 89 | line-height: 4.6rem; 90 | } 91 | 92 | h3 { 93 | font-size: 2rem; 94 | line-height: 2.6rem; 95 | } 96 | 97 | h4 { 98 | font-size: 1.6rem; 99 | line-height: 2.08rem; 100 | } 101 | 102 | em, strong { 103 | font-weight: 700; 104 | } 105 | 106 | p { 107 | margin: 0 auto 0.5em; 108 | } 109 | 110 | hr { 111 | border: solid #D2DDE5; 112 | border-width: 1px 0 0; 113 | clear: both; 114 | margin: 1rem 0 1.5rem; 115 | height: 0; 116 | } 117 | 118 | /* ===LISTS=== */ 119 | ul>li { 120 | list-style: disc inside; 121 | padding-left: 1rem; 122 | } 123 | 124 | /* ===LINKS=== */ 125 | a { 126 | color: #155183; 127 | text-decoration: none; 128 | outline: 0; 129 | } 130 | 131 | a:hover, a:focus { 132 | color: #41586e; 133 | } 134 | 135 | /* ===FORMS=== */ 136 | form, fieldset { 137 | margin-bottom: 1rem; 138 | } 139 | 140 | button, a.button, input, select, textarea { 141 | font-size: 1.6rem; 142 | padding: 0.8rem 1.2rem; 143 | outline: none; 144 | } 145 | 146 | .control-group { 147 | *zoom: 1; 148 | } 149 | 150 | .control-group:after { 151 | content: ""; 152 | display: table; 153 | clear: both; 154 | } 155 | 156 | label { 157 | color: #666; 158 | display: block; 159 | margin-bottom: 0.5rem; 160 | } 161 | .ui-datagrid-content { 162 | border: none; 163 | } 164 | 165 | input, select, textarea { 166 | width: 100%; 167 | -moz-transition: border-color, 0.3s; 168 | -o-transition: border-color, 0.3s; 169 | -webkit-transition: border-color, 0.3s; 170 | transition: border-color, 0.3s; 171 | border: 2px solid #D2DDE5; 172 | margin-top: 1rem; 173 | } 174 | 175 | input:focus, select:focus, textarea:focus { 176 | border-color: #41586e; 177 | } 178 | 179 | .help-block { 180 | font-size: 1.1rem; 181 | } 182 | 183 | ul.errorlist li { 184 | color: #b94a48; 185 | list-style-type: none; 186 | padding-left: 0; 187 | font-size: 1.1rem; 188 | } 189 | 190 | input[type="checkbox"] { 191 | width: auto; 192 | float: left; 193 | } 194 | 195 | input[type="checkbox"]+p.help-block { 196 | font-size: 1.4rem; 197 | } 198 | 199 | .form-horizontal .control-group { 200 | margin-bottom: 1rem; 201 | } 202 | 203 | /* ===RESPONSIVE FORMS=== */ 204 | @media ( min-width : 43.75em) { 205 | .form-horizontal label, .form-horizontal p.help-block, .form-horizontal ul.errorlist 206 | { 207 | float: left; 208 | width: 30%; 209 | } 210 | .form-horizontal input, .form-horizontal textarea, .form-horizontal select 211 | { 212 | float: right; 213 | width: 70%; 214 | } 215 | .form-horizontal #id_license+p.help-block { 216 | width: 70%; 217 | float: right; 218 | } 219 | .form-horizontal input[type="checkbox"] { 220 | float: left; 221 | width: auto; 222 | } 223 | .form-horizontal input[type="checkbox"]+p.help-block { 224 | width: 65%; 225 | float: right; 226 | } 227 | } 228 | /* ===BUTTONS=== */ 229 | button, .button { 230 | border: 0; 231 | /*display: inline-block;*/ 232 | margin: 1rem; 233 | margin-left: 0; 234 | color: #fff; 235 | cursor: pointer; 236 | -moz-transition: background 0.2s; 237 | -o-transition: background 0.2s; 238 | -webkit-transition: background 0.2s; 239 | transition: background 0.2s; 240 | background-color: #91acc0; 241 | } 242 | 243 | button:hover, button:focus, button:active, .button:hover, .button:focus, 244 | .button:active { 245 | background-color: #7194ad; 246 | color: #fff; 247 | } 248 | 249 | button.button-primary, .button.button-primary { 250 | background-color: #155183; 251 | } 252 | 253 | button.button-primary:hover, button.button-primary:active, button.button-primary:focus, 254 | .button.button-primary:hover, .button.button-primary:active, .button.button-primary:focus 255 | { 256 | background: #41586e; 257 | } 258 | /* ===MISC=== */ 259 | .hidden { 260 | display: none; 261 | } -------------------------------------------------------------------------------- /public/old/css/layout.css: -------------------------------------------------------------------------------- 1 | /* ===LAYOUT STRUCTURE=== */ 2 | .top { 3 | padding: 0; 4 | min-height: 25rem; 5 | } 6 | 7 | .header { 8 | overflow: hidden; 9 | *zoom: 1; 10 | } 11 | 12 | .main { 13 | margin-top: 1rem; 14 | padding: 1rem; 15 | } 16 | 17 | .header { 18 | padding: 1rem; 19 | background-color: #D2DDE5; 20 | } 21 | 22 | .header img { 23 | max-height: 4.8rem; 24 | margin-bottom: -0.8rem; 25 | } 26 | 27 | .branding { 28 | float: left; 29 | } -------------------------------------------------------------------------------- /public/old/css/modules.css: -------------------------------------------------------------------------------- 1 | /* ===SUBMIT LINK=== */ 2 | .submit { 3 | margin-top: 1.3rem; 4 | margin-left: 1rem; 5 | float: right; 6 | } 7 | 8 | .submit input { 9 | margin: 0; 10 | } 11 | 12 | .submit input[type="text"] { 13 | width: auto; 14 | } 15 | 16 | /* ===LOGOUT=== */ 17 | 18 | .logout { 19 | margin-top: 1.3rem; 20 | float: right; 21 | } 22 | 23 | /* ===HEADER LOGIN=== */ 24 | .login { 25 | clear: left; 26 | margin-top : 0.5rem; 27 | overflow: hidden; 28 | margin-top: 0.5rem; 29 | } 30 | 31 | .login input { 32 | margin: 0; 33 | margin-right: 1%; 34 | margin-top: 1rem; 35 | float: left; 36 | width: 49%; 37 | } 38 | 39 | @media(min-width: 68em) { 40 | .login { 41 | clear: none; 42 | float: right; 43 | overflow: hidden; 44 | } 45 | .login input { 46 | margin: 0; 47 | margin-left: 1.5rem; 48 | float: left; 49 | width: auto; 50 | } 51 | } 52 | 53 | /* ===REDDITS=== */ 54 | .reddit { 55 | position: relative; 56 | display:block; 57 | min-height: 5rem; 58 | margin-bottom: 2rem; 59 | } 60 | 61 | form.comment-form { 62 | max-width:56rem; 63 | } 64 | 65 | .reddit .reddit-wrapper { 66 | padding-left: 6rem; 67 | } 68 | 69 | .reddit .votebuttons { 70 | position: absolute; 71 | z-index: 2; 72 | } 73 | 74 | 75 | 76 | /* ===VOTE BUTTONS=== */ 77 | .votebuttons { 78 | text-align: center; 79 | width: 5rem; 80 | } 81 | 82 | .votebuttons .upvote, .votebuttons .downvote { 83 | width: 3.2rem; 84 | height: 3.2rem; 85 | fill: #4F4A4A; 86 | } 87 | 88 | .votebuttons .upvote:hover, .votebuttons .downvote:hover { 89 | cursor: pointer; 90 | cursor: hand; 91 | } 92 | 93 | .votebuttons .upvote:hover, .votebuttons .upvote.active { 94 | fill: #4BC35F; 95 | } 96 | 97 | .votebuttons .downvote:hover, .votebuttons .downvote.active { 98 | fill: #C15044; 99 | } 100 | 101 | .votebuttons .vote_sum { 102 | font-size: 3.6rem; 103 | font-family: "Droid Sans", sans-serif; 104 | } 105 | 106 | /* ===NEW REDDIT=== */ 107 | 108 | .new-reddit input { 109 | max-width: 56rem; 110 | display: block; 111 | } 112 | 113 | /* ===LANGUAGE=== */ 114 | 115 | .language-chooser { 116 | float: left; 117 | margin-left: 1rem; 118 | margin-top: 2rem; 119 | } 120 | 121 | .language-chooser > a { 122 | font-size: 1rem; 123 | font-weight: bold; 124 | padding: 0.3rem; 125 | } 126 | 127 | 128 | /* ===COMMENTS=== */ 129 | .comments { 130 | clear: left; 131 | padding-left: 6rem; 132 | } 133 | 134 | .comment { 135 | margin-bottom: 2rem; 136 | position: relative; 137 | display:block; 138 | min-height: 8.5rem; 139 | max-width:56rem; 140 | display:block; 141 | } 142 | 143 | .comment .votebuttons { 144 | position: absolute; 145 | z-index: 2; 146 | } 147 | 148 | .comment .comment-wrapper { 149 | padding-left: 6rem; 150 | } 151 | 152 | .comment-text { 153 | } 154 | 155 | .comment-create-link img { 156 | width: 3.2rem; 157 | height: 3.2rem; 158 | fill: #4F4A4A; 159 | } -------------------------------------------------------------------------------- /public/old/redditEntry.xhtml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |
16 | 17 | 20 | 21 | 22 | #{cc.reddit.votes.votesCount} 23 | 24 | 27 | 28 | 29 | 30 | 31 |
32 |
33 |
34 | 35 |

#{cc.reddit.title}

36 |
37 | 38 |

39 | #{cc.timeAgo} #{cc.reddit.user.name} 40 |

41 |

42 | 43 | 44 | 45 | 46 | 47 | 48 |

49 |
50 |
51 | 52 | 53 |
54 |
55 |
-------------------------------------------------------------------------------- /public/services/loginService.js: -------------------------------------------------------------------------------- 1 | redditclone.factory('loginService', ['$http', function($http) { 2 | return { 3 | loggedIn: false, 4 | user: { username: "", password: "" }, 5 | logout: function() { 6 | this.loggedIn = false; 7 | sessionStorage.username = ""; 8 | sessionStorage.password = ""; 9 | }, 10 | login: function(username, password, callback) { 11 | $http.post('/login', { "name": username, "password": password }) 12 | .success(function(data, status, headers, config) { 13 | console.log("User " + username + " logged in"); 14 | this.loggedIn = true; 15 | this.user = { username: username, password: password }; 16 | sessionStorage.username = username; 17 | sessionStorage.password = password; 18 | callback(); 19 | }.bind(this)) 20 | .error(function(data, status, headers, config) { 21 | this.loggedIn = false; 22 | }.bind(this)); 23 | }, 24 | register: function(username, password, callback) { 25 | $http.post('/register', { "name": username, "password": password }) 26 | .success(function(data, status, headers, config) { 27 | console.log("User " + username + " registered"); 28 | this.login(name, password, function() { 29 | callback(); 30 | }); 31 | }.bind(this)) 32 | .error(function(data, status, headers, config) { 33 | this.loggedIn = false; 34 | }.bind(this)); 35 | } 36 | }; 37 | }]); 38 | -------------------------------------------------------------------------------- /public/services/socketService.js: -------------------------------------------------------------------------------- 1 | redditclone.factory('socketService', function($rootScope) { 2 | var socket = io.connect(); 3 | return { 4 | on: function(eventName, callback) { 5 | socket.on(eventName, function() { 6 | var args = arguments; 7 | console.log(eventName); 8 | $rootScope.$apply(function() { 9 | callback.apply(socket, args); 10 | }); 11 | }); 12 | }, 13 | emit: function(eventName, data, callback) { 14 | if(typeof data == 'function') { 15 | callback = data; 16 | data = {}; 17 | } 18 | socket.emit(eventName, data, function() { 19 | var args = arguments; 20 | $rootScope.$apply(function() { 21 | if(callback) { 22 | callback.apply(socket, args); 23 | } 24 | }); 25 | }); 26 | }, 27 | emitAndListen: function(eventName, data, callback) { 28 | this.emit(eventName, data, callback); 29 | this.on(eventName, callback); 30 | } 31 | }; 32 | }); 33 | -------------------------------------------------------------------------------- /public/view/404.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
-------------------------------------------------------------------------------- /public/view/newReddit.html: -------------------------------------------------------------------------------- 1 |
2 | 13 |
14 | -------------------------------------------------------------------------------- /public/view/table.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |
7 |
8 | 9 |
10 | {{ reddit.rating.value }} 11 |
12 | 13 |
14 |
15 |
16 | 17 |

{{ reddit.title }}

18 |
19 | 20 |

21 | {{ reddit.timeAgo }} by {{ reddit.author }} 22 |

23 |
24 |

25 | 26 | 27 |

{{reddit.commentsCount}} comments

28 | 29 | 30 |

31 |
32 |
33 |
34 |
35 |
37 |
38 | 39 |
40 | {{ comment.rating.value }} 41 |
42 | 43 |
44 |
45 |
46 |
47 |

{{comment.author}} {{comment.createTimeDisplay}}

48 |

{{comment.text}}

49 |
50 |
51 |
52 |
53 | 54 |
55 |
56 |
57 |
58 |
59 |
60 | -------------------------------------------------------------------------------- /rating.js: -------------------------------------------------------------------------------- 1 | module.exports = function Rating() { 2 | this.value = 0; 3 | var voters = []; 4 | var self = this; 5 | 6 | this._up = function(userId) { 7 | if (!voters[userId]) { 8 | self.value++; 9 | voters[userId] = true; 10 | } 11 | return self.value; 12 | }; 13 | 14 | this._down = function (userId) { 15 | if (!voters[userId]) { 16 | self.value--; 17 | voters[userId] = true; 18 | } 19 | return self.value; 20 | }; 21 | }; 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukasmartinelli-alt/reddit-clone-js/e67d1e44cd25bfec2c7a98b1c7b7861e994bd0c8/screenshot.png -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var User = require('./user.js'); 3 | var Link = require('./link.js'); 4 | var Comment = require('./comment.js'); 5 | var http = require('http'); 6 | var io = require('socket.io'); 7 | 8 | var allowCrossDomain = function(req, res, next) { 9 | res.header('Access-Control-Allow-Origin', '*'); 10 | res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); 11 | res.header('Access-Control-Allow-Headers', 'Content-Type'); 12 | next(); 13 | }; 14 | 15 | var app = express(); 16 | app.use(allowCrossDomain); 17 | app.use(express.bodyParser()); 18 | app.use(express.cookieParser()); 19 | app.use(express.session({secret: '2234567890QWERTY'})); 20 | app.use(app.router); 21 | 22 | 23 | function checkAuth(req, res, next) { 24 | if (typeof(req.session.user_id) == "number") { 25 | next(); 26 | } else { 27 | res.send('You are not authorized!'); 28 | } 29 | } 30 | 31 | var entries = []; 32 | var users = []; 33 | var comments = []; 34 | 35 | //sample data 36 | 37 | entries.push(new Link(entries.length, "Title", "Author", "http://www.google.ch")); 38 | var comment = new Comment(0, "TestComment", "Author"); 39 | comments.push(comment); 40 | entries[0].comments.push(comment); 41 | 42 | var entry1 = new Link(entries.length, "Dorfmarkt knackt Umsatzrekord", "Piter Sommerlat", "http://www.20min.ch"); 43 | entry1.rating._up(users[0]); 44 | entries.push(entry1); 45 | 46 | //default user 47 | users.push(new User(users.length, "a", "a") ); 48 | 49 | function findUser(name) 50 | { 51 | for (var i in users) 52 | { 53 | var user = users[i]; 54 | if( user.name == name) 55 | { 56 | return user; 57 | } 58 | } 59 | return null; 60 | } 61 | 62 | function returnIndex(res, id, array) { 63 | if (array.length <= id || id < 0) { 64 | res.statusCode = 404; 65 | return res.send('Error 404: No entry found'); 66 | } 67 | return res.json(array[id]); 68 | } 69 | 70 | app.get('/', function(req, res) { 71 | res.type('text/plain'); 72 | res.json(entries); 73 | }); 74 | 75 | app.get('/login', function (req, res) { 76 | if (typeof (req.session.user_id) == "number") { 77 | res.json(users[req.session.user_id].name); 78 | return; 79 | } 80 | res.json(""); 81 | }); 82 | 83 | app.post('/login', function (req, res) { 84 | var post = req.body; 85 | var user = findUser(post.name); 86 | if( !!user && post.password == user.password) 87 | { 88 | req.session.user_id = user.id; 89 | res.json(true); 90 | return; 91 | } 92 | res.json(false); 93 | }); 94 | 95 | app.post('/register', function(req, res) { 96 | var post = req.body; 97 | 98 | if (typeof(post.name) != "string" || typeof(post.password) != "string") { 99 | res.json(false); 100 | return; 101 | } 102 | 103 | if (findUser(post.name)) { 104 | res.json(false); 105 | return; 106 | } 107 | users.push(new User(users.length, post.name, post.password)); 108 | res.json(true); 109 | }); 110 | 111 | app.get('/users', function (req, res) { 112 | res.json(users); 113 | }); 114 | 115 | 116 | 117 | app.get('/entries', function (req, res) { 118 | res.json(entries); 119 | }); 120 | 121 | 122 | app.post('/entry', function(req, res) { 123 | var newLink = new Link(entries.length, req.body.title, req.body.username, req.body.url); 124 | entries.push(newLink); 125 | res.json(newLink); 126 | io.sockets.emit('message', { action: "AddLink" }); 127 | }); 128 | 129 | app.get('/entry/:id', function(req, res) { 130 | returnIndex(res, req.params.id, entries); 131 | }); 132 | 133 | app.post('/entry/:id/up', checkAuth, function (req, res) { 134 | res.json(entries[req.params.id].rating._up(req.session.user_id)); 135 | io.sockets.emit('message', { action: "Rated" }); 136 | voteState(entries[req.params.id]); 137 | }); 138 | 139 | app.post('/entry/:id/down', checkAuth, function (req, res) { 140 | res.json(entries[req.params.id].rating._down(req.session.user_id)); 141 | io.sockets.emit('message', { action: "Rated" }); 142 | }); 143 | 144 | app.post('/entry/:id/comment', checkAuth, function (req, res) { 145 | var newComment = new Comment(comments.length, req.body.text, users[req.session.user_id].name); 146 | comments.push(newComment); 147 | 148 | var entry = entries[req.params.id]; 149 | entry.comments.push(newComment); 150 | res.json(newComment); 151 | io.sockets.emit('message', { action: "AddComment" }); 152 | }); 153 | 154 | app.post('/comment/:id/', checkAuth, function (req, res) { 155 | var newComment = new Comment(comments.length, req.body.text, users[req.session.user_id].name); 156 | comments.push(newComment); 157 | 158 | var comment = comments[req.params.id]; 159 | comment.comments.push(newComment); 160 | res.json(newComment); 161 | io.sockets.emit('message', { action: "AddComment" }); 162 | }); 163 | 164 | app.post('/comment/:id/up', checkAuth, function (req, res) { 165 | res.json(comments[req.params.id].rating._up(req.session.user_id)); 166 | io.sockets.emit('message', { action: "Rated" }); 167 | voteState(comments[req.params.id]); 168 | }); 169 | 170 | app.post('/comment/:id/down', checkAuth, function (req, res) { 171 | res.json(comments[req.params.id].rating._down(req.session.user_id)); 172 | io.sockets.emit('message', { action: "Rated" }); 173 | }); 174 | 175 | app.post('/logout', function (req, res) { 176 | req.session.user_id = null; 177 | res.json(true); 178 | }); 179 | 180 | app.use('/', express.static(__dirname + '/public/')); 181 | 182 | //socket: 183 | io = io.listen(app.listen(process.env.PORT || 4730)); 184 | 185 | io.sockets.on('connection', function (socket) { 186 | socket.emit('message', { action: 'connected' }); 187 | 188 | socket.on('upEntry', function(ids){ 189 | entries[ids.eId].rating._up(getUserIdByName(ids.uId)); 190 | console.log("upEntry"); 191 | voteEntryState(entries[ids.eId]); 192 | }); 193 | 194 | socket.on('downEntry', function(ids){ 195 | entries[ids.eId].rating._down(getUserIdByName(ids.uId)); 196 | console.log("downEntry"); 197 | voteEntryState(entries[ids.eId]); 198 | }); 199 | 200 | 201 | socket.on('upComment', function(ids){ 202 | var index = getCommentArrayIndex(ids.cId); 203 | comments[index].rating._up(getUserIdByName(ids.uId)); 204 | console.log("upComment"); 205 | voteEntryState(entries[ids.eId]); 206 | }); 207 | 208 | socket.on('downComment', function(ids){ 209 | var index = getCommentArrayIndex(ids.cId); 210 | comments[index].rating._down(getUserIdByName(ids.uId)); 211 | console.log("downComment"); 212 | voteEntryState(entries[ids.eId]); 213 | }); 214 | 215 | }); 216 | 217 | io.sockets.on('disconnect', function (socket) { 218 | socket.emit('message', { action: 'disconnect' }); 219 | }); 220 | 221 | 222 | voteEntryState = function(entry){ 223 | console.log(entry); 224 | io.sockets.emit('voteEntryState', entry); 225 | }; 226 | 227 | 228 | getCommentArrayIndex = function(id){ 229 | for(i = 0; i < comments.length; i++){ 230 | if(comments[i].id === id) { 231 | console.log("index: " + i); 232 | return i; 233 | } 234 | } 235 | return -1; 236 | }; 237 | 238 | getUserIdByName = function(name){ 239 | for(i = 0; i < users.length; i++){ 240 | if(users[i].name === name){ 241 | return i; 242 | } 243 | } 244 | return -1; 245 | } 246 | 247 | -------------------------------------------------------------------------------- /user.js: -------------------------------------------------------------------------------- 1 | module.exports = function User(id, name, pwd) { 2 | this.id = id; 3 | this.name = name; 4 | this.password = pwd; 5 | } 6 | 7 | --------------------------------------------------------------------------------