diff --git a/.gitignore b/.gitignore index cf58cef..0b56d06 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .build* -.test_config* \ No newline at end of file +.test_config* +.idea/ \ No newline at end of file diff --git a/.npm/package/npm-shrinkwrap.json b/.npm/package/npm-shrinkwrap.json index 5ed67eb..e85215f 100644 --- a/.npm/package/npm-shrinkwrap.json +++ b/.npm/package/npm-shrinkwrap.json @@ -1,33 +1,25 @@ { + "lockfileVersion": 1, "dependencies": { "cloudinary": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-1.3.1.tgz", - "from": "https://registry.npmjs.org/cloudinary/-/cloudinary-1.3.1.tgz", - "dependencies": { - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "from": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" - }, - "q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "from": "https://registry.npmjs.org/q/-/q-1.4.1.tgz" - } - } + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-1.10.0.tgz", + "integrity": "sha512-+8GXHTNPKAcCKiSGYwdglIUYMjXxKoOgAVXPQMrDEHjSTVovCeqVnUtoXdF+v0RyAkAqK/sun0hJd5uw4o0plA==" }, - "cloudinary-jquery": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/cloudinary-jquery/-/cloudinary-jquery-2.0.9.tgz", - "from": "cloudinary-jquery@2.0.9", - "dependencies": { - "jquery": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.4.tgz", - "from": "jquery@>=1.6.0" - } - } + "cloudinary-core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cloudinary-core/-/cloudinary-core-2.5.0.tgz", + "integrity": "sha512-lrzdLUzFZPnxpWgIAGtOwfqM2D+rG+fLsgd6KqZwDkQX+DYOUNaJpD3lEqxhoMI90zoT1gP/7+pMh/AscSaQ0w==" + }, + "lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" } } } diff --git a/.versions b/.versions index e88b785..0bb35e9 100644 --- a/.versions +++ b/.versions @@ -1,60 +1,54 @@ -allow-deny@1.0.5 -autoupdate@1.2.10 -babel-compiler@6.8.3 -babel-runtime@0.1.9_1 -base64@1.0.9 -binary-heap@1.0.9 -blaze@2.1.8 -blaze-tools@1.0.9 -boilerplate-generator@1.0.9 -caching-compiler@1.0.5_1 -caching-html-compiler@1.0.6 -callback-hook@1.0.9 -check@1.2.3 -coffeescript@1.1.2_1 -ddp@1.2.5 -ddp-client@1.2.8_1 -ddp-common@1.2.6 -ddp-server@1.2.8_1 -deps@1.0.12 -diff-sequence@1.0.6 -ecmascript@0.4.6_1 -ecmascript-runtime@0.2.11_1 -ejson@1.0.12 -geojson-utils@1.0.9 +allow-deny@1.1.0 +autoupdate@1.4.0 +babel-compiler@7.0.4 +babel-runtime@1.2.0 +base64@1.0.10 +binary-heap@1.0.10 +boilerplate-generator@1.4.0 +caching-compiler@1.1.9 +callback-hook@1.1.0 +check@1.3.0 +coffeescript@1.0.17 +ddp@1.4.0 +ddp-client@2.3.1 +ddp-common@1.4.0 +ddp-server@2.1.2 +diff-sequence@1.1.0 +dynamic-import@0.3.0 +ecmascript@0.10.0 +ecmascript-runtime@0.5.0 +ecmascript-runtime-client@0.6.0 +ecmascript-runtime-server@0.5.0 +ejson@1.1.0 +es5-shim@4.7.3 +geojson-utils@1.0.10 hot-code-push@1.0.4 -html-tools@1.0.10 -htmljs@1.0.10 -http@1.1.7 -id-map@1.0.8 -jquery@1.11.9 -lepozepo:cloudinary@4.2.6 +http@1.4.0 +id-map@1.1.0 livedata@1.0.18 -logging@1.0.13_1 -meteor@1.1.15_1 -meteor-base@1.0.4 -minifier-js@1.1.12_1 -minimongo@1.0.17 -modules@0.6.4 -modules-runtime@0.6.4_1 -mongo@1.1.9_1 -mongo-id@1.0.5 -npm-mongo@1.4.44_1 -observe-sequence@1.0.12 -ordered-dict@1.0.8 -promise@0.7.2_1 -random@1.0.10 -reactive-var@1.0.10 -reload@1.1.10 -retry@1.0.8 -routepolicy@1.0.11 -spacebars@1.0.12 -spacebars-compiler@1.0.12 -templating@1.1.12_1 -templating-tools@1.0.4 -tracker@1.0.14 -ui@1.0.11 -underscore@1.0.9 -url@1.0.10 -webapp@1.2.9_1 +lmachens:cloudinary@5.0.5 +logging@1.1.19 +meteor@1.8.2 +meteor-base@1.3.0 +minimongo@1.4.3 +modules@0.11.3 +modules-runtime@0.9.1 +mongo@1.4.2 +mongo-dev-server@1.1.0 +mongo-id@1.0.6 +npm-mongo@2.2.33 +ordered-dict@1.1.0 +promise@0.10.1 +random@1.1.0 +reactive-var@1.0.11 +reload@1.2.0 +retry@1.1.0 +routepolicy@1.0.12 +server-render@0.3.0 +shim-common@0.1.0 +socket-stream-client@0.1.0 +tracker@1.1.3 +underscore@1.0.10 +url@1.2.0 +webapp@1.5.0 webapp-hashing@1.0.9 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f885b32 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +# Change Log + +## [5.0.5] - 2018-02-21 +- Update npm dependencies +## [5.0.4] - 2018-01-04 +- Replace cloudinary-jquery with cloudinary-core to remove jQuery dependency \ No newline at end of file diff --git a/README.md b/README.md index 1e621c7..8147fa1 100644 --- a/README.md +++ b/README.md @@ -1,96 +1,76 @@ +# Fork +This package based on [lepozepo:cloudinary](https://github.com/Lepozepo/cloudinary). +It has no Blaze template helpers and templating-package dependency. In addition, the npm dependencies are updated. + # Cloudinary Image/File Uploader Cloudinary provides a simple way for uploading files to Cloudinary, which in turn can be set up to sync with your Amazon S3 service. This is useful for uploading and actively manipulating images and files that you want accesible to the public. Cloudinary is built on [Cloudinary (NPM)](https://github.com/cloudinary/cloudinary_npm) and [Cloudinary (JS)](https://github.com/cloudinary/cloudinary_js). Installing this package will make `Cloudinary` available server-side and `$.cloudinary` available client-side. -# Show your support! -Star my code in github or atmosphere if you like my code or shoot me a dollar or two! - -[DONATE HERE](https://cash.me/$lepozepo) - -## New Features -- Signed URLs: You can now easily generate a signed url for resources with transformations. -- Expiring URLs: You can now easily generate signed expiring urls for raw resources. -- More Auth Rules: You can now control who can do what easier with the Cloudinary.rules object. -- Improved Uploads: The method for signatures has been improved and now also allows private and authenticated images. -- Download URLs: You can now easily generate temporary download URLs with Meteor.call("c.get_download_url", public_id,ops,callback) - -## Previous Features -- Client to Cloudinary Uploads - ## Installation ``` sh -$ meteor add lepozepo:cloudinary +$ meteor add lmachens:cloudinary ``` ## How to upload ### Step 1 Configure your Cloudinary Credentials and Delete Authorization Rules. SERVER SIDE AND CLIENT SIDE. -``` coffeescript -#SERVER -Cloudinary.config - cloud_name: 'cloud_name' - api_key: '1237419' +``` js +// SERVER +Cloudinary.config({ + cloud_name: 'cloud_name', + api_key: '1237419', api_secret: 'asdf24adsfjk' - -# Rules are all optional -Cloudinary.rules.delete = -> - @userId is "my_user_id" # The rule must return true to pass validation, if you do not set a rule, the validation will always pass - @public_id # The public_id that is being deleted - -Cloudinary.rules.signature = -> # This one checks whether the user is allowed to upload or not - @userId is "my_user_id" # The rule must return true to pass validation, if you do not set a rule, the validation will always pass - -Cloudinary.rules.private_resource = -> - @userId is "my_user_id" # The rule must return true to pass validation, if you do not set a rule, the validation will always pass - -Cloudinary.rules.download_url = -> - @userId is "my_user_id" # The rule must return true to pass validation, if you do not set a rule, the validation will always pass - -#CLIENT -$.cloudinary.config - cloud_name:"cloud_name" +}); + +// Rules are all optional +Cloudinary.rules.delete = () => { + if (this.userId === "my_user_id") { + // The rule must return true to pass validation, if you do not set a rule, the validation will always pass + } + this.public_id; // The public_id that is being deleted +}; + +Cloudinary.rules.signature = () => { // This one checks whether the user is allowed to upload or not + if (this.userId === "my_user_id") { + // The rule must return true to pass validation, if you do not set a rule, the validation will always pass + } +}; + +Cloudinary.rules.private_resource = () => { + if (this.userId === "my_user_id") { + // The rule must return true to pass validation, if you do not set a rule, the validation will always pass + } +}; + +Cloudinary.rules.download_url = () => { + if (this.userId === "my_user_id") { + // The rule must return true to pass validation, if you do not set a rule, the validation will always pass + } +}; + +// CLIENT +$.cloudinary.config({ + cloud_name: "cloud_name" +}); ``` ### Step 2 Wire up your `input[type="file"]`. CLIENT SIDE. -``` coffeescript -Template.yourtemplate.events - "change input[type='file']": (e) -> - files = e.currentTarget.files - - Cloudinary.upload files, - folder:"secret" # optional parameters described in http://cloudinary.com/documentation/upload_images#remote_upload - type:"private" # optional: makes the image accessible only via a signed url. The signed url is available publicly for 1 hour. - (err,res) -> #optional callback, you can catch with the Cloudinary collection as well - console.log "Upload Error: #{err}" - console.log "Upload Result: #{res}" - -``` - - -## How to read and manipulate -All of Cloudinary's manipulation options are available in the c.url helper. You can access an image by passing a cloudinary public_id: - -``` handlebars - - -``` +``` js +Cloudinary.upload(event.currentTarget.files, { + folder: "secret", // optional parameters described in http://cloudinary.com/documentation/upload_images#remote_upload + type: "private", // optional: makes the image accessible only via a signed url. The signed url is available publicly for 1 hour. + (err, res) => { // optional callback, you can catch with the Cloudinary collection as well + console.log(`Upload Error: ${err}`); + console.log(`Upload Result: ${res}`); + } +}); -You can manipulate an image by adding parameters to the helper -``` handlebars - ``` -Obs: If you want to resize your image in a smaller size you will need to pass the `crop` parameter -``` handlebars - -``` -For more information see the cloudinary's documentation: -[http://cloudinary.com/documentation/image_transformations#crop_modes](http://cloudinary.com/documentation/image_transformations#crop_modes) - ## How to protect your images You will need an **Advanced Cloudinary** account before you can make your images fully private. Once you have your account you can do one of 2 things: @@ -117,19 +97,19 @@ App.accessRule("blob:*"); ## How to delete from Cloudinary Just pass the public_id of the image or file through this function (security features pending). It will return an object with a list of the images deleted as a result. -``` coffeescript -Template.yourtemplate.events - "click button.delete": -> - Cloudinary.delete @response.public_id, (err,res) -> - console.log "Upload Error: #{err}" - console.log "Upload Result: #{res}" +``` js +Cloudinary.delete(response.public_id, (err,res) => { + console.log(`Upload Error: ${err}`); + console.log(`Upload Result: ${res}`); +}); ``` ## How to generate a downloadable link -``` coffeescript -Meteor.call "c.get_download_url", public_id,(err,download_url) -> - console.log "Upload Error: #{err}" - console.log "#{download_url}" +``` js +Meteor.call("c.get_download_url", public_id, (err,d ownload_url) => { + console.log(`Upload Error: ${err}`); + console.log(download_url); +}); ``` ### API @@ -145,28 +125,18 @@ Meteor.call "c.get_download_url", public_id,(err,download_url) -> - Cloudinary.rules.download_url: Checks whether fetching a download link for a resource is allowed. Return true to allow the action. ### Helpers -- {{c.url public_id options}}: Generates a url + +- Cloudinary.url(public_id, options): Generates a url - public_id: The public ID returned after uploading a resource - options: A set of transformations described here [http://cloudinary.com/documentation/image_transformations#reference](http://cloudinary.com/documentation/image_transformations#reference) -- {{c.private_url public_id options}}: Generates a signed url +- Cloudinary.private_url(public_id, options): Generates a signed url - public_id: The public ID returned after uploading a resource - options: A set of transformations described here [http://cloudinary.com/documentation/image_transformations#reference](http://cloudinary.com/documentation/image_transformations#reference) -- {{c.expiring_url public_id}}: Generates a url that will expire in 1 hour, does not take any transformations +- Cloudinary.expiring_url(public_id): Generates a url that will expire in 1 hour, does not take any transformations - public_id: The public ID returned after uploading a resource ## Notes A security filter is missing, I know how I want it to work I just haven't had the time to build it. Enjoy the new version! - -### Donations and Sponsors - Thank You's -**If you prefer I list your github account let me know [who you are](https://github.com/Lepozepo/cloudinary/issues/56)!** - -- Casey R. -- David M. -- NetLive IT - - - - diff --git a/client/functions.coffee b/client/functions.coffee deleted file mode 100644 index 769da89..0000000 --- a/client/functions.coffee +++ /dev/null @@ -1,150 +0,0 @@ -Cloudinary = - collection: new Mongo.Collection "_cloudinary", connection:null - _private_urls:{} - _expiring_urls:{} - xhr:null - _helpers: - "url": (public_id,options) -> - if public_id and not _.isEmpty public_id - $.cloudinary.url(public_id,options.hash) - - "private_url":(public_id,options) -> - private_url = Cloudinary._private_urls[public_id] - if not private_url - Cloudinary._private_urls[public_id] = new ReactiveVar "" - private_url = Cloudinary._private_urls[public_id] - - if public_id and not _.isEmpty(public_id) and _.isEmpty(private_url.get()) - Meteor.call "c.get_private_resource",public_id,options.hash,(error,result) -> - if error - throw new Meteor.Error "Cloudinary","Failed to sign and fetch image" - else - private_url.set result - - private_url.get() - - "expiring_url":(public_id,options) -> - expiring_url = Cloudinary._expiring_urls[public_id] - if not expiring_url - Cloudinary._expiring_urls[public_id] = new ReactiveVar "" - expiring_url = Cloudinary._expiring_urls[public_id] - - if public_id and not _.isEmpty(public_id) and _.isEmpty(expiring_url.get()) - Meteor.call "c.get_download_url",public_id,options.hash,(error,result) -> - if error - throw new Meteor.Error "Cloudinary","Failed to sign and fetch image" - else - expiring_url.set result - - expiring_url.get() - - - delete: (public_id, type, callback) -> - if _.isFunction type - callback = type - type = undefined - - Meteor.call "c.delete_by_public_id", public_id, type, (error,result) -> - if error - return callback and callback error, null - else - if result.deleted[public_id] and result.deleted[public_id] is "not_found" - return callback and callback result, null - else - return callback and callback null,result - - upload: (files, ops={}, callback) -> - if _.isFunction ops - callback = ops - ops = {} - - if files instanceof File or files instanceof Blob - file = files - reader = new FileReader - - reader.onload = -> - Cloudinary._upload_file reader.result, ops, callback - - return reader.readAsDataURL file - - if _.isArray(files) or files instanceof FileList - _.each files, (file) -> - reader = new FileReader - - reader.onload = -> - Cloudinary._upload_file reader.result, ops, callback - - reader.readAsDataURL file - - _upload_file: (file, ops={}, callback) -> - Meteor.call "c.sign", ops, (error,result) -> - if error - return callback and callback error,null - - # Build form - form_data = new FormData() - _.each result.hidden_fields, (v,k) -> - form_data.append k,v - - form_data.append "file",file - - # Create collection document ID - collection_id = Random.id() - - # Send data - Cloudinary.xhr = new XMLHttpRequest() - - Cloudinary.collection.insert - _id:collection_id - status:"uploading" - preview:file - - Cloudinary.xhr.upload.addEventListener "progress", (event) -> - Cloudinary.collection.update _id:collection_id, - $set: - loaded:event.loaded - total:event.total - percent_uploaded: Math.floor ((event.loaded / event.total) * 100) - ,false - - Cloudinary.xhr.addEventListener "load", -> - if Cloudinary.xhr.status < 400 - response = JSON.parse @response - Cloudinary.collection.upsert collection_id, - $set: - status:"complete" - percent_uploaded: 100 - response: response - - callback and callback null,response - else - response = JSON.parse @response - Cloudinary.collection.upsert collection_id, - $set: - status:"error" - response: response - - callback and callback response,null - - Cloudinary.xhr.addEventListener "error", -> - response = JSON.parse @response - Cloudinary.collection.upsert collection_id, - $set: - status:"error" - response: response - - callback and callback response,null - - Cloudinary.xhr.addEventListener "abort", -> - Cloudinary.collection.upsert collection_id, - $set: - status:"aborted" - - Cloudinary.xhr.open "POST",result.form_attrs.action,true - - Cloudinary.xhr.send form_data - - -# Define helpers -Template.registerHelper "c", -> - Cloudinary._helpers \ No newline at end of file diff --git a/client/functions.js b/client/functions.js new file mode 100644 index 0000000..c1f58d2 --- /dev/null +++ b/client/functions.js @@ -0,0 +1,203 @@ +const cloudinary = require('cloudinary-core'); + +const cl = cloudinary.Cloudinary.new(); + +Cloudinary = { + collection: new Mongo.Collection('_cloudinary', { connection: null }), + _private_urls: {}, + _expiring_urls: {}, + xhr: null, + config(options) { + return cl.config(options); + }, + url(public_id, options) { + if (public_id && !_.isEmpty(public_id)) { + return cl.url(public_id, options); + } + }, + + private_url(public_id, options) { + let private_url = Cloudinary._private_urls[public_id]; + if (!private_url) { + Cloudinary._private_urls[public_id] = new ReactiveVar(''); + private_url = Cloudinary._private_urls[public_id]; + } + + if (public_id && !_.isEmpty(public_id) && _.isEmpty(private_url.get())) { + Meteor.call('c.get_private_resource', public_id, options.hash, function(error, result) { + if (error) { + throw new Meteor.Error('Cloudinary', 'Failed to sign and fetch image'); + } else { + return private_url.set(result); + } + }); + } + + return private_url.get(); + }, + + expiring_url(public_id, options) { + let expiring_url = Cloudinary._expiring_urls[public_id]; + if (!expiring_url) { + Cloudinary._expiring_urls[public_id] = new ReactiveVar(''); + expiring_url = Cloudinary._expiring_urls[public_id]; + } + + if (public_id && !_.isEmpty(public_id) && _.isEmpty(expiring_url.get())) { + Meteor.call('c.get_download_url', public_id, options.hash, function(error, result) { + if (error) { + throw new Meteor.Error('Cloudinary', 'Failed to sign and fetch image'); + } else { + return expiring_url.set(result); + } + }); + } + + return expiring_url.get(); + }, + + delete(public_id, type, callback) { + if (_.isFunction(type)) { + callback = type; + type = undefined; + } + + return Meteor.call('c.delete_by_public_id', public_id, type, function(error, result) { + if (error) { + return callback && callback(error, null); + } else { + if (result.deleted[public_id] && result.deleted[public_id] === 'not_found') { + return callback && callback(result, null); + } else { + return callback && callback(null, result); + } + } + }); + }, + + upload(files, ops, callback) { + let reader; + if (ops == null) { + ops = {}; + } + if (_.isFunction(ops)) { + callback = ops; + ops = {}; + } + + if (files instanceof File || files instanceof Blob) { + const file = files; + reader = new FileReader(); + + reader.onload = () => Cloudinary._upload_file(reader.result, ops, callback); + + return reader.readAsDataURL(file); + } + + if (_.isArray(files) || files instanceof FileList) { + return _.each(files, function(file) { + reader = new FileReader(); + + reader.onload = () => Cloudinary._upload_file(reader.result, ops, callback); + + return reader.readAsDataURL(file); + }); + } + }, + + _upload_file(file, ops, callback) { + if (ops == null) { + ops = {}; + } + return Meteor.call('c.sign', ops, function(error, result) { + if (error) { + return callback && callback(error, null); + } + + // Build form + const form_data = new FormData(); + _.each(result.hidden_fields, (v, k) => form_data.append(k, v)); + + form_data.append('file', file); + + // Create collection document ID + const collection_id = Random.id(); + + // Send data + Cloudinary.xhr = new XMLHttpRequest(); + + Cloudinary.collection.insert({ + _id: collection_id, + status: 'uploading', + preview: file + }); + + Cloudinary.xhr.upload.addEventListener( + 'progress', + event => + Cloudinary.collection.update( + { _id: collection_id }, + { + $set: { + loaded: event.loaded, + total: event.total, + percent_uploaded: Math.floor((event.loaded / event.total) * 100) + } + } + ), + + false + ); + + Cloudinary.xhr.addEventListener('load', function() { + let response; + if (Cloudinary.xhr.status < 400) { + response = JSON.parse(this.response); + Cloudinary.collection.upsert(collection_id, { + $set: { + status: 'complete', + percent_uploaded: 100, + response + } + }); + + return callback && callback(null, response); + } else { + response = JSON.parse(this.response); + Cloudinary.collection.upsert(collection_id, { + $set: { + status: 'error', + response + } + }); + + return callback && callback(response, null); + } + }); + + Cloudinary.xhr.addEventListener('error', function() { + const response = JSON.parse(this.response); + Cloudinary.collection.upsert(collection_id, { + $set: { + status: 'error', + response + } + }); + + return callback && callback(response, null); + }); + + Cloudinary.xhr.addEventListener('abort', () => + Cloudinary.collection.upsert(collection_id, { + $set: { + status: 'aborted' + } + }) + ); + + Cloudinary.xhr.open('POST', result.form_attrs.action, true); + + return Cloudinary.xhr.send(form_data); + }); + } +}; diff --git a/example/basic/client/basic.jade b/example/basic/client/basic.jade index b53e586..6f2b2c0 100644 --- a/example/basic/client/basic.jade +++ b/example/basic/client/basic.jade @@ -18,7 +18,7 @@ template(name="tester") p {{percent_uploaded}} % p {{response.public_id}} if complete - img(src="{{c.url response.public_id effect='blur:300' angle=10}}") + img(src="{{Cloudinary.url response.public_id effect='blur:300' angle=10}}") p {{status}} diff --git a/example/basic1_2/client/basic.jade b/example/basic1_2/client/basic.jade index a05cb3f..53b7aec 100644 --- a/example/basic1_2/client/basic.jade +++ b/example/basic1_2/client/basic.jade @@ -15,9 +15,9 @@ template(name="tester") h5 uploaded files each uploaded_images - img(src="{{c.url public_id effect='blur:300' angle=10}}") - img(src="{{c.private_url public_id effect='blur:300' angle=10}}") - img(src="{{c.expiring_url public_id}}") + img(src="{{Cloudinary.url public_id effect='blur:300' angle=10}}") + img(src="{{Cloudinary.private_url public_id effect='blur:300' angle=10}}") + img(src="{{Cloudinary.expiring_url public_id}}") button.delete Delete button.delete_private Delete Private @@ -26,9 +26,9 @@ template(name="tester") //- p {{percent_uploaded}} % //- p {{response.public_id}} //- if complete - //- img(src="{{c.url response.public_id effect='blur:300' angle=10}}") - //- img(src="{{c.private_url response.public_id effect='blur:300' angle=10}}") - //- img(src="{{c.expiring_url response.public_id format='jpg' effect='blur:300' angle=10}}") + //- img(src="{{Cloudinary.url response.public_id effect='blur:300' angle=10}}") + //- img(src="{{Cloudinary.private_url response.public_id effect='blur:300' angle=10}}") + //- img(src="{{Cloudinary.expiring_url response.public_id format='jpg' effect='blur:300' angle=10}}") //- button.delete Delete //- button.delete_private Delete Private diff --git a/example/collection-hooks/client/collection-hooks.html b/example/collection-hooks/client/collection-hooks.html index 45fb1fa..1647347 100644 --- a/example/collection-hooks/client/collection-hooks.html +++ b/example/collection-hooks/client/collection-hooks.html @@ -31,8 +31,8 @@

Cloudinary Upload Stream

Saved images

{{#each saved_images}}
- - + + {{/each}} diff --git a/package.js b/package.js index f8d2908..ec56c5a 100644 --- a/package.js +++ b/package.js @@ -1,35 +1,32 @@ Package.describe({ - name:"lepozepo:cloudinary", - summary: "Upload files to Cloudinary", - version:"4.2.6", - git:"https://github.com/Lepozepo/cloudinary" + name: 'lmachens:cloudinary', + summary: 'Upload files to Cloudinary', + version: '5.0.6', + git: 'https://github.com/lmachens/cloudinary' }); Npm.depends({ - cloudinary: "1.9.0", - "cloudinary-jquery": "2.3.0" + cloudinary: '1.10.0', // Server side + 'cloudinary-core': '2.5.0' // Client side }); -Package.on_use(function (api){ - api.versionsFrom('METEOR@1.0'); +Package.onUse(function(api) { + api.versionsFrom('METEOR@1.0'); - // Core Packages - api.use(["meteor-base@1.0.1","coffeescript","mongo","underscore"], ["client", "server"]); - api.use(["templating"], "client"); - api.use(["check","random","reactive-var"], ["client","server"]); + // Core Packages + api.use(['meteor-base@1.0.1', 'mongo', 'underscore'], ['client', 'server']); + api.use(['check', 'ecmascript@0.9.0', 'random', 'reactive-var'], ['client', 'server']); - // External Packages - api.use(["matb33:collection-hooks@0.7.3","audit-argument-checks"], ["client", "server"],{weak:true}); + // External Packages + api.use(['matb33:collection-hooks@0.7.3', 'audit-argument-checks'], ['client', 'server'], { + weak: true + }); - // Cloudinary Client Side - api.add_files(".npm/package/node_modules/cloudinary-jquery/cloudinary-jquery.min.js","client"); + // Core Files + api.addFiles('server/configuration.js', 'server'); + api.addFiles('server/signature.js', 'server'); - // Core Files - api.add_files("server/configuration.coffee", "server"); - api.add_files("server/signature.coffee", "server"); + api.addFiles('client/functions.js', 'client'); - api.add_files("client/functions.coffee", "client"); - - api.export && api.export("Cloudinary",["server","client"]); + api.export('Cloudinary', ['server', 'client']); }); - diff --git a/server/configuration.coffee b/server/configuration.coffee deleted file mode 100644 index e475788..0000000 --- a/server/configuration.coffee +++ /dev/null @@ -1,3 +0,0 @@ -Cloudinary = Npm.require "cloudinary" - -Cloudinary.rules = {} diff --git a/server/configuration.js b/server/configuration.js new file mode 100644 index 0000000..d5da4d8 --- /dev/null +++ b/server/configuration.js @@ -0,0 +1,3 @@ +Cloudinary = Npm.require('cloudinary'); + +Cloudinary.rules = {}; diff --git a/server/signature.coffee b/server/signature.coffee deleted file mode 100644 index b7045e1..0000000 --- a/server/signature.coffee +++ /dev/null @@ -1,78 +0,0 @@ -Future = Npm.require "fibers/future" - -Meteor.methods - "c.sign": (ops={}) -> - check ops, Match.Optional(Object) - @unblock() - - if Cloudinary.rules.signature - @options = ops - auth_function = _.bind Cloudinary.rules.signature,this - if not auth_function() - throw new Meteor.Error "Unauthorized", "Signature not allowed" - - # Need to add some way to do custom auth - # signature = Cloudinary.utils.sign_request ops - signature = Cloudinary.uploader.direct_upload "",ops # This is better than utils.sign_request, it returns a POST url as well and properly manages optional parameters - - return signature - - - "c.delete_by_public_id": (public_id,type) -> - check public_id, String - check type, Match.OneOf(String,undefined,null) - @unblock() - - if Cloudinary.rules.delete - @public_id = public_id - auth_function = _.bind Cloudinary.rules.delete,this - if not auth_function() - throw new Meteor.Error "Unauthorized", "Delete not allowed" - - if type - ops = - type:type - - future = new Future() - - Cloudinary.api.delete_resources [public_id], (result) -> - future.return result - ,ops - - return future.wait() - - "c.get_private_resource": (public_id,ops={}) -> - check public_id, String - check ops, Match.Optional(Object) - @unblock() - - _.extend ops, - sign_url:true - type:"private" - - if Cloudinary.rules.private_resource - @public_id = public_id - auth_function = _.bind Cloudinary.rules.private_resource,this - if not auth_function() - throw new Meteor.Error "Unauthorized", "Access not allowed" - - - Cloudinary.url public_id,ops - - "c.get_download_url": (public_id,ops={}) -> - check public_id, String - check ops, Match.Optional(Object) - @unblock() - - if Cloudinary.rules.download_url - @public_id = public_id - auth_function = _.bind Cloudinary.rules.download_url,this - if not auth_function() - throw new Meteor.Error "Unauthorized", "Access not allowed" - - format = ops.format or "" - - Cloudinary.utils.private_download_url public_id,format,_.omit(ops,"format") - - - diff --git a/server/signature.js b/server/signature.js new file mode 100644 index 0000000..d0bcce6 --- /dev/null +++ b/server/signature.js @@ -0,0 +1,103 @@ +const Future = Npm.require("fibers/future"); + +Meteor.methods({ + "c.sign"(ops) { + if (ops == null) { + ops = {}; + } + check(ops, Match.Optional(Object)); + this.unblock(); + + if (Cloudinary.rules.signature) { + this.options = ops; + const auth_function = _.bind(Cloudinary.rules.signature, this); + if (!auth_function()) { + throw new Meteor.Error("Unauthorized", "Signature not allowed"); + } + } + + // Need to add some way to do custom auth + // signature = Cloudinary.utils.sign_request ops + const signature = Cloudinary.uploader.direct_upload("", ops); // This is better than utils.sign_request, it returns a POST url as well and properly manages optional parameters + + return signature; + }, + + + "c.delete_by_public_id"(public_id, type) { + let ops; + check(public_id, String); + check(type, Match.OneOf(String, undefined, null)); + this.unblock(); + + if (Cloudinary.rules.delete) { + this.public_id = public_id; + const auth_function = _.bind(Cloudinary.rules.delete, this); + if (!auth_function()) { + throw new Meteor.Error("Unauthorized", "Delete not allowed"); + } + } + + if (type) { + ops = + {type}; + } + + const future = new Future(); + + Cloudinary.api.delete_resources([public_id], result => future.return(result) + , ops); + + return future.wait(); + }, + + "c.get_private_resource"(public_id, ops) { + if (ops == null) { + ops = {}; + } + check(public_id, String); + check(ops, Match.Optional(Object)); + this.unblock(); + + _.extend(ops, { + sign_url: true, + type: "private" + } + ); + + if (Cloudinary.rules.private_resource) { + this.public_id = public_id; + const auth_function = _.bind(Cloudinary.rules.private_resource, this); + if (!auth_function()) { + throw new Meteor.Error("Unauthorized", "Access not allowed"); + } + } + + + return Cloudinary.url(public_id, ops); + }, + + "c.get_download_url"(public_id, ops) { + if (ops == null) { + ops = {}; + } + check(public_id, String); + check(ops, Match.Optional(Object)); + this.unblock(); + + if (Cloudinary.rules.download_url) { + this.public_id = public_id; + const auth_function = _.bind(Cloudinary.rules.download_url, this); + if (!auth_function()) { + throw new Meteor.Error("Unauthorized", "Access not allowed"); + } + } + + const format = ops.format || ""; + + return Cloudinary.utils.private_download_url(public_id, format, _.omit(ops, "format")); + } +}); + + +