Skip to content

Commit

Permalink
add auth and field prefixing
Browse files Browse the repository at this point in the history
  • Loading branch information
COV-GIS committed Jan 11, 2022
1 parent e7166ae commit b1cd01b
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 190 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,4 @@ Set options in `index.js`.

View attachments in `attachments` directory.

### To Do

1. More catchy repo name.
1. Add auth.
1. Option for flattened single output directory with unique file names only when required.

Made with :heart: and :coffee: in Vernonia, Oregon
162 changes: 111 additions & 51 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,108 @@
// service url
const featureServiceUrl = 'https://<SERVER>/FeatureServer/0';

// output directory relative to root of project
const outputDirectory = 'attachments';

// prefix for each feature attachments directory
const directoryPrefix = 'feature';

// prefix field for each file and overrides `directoryPrefix`
// indended for non null unique values
// be careful...no value or type checking and will potentially overwrite some files
const prefixField = '';

// single flat output directory
const flat = false;

// create a token to use in requests
const portal = '';
const username = '';
const password = '';

// log responses (errors always logged)
const log = true;
const log = false;

/**
* Modules...
*/
require('isomorphic-form-data');
const { setDefaultRequestOptions } = require('@esri/arcgis-rest-request');
const { queryFeatures, getAttachments } = require('@esri/arcgis-rest-feature-layer');
const { queryFeatures, getAttachments, getFeature } = require('@esri/arcgis-rest-feature-layer');
const { UserSession } = require('@esri/arcgis-rest-auth');
const download = require('download');
const fs = require('fs-extra');
const chalk = require('chalk');
setDefaultRequestOptions({ fetch: require('node-fetch') });

let token;

/**
* Generic error handling.
* @param {String} message
* @param {String} message
* @param {Error} error
*/
const _error = (message, error) => {
console.log(
chalk.red(message)
);
console.log(chalk.red(message));
console.log(error);
};

/**
* Get all object ids.
*/
const _queryFeatureIds = () => {
queryFeatures({
url: featureServiceUrl,
where: '1 = 1',
returnIdsOnly: true,
params: {
token,
},
})
.then((response) => {
if (log) console.log(response);

response.objectIds.forEach(_getAttachments);
})
.catch((error) => {
_error('_queryFeatures error', error);
});
};

/**
* Get attachments for a feature.
* @param {Number} id
* @param {Number} id
*/
const _getAttachments = (id) => {
getAttachments({
url: featureServiceUrl,
featureId: id,
params: {
returnUrl: true,
token,
},
})
.then((response) => {
if (log) console.log(response);

response.attachmentInfos.forEach((attachmentInfo) => {
_downloadAttachment(attachmentInfo, id);
if (prefixField) {
getFeature({
url: featureServiceUrl,
id,
params: {
token,
},
})
.then((response) => {
const fieldValue = response.attributes ? response.attributes[prefixField] : null;
_downloadAttachment(attachmentInfo, id, fieldValue);
})
.catch((error) => {
_error(`_getAttachments#getFeature error...feature id ${id}`, error);
});
} else {
_downloadAttachment(attachmentInfo, id, null);
}
});
})
.catch((error) => {
Expand All @@ -59,15 +115,17 @@ const _getAttachments = (id) => {

/**
* Download attachment.
* @param {AttachmentInfo} attachmentInfo
* @param {AttachmentInfo} attachmentInfo
* @param {Number} id
*/
const _downloadAttachment = (attachmentInfo, id) => {
const attachmentUrl = `${featureServiceUrl}/${id}/attachments/${attachmentInfo.id}`;
const _downloadAttachment = (attachmentInfo, id, fieldValue) => {
let attachmentUrl = `${featureServiceUrl}/${id}/attachments/${attachmentInfo.id}`;

if (token) attachmentUrl = `${attachmentUrl}?token=${token}`;

download(attachmentUrl)
.then((data) => {
_writeFile(data, attachmentInfo, id);
_writeFile(data, attachmentInfo, id, fieldValue);
})
.catch((error) => {
_error(`_downloadAttachment error...attachment url ${attachmentUrl}`, error);
Expand All @@ -76,53 +134,55 @@ const _downloadAttachment = (attachmentInfo, id) => {

/**
* Write the attachment to disc.
* @param {Buffer} data
* @param {AttachmentInfo} attachmentInfo
* @param {Number} id
* @param {Buffer} data
* @param {AttachmentInfo} attachmentInfo
* @param {Number} id
*/
const _writeFile = (data, attachmentInfo, id) => {
const _writeFile = async (data, attachmentInfo, id, fieldValue) => {
let filePath;
const { id: attachmentId, name } = attachmentInfo;
const [fileName, fileType] = name.split('.');
const writeDirectory = flat === true ? outputDirectory : `${outputDirectory}/${fieldValue || directoryPrefix}_${id}`;

const attachmentDirectory = `attachments/${directoryPrefix}_${id}`;
if (flat === true) {
filePath = fieldValue
? `${writeDirectory}/${fieldValue}_${fileName}_${attachmentId}.${fileType}`
: `${writeDirectory}/${id}_${fileName}_${attachmentId}.${fileType}`;
} else {
filePath = `${writeDirectory}/${fileName}_${attachmentId}.${fileType}`;
}

const fileParts = name.split('.');
await fs.ensureDir(writeDirectory);

const [fileName, fileType] = fileParts;

fs.ensureDir(attachmentDirectory);

const filePath = `${attachmentDirectory}/${fileName}_${attachmentId}.${fileType}`;

fs.writeFile(filePath, data, error => {
fs.writeFile(filePath, data, (error) => {
if (error) {
console.log(
chalk.red(`Failed to write ${filePath}.`)
);
_error(`_writeFile error...file path ${filePath}`, error);
} else if (!error && log) {
console.log(
chalk.green(`Succesfully wrote ${filePath}.`)
);
console.log(chalk.green(`Succesfully wrote ${filePath}.`));
}
});
};

/**
* Ensure attachments directory.
*/
fs.ensureDir('attachments');
(async () => {
await fs.ensureDir(outputDirectory);

/**
* Begin by querying all object ids.
*/
queryFeatures({
url: featureServiceUrl,
returnIdsOnly: true,
})
.then((response) => {
if (log) console.log(response);

response.objectIds.forEach(_getAttachments);
})
.catch((error) => {
_error('_queryFeatures error', error);
});
if (portal && username && password) {
const session = new UserSession({
username,
password,
portal,
});

session
.getToken(featureServiceUrl)
.then((_token) => {
token = _token;
_queryFeatureIds();
})
.catch((error) => {
_error('session.getToken error', error);
});
} else {
_queryFeatureIds();
}
}).call();
Loading

0 comments on commit b1cd01b

Please sign in to comment.