Integrate Image Upload Component

This commit is contained in:
Barry Low committed 2018-10-04 01:36:56 -07:00
1 parent 836a9f2530
commit 9f311fc5b4
11 files changed
+139 -89

No files matched your search

+20 -61
View File
@@ -15,14 +15,11 @@ const { validateIdToken } = require('./auth/validateIdToken')
const { directiveResolvers } = require('./auth/authDirectives')
const Azure = require("@azure/storage-blob")
const { createSASQueryURL } = require('./storage/azure')
const azureAccount = process.env.AZURE_STORAGE_ACCOUNT
const azureKey = process.env.AZURE_STORAGE_ACCESS_KEY
const azureStorageUrl = process.env.AZURE_STORAGE_URL
var debug = require('debug')('http')
, http = require('http')
, name = 'My App';
const TEAMS_FRAGMENT = require('./graphql/TeamsFragment')
const TEAMS_CONNECTIONS_FRAGMENT = require('./graphql/TeamsConnectionsFragment')
@@ -77,7 +74,7 @@ const resolvers = {
return ctx.db.query.team({ where: { name: name } }, `{ name }`)
},
async teamsByOwner(parent, { ownerId }, ctx, info) {
console.log('teamsByOwner: ', ctx.user)
console.log('teamsByOwner: ', ctx)
return ctx.db.query.teams({where: { owner: ownerId }, orderBy:'updatedAt_DESC'}, TEAMS_FRAGMENT)
},
async owner(parent, args, ctx, info) {
@@ -137,60 +134,9 @@ const resolvers = {
})
},
async getAzureSAS(parent, { teamSlug }, ctx, info) {
// Create start and expiry times
let today = new Date()
let week = new Date()
week.setDate(today.getDate() + 7)
// Create SharedKeyCredential and attach to pipline
const SKC = new Azure.SharedKeyCredential(azureAccount, azureKey)
const pipeline = Azure.StorageURL.newPipeline(SKC)
// Create container URL
const serviceURL = new Azure.ServiceURL(azureStorageUrl, pipeline)
const containerName = teamSlug
const containerURL = Azure.ContainerURL.fromServiceURL(serviceURL, containerName)
//list container and check if already exists.
let marker
let containerCheck = null
do {
const listContainersResponse = await serviceURL.listContainersSegment(
Azure.Aborter.None,
marker,
)
// console.log(`ContainerCheck marker: `, listContainersResponse)
marker = listContainersResponse.marker;
for (const container of listContainersResponse.containerItems) {
// console.log(`ContainerCheck: ${container.name} | ${containerName} | ${marker}`)
if(container.name === containerName){
containerCheck = container.name
}
}
} while (marker)
// if container doesn't exist, create one
let newContainer
if(containerCheck === null){
newContainer = await containerURL.create(Azure.Aborter.None, { access: 'blob' })
}
// console.log('getAzureSAS container: ', containerURL, containerCheck, newContainer)
// Set permissions for service, resource types and containers
const SASServicePerms = Azure.AccountSASServices.parse('b')
const SASResourceTypes = Azure.AccountSASResourceTypes.parse('co')
const SASContainerPerms = Azure.ContainerSASPermissions.parse('rwl')
// Generate SAS url
const SASQueryParameters = Azure.generateAccountSASQueryParameters(
{
version: '2017-11-09',
permissions: SASContainerPerms,
startTime: today,
expiryTime: week,
protocol: 'https',
services: SASServicePerms,
resourceTypes: SASResourceTypes
}, SKC )
return SASQueryParameters
const SASUrl = createSASQueryURL(teamSlug)
console.log('createSASQueryURL: ', SASUrl)
return SASUrl
}
}
}
@@ -235,13 +181,26 @@ server.express.use(
server.express.post(server.options.endpoint, (req, res, done) => getUser(req, res, done, db))
const whitelist = [
let whitelist = [
'http://localhost:3000',
'http://localhost:3001',
'http://localhost:3002',
'http://localhost:4000',
'http://localhost:4002'
'http://localhost:4002',
'http://localhost:1337'
]
if(process.env.NODE_ENV === 'production'){
whitelist = [
'https://teams.advancedalgos.net',
'https://users.advancedalgos.net',
'https://users-api.advancedalgos.net',
'https://keyvault.advancedalgos.net',
'https://keyvault-api.advancedalgos.net',
'http://localhost:1337'
]
}
const corsOptionsDelegate = (req, callback) => {
var corsOptions
if (whitelist.indexOf(req.header('Origin')) !== -1) {
+60 -2
View File
@@ -1,4 +1,7 @@
const Azure = require('@azure/storage-blob')
const Azure = require("@azure/storage-blob")
const azureAccount = process.env.AZURE_STORAGE_ACCOUNT
const azureKey = process.env.AZURE_STORAGE_ACCESS_KEY
const azureStorageUrl = process.env.AZURE_STORAGE_URL
/* Create Azure Storage pipeline
* @accountName: Azure Blob Storage account name (required) - Environment variable
@@ -120,6 +123,60 @@ const deleteContainer = async (containerURL) => {
return true
}
const createSASQueryURL = async (containerName) => {
let today = new Date()
let week = new Date()
week.setDate(today.getDate() + 7)
// Create SharedKeyCredential and attach to pipline
const SKC = new Azure.SharedKeyCredential(azureAccount, azureKey)
const pipeline = Azure.StorageURL.newPipeline(SKC)
// Create container URL
const serviceURL = new Azure.ServiceURL(azureStorageUrl, pipeline)
const containerURL = Azure.ContainerURL.fromServiceURL(serviceURL, containerName)
//list container and check if already exists.
let marker
let containerCheck = null
do {
const listContainersResponse = await serviceURL.listContainersSegment(
Azure.Aborter.None,
marker,
)
// console.log(`ContainerCheck marker: `, listContainersResponse)
marker = listContainersResponse.marker;
for (const container of listContainersResponse.containerItems) {
// console.log(`ContainerCheck: ${container.name} | ${containerName} | ${marker}`)
if(container.name === containerName){
containerCheck = container.name
}
}
} while (marker)
// if container doesn't exist, create one
let newContainer
if(containerCheck === null){
newContainer = await containerURL.create(Azure.Aborter.None, { access: 'blob' })
}
console.log('createSASQueryURL container: ', containerURL, containerCheck, newContainer)
// Set permissions for service, resource types and containers
const SASContainerPerms = await Azure.AccountSASPermissions.parse('rwlacu')
const SASServicePerms = await Azure.AccountSASServices.parse('b')
const SASResourceTypes = await Azure.AccountSASResourceTypes.parse('co')
console.log('createSASQueryURL permissions: ', SASServicePerms, SASResourceTypes, SASContainerPerms)
// Generate SAS url
const SASQueryParameters = await Azure.generateBlobSASQueryParameters(
{
version: '2017-11-09',
protocol: 'https,http',
expiryTime: week,
permissions: 'rwlac',
containerName: containerName
}, SKC )
console.log('createSASQueryURL SASQueryParameters: ', containerURL.url, SASQueryParameters)
return SASQueryParameters
}
module.exports = {
createStoragePipline,
createServiceURL,
@@ -129,5 +186,6 @@ module.exports = {
uploadBlob,
downloadBlob,
deleteBlob,
deleteContainer
deleteContainer,
createSASQueryURL
}
+6 -6
View File
@@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"@advancedalgos/web-components": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/@advancedalgos/web-components/-/web-components-0.0.1.tgz",
"integrity": "sha512-RDi7oR5oY4HbcXdzTDhtgYVHRO+/ApBMossZ/UkCrI2lYAWhQaq4mYaKaJ2mtVKnwV1BkeOLFE6rbPZwIkhXJA==",
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/@advancedalgos/web-components/-/web-components-0.0.5.tgz",
"integrity": "sha512-mgaS2AwtVcbP0W8/Rk95TNFTrDmp21rDmoqrO177WGLCcTH5n3rHisQtrdVaEvLiUGoZ/8us/GeclljVJP1edw==",
"requires": {
"@azure/storage-blob": "^10.1.0-preview",
"@material-ui/core": "^3.0.3",
@@ -35,9 +35,9 @@
}
},
"@types/node": {
"version": "9.6.32",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.32.tgz",
"integrity": "sha512-5+L3wQ+FHoQ589EaH6rYICleuj8gnunq+1CJkM9fxklirErIOv+kxm3s/vecYnpJOYnFowE5uUizcb3hgjHUug=="
"version": "9.6.34",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.34.tgz",
"integrity": "sha512-PzJpSs2afoYqBA4yLBgaKUdZRk8+1yvkxcUBW6958h4vYOC+pc4k4C+QmQ6AO5Pt7uA4EIIboFog6YNCuITD0g=="
},
"apollo-cache": {
"version": "1.1.17",
+1 -1
View File
@@ -68,7 +68,7 @@
"workbox-cli": "^3.4.1"
},
"dependencies": {
"@advancedalgos/web-components": "0.0.1",
"@advancedalgos/web-components": "0.0.5",
"@azure/storage-blob": "^10.0.0-preview",
"@material-ui/core": "^3.0.3",
"@material-ui/icons": "^3.0.1",
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import { MessageCard } from '../common/'
import { MessageCard } from '@advancedalgos/web-components'
const styles = theme => ({
tableContainer: {
+1 -1
View File
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import { MessageCard } from '../common/'
import { MessageCard } from '@advancedalgos/web-components'
const styles = theme => ({
tableContainer: {
@@ -11,7 +11,7 @@ import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
import DashTeamItem from './DashTeamItem'
import CreateTeamDialog from './CreateTeamDialog'
import { MessageCard } from '../../common/'
import { MessageCard } from '@advancedalgos/web-components'
import { isDefined, isString } from '../../../utils/js-helpers'
import { getItem } from '../../../utils/local-storage'
@@ -35,13 +35,15 @@ const styles = theme => ({
}
})
const placeholder = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E' // eslint-disable-line max-len
export const DashTeamItem = ({ classes, team }) => (
<Grid item>
<Card className={classes.card}>
<div className={classes.cardDetails}>
<CardMedia
className={classes.cardMedia}
image='data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E' // eslint-disable-line max-len
image={team.profile !== null && team.profile.avatar !== undefined && team.profile.avatar !== null ? team.profile.avatar : placeholder}
title='Image title'
/>
<CardContent className={classes.cardContent}>
@@ -15,8 +15,6 @@ import Typography from '@material-ui/core/Typography'
import { MessageCard, ImageUpload } from '@advancedalgos/web-components'
import { getItem } from '../../../utils/local-storage'
import UPDATE_TEAM_PROFILE from '../../../graphql/teams/UpdateTeamProfileMutation'
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
@@ -51,6 +49,7 @@ export class ManageTeamEdit extends Component {
const description = props.team.profile.description || ''
const avatar = props.team.profile.avatar || ''
const banner = props.team.profile.banner || ''
this.authId = props.authId
this.state = {
open: false,
@@ -62,14 +61,15 @@ export class ManageTeamEdit extends Component {
}
render () {
console.log(this.props, this.props.slug)
console.log('ManageTeamEdit ', this.props, this.props.slug, this.props.team)
const { classes, team } = this.props
return (
<Mutation
mutation={UPDATE_TEAM_PROFILE}
refetchQueries={[
{
query: GET_TEAMS_BY_OWNER
query: GET_TEAMS_BY_OWNER,
variables: { authId: this.authId }
}
]}
>
@@ -114,7 +114,7 @@ export class ManageTeamEdit extends Component {
<DialogContent>
<Mutation mutation={GET_AZURE_SAS} >
{(getAzureSAS, { loading, error, data }) => {
console.log('getAzureSAS: ', loading, error, data)
console.log('getAzureSAS: ', loading, error, data, team.profile)
const AzureStorageUrl = process.env.AZURE_STORAGE_URL
const containerName = team.slug
let AzureSASURL
@@ -124,16 +124,46 @@ export class ManageTeamEdit extends Component {
getAzureSAS({ variables: { teamSlug: containerName } })
}
let avatar = null
if (this.state.avatar !== null) avatar = this.state.avatar
if (team.profile !== null && team.profile.avatar !== undefined && team.profile.avatar !== null) avatar = team.profile.avatar
let banner = null
if (this.state.banner !== null) banner = this.state.banner
if (team.profile !== null && team.profile.banner !== undefined && team.profile.banner !== null) banner = team.profile.banner
console.log('team images: ', avatar, banner)
if (loading || data === undefined) {
return (<MessageCard message='Loading...' />)
} else {
return (
<React.Fragment>
<ImageUpload
key='banner'
handleUrl={this.handleBanner}
fileName={`${team.slug}-banner.jpg`}
containerName={containerName}
existingImage={banner}
cropContainer={{ x: 10, y: 10, width: 800, height: 200 }}
cropPreviewBox={{ width: 650, height: 200 }}
saveImageConfig={{
quality: 0.6,
maxWidth: 800,
maxHeight: 200,
autoRotate: true,
mimeType: 'image/jpeg'
}}
AzureStorageUrl={AzureStorageUrl}
AzureSASURL={AzureSASURL}
cropRatio={4}
debug
/>
<ImageUpload
key='avatar'
handleUrl={this.handleAvatar}
fileName={`${team.slug}-avatar.jpg`}
containerName={containerName}
existingImage={team.profile.avatar}
existingImage={avatar}
cropContainer={{ x: 10, y: 10, width: 200, height: 200 }}
cropPreviewBox={{ width: 350, height: 350 }}
saveImageConfig={{
@@ -145,6 +175,8 @@ export class ManageTeamEdit extends Component {
}}
AzureStorageUrl={AzureStorageUrl}
AzureSASURL={AzureSASURL}
cropRatio={1}
debug
/>
</React.Fragment>
)
@@ -230,24 +262,22 @@ export class ManageTeamEdit extends Component {
handleAvatar (avatarUrl) {
console.log('handleAvatar: ', avatarUrl)
this.setState({ avatar: avatarUrl })
this.setState({ avatar: `${avatarUrl}?${Math.random()}` })
}
handleBanner (bannerUrl) {
console.log('handleBanner: ', bannerUrl)
this.setState({ banner: bannerUrl })
this.setState({ banner: `${bannerUrl}?${Math.random()}` })
}
async handleSubmit (e, updateTeamProfile, slug) {
console.log('handleSubmit: ', this.state)
e.preventDefault()
const currentUser = await getItem('user')
let authId = JSON.parse(currentUser)
authId = authId.authId
await updateTeamProfile({
variables: {
slug,
owner: authId,
owner: this.authId,
description: this.state.description,
motto: this.state.motto,
avatar: this.state.avatar,
@@ -261,7 +291,8 @@ export class ManageTeamEdit extends Component {
ManageTeamEdit.propTypes = {
classes: PropTypes.object.isRequired,
slug: PropTypes.string.isRequired,
team: PropTypes.object
team: PropTypes.object,
authId: PropTypes.string.isRequired
}
export default withStyles(styles)(ManageTeamEdit)
@@ -4,6 +4,7 @@ import { Query } from 'react-apollo'
import { withStateHandlers, lifecycle, compose } from 'recompose'
import Grid from '@material-ui/core/Grid'
import { MessageCard } from '@advancedalgos/web-components'
import { withStyles } from '@material-ui/core/styles'
import { isDefined, isString } from '../../../utils/js-helpers'
@@ -13,7 +14,6 @@ import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
import ManageTeamsItem from './ManageTeamsItem'
import CreateTeamDialog from './CreateTeamDialog'
import { MessageCard } from '../../common/'
const styles = theme => ({
heroContent: {
+1 -1
View File
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import { MessageCard } from '../common/'
import { MessageCard } from '@advancedalgos/web-components'
const styles = theme => ({
tableContainer: {