feat: add cloudinary provider

develop
Sébastien Näser 3 years ago
parent 4632ff71b6
commit da024f8cec

@ -1,6 +1,24 @@
export default [ export default [
'strapi::errors', 'strapi::errors',
'strapi::security', {
name: 'strapi::security',
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
'connect-src': ['\'self\'', 'https:'],
'img-src': ['\'self\'', 'data:', 'blob:', 'res.cloudinary.com'],
'media-src': [
'\'self\'',
'data:',
'blob:',
'res.cloudinary.com',
],
upgradeInsecureRequests: null,
},
},
},
},
'strapi::cors', 'strapi::cors',
'strapi::poweredBy', 'strapi::poweredBy',
'strapi::logger', 'strapi::logger',

@ -25,5 +25,20 @@ module.exports = ({env}) => ({
enabled: true, enabled: true,
resolve: './src/plugins/vendors' resolve: './src/plugins/vendors'
}, },
upload: {
config: {
provider: 'cloudinary',
providerOptions: {
cloud_name: 'djgzqzujy',
api_key: '161331531972295',
api_secret: '-Yk554hkcAD9x7_pkPN_2knXAMg',
},
actionOptions: {
upload: {},
uploadStream: {},
delete: {},
},
},
},
// ... // ...
}); });

@ -16,9 +16,11 @@
"@strapi/plugin-i18n": "4.10.2", "@strapi/plugin-i18n": "4.10.2",
"@strapi/plugin-users-permissions": "4.10.2", "@strapi/plugin-users-permissions": "4.10.2",
"@strapi/provider-email-nodemailer": "4.10.2", "@strapi/provider-email-nodemailer": "4.10.2",
"@strapi/provider-upload-cloudinary": "4.10.2",
"@strapi/strapi": "4.10.2", "@strapi/strapi": "4.10.2",
"@strapi/utils": "4.10.2", "@strapi/utils": "4.10.2",
"better-sqlite3": "8.3.0", "better-sqlite3": "8.3.0",
"cloudinary": "^1.41.0",
"mysql": "2.18.1", "mysql": "2.18.1",
"pg": "8.10.0", "pg": "8.10.0",
"strapi-plugin-import-export-entries": "1.19.1", "strapi-plugin-import-export-entries": "1.19.1",

@ -9,8 +9,7 @@
"displayName": "User" "displayName": "User"
}, },
"options": { "options": {
"draftAndPublish": false, "draftAndPublish": false
"timestamps": true
}, },
"attributes": { "attributes": {
"username": { "username": {

@ -0,0 +1,23 @@
import {request} from "@strapi/helper-plugin";
import {get, has, isEmpty, pickBy, set} from "lodash";
import {auth} from '@strapi/helper-plugin';
const productsRequests = {
getProducts: async () => {
try {
const response = await request("/vendors/products/list", {method: "GET", headers: {
Authorization: `Bearer ${auth.getToken()}`
}});
return response;
} catch (e) {
return {
error: true,
message: e
}
}
return [];
},
};
export default productsRequests;

@ -19,6 +19,8 @@ import {
import {Apps, ExclamationMarkCircle, Plus} from "@strapi/icons"; import {Apps, ExclamationMarkCircle, Plus} from "@strapi/icons";
import './index.css'; import './index.css';
import getPluginRoute from "../../utils/base-route";
import {ROUTES} from "../../utils/constants";
const SubMenu = () => { const SubMenu = () => {
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
@ -27,19 +29,19 @@ const SubMenu = () => {
id: 1, id: 1,
label: 'Products', label: 'Products',
icon: <ExclamationMarkCircle/>, icon: <ExclamationMarkCircle/>,
to: '/catalog/products', to: `${getPluginRoute()}${ROUTES.CatalogProducts}`,
active: false, active: false,
}, },
{ {
id: 2, id: 2,
label: 'Categories', label: 'Categories',
to: '/catalog/categories', to: `${getPluginRoute()}${ROUTES.CatalogCategories}`,
active: false, active: false,
}, },
{ {
id: 2, id: 2,
label: 'Filters', label: 'Filters',
to: '/catalog/filters', to: `${getPluginRoute()}${ROUTES.CatalogFilters}`,
active: false, active: false,
}, },
]; ];
@ -48,13 +50,13 @@ const SubMenu = () => {
id: 1, id: 1,
label: 'Orders', label: 'Orders',
icon: <ExclamationMarkCircle/>, icon: <ExclamationMarkCircle/>,
to: '/customers/orders', to: `${getPluginRoute()}${ROUTES.CustomersOrders}`,
active: false, active: false,
}, },
{ {
id: 2, id: 2,
label: 'Coupons', label: 'Coupons',
to: '/customers/coupons', to: `${getPluginRoute()}${ROUTES.CustomersCoupons}`,
active: false, active: false,
}, },
]; ];
@ -63,50 +65,50 @@ const SubMenu = () => {
id: 1, id: 1,
label: 'General', label: 'General',
icon: <ExclamationMarkCircle/>, icon: <ExclamationMarkCircle/>,
to: '/settings/general', to: `${getPluginRoute()}${ROUTES.ParametersGeneral}`,
active: false, active: false,
}, },
{ {
id: 2, id: 2,
label: 'Products', label: 'Products',
to: '/settings/products', to: `${getPluginRoute()}${ROUTES.ParametersProducts}`,
active: false, active: false,
}, },
{ {
id: 3, id: 3,
label: 'Shipping', label: 'Shipping',
icon: <Apps/>, icon: <Apps/>,
to: '/settings/shipping', to: `${getPluginRoute()}${ROUTES.ParametersShipping}`,
active: true active: true
}, },
{ {
id: 4, id: 4,
label: 'Payments', label: 'Payments',
to: '/settings/payments', to: `${getPluginRoute()}${ROUTES.ParametersPayments}`,
active: false, active: false,
}, },
{ {
id: 4, id: 4,
label: 'Accounts & Privacy', label: 'Accounts & Privacy',
to: '/settings/accounts', to: `${getPluginRoute()}${ROUTES.ParametersAccounts}`,
active: false, active: false,
}, },
{ {
id: 4, id: 4,
label: 'Emails', label: 'Emails',
to: '/settings/emails', to: `${getPluginRoute()}${ROUTES.ParametersEmails}`,
active: false, active: false,
}, },
{ {
id: 4, id: 4,
label: 'Integration', label: 'Integration',
to: '/settings/integration', to: `${getPluginRoute()}${ROUTES.ParametersIntegration}`,
active: false, active: false,
}, },
{ {
id: 4, id: 4,
label: 'Advanced', label: 'Advanced',
to: '/settings/advanced', to: `${getPluginRoute()}${ROUTES.ParametersAdvanced}`,
active: false, active: false,
} }
]; ];
@ -116,18 +118,18 @@ const SubMenu = () => {
<SubNavHeader searchable value={search} onClear={() => setSearch('')} <SubNavHeader searchable value={search} onClear={() => setSearch('')}
onChange={e => setSearch(e.target.value)} label="Vendors admin" searchLabel="Search..."/> onChange={e => setSearch(e.target.value)} label="Vendors admin" searchLabel="Search..."/>
<SubNavSections> <SubNavSections>
<SubNavSection label="Catalog" collapsable badgeLabel={parameters.length.toString()}> <SubNavSection label="Catalog" collapsable badgeLabel={catalog.length.toString()}>
{catalog.map(link => <SubNavLink to={link.to} active={link.active} key={link.id}> {catalog.map(link => <SubNavLink to={link.to} active={link.active} key={link.id}>
{link.label} {link.label}
</SubNavLink>)} </SubNavLink>)}
</SubNavSection> </SubNavSection>
<SubNavSection label="Customers" collapsable badgeLabel={parameters.length.toString()}> <SubNavSection label="Customers" collapsable badgeLabel={customers.length.toString()}>
{customers.map(link => <SubNavLink to={link.to} active={link.active} key={link.id}> {customers.map(link => <SubNavLink to={link.to} active={link.active} key={link.id}>
{link.label} {link.label}
</SubNavLink>)} </SubNavLink>)}
</SubNavSection> </SubNavSection>
<SubNavSection label="Parameters" collapsable badgeLabel={parameters.length.toString()}> <SubNavSection label="Parameters" collapsable badgeLabel={parameters.length.toString()}>
{parameters.map(link => <SubNavLink to={link.to} isSubSectionChild key={link.id}> {parameters.map(link => <SubNavLink to={link.to} key={link.id}>
{link.label} {link.label}
</SubNavLink>)} </SubNavLink>)}
</SubNavSection> </SubNavSection>

@ -1,9 +1,10 @@
import { prefixPluginTranslations } from '@strapi/helper-plugin'; import {prefixPluginTranslations} from '@strapi/helper-plugin';
import pluginPkg from '../../package.json'; import pluginPkg from '../../package.json';
import pluginId from './pluginId'; import pluginId from './pluginId';
import Initializer from './components/Initializer'; import Initializer from './components/Initializer';
import PluginIcon from './components/PluginIcon'; import PluginIcon from './components/PluginIcon';
import {PERMISSION} from "./utils/constants";
const name = pluginPkg.strapi.name; const name = pluginPkg.strapi.name;
@ -39,15 +40,16 @@ export default {
app.registerPlugin(plugin); app.registerPlugin(plugin);
}, },
bootstrap(app: any) {}, bootstrap(app: any) {
},
async registerTrads(app: any) { async registerTrads(app: any) {
const { locales } = app; const {locales} = app;
const importedTrads = await Promise.all( const importedTrads = await Promise.all(
(locales as any[]).map((locale) => { (locales as any[]).map((locale) => {
return import(`./translations/${locale}.json`) return import(`./translations/${locale}.json`)
.then(({ default: data }) => { .then(({default: data}) => {
return { return {
data: prefixPluginTranslations(data, pluginId), data: prefixPluginTranslations(data, pluginId),
locale, locale,

@ -3,3 +3,9 @@
grid-template-columns: 14.5rem 1fr; grid-template-columns: 14.5rem 1fr;
grid-template-rows: 1fr; grid-template-rows: 1fr;
} }
.vendors-container .vendors-section {
display: flex;
width: 100%;
flex-direction: column;
}

@ -4,16 +4,17 @@
* contain code that should be seen on all pages. (e.g. navigation bar) * contain code that should be seen on all pages. (e.g. navigation bar)
* *
*/ */
import React from 'react';
import React, {useState} from 'react';
import {Switch, Route} from 'react-router-dom'; import {Switch, Route} from 'react-router-dom';
import {AnErrorOccurred} from '@strapi/helper-plugin'; import {AnErrorOccurred} from '@strapi/helper-plugin';
import getPluginRoute from "../../utils/base-route";
import {ROUTES} from "../../utils/constants";
import SubMenu from "../../components/SubMenu"; import SubMenu from "../../components/SubMenu";
import pluginId from '../../pluginId';
import HomePage from '../HomePage'; import CatalogProductsPage from "../Catalog/Products";
import HomePage from '../HomePage';
import './index.css'; import './index.css';
@ -23,10 +24,13 @@ const App = () => {
<aside> <aside>
<SubMenu/> <SubMenu/>
</aside> </aside>
<section className='vendors-section'>
<Switch> <Switch>
<Route path={`/plugins/${pluginId}`} component={HomePage} exact/> <Route path={getPluginRoute()} component={HomePage} exact/>
<Route path={`${getPluginRoute()}${ROUTES.CatalogProducts}`} component={CatalogProductsPage} exact/>
<Route component={AnErrorOccurred}/> <Route component={AnErrorOccurred}/>
</Switch> </Switch>
</section>
</div> </div>
); );
}; };

@ -0,0 +1,19 @@
/*
*
* HomePage
*
*/
import React from 'react';
import { EmptyStateLayout, Button } from '@strapi/design-system';
import {Cross, Plus} from "@strapi/icons";
const CatalogProductEmpty = () => {
return (
<EmptyStateLayout content="You don't have any content yet..." action={<Button variant="secondary" startIcon={<Plus />}>
Create your first product
</Button>} />
);
};
export default CatalogProductEmpty;

@ -0,0 +1,26 @@
/*
*
* HomePage
*
*/
import React, {useState} from 'react';
import {HeaderLayout, Button, Link} from '@strapi/design-system';
import {ArrowLeft, Pencil, Plus} from "@strapi/icons";
import getPluginRoute from "../../../../utils/base-route";
const CatalogProductHeader = ({total}) => {
const [isVisible, setIsVisible] = useState(false);
return (
<HeaderLayout navigationAction={<Link startIcon={<ArrowLeft/>} to={getPluginRoute()}>
Go back
</Link>} primaryAction={<Button startIcon={<Plus/>} onClick={() => setIsVisible(true)}>
Add an entry
</Button>} secondaryAction={<Button variant="tertiary" startIcon={<Pencil/>}>
Edit
</Button>} title="Products" subtitle={total + " entries found"} as="h2"/>
);
};
export default CatalogProductHeader;

@ -0,0 +1,38 @@
/*
*
* HomePage
*
*/
import React from 'react';
import {Pagination, PreviousLink, PageLink, NextLink} from '@strapi/design-system';
import {NavLink} from 'react-router-dom';
const CatalogProductPagination = () => {
const buildUrlWithPageParams = (page: number) => {
const url = new URL(window.location.href);
const searchParams = new URLSearchParams(url.searchParams);
searchParams.set("page", page.toString());
return `${url.pathname.replace('admin/', '')}?${searchParams.toString()}`;
}
return (
<Pagination>
<PreviousLink as={NavLink} to={buildUrlWithPageParams(1)}>
Previous
</PreviousLink>
<PageLink as={NavLink} to={buildUrlWithPageParams(1)}>
1
</PageLink>
<PageLink as={NavLink} to={buildUrlWithPageParams(2)}>
2
</PageLink>
<NextLink as={NavLink} to={buildUrlWithPageParams(2)}>
Next page
</NextLink>
</Pagination>
);
};
export default CatalogProductPagination;

@ -0,0 +1,97 @@
/*
*
* HomePage
*
*/
import React from 'react';
import {
Table,
Thead,
Tbody,
Tr,
Td,
Th,
BaseCheckbox,
Typography,
Avatar,
Flex,
IconButton,
VisuallyHidden,
Box
} from '@strapi/design-system';
import {Pencil, Plus, Trash} from "@strapi/icons";
const CatalogProductTable = ({items}) => {
const ROW_COUNT = 6;
const COL_COUNT = 10;
const entry = {
cover: 'https://avatars.githubusercontent.com/u/3874873?v=4',
description: 'Chez Léon is a human sized Parisian',
category: 'French cuisine',
contact: 'Leon Lafrite'
};
return (
<Table colCount={COL_COUNT} rowCount={ROW_COUNT}>
<Thead>
<Tr>
<Th>
<BaseCheckbox aria-label="Select all entries"/>
</Th>
<Th>
<Typography variant="sigma">ID</Typography>
</Th>
<Th>
<Typography variant="sigma">Cover</Typography>
</Th>
<Th>
<Typography variant="sigma">Description</Typography>
</Th>
<Th>
<Typography variant="sigma">Categories</Typography>
</Th>
<Th>
<Typography variant="sigma">Contact</Typography>
</Th>
<Th>
<VisuallyHidden>Actions</VisuallyHidden>
</Th>
</Tr>
</Thead>
<Tbody>
{items.map(entry => <Tr key={entry.id}>
<Td>
<BaseCheckbox aria-label={`Select ${entry.contact}`}/>
</Td>
<Td>
<Typography textColor="neutral800">{entry.id}</Typography>
</Td>
<Td>
<Avatar src={entry.cover} alt={entry.contact}/>
</Td>
<Td>
<Typography textColor="neutral800">{entry.description}</Typography>
</Td>
<Td>
<Typography textColor="neutral800">{entry.category}</Typography>
</Td>
<Td>
<Typography textColor="neutral800">{entry.contact}</Typography>
</Td>
<Td>
<Flex>
<IconButton onClick={() => console.log('edit')} label="Edit" noBorder icon={<Pencil/>}/>
<Box paddingLeft={1}>
<IconButton onClick={() => console.log('delete')} label="Delete" noBorder icon={<Trash/>}/>
</Box>
</Flex>
</Td>
</Tr>)}
</Tbody>
</Table>
);
};
export default CatalogProductTable;

@ -3,16 +3,47 @@
* HomePage * HomePage
* *
*/ */
import React, {useEffect, useState} from 'react';
import {Box, Typography} from '@strapi/design-system';
import {LoadingIndicatorPage, auth} from '@strapi/helper-plugin';
import React from 'react'; import productsRequests from "../../../api/products.api";
import pluginId from '../../../pluginId';
import CatalogProductTable from "./ProductTable";
import CatalogProductPagination from "./ProductPagination";
import CatalogProductEmpty from "./ProductEmpty";
import CatalogProductHeader from "./ProductHeader";
const CatalogProductsPage = () => { const CatalogProductsPage = () => {
const [isLoading, setIsLoading] = useState(true);
const [products, setProducts] = useState([]);
useEffect(() => {
productsRequests.getProducts().then((products) => {
console.log(products);
console.log(auth.getUserInfo());
setProducts(products);
setIsLoading(false);
});
}, [setProducts]);
const hasProducts = () => products.length > 0;
if (isLoading) return <LoadingIndicatorPage/>;
return ( return (
<div> <Box background={'#f6f6f9'}>
<h1>{pluginId}&apos;s Products's Page</h1> <CatalogProductHeader total={products.length}/>
<p>Happy coding</p>
</div> {!hasProducts() && (<Box paddingLeft={10} paddingRight={10}>
<CatalogProductEmpty/>
</Box>)}
{hasProducts() && (<Box paddingLeft={10} paddingRight={10}>
<CatalogProductTable items={products}/>
<CatalogProductPagination/>
</Box>)}
</Box>
); );
}; };

@ -1 +1,3 @@
{} {
"vendors.plugin.name": "Vendors Admin"
}

@ -1 +1,3 @@
{} {
"vendors.plugin.name": "Boutique Admin"
}

@ -0,0 +1,5 @@
const PLUGIN_ROUTE = '/plugins/vendors';
export default function getPluginRoute() {
return PLUGIN_ROUTE;
}

@ -0,0 +1,19 @@
export enum ROUTES {
CatalogProducts = '/catalog/products',
CatalogCategories = '/catalog/categories',
CatalogFilters = '/catalog/filters',
CustomersOrders = '/customers/orders',
CustomersCoupons = '/customers/coupons',
ParametersGeneral = '/settings/general',
ParametersProducts = '/settings/products',
ParametersShipping = '/settings/shipping',
ParametersPayments = '/settings/payments',
ParametersAccounts = '/settings/accounts',
ParametersEmails = '/settings/emails',
ParametersIntegration = '/settings/integration',
ParametersAdvanced = '/settings/advanced',
}
export enum PERMISSION {
CatalogProductsRead = 'plugin::vendors.read'
}

@ -9,9 +9,10 @@
}, },
"dependencies": { "dependencies": {
"@strapi/design-system": "^1.6.3", "@strapi/design-system": "^1.6.3",
"@strapi/helper-plugin": "^4.6.0", "@strapi/helper-plugin": "^4.10.5",
"@strapi/icons": "^1.6.3", "@strapi/icons": "^1.6.3",
"prop-types": "^15.7.2" "prop-types": "^15.7.2",
"strapi-helper-plugin": "^3.6.11"
}, },
"devDependencies": { "devDependencies": {
"@strapi/typescript-utils": "^4.6.0", "@strapi/typescript-utils": "^4.6.0",

@ -1,5 +1,20 @@
import { Strapi } from '@strapi/strapi'; import { Strapi } from '@strapi/strapi';
export default ({ strapi }: { strapi: Strapi }) => { const RBAC_ACTIONS = [
// bootstrap phase {
section: 'plugins',
displayName: `Access to vendor's administration page`,
uid: 'read',
pluginName: 'vendors',
},
];
export default async ({ strapi }: { strapi: any }) => {
await strapi.admin.services.permission.actionProvider.registerMany(RBAC_ACTIONS);
strapi.store({
environment: '',
type: 'plugin',
name: 'vendors',
});
}; };

@ -1,5 +1,5 @@
import myController from './my-controller'; import products from './products';
export default { export default {
myController, products,
}; };

@ -1,10 +0,0 @@
import { Strapi } from '@strapi/strapi';
export default ({ strapi }: { strapi: Strapi }) => ({
index(ctx) {
ctx.body = strapi
.plugin('vendors')
.service('myService')
.getWelcomeMessage();
},
});

@ -0,0 +1,28 @@
import {Strapi} from '@strapi/strapi';
import {string} from "prop-types";
export default ({strapi}: { strapi: Strapi }) => ({
index(ctx) {
ctx.body = strapi
.plugin('vendors')
.service('vendors')
.getWelcomeMessage();
},
async list(ctx) {
const user = ctx.state.user;
strapi.log.debug(JSON.stringify(user));
const vendor = await strapi.plugin('vendors')
.service('vendors')
.get(user.roles.code);
if (!vendor) {
strapi.log.error('No vendor found');
}
strapi.log.debug(JSON.stringify(vendor));
ctx.body = await strapi.plugin('vendors')
.service('products')
.list(vendor.id);
}
});

@ -2,7 +2,15 @@ export default [
{ {
method: 'GET', method: 'GET',
path: '/', path: '/',
handler: 'myController.index', handler: 'products.index',
config: {
policies: [],
},
},
{
method: 'GET',
path: '/products/list',
handler: 'products.list',
config: { config: {
policies: [], policies: [],
}, },

@ -1,5 +1,7 @@
import myService from './my-service'; import products from './products';
import vendors from './vendors';
export default { export default {
myService, products,
vendors
}; };

@ -1,7 +0,0 @@
import { Strapi } from '@strapi/strapi';
export default ({ strapi }: { strapi: Strapi }) => ({
getWelcomeMessage() {
return 'Welcome to Strapi 🚀';
},
});

@ -0,0 +1,17 @@
import {Strapi} from '@strapi/strapi';
export default ({strapi}: { strapi: Strapi }) => ({
getWelcomeMessage() {
return 'Welcome to Strapi 🚀';
},
async list(vendorId: string) {
console.log(vendorId);
return await strapi.query('api::product.product').findMany({
where: {
vendors: {
id: vendorId
}
}
});
}
});

@ -0,0 +1,14 @@
import {Strapi} from '@strapi/strapi';
export default ({strapi}: { strapi: Strapi }) => ({
getWelcomeMessage() {
return 'Welcome to Strapi 🚀';
},
async get(roleName: string) {
return await strapi.query('api::vendor.vendor').findOne({
where: {
slug: roleName
}
});
}
});

File diff suppressed because it is too large Load Diff

@ -2182,6 +2182,15 @@
"@strapi/utils" "4.10.2" "@strapi/utils" "4.10.2"
sendmail "^1.6.1" sendmail "^1.6.1"
"@strapi/provider-upload-cloudinary@4.10.2":
version "4.10.2"
resolved "https://registry.yarnpkg.com/@strapi/provider-upload-cloudinary/-/provider-upload-cloudinary-4.10.2.tgz#3a355c8a5dd6490aaa18699a27a3b86e949e9649"
integrity sha512-H5ZFPYfXqUIGV6PoU5IfhEX8QYsiA9Xus6p1jitFFHIK9+sVIVLvMgEZrDirgE9CctHIZEAerLaV0JD6mzWzPQ==
dependencies:
"@strapi/utils" "4.10.2"
cloudinary "^1.33.0"
into-stream "^5.1.0"
"@strapi/provider-upload-local@4.10.2": "@strapi/provider-upload-local@4.10.2":
version "4.10.2" version "4.10.2"
resolved "https://registry.npmjs.org/@strapi/provider-upload-local/-/provider-upload-local-4.10.2.tgz" resolved "https://registry.npmjs.org/@strapi/provider-upload-local/-/provider-upload-local-4.10.2.tgz"
@ -3661,6 +3670,21 @@ clone@^1.0.2:
resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz" resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz"
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
cloudinary-core@^2.13.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/cloudinary-core/-/cloudinary-core-2.13.0.tgz#b59f90871b6c708c3d0735b9be47ac08181c57fb"
integrity sha512-Nt0Q5I2FtenmJghtC4YZ3MZZbGg1wLm84SsxcuVwZ83OyJqG9CNIGp86CiI6iDv3QobaqBUpOT7vg+HqY5HxEA==
cloudinary@^1.33.0, cloudinary@^1.41.0:
version "1.41.0"
resolved "https://registry.yarnpkg.com/cloudinary/-/cloudinary-1.41.0.tgz#f9ac2653222ed8fb52d4b3d78ddcf7b5556f8c70"
integrity sha512-qFf2McjvILJITePf4VF1PrY/8c2zy+/q5FVV6V3VWrP/gpIZsusPqXL4QZ6ZKXibPRukzMYqsQEhaSQgJHKKow==
dependencies:
cloudinary-core "^2.13.0"
core-js "^3.30.1"
lodash "^4.17.21"
q "^1.5.1"
co-body@^5.1.1: co-body@^5.1.1:
version "5.2.0" version "5.2.0"
resolved "https://registry.npmjs.org/co-body/-/co-body-5.2.0.tgz" resolved "https://registry.npmjs.org/co-body/-/co-body-5.2.0.tgz"
@ -3952,6 +3976,11 @@ core-js-pure@^3.23.3, core-js-pure@^3.25.1:
resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.30.1.tgz" resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.30.1.tgz"
integrity sha512-nXBEVpmUnNRhz83cHd9JRQC52cTMcuXAmR56+9dSMpRdpeA4I1PX6yjmhd71Eyc/wXNsdBdUDIj1QTIeZpU5Tg== integrity sha512-nXBEVpmUnNRhz83cHd9JRQC52cTMcuXAmR56+9dSMpRdpeA4I1PX6yjmhd71Eyc/wXNsdBdUDIj1QTIeZpU5Tg==
core-js@^3.30.1:
version "3.33.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.1.tgz#ef3766cfa382482d0a2c2bc5cb52c6d88805da52"
integrity sha512-qVSq3s+d4+GsqN0teRCJtM6tdEEXyWxjzbhVrCHmBS5ZTM0FS2MOS0D13dUXAWDUN6a+lHI/N1hF9Ytz6iLl9Q==
core-util-is@1.0.2: core-util-is@1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
@ -5027,6 +5056,14 @@ fresh@0.5.2, fresh@~0.5.2:
resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz"
integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
from2@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
integrity sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==
dependencies:
inherits "^2.0.1"
readable-stream "^2.0.0"
fs-constants@^1.0.0: fs-constants@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz"
@ -5777,6 +5814,14 @@ intl-messageformat@9.13.0:
"@formatjs/icu-messageformat-parser" "2.1.0" "@formatjs/icu-messageformat-parser" "2.1.0"
tslib "^2.1.0" tslib "^2.1.0"
into-stream@^5.1.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-5.1.1.tgz#f9a20a348a11f3c13face22763f2d02e127f4db8"
integrity sha512-krrAJ7McQxGGmvaYbB7Q1mcA+cRwg9Ij2RfWIeVesNBgVDZmzY/Fa4IpZUT3bmdRzMzdf/mzltCG2Dq99IZGBA==
dependencies:
from2 "^2.3.0"
p-is-promise "^3.0.0"
invariant@^2.2.4: invariant@^2.2.4:
version "2.2.4" version "2.2.4"
resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz"
@ -7407,6 +7452,11 @@ p-finally@^1.0.0:
resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz" resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz"
integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==
p-is-promise@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-3.0.0.tgz#58e78c7dfe2e163cf2a04ff869e7c1dba64a5971"
integrity sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==
p-limit@^2.2.0: p-limit@^2.2.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
@ -7924,6 +7974,11 @@ purest@4.0.2:
request-multipart "^1.0.0" request-multipart "^1.0.0"
request-oauth "^1.0.1" request-oauth "^1.0.1"
q@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==
qs@6.11.0: qs@6.11.0:
version "6.11.0" version "6.11.0"
resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz"
@ -8271,9 +8326,9 @@ readable-stream@2.3.7:
string_decoder "~1.1.1" string_decoder "~1.1.1"
util-deprecate "~1.0.1" util-deprecate "~1.0.1"
readable-stream@^2.0.1, readable-stream@~2.3.6: readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@~2.3.6:
version "2.3.8" version "2.3.8"
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
dependencies: dependencies:
core-util-is "~1.0.0" core-util-is "~1.0.0"

Loading…
Cancel
Save