├── .gitignore
├── static-web
└── index.html
├── manifest.yml
├── start.sh
├── env.js
├── README.md
├── package.json
├── templates
└── test.md
├── CONTRIBUTING.md
├── LICENSE.md
└── main.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .env
3 |
--------------------------------------------------------------------------------
/static-web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/manifest.yml:
--------------------------------------------------------------------------------
1 | ---
2 | applications:
3 | - name: mgw-rfp-template
4 | buildpack: https://github.com/cloudfoundry/nodejs-buildpack.git#v1.5.14
5 | command: ./start.sh
6 | memory: 256MB
7 | instances: 1
8 |
--------------------------------------------------------------------------------
/start.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | CACHE_DIR="`pwd`/cache"
3 |
4 | mkdir -p $CACHE_DIR
5 |
6 | if [[ ! -d "$CACHE_DIR/pandoc" ]]; then
7 | cd $CACHE_DIR
8 | mkdir pandoc && cd pandoc
9 | curl https://dropshare-ro.s3-eu-central-1.amazonaws.com/pandoc.tar.gz -s | tar xz &> /dev/null
10 | cd ../..
11 | fi
12 | export PATH=$CACHE_DIR/pandoc:$PATH
13 |
14 | npm start
15 |
--------------------------------------------------------------------------------
/env.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('dotenv').config();
4 | const cfenv = require('cfenv');
5 | const appEnv = cfenv.getAppEnv();
6 |
7 | const knownEnvs = [
8 | 'TRELLO_API_KEY',
9 | 'TRELLO_API_TOK',
10 | 'LOG_LEVEL'
11 | ];
12 |
13 | if (appEnv.getServices() && Object.keys(appEnv.getServices()).length) {
14 | // If running on Cloud Foundry
15 | //for (const env of knownEnvs) {
16 | // process.env[env] = appEnv.getServiceCreds('acq-trello-cups')[env];
17 | //}
18 | }
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # acq-templates
2 |
3 | ### Public domain
4 |
5 | This project is in the worldwide [public domain](LICENSE.md). As stated in [CONTRIBUTING](CONTRIBUTING.md):
6 |
7 | > This project is in the public domain within the United States, and copyright and related rights in the work worldwide are waived through the [CC0 1.0 Universal public domain dedication](https://creativecommons.org/publicdomain/zero/1.0/).
8 | >
9 | > All contributions to this project will be released under the CC0 dedication. By submitting a pull request, you are agreeing to comply with this waiver of copyright interest.
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "acq-templates",
3 | "version": "1.0.0",
4 | "description": "18F acquisitions templates",
5 | "main": "main.js",
6 | "keywords": [
7 | ""
8 | ],
9 | "scripts": {
10 | "start": "node main.js"
11 | },
12 | "author": "Greg Walker ",
13 | "license": "CC0-1.0",
14 | "dependencies": {
15 | "cfenv": "^1.0.3",
16 | "dotenv": "^2.0.0",
17 | "mustache": "^2.2.1",
18 | "node-trello": "^1.1.2",
19 | "pdc": "^0.2.2",
20 | "restify": "^4.1.1",
21 | "uuid": "^2.0.2"
22 | },
23 | "engines": {
24 | "node": "^6.1.0",
25 | "npm": "^3.8.6"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/templates/test.md:
--------------------------------------------------------------------------------
1 | # Template-Based Magical Thing
2 |
3 | This document was populated with data from Trello. For example, in the general list, you have a card called "Product Name" and its value is {{ general.product_name }}. Your "Release Date" is {{ general.release_date }}
4 |
5 | ## Section 1
6 |
7 | Here's the background you entered for Section 1:
8 | **{{ section_1.background }}**
9 |
10 | ## Section 2
11 |
12 | In section 2, you said that **{{ general.client_name }}** has some business goals. You listed out those goals by making several different cards named "Business Goal" and giving them unique descriptions. Here's what you put:
13 |
14 | {{# section_2.business_goal }}
15 | - {{ . }}
16 | {{/ section_2.business_goal }}
17 |
18 | ## Section 3
19 |
20 | For section three, you listed some goals: {{ section_3.goals }}.
21 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Welcome!
2 |
3 | We're so glad you're thinking about contributing to an 18F open source project! If you're unsure about anything, just ask -- or submit the issue or pull request anyway. The worst that can happen is you'll be politely asked to change something. We love all friendly contributions.
4 |
5 | We want to ensure a welcoming environment for all of our projects. Our staff follow the [18F Code of Conduct](https://github.com/18F/code-of-conduct/blob/master/code-of-conduct.md) and all contributors should do the same.
6 |
7 | We encourage you to read this project's CONTRIBUTING policy (you are here), its [LICENSE](LICENSE.md), and its [README](README.md).
8 |
9 | If you have any questions or want to read more, check out the [18F Open Source Policy GitHub repository]( https://github.com/18f/open-source-policy), or just [shoot us an email](mailto:18f@gsa.gov).
10 |
11 | ## Public domain
12 |
13 | This project is in the public domain within the United States, and
14 | copyright and related rights in the work worldwide are waived through
15 | the [CC0 1.0 Universal public domain dedication](https://creativecommons.org/publicdomain/zero/1.0/).
16 |
17 | All contributions to this project will be released under the CC0
18 | dedication. By submitting a pull request, you are agreeing to comply
19 | with this waiver of copyright interest.
20 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | As a work of the United States Government, this project is in the
2 | public domain within the United States.
3 |
4 | Additionally, we waive copyright and related rights in the work
5 | worldwide through the CC0 1.0 Universal public domain dedication.
6 |
7 | ## CC0 1.0 Universal Summary
8 |
9 | This is a human-readable summary of the [Legal Code (read the full text)](https://creativecommons.org/publicdomain/zero/1.0/legalcode).
10 |
11 | ### No Copyright
12 |
13 | The person who associated a work with this deed has dedicated the work to
14 | the public domain by waiving all of his or her rights to the work worldwide
15 | under copyright law, including all related and neighboring rights, to the
16 | extent allowed by law.
17 |
18 | You can copy, modify, distribute and perform the work, even for commercial
19 | purposes, all without asking permission.
20 |
21 | ### Other Information
22 |
23 | In no way are the patent or trademark rights of any person affected by CC0,
24 | nor are the rights that other persons may have in the work or in how the
25 | work is used, such as publicity or privacy rights.
26 |
27 | Unless expressly stated otherwise, the person who associated a work with
28 | this deed makes no warranties about the work, and disclaims liability for
29 | all uses of the work, to the fullest extent permitted by applicable law.
30 | When using or citing the work, you should not imply endorsement by the
31 | author or the affirmer.
32 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('./env');
4 | const restify = require('restify');
5 | const fs = require('fs');
6 | const uuid = require('uuid');
7 | const mustache = require('mustache');
8 | const pdc = require('pdc');
9 | const Trello = require('node-trello');
10 |
11 | function getDataFromTrello(boardID) {
12 | const trello = new Trello(process.env.TRELLO_API_KEY, process.env.TRELLO_API_TOK);
13 | const data = { };
14 |
15 | return new Promise(mainResolve => {
16 | trello.get(`/1/boards/${boardID}/lists`, function(err, lists) {
17 | const promises = [ ];
18 | lists.forEach(l => {
19 | const listName = l.name.toLowerCase().replace(' ', '_');
20 | data[listName] = { };
21 | promises.push(new Promise(resolve => {
22 | trello.get(`/1/lists/${l.id}/cards?fields=name,desc`, (e, cards) => {
23 | cards.forEach(card => {
24 | const cardName = card.name.toLowerCase().replace(' ', '_')
25 | if(data[listName][cardName] && !Array.isArray(data[listName][cardName])) {
26 | data[listName][cardName] = [ data[listName][cardName] ];
27 | }
28 |
29 | if(Array.isArray(data[listName][cardName])) {
30 | data[listName][cardName].push(card.desc);
31 | } else {
32 | data[listName][cardName] = card.desc;
33 | }
34 | });
35 | resolve();
36 | });
37 | }));
38 | });
39 |
40 | Promise.all(promises)
41 | .then(() => {
42 | data.format = {
43 | uc: () => (str, render) => render(str).toUpperCase(),
44 | lc: () => (str, render) => render(str).toLowerCase()
45 | }
46 | mainResolve(data);
47 | });
48 | });
49 | });
50 | };
51 |
52 | const server = restify.createServer({ name: 'Template Demo' });
53 |
54 | server.get('/build', (req, res, next) => {
55 | getDataFromTrello('sgPeUjGo')
56 | .then(data => {
57 | //const template = fs.readFileSync('./templates/agile_bpa_rfp_and_pws.md', { 'encoding': 'utf-8' });
58 | const template = fs.readFileSync('./templates/test.md', { 'encoding': 'utf-8' });
59 | const markdown = mustache.render(template, data);
60 | const filename = `${uuid.v4()}.docx`;
61 | pdc(markdown, 'markdown', 'docx', [ '-o', filename ], (err, out) => {
62 | res.setHeader('Content-type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
63 | res.setHeader('Content-disposition', 'attachment; filename=rfp.docx');
64 | res.send(fs.readFileSync(filename));
65 | fs.unlink(filename);
66 | });
67 | })
68 | .catch(e => console.log(`ERROR: ${e}`));
69 | next();
70 | });
71 |
72 | server.get('/', restify.serveStatic({
73 | directory: './static-web',
74 | default: 'index.html'
75 | }));
76 |
77 | server.listen(process.env.PORT, () => {
78 | console.log(`${server.name} listening at ${server.url}`);
79 | });
80 |
--------------------------------------------------------------------------------