export function* uploadReplacingIcon(next) { const { userId } = this.state.user; invariant( this.req.file, '未获取上传的图标文件,请检查 formdata 的 icon 字段' ); const { originalname, buffer } = this.req.file; const name = getFileName(originalname); const param = { icons: [{ name, buffer }], writeFiles: false }; let icons; try { icons = yield fontBuilder(param); } catch (e) { invariant(false, '读取 svg 文件内容有误,请检查文件'); } const icon = icons[0]; let iconData = {}; yield seq.transaction(transaction => Icon.create( { name: icon.name, path: icon.d, status: iconStatus.REPLACING, uploader: userId }, { transaction } ).then(addedIcon => { iconData = addedIcon; const svg = (buffer && buffer.toString()) || null; return Cache.create( { iconId: addedIcon && addedIcon.id, svg }, { transaction } ); }) ); this.state.respond = { replaceId: iconData.id }; yield next; }
export function* downloadFont(next) { const { type, id, icons } = this.param; let { version } = this.param; let { fontName, isNeedNewFontFamily } = this.param; let iconData; let foldName; let lastModify = null; let baselineShouldBeAdjusted = true; const isRepo = type === 'repo'; if (Array.isArray(icons) && icons.length) { iconData = yield Icon.findAll({ where: { id: { $in: icons }, status: iconStatus.RESOLVED }, attributes: [['fontClass', 'name'], ['code', 'codepoint'], ['path', 'd']], raw: true }); foldName = `temporary_${+new Date()}`; fontName = fontName || 'iconfont'; } else { const model = isRepo ? Repo : Project; const throughModel = isRepo ? RepoVersion : ProjectVersion; const instance = yield model.findOne({ where: { id } }); // 仅对项目进行处理,迫使每次下载都是最新版本 if (!isRepo) { const getVersion = version ? Promise.resolve(version) : ProjectVersion.max('version', { where: { projectId: id } }); version = yield getVersion; baselineShouldBeAdjusted = !!instance.baseline; } else { version = 0; } invariant(instance, `不存在 id 为 ${id} 的 ${isRepo ? '大库' : '项目'}`); // 检查项目中是否存在系统占用的图标,若存在则阻止下载 if (type === 'project') { const icon = yield instance.getIcons({ attributes: ['name'], where: { status: iconStatus.DISABLED }, through: { model: ProjectVersion, where: { version: 0 } }, raw: true }); invariant( !icon.length, `项目中的 ${icon .map(item => item.name) .join('、')} 等图标被系统占用,请先删除,再下载或同步` ); } iconData = yield instance.getIcons({ attributes: [['fontClass', 'name'], ['code', 'codepoint'], ['path', 'd']], through: { model: throughModel, where: { version } }, where: { status: iconStatus.RESOLVED }, raw: true }); foldName = `${type}-${ isRepo ? instance.id : instance.name }-${versionTools.n2v(version)}`; fontName = fontName || (isRepo ? `iconfont${instance.id}` : instance.name); if (isRepo) { lastModify = +new Date(instance.updatedAt); } } // font-family增加版本号 let originFontName = ''; if (isNeedNewFontFamily) { originFontName = fontName; fontName += '-' + versionTools.n2v(version); } const fontDest = yield ensureCachesExist(foldName, 'font'); let needReBuild = true; // 如果是大库则检查一下当前文件是否过期 if (isRepo) { const modifyTime = yield getModifyTime(foldName, 'font', 'zip'); needReBuild = !modifyTime || modifyTime < lastModify; } // 除了大库已存在副本之外,项目和单独下载都需要 rebuild if (needReBuild) { const zipDest = `${fontDest}.zip`; yield fontBuilder({ icons: iconData, readFiles: false, dest: fontDest, descent: baselineShouldBeAdjusted ? 128 : 0, fontName, translate: baselineShouldBeAdjusted ? -128 : 0 }); // font-name 是否需要加版本号 if (isNeedNewFontFamily) { // 处理文件名 改回原来的 fs.readdirSync(fontDest).forEach(fileName => { const path = fontDest + '/' + fileName; let fileExt = fileName.replace(/.+\./, ''); // 处理html 删除带版本号的后缀 if (fileExt === 'html') { let htmlContent = fs.readFileSync(path, 'utf8'); let arr = htmlContent.split(fontName + '.'); htmlContent = arr.join(originFontName + '.'); fs.writeFileSync(path, htmlContent); } const oldPath = path; const newPath = fontDest + '/' + fileName.replace(/.+\./, originFontName + '.'); // 替换回原文件名 fs.renameSync(oldPath, newPath); }); let fileCc = fs.readdirSync(fontDest).length; invariant(fileCc >= 5, '文件缺失, 请重试'); } yield Q.nfcall(zip, fontDest, { saveTo: zipDest }); } this.state.respond = { foldName: `${foldName}.zip`, fontDest: `${fontDest}.zip` }; yield next; }
export function* uploadIcons(next) { const { userId } = this.state.user; invariant( this.req.files && this.req.files.length, '未获取上传的图标文件,请检查 formdata 的 icon 字段' ); // 处理传入文件 const param = { icons: this.req.files.map(file => { const { originalname } = file; console.log(file); let buffer = file.buffer; buffer = replaceDefs(buffer, originalname); const name = getFileName(originalname); return { name, buffer }; }), // 标记只返回图标信息数据 writeFiles: false }; yield saveOriginalSVG(param.icons); let icons; try { icons = yield fontBuilder(param); } catch (e) { invariant(false, '读取 svg 文件内容有误,请检查文件'); } const data = icons.map(icon => { invariant( ICON_NAME.reg.test(icon.name), '文件名称长度为 1-20,支持中文、英文、数字、连字符和下划线等,不能含有其他非法字符,请修改后重新上传' ); return { name: icon.name, tags: icon.name, path: icon.d, status: iconStatus.UPLOADED, uploader: userId }; }); yield seq.transaction(transaction => Icon.bulkCreate(data, { individualHooks: true, transaction }).then( addedIcons => { const cacheIcons = []; addedIcons.forEach((icon, index) => { const { id, name } = icon || {}; const originalIcons = param.icons; if ( originalIcons && originalIcons[index] && name === originalIcons[index].name ) { // 将 icon id 和 对应的 svg 插入 cache 表 const svg = (originalIcons[index].buffer && originalIcons[index].buffer.toString()) || null; cacheIcons.push({ iconId: id, svg }); } }); return Cache.bulkCreate(cacheIcons, { transaction }); } ) ); // TODO: 看一下上传失败是否会直接抛出异常 this.state.respond = '图标上传成功'; yield next; }