-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathemojme-upload.js
194 lines (174 loc) · 8.02 KB
/
emojme-upload.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
const _ = require('lodash');
const fs = require('graceful-fs');
const commander = require('commander');
const EmojiAdminList = require('./lib/emoji-admin-list');
const EmojiAdd = require('./lib/emoji-add');
const Cli = require('./lib/util/cli');
const FileUtils = require('./lib/util/file-utils');
const Helpers = require('./lib/util/helpers');
/** @module upload */
/**
* The upload response object, like other response objects, is organized by input subdomain.
* @typedef {object} syncResponseObject
* @property {object} subdomain each subdomain passed in to add will appear as a key in the response
* @property {emojiList[]} subdomain.emojiList the list of emoji added to `subdomain`, with each element an emoji pulled from either `srcSubdomain` or `subdomains` less the subdomain in question.
* @property {emojiList[]} subdomain.collisions if `options.avoidCollisions` is `false`, emoji that cannot be uploaded due to existing conflicting emoji names will exist here
*/
/**
* The required format of a json file that can be used as the `options.src` for {@link upload}
*
* To see an example, use {@link download}, then look at `buidl/*.adminList.json`
*
* @typedef {Array} jsonEmojiListFormat
* @property {Array} emojiList
* @property {object} emojiList.emojiObject
* @property {string} emojiList.emojiObject.name the name of the emoji
* @property {1|0} emojiList.emojiObject.is_alias whether or not the emoji is an alias. If `1`, `alias_for` is require and `url` is ignored. If `0` vice versa
* @property {string} emojiList.emojiObject.alias_for the name of the emoji this emoji is apeing
* @property {string} emojiList.emojiObject.url the remote url or local path of the emoji
* @property {string} emojiList.emojiObject.user_display_name the name of the emoji creator
*
* @example
* [
* {
* "name": "a_giving_lovely_generous_individual",
* "is_alias": 1,
* "alias_for": "caleb"
* },
* {
* "name": "gooddoggy",
* "is_alias": 0,
* "alias_for": null,
* "url": "https://emoji.slack-edge.com/T3T9KQULR/gooddoggy/849f53cf1de25f97.png"
* }
* ]
*/
/**
* The required format of a yaml file that can be used as the `options.src` for {@link upload}
* @typedef {object} yamlEmojiListFormat
* @property {object} topLevelYaml all keys execpt for `emojis` are ignored
* @property {Array} emojis the array of emoji objects
* @property {object} emojis.emojiObject
* @property {string} emojis.emojiObject.name the name of the emoji
* @property {string} emojis.emojiObject.src alias for `name`
* @property {1|0} emojis.emojiObject.is_alias whether or not the emoji is an alias. If `1`, `alias_for` is require and `url` is ignored. If `0` vice versa
* @property {string} emojis.emojiObject.alias_for the name of the emoji this emoji is apeing
* @property {string} emojis.emojiObject.url the remote url or local path of the emoji
* @property {string} emojis.emojiObject.user_display_name the name of the emoji creator
*
* @example
* title: animals
* emojis:
* - name: llama
* src: http://i.imgur.com/6bKXKUP.gif
* - name: alpaca
* src: http://i.imgur.com/c6QxTbM.gif
*/
/**
* Upload multiple emoji described by an existing list on disk, either as a json emoji admin list or emojipacks-like yaml.
*
* @async
* @param {string|string[]} subdomains a single or list of subdomains from which to download emoji. Must match respectively to `token`s and `cookie`s.
* @param {string|string[]} tokens a single or list of tokens with which to authenticate. Must match respectively to `subdomain`s and `cookie`s.
* @param {string|string[]} cookies a single or list of cookies used to authenticate access to the given subdomain. Must match respectively to `subdomain`s and `token`s.
* @param {object} options contains singleton or arrays of emoji descriptors.
* @param {string|string[]} options.src source emoji list files for the emoji to be added. Can either be in {@link jsonEmojiListFormat} or {@link yamlEmojiListFormat}
* @param {boolean} [options.avoidCollisions] if `true`, emoji being added will be renamed to not collide with existing emoji. See {@link lib/util/helpers.avoidCollisions} for logic and details // TODO: fix this link, maybe link to tests which has better examples
* @param {string} [options.prefix] string to prefix all emoji being uploaded
* @param {boolean} [options.bustCache] if `true`, ignore any adminList younger than 24 hours and repull slack instance's existing emoji. Can be useful for making `options.avoidCollisions` more accurate
* @param {boolean} [options.output] if `false`, no files will be written during execution. Prevents saving of adminList for future use, as well as the writing of log files
* @param {boolean} [options.verbose] if `true`, all messages will be written to stdout in addition to combined log file.
*
* @returns {Promise<uploadResponseObject>} uploadResponseObject result object
*
* @example
var uploadOptions = {
src: './emoji-list.json', // upload all the emoji in this json array of objects
avoidCollisions: true, // append '-1' or similar if we try to upload a dupe
prefix: 'new-' // prepend every emoji in src with "new-", e.g. "emoji" becomes "new-emoji"
};
var uploadResults = await emojme.upload('mySubdomain', 'myToken', 'myCookie', uploadOptions);
console.log(uploadResults);
// {
// mySubdomain: {
// collisions: [
// { name: an-emoji-that-already-exists-in-mySubdomain ... }
// ],
// emojiList: [
// { name: emoji-from-emoji-list-json ... },
// { name: emoji-from-emoji-list-json ... },
// ...
// ]
// }
// }
*/
async function upload(subdomains, tokens, cookies, options) {
subdomains = Helpers.arrayify(subdomains);
tokens = Helpers.arrayify(tokens);
cookies = Helpers.arrayify(cookies);
options = options || {};
let inputEmoji;
// TODO this isn't handling --src file --src file correctly
if (Array.isArray(options.src)) {
inputEmoji = options.src;
} else if (!fs.existsSync(options.src)) {
throw new Error(`Emoji source file ${options.src} does not exist`);
} else {
const fileType = options.src.split('.').slice(-1)[0];
if (fileType.match(/yaml|yml/)) {
inputEmoji = FileUtils.readYaml(options.src);
} else if (fileType.match(/json/)) {
inputEmoji = FileUtils.readJson(options.src);
} else {
throw new Error(`Filetype ${fileType} is not supported`);
}
}
const [authTuples] = Helpers.zipAuthTuples(subdomains, tokens, cookies);
const uploadPromises = authTuples.map(async (authTuple) => {
let emojiToUpload = []; let
collisions = [];
if (options.prefix) {
inputEmoji = Helpers.applyPrefix(inputEmoji, options.prefix);
}
if (options.allowCollisions) {
emojiToUpload = inputEmoji;
} else {
const existingEmojiList = await new EmojiAdminList(...authTuple, options.output)
.get(options.bustCache);
const existingNameList = existingEmojiList.map(e => e.name);
if (options.avoidCollisions) {
inputEmoji = Helpers.avoidCollisions(inputEmoji, existingEmojiList);
}
[collisions, emojiToUpload] = _.partition(inputEmoji,
emoji => existingNameList.includes(emoji.name));
}
const emojiAdd = new EmojiAdd(...authTuple);
const uploadResult = await emojiAdd.upload(emojiToUpload);
return Object.assign({}, uploadResult, { collisions });
});
return Helpers.formatResultsHash(await Promise.all(uploadPromises));
}
function uploadCli() {
const program = new commander.Command();
Cli.requireAuth(program);
Cli.allowIoControl(program);
Cli.allowEmojiAlterations(program)
.option('--src <value>', 'source file(s) for emoji json or yaml you\'d like to upload')
.parse(process.argv);
Cli.unpackAuthJson(program);
return upload(program.subdomain, program.token, program.cookie, {
src: program.src,
bustCache: program.bustCache,
allowCollisions: program.allowCollisions,
avoidCollisions: program.avoidCollisions,
prefix: program.prefix,
output: program.output,
});
}
if (require.main === module) {
uploadCli();
}
module.exports = {
upload,
uploadCli,
};