From 126097a8bc7345fbea1f5c1e07b828fb6578e199 Mon Sep 17 00:00:00 2001
From: Mikael Korpela
Date: Mon, 6 Oct 2014 17:45:23 +0300
Subject: [PATCH 01/12] Remove articles example
---
app/controllers/articles.server.controller.js | 116 ------------
app/models/article.server.model.js | 34 ----
app/routes/articles.server.routes.js | 22 ---
app/tests/article.server.model.test.js | 64 -------
.../articles/articles.client.module.js | 4 -
.../articles/config/articles.client.routes.js | 25 ---
.../controllers/articles.client.controller.js | 62 -------
public/modules/articles/less/articles.less | 0
.../services/articles.client.service.js | 14 --
.../tests/articles.client.controller.test.js | 170 ------------------
.../views/create-article.client.view.html | 29 ---
.../views/edit-article.client.view.html | 35 ----
.../views/list-articles.client.view.html | 20 ---
.../views/view-article.client.view.html | 22 ---
14 files changed, 617 deletions(-)
delete mode 100644 app/controllers/articles.server.controller.js
delete mode 100644 app/models/article.server.model.js
delete mode 100644 app/routes/articles.server.routes.js
delete mode 100644 app/tests/article.server.model.test.js
delete mode 100755 public/modules/articles/articles.client.module.js
delete mode 100755 public/modules/articles/config/articles.client.routes.js
delete mode 100644 public/modules/articles/controllers/articles.client.controller.js
delete mode 100644 public/modules/articles/less/articles.less
delete mode 100644 public/modules/articles/services/articles.client.service.js
delete mode 100644 public/modules/articles/tests/articles.client.controller.test.js
delete mode 100644 public/modules/articles/views/create-article.client.view.html
delete mode 100644 public/modules/articles/views/edit-article.client.view.html
delete mode 100644 public/modules/articles/views/list-articles.client.view.html
delete mode 100644 public/modules/articles/views/view-article.client.view.html
diff --git a/app/controllers/articles.server.controller.js b/app/controllers/articles.server.controller.js
deleted file mode 100644
index 311f1875fb..0000000000
--- a/app/controllers/articles.server.controller.js
+++ /dev/null
@@ -1,116 +0,0 @@
-'use strict';
-
-/**
- * Module dependencies.
- */
-var mongoose = require('mongoose'),
- errorHandler = require('./errors'),
- Article = mongoose.model('Article'),
- _ = require('lodash');
-
-/**
- * Create a article
- */
-exports.create = function(req, res) {
- var article = new Article(req.body);
- article.user = req.user;
-
- article.save(function(err) {
- if (err) {
- return res.status(400).send({
- message: errorHandler.getErrorMessage(err)
- });
- } else {
-
- // Article is saved, notify everyone who's listening...
-
- var socketio = req.app.get('socketio'); // tacke out socket instance from the app container
- socketio.sockets.emit('article.created', article); // emit an event for all connected clients
-
- // Return it
- res.jsonp(article);
- }
- });
-};
-
-/**
- * Show the current article
- */
-exports.read = function(req, res) {
- res.jsonp(req.article);
-};
-
-/**
- * Update a article
- */
-exports.update = function(req, res) {
- var article = req.article;
-
- article = _.extend(article, req.body);
-
- article.save(function(err) {
- if (err) {
- return res.status(400).send({
- message: errorHandler.getErrorMessage(err)
- });
- } else {
- res.jsonp(article);
- }
- });
-};
-
-/**
- * Delete an article
- */
-exports.delete = function(req, res) {
- var article = req.article;
-
- article.remove(function(err) {
- if (err) {
- return res.status(400).send({
- message: errorHandler.getErrorMessage(err)
- });
- } else {
- res.jsonp(article);
- }
- });
-};
-
-/**
- * List of Articles
- */
-exports.list = function(req, res) {
- Article.find().sort('-created').populate('user', 'displayName').exec(function(err, articles) {
- if (err) {
- return res.status(400).send({
- message: errorHandler.getErrorMessage(err)
- });
- } else {
- res.jsonp(articles);
- }
- });
-};
-
-/**
- * Article middleware
- */
-exports.articleByID = function(req, res, next, id) {
- Article.findById(id).populate('user', 'displayName').exec(function(err, article) {
- if (err) return next(err);
- if (!article) return next(new Error('Failed to load article ' + id));
- req.article = article;
- next();
- });
-};
-
-/**
- * Article authorization middleware
- */
-exports.hasAuthorization = function(req, res, next) {
- if (req.article.user.id !== req.user.id) {
- return res.status(403).send({
- message: 'User is not authorized'
- });
- }
- next();
-};
\ No newline at end of file
diff --git a/app/models/article.server.model.js b/app/models/article.server.model.js
deleted file mode 100644
index 3f6fd0df1f..0000000000
--- a/app/models/article.server.model.js
+++ /dev/null
@@ -1,34 +0,0 @@
-'use strict';
-
-/**
- * Module dependencies.
- */
-var mongoose = require('mongoose'),
- Schema = mongoose.Schema;
-
-/**
- * Article Schema
- */
-var ArticleSchema = new Schema({
- created: {
- type: Date,
- default: Date.now
- },
- title: {
- type: String,
- default: '',
- trim: true,
- required: 'Title cannot be blank'
- },
- content: {
- type: String,
- default: '',
- trim: true
- },
- user: {
- type: Schema.ObjectId,
- ref: 'User'
- }
-});
-
-mongoose.model('Article', ArticleSchema);
\ No newline at end of file
diff --git a/app/routes/articles.server.routes.js b/app/routes/articles.server.routes.js
deleted file mode 100644
index 9dfcb03887..0000000000
--- a/app/routes/articles.server.routes.js
+++ /dev/null
@@ -1,22 +0,0 @@
-'use strict';
-
-/**
- * Module dependencies.
- */
-var users = require('../../app/controllers/users'),
- articles = require('../../app/controllers/articles');
-
-module.exports = function(app) {
- // Article Routes
- app.route('/articles')
- .get(articles.list)
- .post(users.requiresLogin, articles.create);
-
- app.route('/articles/:articleId')
- .get(articles.read)
- .put(users.requiresLogin, articles.hasAuthorization, articles.update)
- .delete(users.requiresLogin, articles.hasAuthorization, articles.delete);
-
- // Finish by binding the article middleware
- app.param('articleId', articles.articleByID);
-};
\ No newline at end of file
diff --git a/app/tests/article.server.model.test.js b/app/tests/article.server.model.test.js
deleted file mode 100644
index e3dd60c889..0000000000
--- a/app/tests/article.server.model.test.js
+++ /dev/null
@@ -1,64 +0,0 @@
-'use strict';
-
-/**
- * Module dependencies.
- */
-var should = require('should'),
- mongoose = require('mongoose'),
- User = mongoose.model('User'),
- Article = mongoose.model('Article');
-
-/**
- * Globals
- */
-var user, article;
-
-/**
- * Unit tests
- */
-describe('Article Model Unit Tests:', function() {
- beforeEach(function(done) {
- user = new User({
- firstName: 'Full',
- lastName: 'Name',
- displayName: 'Full Name',
- email: 'test@test.com',
- username: 'username',
- password: 'password'
- });
-
- user.save(function() {
- article = new Article({
- title: 'Article Title',
- content: 'Article Content',
- user: user
- });
-
- done();
- });
- });
-
- describe('Method Save', function() {
- it('should be able to save without problems', function(done) {
- return article.save(function(err) {
- should.not.exist(err);
- done();
- });
- });
-
- it('should be able to show an error when try to save without title', function(done) {
- article.title = '';
-
- return article.save(function(err) {
- should.exist(err);
- done();
- });
- });
- });
-
- afterEach(function(done) {
- Article.remove().exec();
- User.remove().exec();
- done();
- });
-});
\ No newline at end of file
diff --git a/public/modules/articles/articles.client.module.js b/public/modules/articles/articles.client.module.js
deleted file mode 100755
index 7435fc78a8..0000000000
--- a/public/modules/articles/articles.client.module.js
+++ /dev/null
@@ -1,4 +0,0 @@
-'use strict';
-
-// Use Applicaion configuration module to register a new module
-ApplicationConfiguration.registerModule('articles');
\ No newline at end of file
diff --git a/public/modules/articles/config/articles.client.routes.js b/public/modules/articles/config/articles.client.routes.js
deleted file mode 100755
index 1531a9a57c..0000000000
--- a/public/modules/articles/config/articles.client.routes.js
+++ /dev/null
@@ -1,25 +0,0 @@
-'use strict';
-
-// Setting up route
-angular.module('articles').config(['$stateProvider',
- function($stateProvider) {
- // Articles state routing
- $stateProvider.
- state('listArticles', {
- url: '/articles',
- templateUrl: 'modules/articles/views/list-articles.client.view.html'
- }).
- state('createArticle', {
- url: '/articles/create',
- templateUrl: 'modules/articles/views/create-article.client.view.html'
- }).
- state('viewArticle', {
- url: '/articles/:articleId',
- templateUrl: 'modules/articles/views/view-article.client.view.html'
- }).
- state('editArticle', {
- url: '/articles/:articleId/edit',
- templateUrl: 'modules/articles/views/edit-article.client.view.html'
- });
- }
-]);
\ No newline at end of file
diff --git a/public/modules/articles/controllers/articles.client.controller.js b/public/modules/articles/controllers/articles.client.controller.js
deleted file mode 100644
index dfa2120eca..0000000000
--- a/public/modules/articles/controllers/articles.client.controller.js
+++ /dev/null
@@ -1,62 +0,0 @@
-'use strict';
-
-angular.module('articles').controller('ArticlesController', ['$scope', '$stateParams', '$location', 'Socket', 'Authentication', 'Articles',
- function($scope, $stateParams, $location, Socket, Authentication, Articles) {
- $scope.authentication = Authentication;
-
- Socket.on('article.created', function(article) {
- console.log(article);
- });
-
- $scope.create = function() {
- var article = new Articles({
- title: this.title,
- content: this.content
- });
- article.$save(function(response) {
- $location.path('articles/' + response._id);
-
- $scope.title = '';
- $scope.content = '';
- }, function(errorResponse) {
- $scope.error = errorResponse.data.message;
- });
- };
-
- $scope.remove = function(article) {
- if (article) {
- article.$remove();
-
- for (var i in $scope.articles) {
- if ($scope.articles[i] === article) {
- $scope.articles.splice(i, 1);
- }
- }
- } else {
- $scope.article.$remove(function() {
- $location.path('articles');
- });
- }
- };
-
- $scope.update = function() {
- var article = $scope.article;
-
- article.$update(function() {
- $location.path('articles/' + article._id);
- }, function(errorResponse) {
- $scope.error = errorResponse.data.message;
- });
- };
-
- $scope.find = function() {
- $scope.articles = Articles.query();
- };
-
- $scope.findOne = function() {
- $scope.article = Articles.get({
- articleId: $stateParams.articleId
- });
- };
- }
-]);
\ No newline at end of file
diff --git a/public/modules/articles/less/articles.less b/public/modules/articles/less/articles.less
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/public/modules/articles/services/articles.client.service.js b/public/modules/articles/services/articles.client.service.js
deleted file mode 100644
index deeb7da58c..0000000000
--- a/public/modules/articles/services/articles.client.service.js
+++ /dev/null
@@ -1,14 +0,0 @@
-'use strict';
-
-//Articles service used for communicating with the articles REST endpoints
-angular.module('articles').factory('Articles', ['$resource',
- function($resource) {
- return $resource('articles/:articleId', {
- articleId: '@_id'
- }, {
- update: {
- method: 'PUT'
- }
- });
- }
-]);
\ No newline at end of file
diff --git a/public/modules/articles/tests/articles.client.controller.test.js b/public/modules/articles/tests/articles.client.controller.test.js
deleted file mode 100644
index 7e25c699bb..0000000000
--- a/public/modules/articles/tests/articles.client.controller.test.js
+++ /dev/null
@@ -1,170 +0,0 @@
-'use strict';
-
-(function() {
- // Articles Controller Spec
- describe('ArticlesController', function() {
- // Initialize global variables
- var ArticlesController,
- scope,
- $httpBackend,
- $stateParams,
- $location;
-
- // The $resource service augments the response object with methods for updating and deleting the resource.
- // If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
- // the responses exactly. To solve the problem, we define a new toEqualData Jasmine matcher.
- // When the toEqualData matcher compares two objects, it takes only object properties into
- // account and ignores methods.
- beforeEach(function() {
- jasmine.addMatchers({
- toEqualData: function(util, customEqualityTesters) {
- return {
- compare: function(actual, expected) {
- return {
- pass: angular.equals(actual, expected)
- };
- }
- };
- }
- });
- });
-
- // Then we can start by loading the main application module
- beforeEach(module(ApplicationConfiguration.applicationModuleName));
-
- // The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
- // This allows us to inject a service but then attach it to a variable
- // with the same name as the service.
- beforeEach(inject(function($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_) {
- // Set a new global scope
- scope = $rootScope.$new();
-
- // Point global variables to injected services
- $stateParams = _$stateParams_;
- $httpBackend = _$httpBackend_;
- $location = _$location_;
-
- // Initialize the Articles controller.
- ArticlesController = $controller('ArticlesController', {
- $scope: scope
- });
- }));
-
- it('$scope.find() should create an array with at least one article object fetched from XHR', inject(function(Articles) {
- // Create sample article using the Articles service
- var sampleArticle = new Articles({
- title: 'An Article about MEAN',
- content: 'MEAN rocks!'
- });
-
- // Create a sample articles array that includes the new article
- var sampleArticles = [sampleArticle];
-
- // Set GET response
- $httpBackend.expectGET('articles').respond(sampleArticles);
-
- // Run controller functionality
- scope.find();
- $httpBackend.flush();
-
- // Test scope value
- expect(scope.articles).toEqualData(sampleArticles);
- }));
-
- it('$scope.findOne() should create an array with one article object fetched from XHR using a articleId URL parameter', inject(function(Articles) {
- // Define a sample article object
- var sampleArticle = new Articles({
- title: 'An Article about MEAN',
- content: 'MEAN rocks!'
- });
-
- // Set the URL parameter
- $stateParams.articleId = '525a8422f6d0f87f0e407a33';
-
- // Set GET response
- $httpBackend.expectGET(/articles\/([0-9a-fA-F]{24})$/).respond(sampleArticle);
-
- // Run controller functionality
- scope.findOne();
- $httpBackend.flush();
-
- // Test scope value
- expect(scope.article).toEqualData(sampleArticle);
- }));
-
- it('$scope.create() with valid form data should send a POST request with the form input values and then locate to new object URL', inject(function(Articles) {
- // Create a sample article object
- var sampleArticlePostData = new Articles({
- title: 'An Article about MEAN',
- content: 'MEAN rocks!'
- });
-
- // Create a sample article response
- var sampleArticleResponse = new Articles({
- _id: '525cf20451979dea2c000001',
- title: 'An Article about MEAN',
- content: 'MEAN rocks!'
- });
-
- // Fixture mock form input values
- scope.title = 'An Article about MEAN';
- scope.content = 'MEAN rocks!';
-
- // Set POST response
- $httpBackend.expectPOST('articles', sampleArticlePostData).respond(sampleArticleResponse);
-
- // Run controller functionality
- scope.create();
- $httpBackend.flush();
-
- // Test form inputs are reset
- expect(scope.title).toEqual('');
- expect(scope.content).toEqual('');
-
- // Test URL redirection after the article was created
- expect($location.path()).toBe('/articles/' + sampleArticleResponse._id);
- }));
-
- it('$scope.update() should update a valid article', inject(function(Articles) {
- // Define a sample article put data
- var sampleArticlePutData = new Articles({
- _id: '525cf20451979dea2c000001',
- title: 'An Article about MEAN',
- content: 'MEAN Rocks!'
- });
-
- // Mock article in scope
- scope.article = sampleArticlePutData;
-
- // Set PUT response
- $httpBackend.expectPUT(/articles\/([0-9a-fA-F]{24})$/).respond();
-
- // Run controller functionality
- scope.update();
- $httpBackend.flush();
-
- // Test URL location to new object
- expect($location.path()).toBe('/articles/' + sampleArticlePutData._id);
- }));
-
- it('$scope.remove() should send a DELETE request with a valid articleId and remove the article from the scope', inject(function(Articles) {
- // Create new article object
- var sampleArticle = new Articles({
- _id: '525a8422f6d0f87f0e407a33'
- });
-
- // Create new articles array and include the article
- scope.articles = [sampleArticle];
-
- // Set expected DELETE response
- $httpBackend.expectDELETE(/articles\/([0-9a-fA-F]{24})$/).respond(204);
-
- // Run controller functionality
- scope.remove(sampleArticle);
- $httpBackend.flush();
-
- // Test array after successful delete
- expect(scope.articles.length).toBe(0);
- }));
- });
-}());
\ No newline at end of file
diff --git a/public/modules/articles/views/create-article.client.view.html b/public/modules/articles/views/create-article.client.view.html
deleted file mode 100644
index ab8db8ef61..0000000000
--- a/public/modules/articles/views/create-article.client.view.html
+++ /dev/null
@@ -1,29 +0,0 @@
-
\ No newline at end of file
diff --git a/public/modules/articles/views/edit-article.client.view.html b/public/modules/articles/views/edit-article.client.view.html
deleted file mode 100644
index 353cb8e666..0000000000
--- a/public/modules/articles/views/edit-article.client.view.html
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/public/modules/articles/views/list-articles.client.view.html b/public/modules/articles/views/list-articles.client.view.html
deleted file mode 100644
index 861ae5b6ba..0000000000
--- a/public/modules/articles/views/list-articles.client.view.html
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
- No articles yet, why don't you
create one ?
-
-
\ No newline at end of file
diff --git a/public/modules/articles/views/view-article.client.view.html b/public/modules/articles/views/view-article.client.view.html
deleted file mode 100644
index 312d25c84e..0000000000
--- a/public/modules/articles/views/view-article.client.view.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- Posted on
-
- by
-
-
-
-
-
\ No newline at end of file
From b835de490ccde6381ffb0592ec82f0fd40c6520f Mon Sep 17 00:00:00 2001
From: Mikael Korpela
Date: Mon, 6 Oct 2014 19:16:09 +0300
Subject: [PATCH 02/12] #11 Basic location selector directive
Uses genomes.org for now
---
.../tr-location.client.directive.js | 46 +++++++++++++++++++
.../profile/edit-profile.client.view.html | 6 ++-
2 files changed, 50 insertions(+), 2 deletions(-)
create mode 100644 public/modules/core/directives/tr-location.client.directive.js
diff --git a/public/modules/core/directives/tr-location.client.directive.js b/public/modules/core/directives/tr-location.client.directive.js
new file mode 100644
index 0000000000..aee1139827
--- /dev/null
+++ b/public/modules/core/directives/tr-location.client.directive.js
@@ -0,0 +1,46 @@
+'use strict';
+
+angular.module('core').directive('trLocation', [
+ '$http',
+ function($http) {
+ return {
+ template: ' ' +
+ ' ',
+ restrict: 'EA',
+ controller: function($scope, $http) {
+
+ $scope.getLocation = function(val) {
+
+ // http://www.geonames.org/export/geonames-search.html
+ return $http.get('http://api.geonames.org/searchJSON', {
+ params: {
+ q: val,
+ maxRows: 10,
+ lang: 'en',
+ featureClass: 'P', // P for city, A for country - http://www.geonames.org/export/codes.html
+ style: 'full',
+ username: 'trustroots'
+ }
+ }).then(function(response){
+ return response.data.geonames.map(function(place){
+
+ var title = '';
+
+ // Prefer toponym name like 'Jyväskylä' instead of 'Jyvaskyla'
+ if(place.toponymName) title += place.toponymName;
+ else if(place.name) title += place.name;
+
+ if(place.countryName) title += ', ' + place.countryName;
+
+ place.trTitle = title;
+
+ return place;
+ });
+ });
+ };
+
+
+ }
+ };
+ }
+]);
diff --git a/public/modules/users/views/profile/edit-profile.client.view.html b/public/modules/users/views/profile/edit-profile.client.view.html
index aaf6f77366..830488daa6 100644
--- a/public/modules/users/views/profile/edit-profile.client.view.html
+++ b/public/modules/users/views/profile/edit-profile.client.view.html
@@ -29,12 +29,14 @@
-
diff --git a/public/modules/messages/config/messages.client.config.js b/public/modules/messages/config/messages.client.config.js
index 2edc20c8d4..28438667d4 100644
--- a/public/modules/messages/config/messages.client.config.js
+++ b/public/modules/messages/config/messages.client.config.js
@@ -4,6 +4,6 @@
angular.module('messages').run(['Menus',
function(Menus) {
// Set top bar menu items
- Menus.addMenuItem('topbar', 'Messages', 'messages', 'messages');
+ Menus.addMenuItem('topuserbar', 'Messages', 'messages', 'messages');
}
-]);
\ No newline at end of file
+]);
diff --git a/public/modules/messages/views/thread-messages.client.view.html b/public/modules/messages/views/thread-messages.client.view.html
index 7981ec3ab3..545457fd77 100644
--- a/public/modules/messages/views/thread-messages.client.view.html
+++ b/public/modules/messages/views/thread-messages.client.view.html
@@ -21,7 +21,9 @@
diff --git a/public/modules/references/config/references.client.routes.js b/public/modules/references/config/references.client.routes.js
deleted file mode 100644
index 8e16f8c04f..0000000000
--- a/public/modules/references/config/references.client.routes.js
+++ /dev/null
@@ -1,25 +0,0 @@
-'use strict';
-
-//Setting up route
-angular.module('references').config(['$stateProvider',
- function($stateProvider) {
- // References state routing
- $stateProvider.
- state('listReferences', {
- url: '/references',
- templateUrl: 'modules/references/views/list-references.client.view.html'
- }).
- state('createReference', {
- url: '/references/create',
- templateUrl: 'modules/references/views/create-reference.client.view.html'
- }).
- state('viewReference', {
- url: '/references/:referenceId',
- templateUrl: 'modules/references/views/view-reference.client.view.html'
- }).
- state('editReference', {
- url: '/references/:referenceId/edit',
- templateUrl: 'modules/references/views/edit-reference.client.view.html'
- });
- }
-]);
\ No newline at end of file
diff --git a/public/modules/references/controllers/references.client.controller.js b/public/modules/references/controllers/references.client.controller.js
index b0367da457..f4e795a2ec 100644
--- a/public/modules/references/controllers/references.client.controller.js
+++ b/public/modules/references/controllers/references.client.controller.js
@@ -1,31 +1,51 @@
'use strict';
// References controller
-angular.module('references').controller('ReferencesController', ['$scope', '$stateParams', '$location', 'Authentication', 'References',
- function($scope, $stateParams, $location, Authentication, References ) {
+angular.module('references').controller('ReferencesController', ['$scope', '$log', '$state', '$stateParams', '$location', '$modal', 'Authentication', 'ReferencesBy', 'References',
+ function($scope, $log, $state, $stateParams, $location, $modal, Authentication, ReferencesBy, References ) {
$scope.authentication = Authentication;
// Create new Reference
$scope.create = function() {
+
+ $log.log('Reference to: ' + $scope.userTo);
+
// Create new Reference object
var reference = new References ({
- name: this.name
+ reference: this.reference,
+ userTo: $scope.userTo
});
// Redirect after save
reference.$save(function(response) {
- $location.path('references/' + response._id);
+
+
+ //if(modalInstance) {
+ // $log.log('Close modal');
+ // modalInstance.dismiss('cancel');
+ //}
+
+ $log.log('->Success');
+ $log.log(response);
+
+ $state.go('profile-reference', {'username': response.userTo.username, 'referenceId': response._id});
// Clear form fields
- $scope.name = '';
+ //$scope.reference = '';
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
// Remove existing Reference
- $scope.remove = function( reference ) {
- if ( reference ) { reference.$remove();
+ $scope.remove = function( reference, profile ) {
+ $log.log('->remove');
+ $log.log($stateParams);
+ $log.log(reference);
+
+ if ( reference ) {
+
+ reference.$remove();
for (var i in $scope.references ) {
if ($scope.references [i] === reference ) {
@@ -34,25 +54,32 @@ angular.module('references').controller('ReferencesController', ['$scope', '$sta
}
} else {
$scope.reference.$remove(function() {
- $location.path('references');
+ //$location.path('references');
+ $state.go('profile-tab', {'username': profile.username, 'tab': 'references'});
});
}
};
// Update existing Reference
- $scope.update = function() {
- var reference = $scope.reference ;
-
+ $scope.update = function(profile) {
+ var reference = $scope.reference;
+ $log.log('->update');
+ $log.log($stateParams);
+ $log.log(reference);
reference.$update(function() {
- $location.path('references/' + reference._id);
+ //$location.path('references/' + reference._id);
+ $state.go('profile-tab', {'username': profile.username, 'tab': 'references'});
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
// Find a list of References
- $scope.find = function() {
- $scope.references = References.query();
+ $scope.list = function(profile) {
+ $log.log('list references: ' + profile.id);
+ $scope.references = ReferencesBy.query({
+ userId: profile.id || profile._id
+ });
};
// Find existing Reference
@@ -61,5 +88,6 @@ angular.module('references').controller('ReferencesController', ['$scope', '$sta
referenceId: $stateParams.referenceId
});
};
+
}
]);
diff --git a/public/modules/references/less/references.less b/public/modules/references/less/references.less
index e69de29bb2..54888ecc6d 100644
--- a/public/modules/references/less/references.less
+++ b/public/modules/references/less/references.less
@@ -0,0 +1,152 @@
+.reference-list {
+ list-style: none;
+ display: block;
+ padding: 0;
+ margin: 0;
+ li {
+ .reference-author {
+ .text-center();
+ font-size: @font-size-small;
+ .avatar {
+ margin: 10px auto @padding-small-vertical auto;
+ }
+ a {
+ &,
+ &:hover,
+ &:hover {
+ .text-muted();
+ text-decoration: none;
+ }
+ }
+ }
+ .reference-meta {
+ .text-right();
+ .reference-reputation {
+ .pull-left();
+ }
+ &, a {
+ .text-muted();
+ }
+ }
+ .panel {
+ .panel-triangle-right();
+ }
+ }
+}
+/*
+.reference-list {
+ display: block;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ li {
+ .avatar {
+ float: left;
+ margin-right: @padding-base-vertical;
+ }
+ h4 {
+ font-size: @font-size-base;
+ font-weight: bold;
+ margin: 1px 0;
+ padding: 0;
+ }
+ .reference-body {
+ padding: 1px 0 0 42px;
+ clear: both;
+ }
+ .reference-reply {
+ clear: both;
+ position: relative;
+ margin-top: 13px;
+ padding-top: 7px;
+ margin-left: 30px;
+ border-top: 1px solid @gray-lighter;
+ font-style: italic;
+ color: @gray-darker;
+ &:after {
+ content: '';
+ position: absolute;
+ .square(0);
+ top: 0;
+ left: 7px;
+ margin-top: -7px;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-bottom: 6px solid @gray-lighter;
+ }
+ h4,
+ h4 a {
+ color: @gray-darker;
+ }
+ &.reference-reply-neutral {
+ border-top: 2px solid @experience-neutral;
+ &:after {
+ margin-top: -8px;
+ border-bottom-color: @experience-neutral;
+ }
+ }
+ &.reference-reply-negative {
+ border-top: 2px solid @experience-negative;
+ &:after {
+ margin-top: -8px;
+ border-bottom-color: @experience-negative;
+ }
+ }
+ }
+ &.reference-neutral {
+ .box-shadow(0 1px 3px @experience-neutral);
+ border-color: @experience-neutral;
+ }
+ &.reference-negative {
+ .box-shadow(0 1px 3px @experience-negative);
+ border-color: @experience-neutral;
+ }
+ }
+}
+*/
+
+
+/**
+ * New reference -form
+ */
+/* Modal: */
+.profile-reference-new {
+ .modal-footer {
+ margin-top: 0;
+ }
+}
+.reference-new-reputation {
+ clear: both;
+ overflow: hidden;
+ .form-group {
+ margin-bottom: 0;
+ }
+ .checkbox {
+ margin: 0;
+ padding-left: 10px;
+ }
+ .help-block {
+ display: none;
+ }
+}
+.reference-new-body {
+ margin-bottom: 0;
+ textarea {
+ min-height: 80px;
+ padding: 20px;
+ border: 0;
+ outline: none;
+ border: 0;
+ border-top: 1px solid #ccc;
+ border-radius: 0;
+ font-size: 16px;
+ line-height: 25px;
+ .box-shadow(none);
+ resize: none;
+ &:focus {
+ border-color: @brand-primary;
+ outline: none;
+ .box-shadow(none);
+ }
+ }
+}
diff --git a/public/modules/references/services/references.client.service.js b/public/modules/references/services/references.client.service.js
index 371595d638..ec9d3b1d01 100644
--- a/public/modules/references/services/references.client.service.js
+++ b/public/modules/references/services/references.client.service.js
@@ -1,13 +1,23 @@
'use strict';
-//References service used to communicate References REST endpoints
+//References services used to communicate References REST endpoints
+
angular.module('references').factory('References', ['$resource',
function($resource) {
- return $resource('references/:referenceId', { referenceId: '@_id'
+ return $resource('references/:referenceId', {
+ referenceId: '@_id'
}, {
update: {
method: 'PUT'
}
});
}
-]);
\ No newline at end of file
+]);
+
+angular.module('references').factory('ReferencesBy', ['$resource',
+ function($resource) {
+ return $resource('references/by/:userId', {
+ userId: '@userId'
+ });
+ }
+]);
diff --git a/public/modules/references/views/create-reference.client.modal.html b/public/modules/references/views/create-reference.client.modal.html
new file mode 100644
index 0000000000..4bb0bbfc59
--- /dev/null
+++ b/public/modules/references/views/create-reference.client.modal.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+ Reference
+ {{ profile.reference.reference }}
+
+
+
+
+
+
diff --git a/public/modules/references/views/create-reference.client.view.html b/public/modules/references/views/create-reference.client.view.html
deleted file mode 100644
index 7a04ee0796..0000000000
--- a/public/modules/references/views/create-reference.client.view.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
\ No newline at end of file
diff --git a/public/modules/references/views/list-references.client.view.html b/public/modules/references/views/list-references.client.view.html
index ea8da0ee03..d571d05756 100644
--- a/public/modules/references/views/list-references.client.view.html
+++ b/public/modules/references/views/list-references.client.view.html
@@ -1,19 +1,76 @@
-
-
-
“Everyone is necessarily the hero of his own life story.”
+
+
+
+ “Everyone is necessarily the hero of his own life story.”
+
diff --git a/public/modules/users/views/profile/view-profile.client.view.html b/public/modules/users/views/profile/view-profile.client.view.html
index 80da15c3fc..340fd1200f 100644
--- a/public/modules/users/views/profile/view-profile.client.view.html
+++ b/public/modules/users/views/profile/view-profile.client.view.html
@@ -18,10 +18,12 @@
From City, Country
+
Languages
@@ -51,16 +53,24 @@ @{{profile.username
-
-
This is your profile as others see it. Edit your profile
+
+
This is your profile as others see it.
+
+
Edit your profile
-
+
From e7d2c45443b8f4ce77229211cc148d401239d982 Mon Sep 17 00:00:00 2001
From: Mikael Korpela
Date: Mon, 6 Oct 2014 19:23:47 +0300
Subject: [PATCH 05/12] Production auth callback urls
---
config/env/production.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/config/env/production.js b/config/env/production.js
index 60188c6cc5..97faaa7b52 100644
--- a/config/env/production.js
+++ b/config/env/production.js
@@ -24,27 +24,27 @@ module.exports = {
facebook: {
clientID: process.env.FACEBOOK_ID || 'APP_ID',
clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
- callbackURL: 'http://localhost:3000/auth/facebook/callback'
+ callbackURL: 'http://www.trustroots.org/auth/facebook/callback'
},
twitter: {
clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
- callbackURL: 'http://localhost:3000/auth/twitter/callback'
+ callbackURL: 'http://www.trustroots.org/auth/twitter/callback'
},
google: {
clientID: process.env.GOOGLE_ID || 'APP_ID',
clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
- callbackURL: 'http://localhost:3000/auth/google/callback'
+ callbackURL: 'http://www.trustroots.org/auth/google/callback'
},
linkedin: {
clientID: process.env.LINKEDIN_ID || 'APP_ID',
clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET',
- callbackURL: 'http://localhost:3000/auth/linkedin/callback'
+ callbackURL: 'http://www.trustroots.org/auth/linkedin/callback'
},
github: {
clientID: process.env.GITHUB_ID || 'APP_ID',
clientSecret: process.env.GITHUB_SECRET || 'APP_SECRET',
- callbackURL: 'http://localhost:3000/auth/github/callback'
+ callbackURL: 'http://www.trustroots.org/auth/github/callback'
},
mailer: {
from: process.env.MAILER_FROM || 'MAILER_FROM',
@@ -56,4 +56,4 @@ module.exports = {
}
}
}
-};
\ No newline at end of file
+};
From 2e2b74978cd3d1f4ff8037d005efa413fb2cfc8f Mon Sep 17 00:00:00 2001
From: Mikael Korpela
Date: Mon, 6 Oct 2014 19:35:59 +0300
Subject: [PATCH 06/12] #15 Fixes to remove front logic
---
.../controllers/settings.client.controller.js | 24 ++++++++++++-------
.../profile/edit-settings.client.view.html | 14 +++++++++--
2 files changed, 28 insertions(+), 10 deletions(-)
diff --git a/public/modules/users/controllers/settings.client.controller.js b/public/modules/users/controllers/settings.client.controller.js
index 94d8c1da58..8860017d13 100644
--- a/public/modules/users/controllers/settings.client.controller.js
+++ b/public/modules/users/controllers/settings.client.controller.js
@@ -83,18 +83,26 @@ angular.module('users').controller('SettingsController', ['$scope', '$http', '$s
// Remove user permanently
+ $scope.removalConfirm = false;
$scope.removeUser = function() {
$scope.success = $scope.error = null;
- var duhhAreYouSureYouWantToRemoveYourself = confirm('Are you sure you want to remove your account? This cannot be undone.');
+ if($scope.removalConfirm === true) {
- if(duhhAreYouSureYouWantToRemoveYourself) {
- $http.post('/users/remove').success(function(response) {
- // Do something!
- }).error(function(response) {
- $scope.error = response.message;
- });
- }//yup, user is sure
+ var duhhAreYouSureYouWantToRemoveYourself = confirm('Are you sure you want to remove your account? This cannot be undone.');
+
+ if(duhhAreYouSureYouWantToRemoveYourself) {
+ $http.post('/users/remove').success(function(response) {
+ // Do something!
+ }).error(function(response) {
+ $scope.error = response.message;
+ });
+ }//yup, user is sure
+
+ } // Require checkbox
+ else {
+ alert('Choose "I understand this cannot be undone"');
+ }
};
diff --git a/public/modules/users/views/profile/edit-settings.client.view.html b/public/modules/users/views/profile/edit-settings.client.view.html
index a0f5eff742..b92fac1370 100644
--- a/public/modules/users/views/profile/edit-settings.client.view.html
+++ b/public/modules/users/views/profile/edit-settings.client.view.html
@@ -34,6 +34,7 @@ Change your password
+
@@ -41,9 +42,18 @@ Change your password
-
Remove your account
-
Yes, remove my profile
+
Remove your account
+
+
+
+ I understand this cannot be undone
+
+
+
+ Yes, remove my account permanently
+
+
From 272c1b1d21f22cd326a0b4a1d4331a9110154ff2 Mon Sep 17 00:00:00 2001
From: Mikael Korpela
Date: Mon, 6 Oct 2014 19:36:59 +0300
Subject: [PATCH 07/12] #5 Pass profile for modal
---
public/modules/users/controllers/profile.client.controller.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/public/modules/users/controllers/profile.client.controller.js b/public/modules/users/controllers/profile.client.controller.js
index 1973ffbda0..317cefda2e 100644
--- a/public/modules/users/controllers/profile.client.controller.js
+++ b/public/modules/users/controllers/profile.client.controller.js
@@ -90,7 +90,7 @@ angular.module('users').controller('ProfileController', ['$scope', '$stateParams
/**
* Open write/update reference -modal
*/
- $scope.referenceModal = function (userTo, $event) {
+ $scope.referenceModal = function (profile, $event) {
if($event) $event.preventDefault();
From 8d3f83c4b9bf9f2525c965121b612f951deac061 Mon Sep 17 00:00:00 2001
From: Mikael Korpela
Date: Mon, 6 Oct 2014 19:37:12 +0300
Subject: [PATCH 08/12] #12 Fixes to profile navigation
---
public/modules/users/config/users.client.config.js | 4 ++--
public/modules/users/config/users.client.routes.js | 4 ++--
.../modules/users/views/profile/edit-profile.client.view.html | 2 +-
.../modules/users/views/profile/view-profile.client.view.html | 2 +-
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/public/modules/users/config/users.client.config.js b/public/modules/users/config/users.client.config.js
index 45b495ce7a..c553ee3a00 100644
--- a/public/modules/users/config/users.client.config.js
+++ b/public/modules/users/config/users.client.config.js
@@ -6,9 +6,9 @@ angular.module('users').run(['Menus', 'Authentication',
// Set top bar menu items
Menus.addMenuItem('topuserbar', Authentication.user.displayName, 'profile', 'dropdown', '/profile');
- Menus.addSubMenuItem('topuserbar', 'profile', 'My profile', 'profile', 'profile', null, null, 0, 'user');
+ Menus.addSubMenuItem('topuserbar', 'profile', 'My profile', 'profile/' + Authentication.user.username, 'profile', null, null, 0, 'user');
Menus.addSubMenuItem('topuserbar', 'profile', 'Edit profile', 'profile/' + Authentication.user.username + '/edit', 'profile-edit', null, null, 0, 'edit');
- Menus.addSubMenuItem('topuserbar', 'profile', 'Settings', 'profile-settings', 'profile-settings', null, null, 0, 'cog');
+ Menus.addSubMenuItem('topuserbar', 'profile', 'Settings', 'profile/' + Authentication.user.username + '/settings', 'profile-settings', null, null, 0, 'cog');
Menus.addSubMenuItem('topuserbar', 'profile', 'Help', 'contact', 'contact', null, null, 0, 'bolt');
Menus.addSubMenuDivider('topuserbar', 'profile');
Menus.addSubMenuItem('topuserbar', 'profile', 'Sign out', 'auth/signout', 'signout', null, null, 0, 'sign-out');
diff --git a/public/modules/users/config/users.client.routes.js b/public/modules/users/config/users.client.routes.js
index b606ee6602..735270e6cb 100755
--- a/public/modules/users/config/users.client.routes.js
+++ b/public/modules/users/config/users.client.routes.js
@@ -10,11 +10,11 @@ angular.module('users').config(['$stateProvider',
templateUrl: 'modules/users/views/authentication/welcome.client.view.html'
}).
state('profile-edit', {
- url: '/profile-edit',
+ url: '/profile/:username/edit',
templateUrl: 'modules/users/views/profile/edit-profile.client.view.html'
}).
state('profile-settings', {
- url: '/profile-settings',
+ url: '/profile/:username/settings',
templateUrl: 'modules/users/views/profile/edit-settings.client.view.html'
}).
state('profile', {
diff --git a/public/modules/users/views/profile/edit-profile.client.view.html b/public/modules/users/views/profile/edit-profile.client.view.html
index 830488daa6..55f9de197e 100644
--- a/public/modules/users/views/profile/edit-profile.client.view.html
+++ b/public/modules/users/views/profile/edit-profile.client.view.html
@@ -135,7 +135,7 @@
-
Cancel
+
Cancel
Save profile
diff --git a/public/modules/users/views/profile/view-profile.client.view.html b/public/modules/users/views/profile/view-profile.client.view.html
index 340fd1200f..b2be07abea 100644
--- a/public/modules/users/views/profile/view-profile.client.view.html
+++ b/public/modules/users/views/profile/view-profile.client.view.html
@@ -56,7 +56,7 @@ @{{profile.username
This is your profile as others see it.
-
Edit your profile
+
Edit your profile
From 9fd8179121c69bb0c83259cd62c34193b3291fdc Mon Sep 17 00:00:00 2001
From: Mikael Korpela
Date: Tue, 7 Oct 2014 13:24:44 +0300
Subject: [PATCH 09/12] #7 Let user choose avatar source
FB, Gravatar, none, local upload
---
app/controllers/messages.server.controller.js | 16 ++-
.../references.server.controller.js | 10 +-
.../users/users.profile.server.controller.js | 20 ++-
app/models/user.server.model.js | 26 ++--
config/env/all.js | 5 +-
config/env/development.js | 5 +-
.../views/list-references.client.view.html | 2 +-
.../controllers/settings.client.controller.js | 23 +++-
.../directives/tr-avatar.client.directive.js | 127 +++++++++++++++++-
public/modules/users/less/editor.less | 16 +--
.../directives/tr-avatar.client.view.html | 5 -
.../profile/edit-profile.client.view.html | 61 ++++++++-
12 files changed, 263 insertions(+), 53 deletions(-)
delete mode 100644 public/modules/users/views/directives/tr-avatar.client.view.html
diff --git a/app/controllers/messages.server.controller.js b/app/controllers/messages.server.controller.js
index eb3e1b3e16..8efe3b4b18 100755
--- a/app/controllers/messages.server.controller.js
+++ b/app/controllers/messages.server.controller.js
@@ -5,6 +5,7 @@
*/
var mongoose = require('mongoose'),
errorHandler = require('./errors'),
+ config = require('../../config/config'),
sanitizeHtml = require('sanitize-html'),
Message = mongoose.model('Message'),
Thread = mongoose.model('Thread'),
@@ -27,6 +28,8 @@ var messageSanitizeOptions = {
allowedSchemes: [ 'http', 'https', 'ftp', 'mailto', 'tel' ]
};
+// Populate users with these fields
+var userPopulateFields = config.app.miniUserProfileFields.join(' ');
/**
* List of threads aka inbox
@@ -42,8 +45,8 @@ exports.inbox = function(req, res) {
}
)
.sort('updated')
- .populate('userFrom', 'displayName username')
- .populate('userTo', 'displayName username')
+ .populate('userFrom', userPopulateFields)
+ .populate('userTo', userPopulateFields)
.populate('message', 'content')
.exec(function(err, threads) {
if (err) {
@@ -139,10 +142,10 @@ exports.send = function(req, res) {
// We'll need some info about related users, populate some fields
message
- .populate('userFrom', 'displayName username')
+ .populate('userFrom', userPopulateFields)
.populate({
path: 'userTo',
- select: 'displayName username'
+ select: userPopulateFields
}, function(err, message) {
if (err) {
return res.status(400).send({
@@ -175,6 +178,7 @@ exports.thread = function(req, res) {
* Thread middleware
*/
exports.threadByUser = function(req, res, next, userId) {
+
Message.find(
{
$or: [
@@ -184,8 +188,8 @@ exports.threadByUser = function(req, res, next, userId) {
}
)
.sort('-created')
- .populate('userFrom', 'displayName username')
- .populate('userTo', 'displayName username')
+ .populate('userFrom', userPopulateFields)
+ .populate('userTo', userPopulateFields)
.exec(function(err, messages) {
if (err) return next(err);
if (!messages) return next(new Error('Failed to load messages.'));
diff --git a/app/controllers/references.server.controller.js b/app/controllers/references.server.controller.js
index a219986816..483ba0870c 100644
--- a/app/controllers/references.server.controller.js
+++ b/app/controllers/references.server.controller.js
@@ -5,9 +5,13 @@
*/
var mongoose = require('mongoose'),
errorHandler = require('./errors'),
+ config = require('../../config/config'),
Reference = mongoose.model('Reference'),
_ = require('lodash');
+// Populate users with these fields
+var userPopulateFields = config.app.miniUserProfileFields.join(' ');
+
/**
* Create a Reference
*/
@@ -58,7 +62,7 @@ exports.update = function(req, res) {
reference
.populate({
path: 'userTo',
- select: 'displayName username'
+ select: userPopulateFields
}, function(err, reference) {
if (err) {
return res.status(400).send({
@@ -136,8 +140,8 @@ exports.referencesByUser = function(req, res, next, userId) {
{ userTo: userId }
]
})
- .populate('userFrom', 'displayName username')
- .populate('userTo', 'displayName username')
+ .populate('userFrom', userPopulateFields)
+ .populate('userTo', userPopulateFields)
.exec(function(err, references) {
if (err) return next(err);
if (! references) return next(new Error('Failed to load References for user ' + userId));
diff --git a/app/controllers/users/users.profile.server.controller.js b/app/controllers/users/users.profile.server.controller.js
index ad2cf74cf1..6233350f65 100644
--- a/app/controllers/users/users.profile.server.controller.js
+++ b/app/controllers/users/users.profile.server.controller.js
@@ -5,6 +5,7 @@
*/
var _ = require('lodash'),
errorHandler = require('../errors'),
+ config = require('../../../config/config'),
mongoose = require('mongoose'),
passport = require('passport'),
sanitizeHtml = require('sanitize-html'),
@@ -29,6 +30,8 @@ var userSanitizeOptions = {
allowedSchemes: [ 'http', 'https', 'ftp', 'mailto', 'tel' ]
};
+// Populate users with these fields
+var userPopulateFields = config.app.miniUserProfileFields.join(' ');
/**
* Update user details
@@ -84,7 +87,6 @@ exports.me = function(req, res) {
* Show the profile of the user
*/
exports.getUser = function(req, res) {
- console.log(req.user);
res.jsonp(req.user || null);
};
@@ -93,7 +95,7 @@ exports.getUser = function(req, res) {
* Pick only certain fields from whole profile @link http://underscorejs.org/#pick
*/
exports.getMiniUser = function(req, res) {
- res.jsonp( _.pick(req.user, 'id', 'displayName', 'username') || null );
+ res.jsonp( _.pick(req.user, userPopulateFields) || null );
};
@@ -134,14 +136,17 @@ exports.userByID = function(req, res, next, id) {
'birthdate',
'seen',
'created',
- 'updated'
+ 'updated',
+ 'avatarSource',
+ 'emailHash' // MD5 hashed email to use with Gravatars
);
// Sanitize output
if(user.description) user.description = sanitizeHtml(user.description, userSanitizeOptions);
// Check if logged in user has left reference for this profile
- console.log('->userByID, check if user ' + req.user._id + ' has written reference for ' + user._id);
+ //console.log('->userByID, check if user ' + req.user._id + ' has written reference for ' + user._id);
+
Reference.findOne({
userTo: user._id,
userFrom: req.user._id
@@ -174,14 +179,17 @@ exports.userByUsername = function(req, res, next, username) {
'birthdate',
'seen',
'created',
- 'updated'
+ 'updated',
+ 'avatarSource',
+ 'emailHash' // MD5 hashed email to use with Gravatars
);
// Sanitize output
if(user.description) user.description = sanitizeHtml(user.description, userSanitizeOptions);
// Check if logged in user has left reference for this profile
- console.log('->userByUsername, check if user ' + req.user._id + ' has written reference for ' + user._id);
+ //console.log('->userByUsername, check if user ' + req.user._id + ' has written reference for ' + user._id);
+
Reference.findOne({
userTo: user._id,
userFrom: req.user._id
diff --git a/app/models/user.server.model.js b/app/models/user.server.model.js
index 488bc2a722..cd76dbe9ec 100755
--- a/app/models/user.server.model.js
+++ b/app/models/user.server.model.js
@@ -21,19 +21,18 @@ var validateLocalStrategyPassword = function(password) {
return (this.provider !== 'local' || (password && password.length >= 8));
};
-
/**
* A Validation function for username
* - at least 3 characters
* - maximum 32 characters
* - only a-z0-9_-.
* - not in list of illegal usernames
- * - no consecutive dots, "." ok, ".." nope
+ * - no consecutive dots: "." ok, ".." nope
*/
var validateUsername = function(username) {
var usernameRegex = /^[a-z0-9.\-_]{3,32}$/,
dotsRegex = /^([^.]+\.?)$/,
- illegalUsernames = ['trustroots', 'trust', 'roots', 're', 're:', 'fwd', 'fwd:', 'reply', 'admin', 'administrator', 'user', 'password', 'username', 'unknown', 'anonymous', 'home', 'signup', 'signin', 'edit', 'password', 'username', 'user', ' demo', 'test'];
+ illegalUsernames = ['trustroots', 'trust', 'roots', 're', 're:', 'fwd', 'fwd:', 'reply', 'admin', 'administrator', 'user', 'password', 'username', 'unknown', 'anonymous', 'home', 'signup', 'signin', 'edit', 'settings', 'password', 'username', 'user', ' demo', 'test'];
return (this.provider !== 'local' || ( username &&
usernameRegex.test(username) &&
illegalUsernames.indexOf(username) < 0) &&
@@ -41,8 +40,6 @@ var validateUsername = function(username) {
);
};
-
-
/**
* User Schema
*/
@@ -113,6 +110,9 @@ var UserSchema = new Schema({
default: '',
validate: [validateLocalStrategyPassword, 'Password should be more than 8 characters long.']
},
+ emailHash: {
+ type: String,
+ },
salt: {
type: String
},
@@ -139,13 +139,20 @@ var UserSchema = new Schema({
type: Date,
default: Date.now
},
+ avatarSource: {
+ type: [{
+ type: String,
+ enum: ['none','gravatar','facebook','local']
+ }],
+ default: ['gravatar']
+ },
/* For reset password */
resetPasswordToken: {
type: String
},
- resetPasswordExpires: {
- type: Date
- }
+ resetPasswordExpires: {
+ type: Date
+ }
});
/**
@@ -157,6 +164,9 @@ UserSchema.pre('save', function(next) {
this.password = this.hashPassword(this.password);
}
+ // Pre-cached email hash to use with Gravatar
+ this.emailHash = crypto.createHash('md5').update( this.email.trim().toLowerCase() ).digest('hex');
+
next();
});
diff --git a/config/env/all.js b/config/env/all.js
index 6543b7d185..bc87092617 100644
--- a/config/env/all.js
+++ b/config/env/all.js
@@ -4,7 +4,8 @@ module.exports = {
app: {
title: 'Trust Roots',
description: 'Travellers network',
- keywords: 'traveling,hospitality exchange,nomadism'
+ keywords: 'traveling,hospitality exchange,nomadism',
+ miniUserProfileFields: ['id', 'displayName', 'username', 'avatarSource', 'emailHash']
},
port: process.env.PORT || 3000,
templateEngine: 'swig',
@@ -60,4 +61,4 @@ module.exports = {
'public/modules/*/tests/*.js'
]
}
-};
\ No newline at end of file
+};
diff --git a/config/env/development.js b/config/env/development.js
index 743a108a71..b12fdf0bfe 100644
--- a/config/env/development.js
+++ b/config/env/development.js
@@ -3,7 +3,8 @@
module.exports = {
db: 'mongodb://localhost/trust-roots-dev',
app: {
- title: 'Trust Roots - Development Environment'
+ title: 'Trust Roots - Development Environment',
+ miniUserProfileFields: ['id', 'displayName', 'username', 'avatarSource', 'emailHash']
},
facebook: {
clientID: process.env.FACEBOOK_ID || 'APP_ID',
@@ -40,4 +41,4 @@ module.exports = {
}
}
}
-};
\ No newline at end of file
+};
diff --git a/public/modules/references/views/list-references.client.view.html b/public/modules/references/views/list-references.client.view.html
index d571d05756..fa7eae4be4 100644
--- a/public/modules/references/views/list-references.client.view.html
+++ b/public/modules/references/views/list-references.client.view.html
@@ -44,7 +44,7 @@
-
+
{{ reference.userFrom.displayName }}
diff --git a/public/modules/users/controllers/settings.client.controller.js b/public/modules/users/controllers/settings.client.controller.js
index 8860017d13..fa0084e288 100644
--- a/public/modules/users/controllers/settings.client.controller.js
+++ b/public/modules/users/controllers/settings.client.controller.js
@@ -1,7 +1,7 @@
'use strict';
-angular.module('users').controller('SettingsController', ['$scope', '$http', '$stateParams', '$state', '$location', 'Users', 'Authentication',
- function($scope, $http, $stateParams, $state, $location, Users, Authentication) {
+angular.module('users').controller('SettingsController', ['$scope', '$modal', '$http', '$stateParams', '$state', '$location', 'Users', 'Authentication',
+ function($scope, $modal, $http, $stateParams, $state, $location, Users, Authentication) {
$scope.user = Authentication.user;
$scope.profile = false;
@@ -81,6 +81,25 @@ angular.module('users').controller('SettingsController', ['$scope', '$http', '$s
}
};
+ /**
+ * Open avatar -modal
+ */
+ $scope.avatarModal = function (user, $event) {
+
+ if($event) $event.preventDefault();
+
+ var modalInstance = $modal.open({
+ templateUrl: 'avatar.client.modal.html', //inline at template
+ controller: function ($scope, $modalInstance) {
+ $scope.user = user;
+ $scope.close = function () {
+ $modalInstance.dismiss('close');
+ };
+ }
+ });
+
+ };
+
// Remove user permanently
$scope.removalConfirm = false;
diff --git a/public/modules/users/directives/tr-avatar.client.directive.js b/public/modules/users/directives/tr-avatar.client.directive.js
index 8fbe02cf36..6d519bea62 100644
--- a/public/modules/users/directives/tr-avatar.client.directive.js
+++ b/public/modules/users/directives/tr-avatar.client.directive.js
@@ -2,18 +2,137 @@
/**
* Produce user's avatar
+ *
+ * Basic usage:
+ *
+ *
+ * user (User model)
+ *
+ * Optional parameters:
+ * size (default 32)
+ * source (overwrite user's source selection)
+ * link (will not wrap into link)
+ * watch (will start watching user.avatarSource and refresh each time that changes)
*/
angular.module('users').directive('trAvatar', [
function() {
+ var validSources = ['none', 'facebook' ,'gravatar', 'locale'];
return {
- templateUrl: '/modules/users/views/directives/tr-avatar.client.view.html',
+ //templateUrl: '/modules/users/views/directives/tr-avatar.client.view.html',
+ template: ' ',
restrict: 'EA',
+ replace: true,
scope: {
user: '=user'
},
- link: function (scope, element, attr) {
- scope.size = attr.size;
+ controller: ['$scope', function($scope) {
+
+ if($scope.user) {
+ console.log('->avatar: ' + $scope.user.username);
+ console.log($scope.user);
+ }
+ else console.log('->avatar ');
+
+ // Options
+ $scope.defaultAvatar = '/modules/users/img/avatar.png';
+
+
+ $scope.determineSource = function() {
+
+ // Determine source for avatar
+ if($scope.fixedSource) {// && validSources.indexOf(attr.source)==-1)
+ $scope.source = $scope.fixedSource;
+ }
+ else if($scope.user && $scope.user.avatarSource) {
+ // && validSources.indexOf($scope.user.avatarSource.toString())==-1)
+ $scope.source = $scope.user.avatarSource.toString();
+ console.log('users avatarSource: ' + $scope.source);
+ }
+ else {
+ $scope.source = 'none';
+ }
+
+ /**
+ * Avatar via FB
+ * @link https://developers.facebook.com/docs/graph-api/reference/user/picture/
+ */
+ if($scope.source === 'facebook' ) {
+ console.log('->determineSource: fb');
+
+ if($scope.user && $scope.user.email) {
+ var fb_id = '#';
+
+ $scope.avatar = '//graph.facebook.com/' + fb_id + '/picture/?width=' + $scope.size + '&height=' + $scope.size;
+ }
+ else {
+ console.log('->determineSource facebook: fall to default');
+ $scope.avatar = $scope.defaultAvatar;
+ }
+ }
+
+ /**
+ * Avatar via Gravatar
+ * @link https://en.gravatar.com/site/implement/images/
+ * @todo: pre-save email md5 hash to the db
+ */
+ else if($scope.source === 'gravatar') {
+ console.log('->determineSource gravatar: ' + $scope.user.emailHash);
+ if($scope.user.emailHash) {
+ $scope.avatar = '//gravatar.com/avatar/' + $scope.user.emailHash + '?s=' + $scope.size;
+
+ // Gravatar fallback is required to be online. It's defined at settings.json
+ // If public default avatar is set, send it to Gravatar as failback
+ // @todo: pass $scope.defaultAvatar with public domain here
+ $scope.avatar += '&d=' + encodeURIComponent('http://ideas.trustroots.org/wordpress/wp-content/uploads/2014/10/avatar.png');
+ }
+ else {
+ console.log('->determineSource gravatar: fall to default');
+ $scope.avatar = $scope.defaultAvatar;
+ }
+ }
+
+ /**
+ * Locally uploaded image
+ */
+ else if($scope.source === 'locale') {
+ console.log('->determineSource: locale');
+ $scope.avatar = $scope.defaultAvatar + '?locale';
+ }
+
+ // Dummy
+ else {
+ console.log('->determineSource: none');
+ $scope.avatar = $scope.defaultAvatar + '?none';
+ }
+ };// determineSource()
+
+ // Sets $scope.avatar
+ $scope.determineSource();
+
+ // If asked to, start watching user.avatarSource and refresh directive each time that changes
+ //if(attr.watch) {
+ $scope.$watch('user.avatarSource',function(newSource, oldSource) {
+ console.log('avatarSource changed. new: ' + newSource + ', old: ' + oldSource);
+ $scope.source = newSource;
+ $scope.determineSource();
+ });
+ //}
+
+
+ }],
+ link: function (scope, element, attr, ctrl) {
+
+ scope.size = attr.size || 32;
+
+ // Wrap it to link by default
+ //if(!attr.link && scope.user) {
+ // angular.element(element).wrap(' ');
+ //}
+ if(attr.source) {
+ scope.fixedSource = attr.source;
+ }
+
}
};
}
-]);
\ No newline at end of file
+]);
diff --git a/public/modules/users/less/editor.less b/public/modules/users/less/editor.less
index c16e05a6af..83d1de7bbd 100644
--- a/public/modules/users/less/editor.less
+++ b/public/modules/users/less/editor.less
@@ -1,7 +1,7 @@
#profile-editor {
.angular-medium-editor {
- display: inline;
+ //display: inline;
border: 0;
background: transparent;
.box-shadow(none);
@@ -135,21 +135,13 @@
/* Choose avatar -modal */
#profile-avatar-choises {
- list-style: none;
- margin: 0;
- padding: 0;
- clear: both;
- overflow: hidden;
- li {
- float: left;
- margin: 0 10px;
- padding: 0;
- text-align: center;
- }
.avatar-source-init-upload {
display: block;
position: relative;
.square(144px);
+ label {
+ margin: 10px 0;
+ }
img {
position: absolute;
top: 0;
diff --git a/public/modules/users/views/directives/tr-avatar.client.view.html b/public/modules/users/views/directives/tr-avatar.client.view.html
deleted file mode 100644
index adca9d261a..0000000000
--- a/public/modules/users/views/directives/tr-avatar.client.view.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/public/modules/users/views/profile/edit-profile.client.view.html b/public/modules/users/views/profile/edit-profile.client.view.html
index 55f9de197e..5b69e5914e 100644
--- a/public/modules/users/views/profile/edit-profile.client.view.html
+++ b/public/modules/users/views/profile/edit-profile.client.view.html
@@ -14,8 +14,9 @@
diff --git a/public/modules/users/config/users.client.config.js b/public/modules/users/config/users.client.config.js
index c553ee3a00..7ceafd8216 100644
--- a/public/modules/users/config/users.client.config.js
+++ b/public/modules/users/config/users.client.config.js
@@ -11,7 +11,7 @@ angular.module('users').run(['Menus', 'Authentication',
Menus.addSubMenuItem('topuserbar', 'profile', 'Settings', 'profile/' + Authentication.user.username + '/settings', 'profile-settings', null, null, 0, 'cog');
Menus.addSubMenuItem('topuserbar', 'profile', 'Help', 'contact', 'contact', null, null, 0, 'bolt');
Menus.addSubMenuDivider('topuserbar', 'profile');
- Menus.addSubMenuItem('topuserbar', 'profile', 'Sign out', 'auth/signout', 'signout', null, null, 0, 'sign-out');
+ Menus.addSubMenuItem('topuserbar', 'profile', 'Sign out', '/auth/signout', '/auth/signout', null, null, 0, 'sign-out');
}
]);
From db86af176563a2baaad514357bb11f7eaa72059a Mon Sep 17 00:00:00 2001
From: Mikael Korpela
Date: Tue, 7 Oct 2014 13:25:08 +0300
Subject: [PATCH 11/12] Blog url
---
public/modules/core/views/footer.client.view.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/public/modules/core/views/footer.client.view.html b/public/modules/core/views/footer.client.view.html
index 6e2313f147..60f20985d5 100644
--- a/public/modules/core/views/footer.client.view.html
+++ b/public/modules/core/views/footer.client.view.html
@@ -8,7 +8,7 @@
-
\ No newline at end of file
+
From 4e5e12e71bab89d26cedafb2de52e052b0d2a631 Mon Sep 17 00:00:00 2001
From: Mikael Korpela
Date: Tue, 7 Oct 2014 14:40:51 +0300
Subject: [PATCH 12/12] Add @aurimus to humans
---
public/humans.txt | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/public/humans.txt b/public/humans.txt
index 3fd6604a8f..18013321dc 100755
--- a/public/humans.txt
+++ b/public/humans.txt
@@ -1,7 +1,7 @@
# humanstxt.org/
# The humans responsible
-# TEAM
+# CORE TEAM
Mikael -- mikaelkorpela.fi
Callum -- callum-macdonald.com
@@ -9,4 +9,6 @@
# THANKS
- Rémi, BeWelcome Welen -project dudes
+ Rémi
+ Aurimas
+ BeWelcome Welen -project dudes