├── .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 |
4 | Click that --> 5 |
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 | --------------------------------------------------------------------------------