Skip to content

Commit

Permalink
Merge pull request #14 from MayOneUS/devel
Browse files Browse the repository at this point in the history
Bringing master up to date
  • Loading branch information
Rio517 committed Oct 10, 2015
2 parents a32f202 + ed84118 commit 8a44ac2
Show file tree
Hide file tree
Showing 252 changed files with 8,568 additions and 5,559 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
sudo: false
language: node_js
node_js:
- "0.10"

before_install:
- "npm install [email protected] -g"
22 changes: 22 additions & 0 deletions CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,25 @@ If you don't want to use Winston to write a log to file, then do not include the
custom: logger
}
```

## Set up SMTP for Email Notifications

To set up an email provider, add the credentials for your SMTP service to the `/config/local.js` file. For example, using Mandrill:

```js
emailProtocol: 'SMTP',
smtp: {
service : '',
host : 'smtp.mandrillapp.com',
secureConnection : false,
port : 587,
auth : {
user : '[mandrill user]',
pass : '[mandrill pass]'
},
ignoreTLS : false,
debug : false,
maxConnections : 5
},
systemEmail: '[from address (don't use a GSA address — GSA will block the incoming messages]',
```
8 changes: 7 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ with this waiver of copyright interest.

## Communication

Anyone actively contributing or using Midas, should join our [Mailing List](https://groups.google.com/forum/#!forum/midascrowd).
Anyone actively contributing or using Midas, should join our [Mailing List](https://groups.google.com/forum/#!forum/midascrowd).
We also have a public Slack chat room. If you're interested in following along with the development process or have questions, feel free to join us at http://chat.18f.gov/, and select "midas-public".

You should be using the master branch for most stable release, please review [release notes](https://github.com/18F/midas/releases) regularly. We do releases every week or two and send out notes. We're generally using [semantic versioning](http://semver.org/), but we're pre-1.0, so API can change at any time. We use the minor version for changes where there are significant installation process changes or API changes or a database migration is needed.
Expand Down Expand Up @@ -225,3 +225,9 @@ from the main (upstream) repository:
```shell
git pull --ff upstream devel
```
### Reviewing Pull Requests
Except for critical, urgent or very small fixes, we try to leave pull requests open for most of the day or overnight if something comes in late in the day, so that multiple people have the chance to review/comment. Anyone who reviews a pull request should leave a note to let others know that someone has looked at it. For larger commits, we like to have a +1 from someone else on the core team and/or from other contributor(s). Please note if you reviewed the code or tested locally -- a +1 by itself will typically be interpreted as your thinking its a good idea, but not having reviewed in detail.
5 changes: 3 additions & 2 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ module.exports = function (grunt) {
ext: '.min.css',
extDot: 'last',
options: {
report: 'min'
report: 'min',
sourceMap: process.env.NODE_ENV !== 'production'
}
}
},
Expand All @@ -95,7 +96,7 @@ module.exports = function (grunt) {
{
expand: true,
cwd: './assets',
src: ['build/**/*', 'js/vendor/**/*', 'images/**/*', 'locales/**/*', 'data/**/*'],
src: ['build/**/*', 'js/vendor/**/*', 'images/**/*', 'locales/**/*', 'data/**/*', 'uploads/**/*'],
dest: '.tmp/public'
}
]
Expand Down
2 changes: 1 addition & 1 deletion INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Start the postgres console acting on the midas database with: `psql midas`
ALTER SCHEMA public OWNER TO midas;
\q

Install node.js. As of Feb 2015 Node.js has moved to 0.12 for its stable version. But many dependencies, especially native compiled packages, don't work with 0.10 yet. So consider running Node.js 0.10. Consider using [nvm](https://github.com/creationix/nvm) to manage Node versions. Once installed and sourced into your environment nvm can handle manage versions.
Install node.js. As of Feb 2015 Node.js has moved to 0.12 for its stable version. But many dependencies, especially native compiled packages, don't work with 0.12 yet. So consider running Node.js 0.10. Consider using [nvm](https://github.com/creationix/nvm) to manage Node versions. Once installed and sourced into your environment nvm can handle manage versions.

So back to the command line. We assume that nvm is installed and set up
(added to `.bashrc` or equivalent).
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

Here’s how Midas works: You come up with a great idea that would help your workplace, but you and your coworkers don’t have the skills to execute it. Rather than bringing in a contractor, you can post your project idea to Midas, where other people within your organization can see it and then work on it, if they’d like.

Midas is currently in active use [inside the US federal government](https://18f.gsa.gov/2014/07/16/midas-a-marketplace-for-innovation-in-government/) as the software that drives the [Open Opportunities](http://www.digitalgov.gov/join-digitalgov/open-opportunities-in-digitalgov/) program, which connects people from across and within government agencies to collaborate on projects. Open Opportunities validated the model using WordPress and a Lean Startup "concierge" approach, with people from over 50 government agencies, completing over 100 projects, ranging from 1 hour tasks to working part-time for 3-6 months. Open Opportunities moved to Midas in October 2014, and is available for all federal employees [here](https://midas.18f.us/). Midas was originally developed by the Department of State and is being piloted there, specifically for foreign service officers.
Midas is currently in active use [inside the US federal government](https://18f.gsa.gov/2014/07/16/midas-a-marketplace-for-innovation-in-government/) as the software that drives the [Open Opportunities](http://www.digitalgov.gov/join-digitalgov/open-opportunities-in-digitalgov/) program, which connects people from across and within government agencies to collaborate on projects. Open Opportunities validated the model using WordPress and a Lean Startup "concierge" approach, with people from over 50 government agencies, completing over 100 projects, ranging from 1 hour tasks to working part-time for 3-6 months. Open Opportunities moved to Midas in October 2014, and is available for all federal employees [here](https://openopps.digitalgov.gov/). Midas was originally developed by the Department of State and is being piloted there, specifically for foreign service officers.

Our Goal: to foster innovation across team boundaries by connecting individuals who identify challenges and then work collaboratively to implement solutions.

Expand All @@ -24,7 +24,7 @@ Midas can benefit all organizations, but it’s especially useful for those with
![screen shot 2014-10-06 at 3 17 53 pm](https://cloud.githubusercontent.com/assets/633088/4531895/555718c4-4d8e-11e4-8960-9585b2adb640.png)

## How you can help
* Use our [test server](https://midas-dev.18f.us/) and write up [issues](https://github.com/18F/midas/issues)
* Use our [community test server](https://midas-dev.18f.us/) and write up [issues](https://github.com/18F/midas/issues)
* Join our [Google Group](https://groups.google.com/forum/#!forum/midascrowd) and introduce yourself, please ask any general questions here -- how the product is supposed to work, usability issues, technical questions, whatever you want to know, we want to hear about. If you are interested in using Midas for your organization, let us know.
* Read our [Contribution Guide](https://github.com/18F/midas/blob/devel/CONTRIBUTING.md) -- everything you do with us is a contribution to the public domain, there are also some tips for getting started
* If you are a developer, [install](https://github.com/18F/midas/blob/devel/INSTALL.md) the software for development
Expand Down
204 changes: 166 additions & 38 deletions api/controllers/AdminController.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,152 @@ module.exports = {
});
},

/**
* Task metrics API
* Provides data for the task metrics section of the admin
* dashboard. At some point, it may be consolidated
* with the above endpoint.
*/
taskMetrics: function(req, res) {
var pad = function(num, size) {
size = size || 2;
var s = num + '';
while (s.length < size) s = '0' + s;
return s;
},
getFY = function(input) {
if (!input) return undefined;
var date = new Date(input);
return new Date(date.setMonth(date.getMonth() + 3)).getFullYear();
},
getYear = function(input) {
if (!input) return undefined;
return new Date(input).getFullYear();
},
getMonth = function(input) {
if (!input) return undefined;
var date = new Date(input);
return +date.getFullYear() + pad((date.getMonth() + 1));
},
getWeek = function(input) {
if (!input) return undefined;
var date = new Date(input);
var getWeekNumber = function(date) {
var d = new Date(date);
d.setHours(0,0,0);
d.setDate(d.getDate()+4-(d.getDay()||7));
return Math.ceil((((d-new Date(d.getFullYear(),0,1))/8.64e7)+1)/7);
};
return +date.getFullYear() + pad(getWeekNumber(date));
},
getQuarter = function(input) {
if (!input) return undefined;
var date = new Date(input),
month = date.getMonth() + 1,
quarter = month <= 3 ? '1' :
month <= 6 ? '2' :
month <= 9 ? '3' : '4';
return +date.getFullYear() + quarter;
},
getFYQuarter = function(input) {
if (!input) return undefined;
var date = new Date(input),
fyDate = new Date(date.setMonth(date.getMonth() + 3)),
month = fyDate.getMonth() + 1,
quarter = month <= 3 ? '1' :
month <= 6 ? '2' :
month <= 9 ? '3' : '4';
return +fyDate.getFullYear() + quarter;
},
output = {
tasks: {},
volunteers: {},
agencies: {}
},
count = req.param('group') === 'week' ? getWeek :
req.param('group') === 'month' ? getMonth :
req.param('group') === 'quarter' ? getQuarter :
req.param('group') === 'fyquarter' ? getFYQuarter :
req.param('group') === 'year' ? getYear : getFY;

async.parallel([
function(done) {
Task.find({}).exec(function(err, tasks) {
if (err) return done('task');
var groups = {
carryOver: {},
published: _.countBy(tasks, function(task) {
return count(task.publishedAt);
}),
completed: _.countBy(tasks, function(task) {
return count(task.completedAt);
})
},
range = _.keys(groups.published);

// Evaluate whether a task was started and remained open in a previous FY
_.each(tasks, function(task) {
range.forEach(function(i) {
var openedBefore = count(task.publishedAt) < i,
openAfter = task.state !== 'archived' &&
(!task.completedAt || count(task.completedAt) > i);
groups.carryOver[i] = groups.carryOver[i] || 0;
if (openedBefore && openAfter) groups.carryOver[i] += 1;
});
});

output.range = range;
output.tasks = groups;
done();
});
},
function(done) {
Volunteer.find({}).exec(function(err, volunteers) {
if (err) return done('volunteer');

// Group volunteers by created FY
output.volunteers = _.groupBy(volunteers, function(volunteer) {
return count(volunteer.createdAt);
});

// Get volunteer users and tags to count agencies
User.find({ id: _.pluck(volunteers, 'userId') })
.populate('tags', { type: 'agency' })
.exec(function(err, users) {
if (err) return done('volunteer');

// Get unique agencies with volunteers
output.agencies = _.reduce(output.volunteers, function(o, vols, fy) {

// Return agency (first tag) for matching user
o[fy] = _(vols).map(function(vol) {
var volUser = _.findWhere(users, { id: vol.userId });
if (!volUser || !volUser.tags || !volUser.tags[0]) return undefined;
return (volUser.tags[0] || {}).id;
}).compact().uniq().value().length;

return o;

}, {});

// Count volunteers
output.volunteers = _.reduce(output.volunteers, function(o, vols, fy) {
o[fy] = vols.length;
return o;
}, {});

done();
});

});
}
], function(err) {
if (err) res.serverError(err + ' metrics are unavailable.');
res.send(output);
});
},


/**
* Add or remove admin priviledges from a user account
* @param id the user id to make an admin or remove
Expand Down Expand Up @@ -301,7 +447,8 @@ module.exports = {

// Get comment model
steps.push(function(done) {
Comment.findOne({ id: event.callerId }).exec(function(err, result) {
var id = (event.model || {}).id;
Comment.findOne({ id: id }).exec(function(err, result) {
if (err) return done('Failed to find model' + err);
activity.comment = result || {};
activity.comment.value = activity.comment.value || "";
Expand Down Expand Up @@ -335,7 +482,9 @@ module.exports = {
});

async.series(steps, function(err) {
if ( activity.comment.value == "" ) { activity.comment = {}; }
if (!activity.comment || activity.comment.value === "") {
activity.comment = {};
}
done(err, activity);
});

Expand All @@ -350,7 +499,8 @@ module.exports = {

// Get task model
steps.push(function(done) {
Task.findOne({ id: event.callerId }).exec(function(err, result) {
var id = (event.model || {}).taskId;
Task.findOne({ id: id }).exec(function(err, result) {
if (err) return done('Failed to find model' + err);
activity.task = result;
done();
Expand All @@ -359,8 +509,8 @@ module.exports = {

// Get user model
steps.push(function(done) {
var userId = JSON.parse(event.localParams).fields.volunteerId;
User.findOne({ id: userId }).exec(function(err, user) {
var id = (event.model || {}).userId;
User.findOne({ id: id }).exec(function(err, user) {
if (err) return done('Failed to find model' + err);
activity.user = user;
done();
Expand All @@ -381,34 +531,15 @@ module.exports = {

// Get user model
steps.push(function(done) {
var userId = JSON.parse(event.localParams).fields.userId;
User.findOne({ id: userId }).exec(function(err, user) {
var id = (event.model || {}).id;
User.findOne({ id: id }).exec(function(err, user) {
if (err) return done('Failed to find model' + err);
activity.user = user;
done();
});
});

async.series(steps, function(err) { done(err, activity) });
},

updatedUser: function(event, done) {
var activity = {
type: 'updatedUser',
createdAt: event.createdAt
},
steps = [];

// Get user model
steps.push(function(done) {
User.findOne({ id: event.callerId }).exec(function(err, user) {
if (err) return done('Failed to find model' + err);
activity.user = user;
done();
});
});

async.series(steps, function(err) { done(err, activity) });
async.series(steps, function(err) { done(err, activity); });
},

newTask: function(event, done) {
Expand All @@ -420,7 +551,8 @@ module.exports = {

// Get task model
steps.push(function(done) {
Task.findOne({ id: event.callerId }).exec(function(err, task) {
var id = (event.model || {}).id;
Task.findOne({ id: id }).exec(function(err, task) {
if (err) return done('Failed to find model' + err);
activity.task = task;
done();
Expand All @@ -437,22 +569,21 @@ module.exports = {
});
});

async.series(steps, function(err) { done(err, activity) });
async.series(steps, function(err) { done(err, activity); });
}

};

// Map actions to templates
var actions = {
projectCommentAdded: templates.newComment,
taskCommentAdded: templates.newComment,
taskVolunteerAdded: templates.newVolunteer,
welcomeUser: templates.newUser,
taskCreated: templates.newTask
'comment.create.owner': templates.newComment,
'volunteer.create.thanks': templates.newVolunteer,
'user.create.welcome': templates.newUser,
'task.create.thanks': templates.newTask
};

// Get active notifications
Notification.find({ isActive: true })
Notification.find({})
.sort(sort)
.paginate({ page: page, limit: limit})
.exec(next);
Expand All @@ -466,9 +597,6 @@ module.exports = {

var activities = [];

// Filter unique notifications
notifications = _.uniq(notifications, false, 'triggerGuid');

// Apply templates
async.map(notifications, function(notification, done) {
if (actions[notification.action]) {
Expand Down
Loading

0 comments on commit 8a44ac2

Please sign in to comment.