Skip to content

Commit

Permalink
Merge branch 'master' into 395-xml-form-version
Browse files Browse the repository at this point in the history
  • Loading branch information
aodhan-domhnaill authored Mar 29, 2022
2 parents ab3dfa1 + cc8fa8b commit 6235de0
Show file tree
Hide file tree
Showing 47 changed files with 759 additions and 238 deletions.
19 changes: 9 additions & 10 deletions admin/src/js/controllers/images-branding.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,9 @@ angular.module('controllers').controller('ImagesBrandingCtrl',
const DOC_ID = 'branding';
const MAX_FILE_SIZE = 100000; // 100KB

$('#logo-upload .choose').on('click', _ev => {
_ev.preventDefault();
$('#logo-upload .uploader').click();
});

$('#favicon-upload .choose').on('click', _ev => {
_ev.preventDefault();
$('#favicon-upload .uploader').click();
$('#images-branding .choose').on('click', ev => {
ev.preventDefault();
$(ev.target).closest('.form-group').find('.uploader').click();
});

$scope.loading = true;
Expand All @@ -31,6 +26,7 @@ angular.module('controllers').controller('ImagesBrandingCtrl',
.then(doc => {
$scope.doc = doc;
$scope.favicon = doc._attachments[doc.resources.favicon];
$scope.icon = doc._attachments[doc.resources.icon];
})
.catch(err => {
$log.error('Error fetching resources file', err);
Expand Down Expand Up @@ -85,10 +81,12 @@ angular.module('controllers').controller('ImagesBrandingCtrl',

const updateFavicon = () => updateImage(getFile('#favicon-upload'), 'favicon');

const updateIcon = () => updateImage(getFile('#icon-upload'), 'icon');

const removeObsoleteAttachments = () => {
const current = $scope.doc._attachments;
const updated = {};
['logo', 'favicon'].forEach(key => {
['logo', 'favicon', 'icon'].forEach(key => {
const name = $scope.doc.resources[key];
if (name) {
updated[name] = current[name];
Expand All @@ -108,7 +106,8 @@ angular.module('controllers').controller('ImagesBrandingCtrl',

if (!validateTitle() ||
!updateLogo() ||
!updateFavicon()) {
!updateFavicon() ||
!updateIcon()) {
return;
}

Expand Down
21 changes: 20 additions & 1 deletion admin/src/templates/images_branding.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@
<input class="uploader" type="file" accept="image/*">
</div>
</div>
<span class="help-block" translate>branding.logo.field.help</span>
</div>
<div class="form-group required">
<label translate>branding.favicon.field</label>
<label translate>branding.favicon.field</label>
<div class="favicon">
<img src="data:{{favicon.content_type}};base64,{{favicon.data}}" />
</div>
Expand All @@ -40,6 +41,24 @@
<input class="uploader" type="file" accept="image/*">
</div>
</div>
<span class="help-block" translate>branding.favicon.field.help</span>
</div>
<div class="form-group required">
<label translate>branding.icon.field</label>
<div class="favicon">
<img src="data:{{icon.content_type}};base64,{{icon.data}}" />
</div>
<div id="icon-upload">
<button type="button" class="btn btn-default choose">
<i class="fa fa-arrow-up"></i>
<span translate>Choose file</span>
</button>
<div class="loader" ng-show="uploading"></div>
<div class="hide">
<input class="uploader" type="file" accept="image/*">
</div>
</div>
<span class="help-block" translate>branding.icon.field.help</span>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary" ng-click="submit()" ng-disabled="submitting" translate>Submit</button>
Expand Down
5 changes: 5 additions & 0 deletions api/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ process
const serverUtils = require('./src/server-utils');
const uploadDefaultDocs = require('./src/upload-default-docs');
const generateServiceWorker = require('./src/generate-service-worker');
const manifest = require('./src/services/manifest');
const apiPort = process.env.API_PORT || 5988;

try {
Expand Down Expand Up @@ -61,6 +62,10 @@ process
await migrations.run();
logger.info('Database migrations completed successfully');

logger.info('Generating manifest');
await manifest.generate();
logger.info('Manifest generated successfully');

logger.info('Generating service worker');
await generateServiceWorker.run();
logger.info('Service worker generated successfully');
Expand Down
34 changes: 4 additions & 30 deletions api/src/controllers/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const logger = require('../logger');
const db = require('../db');
const localeUtils = require('locale');
const cookie = require('../services/cookie');
const brandingService = require('../services/branding');

const templates = {
login: {
Expand Down Expand Up @@ -192,36 +193,8 @@ const setCookies = (req, res, sessionRes) => {
});
};

const getInlineImage = (data, contentType) => `data:${contentType};base64,${data}`;

const getDefaultBranding = () => {
const logoPath = path.join(__dirname, '..', 'resources', 'logo', 'medic-logo-light-full.svg');
return promisify(fs.readFile)(logoPath, {}).then(logo => {
const data = Buffer.from(logo).toString('base64');
return {
name: 'Medic',
logo: getInlineImage(data, 'image/svg+xml')
};
});
};

const getBranding = () => {
return db.medic.get('branding', {attachments: true})
.then(doc => {
const image = doc._attachments[doc.resources.logo];
return {
name: doc.title,
logo: getInlineImage(image.data, image.content_type)
};
})
.catch(err => {
logger.warn('Could not find branding doc on CouchDB: %o', err);
return getDefaultBranding();
});
};

const renderTokenLogin = (req, res) => {
return getBranding()
return brandingService.get()
.then(branding => render('tokenLogin', req, branding, { tokenUrl: req.url }))
.then(body => res.send(body));
};
Expand Down Expand Up @@ -283,7 +256,8 @@ const loginByToken = (req, res) => {
};

const renderLogin = (req) => {
return getBranding().then(branding => render('login', req, branding));
return brandingService.get()
.then(branding => render('login', req, branding));
};

module.exports = {
Expand Down
52 changes: 52 additions & 0 deletions api/src/services/branding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const fs = require('fs');
const { promisify } = require('util');
const path = require('path');

const db = require('../db');
const logger = require('../logger');

const DEFAULT_LOGO_PATH = path.join(__dirname, '..', 'resources', 'logo', 'medic-logo-light-full.svg');

const getInlineImage = (data, contentType) => `data:${contentType};base64,${data}`;

const getBrandingDoc = async () => {
try {
return await db.medic.get('branding', { attachments: true });
} catch(e) {
logger.warn('Could not find branding doc on CouchDB: %o', e);
return;
}
};

const getName = (doc) => (doc && doc.title) || 'CHT';

const getLogo = async (doc) => {
let data;
let contentType;
const name = doc && doc.resources && doc.resources.logo;
if (name) {
const image = doc._attachments[name];
data = image.data;
contentType = image.content_type;
} else {
const logo = await promisify(fs.readFile)(DEFAULT_LOGO_PATH, {});
data = Buffer.from(logo).toString('base64');
contentType = 'image/svg+xml';
}
return getInlineImage(data, contentType);
};

const getIcon = (doc) => (doc && doc.resources && doc.resources.icon) || 'icon.png';

const getBranding = async () => {
const doc = await getBrandingDoc();
const logo = await getLogo(doc);
return {
name: getName(doc),
logo: logo,
icon: getIcon(doc),
doc: doc
};
};

module.exports.get = getBranding;
10 changes: 9 additions & 1 deletion api/src/services/config-watcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const ddocExtraction = require('../ddoc-extraction');
const resourceExtraction = require('../resource-extraction');
const generateXform = require('./generate-xform');
const generateServiceWorker = require('../generate-service-worker');
const manifest = require('./manifest');
const config = require('../config');

const MEDIC_DDOC_ID = '_design/medic';
Expand Down Expand Up @@ -119,7 +120,14 @@ const handleFormChange = (change) => {
};

const handleBrandingChanges = () => {
return updateServiceWorker();
return updateManifest()
.then(() => updateServiceWorker());
};

const updateManifest = () => {
return manifest.generate().catch(err => {
logger.error('Failed to generate manifest: %o', err);
});
};

const updateServiceWorker = () => {
Expand Down
35 changes: 35 additions & 0 deletions api/src/services/manifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const { promisify } = require('util');
const fs = require('fs');
const path = require('path');

const _ = require('lodash');

const environment = require('../environment');
const brandingService = require('./branding');

const EXTRACTED_RESOURCES_PATH = environment.getExtractedResourcesPath();
const MANIFEST_OUTPUT_PATH = path.join(EXTRACTED_RESOURCES_PATH, 'manifest.json');
const TEMPLATE_PATH = path.join(__dirname, '..', 'templates', 'manifest.json');

const writeJson = async (branding) => {
const file = await promisify(fs.readFile)(TEMPLATE_PATH, { encoding: 'utf-8' });
const template = _.template(file);
const json = template({ branding });
return await promisify(fs.writeFile)(MANIFEST_OUTPUT_PATH, json);
};

const writeIcon = async (doc) => {
const name = doc && doc.resources && doc.resources.icon;
const attachment = name && doc._attachments[name];
if (attachment) {
const contents = Buffer.from(attachment.data, 'base64');
const outputPath = path.join(EXTRACTED_RESOURCES_PATH, 'img', name);
await promisify(fs.writeFile)(outputPath, contents);
}
};

module.exports.generate = async () => {
const branding = await brandingService.get();
await writeJson(branding);
await writeIcon(branding.doc);
};
2 changes: 2 additions & 0 deletions api/src/templates/login/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#323232">
<title>{{ branding.name }}</title>
<link href="/login/style.css" media="all" rel="stylesheet">
<link rel="shortcut icon" href="/favicon.ico">
<link rel="manifest" href="/manifest.json">
</head>
<body data-default-locale="{{ defaultLocale }}" data-translations="{{ translations }}">
<div class="center">
Expand Down
2 changes: 2 additions & 0 deletions api/src/templates/login/token-login.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#323232">
<title>{{ branding.name }}</title>
<link href="/login/style.css" media="all" rel="stylesheet">
<link rel="shortcut icon" href="/favicon.ico">
<link rel="manifest" href="/manifest.json">
</head>
<body data-default-locale="{{ defaultLocale }}" data-translations="{{ translations }}">
<div class="center">
Expand Down
19 changes: 19 additions & 0 deletions api/src/templates/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"start_url": "./",
"name": "{{ branding.name }}",
"display": "standalone",
"background_color": "#323232",
"theme_color": "#323232",
"icons": [
{
"src": "/img/{{ branding.icon }}",
"sizes": "any",
"purpose": "any"
},
{
"src": "/favicon.ico",
"sizes": "32x32",
"type": "image"
}
]
}
Loading

0 comments on commit 6235de0

Please sign in to comment.