Skip to content

Commit 36a35af

Browse files
authored
Merge pull request #953 from solid/feature/index-update
Update index.html based on whether meta-tag is set or not
2 parents e8d5a0c + bf9a59e commit 36a35af

File tree

20 files changed

+418
-56
lines changed

20 files changed

+418
-56
lines changed

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,21 @@ Run with:
228228
docker run -p 8443:8443 --name solid node-solid-server
229229
```
230230

231-
Modify the config as follows:
231+
This will enable you to login to solid on https://localhost:8443 and then create a new account
232+
but not yet use that account. After a new account is made you will need to create an entry for
233+
it in your local (/etc/)hosts file in line with the account and subdomain i.e.
234+
235+
127.0.0.1 newsoliduser.localhost
236+
237+
Then you'll be able to use solid as intended.
238+
239+
You can modify the config within the docker container as follows:
232240

233241
- Copy the config to the current directory with: `docker cp solid:/usr/src/app/config.json .`
234242
- Edit the `config.json` file
235243
- Copy the file back with `docker cp config.json solid:/usr/src/app/`
236244
- Restart the server with `docker restart solid`
237245

238-
239246
## Library Usage
240247

241248
### Install Dependencies

bin/lib/cli-utils.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
const fs = require('fs-extra')
2+
const { cyan, bold } = require('colorette')
3+
const { URL } = require('url')
4+
const LDP = require('../../lib/ldp')
5+
const AccountManager = require('../../lib/models/account-manager')
6+
const SolidHost = require('../../lib/models/solid-host')
7+
8+
module.exports.getAccountManager = getAccountManager
9+
module.exports.loadAccounts = loadAccounts
10+
module.exports.loadConfig = loadConfig
11+
module.exports.loadUsernames = loadUsernames
12+
13+
/**
14+
* Returns an instance of AccountManager
15+
*
16+
* @param {Object} config
17+
* @param {Object} [options]
18+
* @returns {AccountManager}
19+
*/
20+
function getAccountManager (config, options = {}) {
21+
const ldp = options.ldp || new LDP(config)
22+
const host = options.host || SolidHost.from({ port: config.port, serverUri: config.serverUri })
23+
return AccountManager.from({
24+
host,
25+
store: ldp,
26+
multiuser: config.multiuser
27+
})
28+
}
29+
30+
function loadConfig (program, options) {
31+
let argv = {
32+
...options,
33+
version: program.version()
34+
}
35+
let configFile = argv['configFile'] || './config.json'
36+
37+
try {
38+
const file = fs.readFileSync(configFile)
39+
40+
// Use flags with priority over config file
41+
const config = JSON.parse(file)
42+
argv = { ...config, ...argv }
43+
} catch (err) {
44+
// No file exists, not a problem
45+
console.log(cyan(bold('TIP')), 'create a config.json: `$ solid init`')
46+
}
47+
48+
return argv
49+
}
50+
51+
/**
52+
*
53+
* @param root
54+
* @param [serverUri] If not set, hostname must be set
55+
* @param [hostname] If not set, serverUri must be set
56+
* @returns {*}
57+
*/
58+
function loadAccounts ({ root, serverUri, hostname }) {
59+
const files = fs.readdirSync(root)
60+
hostname = hostname || new URL(serverUri).hostname
61+
const isUserDirectory = new RegExp(`.${hostname}$`)
62+
return files
63+
.filter(file => isUserDirectory.test(file))
64+
}
65+
66+
function loadUsernames ({ root, serverUri }) {
67+
const hostname = new URL(serverUri).hostname
68+
return loadAccounts({ root, hostname })
69+
.map(userDirectory => userDirectory.substr(0, userDirectory.length - hostname.length - 1))
70+
}

bin/lib/cli.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const loadInit = require('./init')
33
const loadStart = require('./start')
44
const loadInvalidUsernames = require('./invalidUsernames')
55
const loadMigrateLegacyResources = require('./migrateLegacyResources')
6+
const loadUpdateIndex = require('./updateIndex')
67
const { spawnSync } = require('child_process')
78
const path = require('path')
89

@@ -13,6 +14,7 @@ module.exports = function startCli (server) {
1314
loadStart(program, server)
1415
loadInvalidUsernames(program)
1516
loadMigrateLegacyResources(program)
17+
loadUpdateIndex(program)
1618

1719
program.parse(process.argv)
1820
if (program.args.length === 0) program.help()

bin/lib/common.js

Lines changed: 0 additions & 25 deletions
This file was deleted.

bin/lib/invalidUsernames.js

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
const fs = require('fs-extra')
22
const Handlebars = require('handlebars')
33
const path = require('path')
4-
const { URL } = require('url')
54

6-
const { loadConfig } = require('./common')
5+
const { getAccountManager, loadConfig, loadUsernames } = require('./cli-utils')
76
const { isValidUsername } = require('../../lib/common/user-utils')
87
const blacklistService = require('../../lib/services/blacklist-service')
98
const { initConfigDir, initTemplateDirs } = require('../../lib/server-config')
109
const { fromServerConfig } = require('../../lib/models/oidc-manager')
1110

12-
const AccountManager = require('../../lib/models/account-manager')
1311
const EmailService = require('../../lib/services/email-service')
14-
const LDP = require('../../lib/ldp')
1512
const SolidHost = require('../../lib/models/solid-host')
1613

1714
module.exports = function (program) {
@@ -28,7 +25,7 @@ module.exports = function (program) {
2825

2926
const invalidUsernames = getInvalidUsernames(config)
3027
const host = SolidHost.from({ port: config.port, serverUri: config.serverUri })
31-
const accountManager = getAccountManager(config, host)
28+
const accountManager = getAccountManager(config, { host })
3229

3330
if (options.notify) {
3431
return notifyUsers(invalidUsernames, accountManager, config)
@@ -96,23 +93,9 @@ async function deleteUsers (usernames, accountManager, config, host) {
9693
console.info(`Deleted ${deletingUsers.length} users succeeded`)
9794
}
9895

99-
function getAccountManager (config, host) {
100-
const ldp = new LDP(config)
101-
return AccountManager.from({
102-
host,
103-
store: ldp,
104-
multiuser: config.multiuser
105-
})
106-
}
107-
10896
function getInvalidUsernames (config) {
109-
const files = fs.readdirSync(config.root)
110-
const hostname = new URL(config.serverUri).hostname
111-
const isUserDirectory = new RegExp(`.${hostname}$`)
112-
return files
113-
.filter(file => isUserDirectory.test(file))
114-
.map(userDirectory => userDirectory.substr(0, userDirectory.length - hostname.length - 1))
115-
.filter(username => !isValidUsername(username) || !blacklistService.validate(username))
97+
const usernames = loadUsernames(config)
98+
return usernames.filter(username => !isValidUsername(username) || !blacklistService.validate(username))
11699
}
117100

118101
function listUsernames (usernames) {

bin/lib/start.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
const options = require('./options')
44
const fs = require('fs')
5-
const { loadConfig } = require('./common')
5+
const { loadConfig } = require('./cli-utils')
66
const { red, bold } = require('colorette')
77

88
module.exports = function (program, server) {

bin/lib/updateIndex.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
const fs = require('fs')
2+
const path = require('path')
3+
const cheerio = require('cheerio')
4+
const LDP = require('../../lib/ldp')
5+
const { URL } = require('url')
6+
const debug = require('../../lib/debug')
7+
const { readFile } = require('../../lib/common/fs-utils')
8+
9+
const { compileTemplate, writeTemplate } = require('../../lib/common/template-utils')
10+
const { loadConfig, loadAccounts } = require('./cli-utils')
11+
const { getName, getWebId } = require('../../lib/common/user-utils')
12+
const { initConfigDir, initTemplateDirs } = require('../../lib/server-config')
13+
14+
module.exports = function (program) {
15+
program
16+
.command('updateindex')
17+
.description('Update index.html in root of all PODs that haven\'t been marked otherwise')
18+
.action(async (options) => {
19+
const config = loadConfig(program, options)
20+
const configPath = initConfigDir(config)
21+
const templates = initTemplateDirs(configPath)
22+
const indexTemplatePath = path.join(templates.account, 'index.html')
23+
const indexTemplate = await compileTemplate(indexTemplatePath)
24+
const ldp = new LDP(config)
25+
const accounts = loadAccounts(config)
26+
const usersProcessed = accounts.map(async account => {
27+
const accountDirectory = path.join(config.root, account)
28+
const indexFilePath = path.join(accountDirectory, '/index.html')
29+
if (!isUpdateAllowed(indexFilePath)) {
30+
return
31+
}
32+
const accountUrl = getAccountUrl(account, config)
33+
try {
34+
const webId = await getWebId(accountDirectory, accountUrl, ldp.suffixMeta, (filePath) => readFile(filePath))
35+
const name = await getName(webId, ldp.fetchGraph)
36+
writeTemplate(indexFilePath, indexTemplate, { name, webId })
37+
} catch (err) {
38+
debug.errors(`Failed to create new index for ${account}: ${JSON.stringify(err, null, 2)}`)
39+
}
40+
})
41+
await Promise.all(usersProcessed)
42+
debug.accounts(`Processed ${usersProcessed.length} users`)
43+
})
44+
}
45+
46+
function getAccountUrl (name, config) {
47+
const serverUrl = new URL(config.serverUri)
48+
return `${serverUrl.protocol}//${name}.${serverUrl.host}/`
49+
}
50+
51+
function isUpdateAllowed (indexFilePath) {
52+
const indexSource = fs.readFileSync(indexFilePath, 'utf-8')
53+
const $ = cheerio.load(indexSource)
54+
const allowAutomaticUpdateValue = $('meta[name="solid-allow-automatic-updates"]').prop('content')
55+
return !allowAutomaticUpdateValue || allowAutomaticUpdateValue === 'true'
56+
}

default-templates/new-account/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
<head>
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<!-- Set content in the next line to false if you do not want your homepage to be automatically updated whenever a new version becomes available. -->
7+
<meta name="solid-allow-automatic-updates" content="true">
68
<title>{{#if name}}{{name}} &ndash; {{/if}}Solid Home</title>
79
<link rel="stylesheet" href="/common/css/bootstrap.min.css">
810
<link rel="stylesheet" href="/common/css/solid.css">

lib/common/fs-utils.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module.exports.copyTemplateDir = copyTemplateDir
22
module.exports.processFile = processFile
3+
module.exports.readFile = readFile
4+
module.exports.writeFile = writeFile
35

46
const fs = require('fs-extra')
57

@@ -31,3 +33,11 @@ async function processFile (filePath, manipulateSourceFn) {
3133
})
3234
})
3335
}
36+
37+
function readFile (filePath, options = 'utf-8') {
38+
return fs.readFileSync(filePath, options)
39+
}
40+
41+
function writeFile (filePath, fileSource, options = 'utf-8') {
42+
fs.writeFileSync(filePath, fileSource, options)
43+
}

lib/common/template-utils.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1+
module.exports.compileTemplate = compileTemplate
12
module.exports.processHandlebarFile = processHandlebarFile
3+
module.exports.writeTemplate = writeTemplate
24

35
const Handlebars = require('handlebars')
46
const debug = require('../debug').errors
5-
const { processFile } = require('./fs-utils')
7+
const { processFile, readFile, writeFile } = require('./fs-utils')
8+
9+
async function compileTemplate (filePath) {
10+
const indexTemplateSource = readFile(filePath)
11+
return Handlebars.compile(indexTemplateSource)
12+
}
613

714
/**
815
* Reads a file, processes it (performing template substitution), and saves
@@ -36,3 +43,9 @@ function processHandlebarTemplate (source, substitutions) {
3643
return source
3744
}
3845
}
46+
47+
function writeTemplate (filePath, template, substitutions) {
48+
const source = template(substitutions)
49+
writeFile(filePath, source)
50+
}
51+

0 commit comments

Comments
 (0)