let getParameters = (input, cursor) => { logger.debug(`Getting parameters from input`, input) let title = trimWhitespace(input.title) let description = markdownService.getDescription() let instructions = markdownService.getInstructions() let tags = R.map(trimWhitespace, S.wordsDelim(/,/, input.tagsString)) let user = userManagement.getLoggedInUser(cursor) let username = user.username let licenseSelect = document.getElementById('license-select') let licenseId = input.licenseId if (licenseId == null) { throw new Error(`licenseId is null`) } if (S.isBlank(title) || R.isEmpty(tags)) { throw new ValidationError('Fields not correctly filled in') } if (S.isBlank(description)) { throw new ValidationError('Description must be filled in') } if (S.isBlank(instructions)) { throw new ValidationError('Instructions must be filled in') } let allPictures = pictureDropzone.getAcceptedFiles() if (R.isEmpty(allPictures)) { throw new ValidationError('There must be at least one picture') } let queuedPictures = pictureDropzone.getQueuedFiles() let queuedFiles = fileDropzone.getQueuedFiles() return [title, description, instructions, tags, licenseId, username, queuedPictures, queuedFiles,] }
.then(({title, description, instructions, tags, licenseId, username, pictureFiles, files,}) => { logger.debug(`Picture files:`, pictureFiles) logger.debug(`Files:`, files) logger.debug(`title: ${title}, description: ${description}, tags: ${S.join(`,`, tags)}`) let qualifiedProjectId = `${username}/${input.id}` let data = { id: input.id, title, description, instructions, tags, licenseId, pictures: pictureFiles, files, } logger.debug(`Creating project '${qualifiedProjectId}'...:`, data) cursor.cursor('createProject').set('isWaiting', 'Saving project...') ajax.postJson(`/api/projects/${username}`, data) .then(() => { logger.info(`Successfully created project '${qualifiedProjectId}' on server`) router.goTo(`/u/${qualifiedProjectId}`) }, (error) => { cursor.cursor('createProject').set('isWaiting', false) logger.warn(`Failed to create project '${qualifiedProjectId}' on server: ${error}`, error.stack) }) }, (error) => {
render: (cursor) => { let profileCursor = cursor.cursor('userProfile') let user = profileCursor.get('user').toJS() let currentHash = cursor.cursor('router').get('currentHash') let soundCloud = user.soundCloud || {} let profileTabs = [ new UserTab('Projects'), new UserTab('Plans'), new UserTab('About'), new UserTab('Media', null, !R.isEmpty(soundCloud.uploads || [])), new UserTab('Workshops', null, !S.isBlank(user.workshopsInfo)), ] let activeTab = R.contains(currentHash, R.map((tab) => { return tab.name }, profileTabs)) ? currentHash : 'projects' logger.debug(`Rendering profile of user '${user.username}', active tab '${activeTab}':`, user) logger.debug(`State:`, profileCursor.toJS()) let tabContents if (activeTab === 'about') { tabContents = About(user) } else if (activeTab === 'projects') { tabContents = Projects(user) } else if (activeTab === 'plans') { tabContents = ProjectPlans({user, cursor,}) } else if (activeTab === 'media') { tabContents = Media(user) } else if (activeTab === 'workshops') { tabContents = Workshops(user) } return h('#user-pad', [ h('.pure-g', [ h('.pure-u-1-4', [ VCard(user), ]), h('.pure-u-3-4', [ h('ul.tabs', {role: 'tablist',}, R.map((profileTab) => { return h(`li.${S.join('.', profileTab.getClasses(activeTab))}`, [ profileTab.enabled ? h('a', { role: 'tab', href: profileTab.url, }, [ profileTab.icon != null ? h(`span.icon-${profileTab.icon}`, nbsp) : null, h('span', profileTab.title), ]) : h('div', [ profileTab.icon != null ? h(`span.icon-${profileTab.icon}`, nbsp) : null, h('span', profileTab.title), ]), ]) }, profileTabs)), h('#tab-contents', [tabContents,]), ]), ]), ]) },
getClasses(activeTab) { let classes if (this.name === activeTab) { logger.debug(`${this.name} is active tab`) classes = ['active',] } else { classes = [] } return S.join(' ', R.concat(classes, !this.enabled ? ['disabled',] : [])) }
withDb(reply, (conn) => { let reTag = /\[[^\]]*\]/g let queryWithoutTags = '' let tags = [] let offset = 0 let query = request.query.query while (true) { let m = reTag.exec(query) if (m == null) { break } let tag = trimWhitespace(m[0].slice(1, -1)) logger.debug(`Found tag '${tag}'`) tags.push(tag) queryWithoutTags += ' ' + query.slice(offset, m.index) offset = reTag.lastIndex } queryWithoutTags += ' ' + query.slice(offset) queryWithoutTags = trimWhitespace(queryWithoutTags.replace(/\s+/g, ' ')) if (!S.isBlank(queryWithoutTags)) { logger.debug(`Tag-less query: '${queryWithoutTags}'`) } else { logger.debug(`Tag-less query is empty`) } if (!R.isEmpty(tags)) { logger.debug(`Tags:`, tags) } else { logger.debug(`No tags`) } let regex = `(?i)${queryWithoutTags}` return r.table('projects') .filter((project) => { let pred = project('projectId').match(regex).or(project('title').match(regex)) .or(project('owner').match(regex)) R.forEach((tag) => { pred = pred.and(project('tags').contains(tag)) }, tags) return pred }) .run(conn) .then((projectsCursor) => { return projectsCursor.toArray() .then((projects) => { logger.debug(`Found ${projects.length} project(s):`, projects) return projects }, (error) => { logger.warn(`Failed to iterate projects: '${error}'`, error.stack) throw new Error(error) }) }) })
let Media = component('Media', (user) => { let soundCloud = user.soundCloud || {} return h('div', !R.isEmpty(user.soundCloudUploads) ? [ h('h1#soundcloud-header', [ h('span.icon-soundcloud', 'SoundCloud'), ]), h('p', `${S.words(user.name)[0]}'s sounds on SoundCloud`), h('ul#soundcloud-uploads', R.map((upload) => { return h('li', [SoundCloudUpload({upload,}),]) }, soundCloud.uploads)), ] : null) })
h('ul.tabs', {role: 'tablist',}, R.map((profileTab) => { return h(`li.${S.join('.', profileTab.getClasses(activeTab))}`, [ profileTab.enabled ? h('a', { role: 'tab', href: profileTab.url, }, [ profileTab.icon != null ? h(`span.icon-${profileTab.icon}`, nbsp) : null, h('span', profileTab.title), ]) : h('div', [ profileTab.icon != null ? h(`span.icon-${profileTab.icon}`, nbsp) : null, h('span', profileTab.title), ]), ]) }, profileTabs)),
let removeStaleFiles = (oldFiles, newFiles, fileType) => { if (oldFiles == null) { logger.debug(`Project has no old ${fileType}s - nothing to remove`) return } let removedFiles = R.differenceWith(((a, b) => { return a.url === b.url }), oldFiles, newFiles) if (!R.isEmpty(removedFiles)) { logger.debug( `Removing ${removedFiles.length} stale ${fileType}(s) (type: ${fileType}), old files vs new files:`, oldFiles, newFiles) } else { logger.debug(`No ${fileType}s to remove`) return } let filePaths = R.map((file) => { let filePath = `u/${owner}/${projectId}/${fileType}s/${file.fullPath}` return filePath }, removedFiles) let filePathsStr = S.join(', ', filePaths) logger.debug(`Removing outdated ${fileType}s ${filePathsStr}`) return new Promise((resolve, reject) => { s3Client.deleteObjects({ Delete: { Objects: R.map((filePath) => { return { Key: filePath, } }, filePaths), }, }, (error, data) => { if (error == null) { resolve(data) } else { reject(error) } }) }) .then(() => { logger.debug(`Successfully removed ${fileType}(s) ${filePathsStr}`) }, (error) => { logger.warn(`Failed to remove ${fileType}(s) ${filePathsStr}: '${error}':`, error.stack) }) }
resolveWithResponse: (json, resolve, reject) => { if (!S.isBlank(json)) { let result try { result = JSON.parse(json) } catch (error) { logger.warn(`Received malformed JSON from server:`, json) reject(`Parsing JSON from server failed: ${error}`) return } resolve(result) } else { resolve() } },
}, ({id, value, placeholder, ref, classes, type, name, required, onChange, onEnter,}) => { return h('input', { id, className: S.join(' ', classes || []), type: type || 'text', name, placeholder, required, value, ref, onChange, onKeyUp: (event) => { if (event.keyCode === 13 && onEnter != null) { logger.debug('Enter pressed') onEnter() } }, }) })
.then((user) => { if (user == null) { throw new Error(`Couldn't find user '${username}'`) } let closeBoardPromise if (!S.isBlank(closeBoard)) { logger.debug(`Closing associated Trello board as well`) let projectPlan = R.find((projectPlan) => { return projectPlan.id === planId }, user.projectPlans) closeBoardPromise = doCloseBoard(projectPlan, closeBoard) } else { closeBoardPromise = Promise.resolve() } return closeBoardPromise.then(() => { let projectPlans = R.filter((projectPlan) => { return projectPlan.id !== planId }, user.projectPlans) return r.table('users') .get(username) .update({ projectPlans, }) .run(conn) .then(() => { logger.debug(`Successfully removed project plan ${planId} for user '${username}'`) return R.merge(user, { projectPlans, }) }, (error) => { logger.warn(`Failed to remove project plan ${planId} for user '${username}':`, error) throw error }) }) })
let getFolder = (file) => { let path = S.wordsDelim(/\//)(file.fullPath) return path.length > 1 ? '/' + S.join('/', path.slice(0, -1)) : '' }