diff --git a/addons/web_unsplash/__manifest__.py b/addons/web_unsplash/__manifest__.py index 3ad4b1334b3..a139e64743b 100644 --- a/addons/web_unsplash/__manifest__.py +++ b/addons/web_unsplash/__manifest__.py @@ -4,7 +4,7 @@ 'name': 'Unsplash Image Library', 'category': 'Web', 'summary': 'Find free high-resolution images from Unsplash', - 'version': '1.0', + 'version': '1.1', 'description': """Explore the free high-resolution image library of Unsplash.com and find images to use in Odoo. An Unsplash search bar is added to the image library modal.""", 'depends': ['base_setup', 'web_editor'], 'data': [ diff --git a/addons/web_unsplash/controllers/main.py b/addons/web_unsplash/controllers/main.py index c53c03ba5bf..7a53cd8e115 100644 --- a/addons/web_unsplash/controllers/main.py +++ b/addons/web_unsplash/controllers/main.py @@ -9,12 +9,34 @@ import werkzeug.utils from PIL import Image from odoo import http, tools, _ from odoo.http import request +from werkzeug.urls import url_encode logger = logging.getLogger(__name__) class Web_Unsplash(http.Controller): + def _get_access_key(self): + if request.env.user._has_unsplash_key_rights(): + return request.env['ir.config_parameter'].sudo().get_param('unsplash.access_key') + raise werkzeug.exceptions.NotFound() + + def _notify_download(self, url): + ''' Notifies Unsplash from an image download. (API requirement) + :param url: the download_url of the image to be notified + + This method won't return anything. This endpoint should just be + pinged with a simple GET request for Unsplash to increment the image + view counter. + ''' + try: + if not url.startswith('https://api.unsplash.com/photos/'): + raise Exception(_("ERROR: Unknown Unsplash notify URL!")) + access_key = self._get_access_key() + requests.get(url, params=url_encode({'client_id': access_key})) + except Exception as e: + logger.exception("Unsplash download notification failed: " + str(e)) + # ------------------------------------------------------ # add unsplash image url # ------------------------------------------------------ @@ -22,8 +44,14 @@ class Web_Unsplash(http.Controller): def save_unsplash_url(self, unsplashurls=None, **kwargs): """ unsplashurls = { - image_id1: image_url1, - image_id2: image_url2, + image_id1: { + url: image_url, + download_url: download_url, + }, + image_id2: { + url: image_url, + download_url: download_url, + }, ..... } """ @@ -82,13 +110,23 @@ class Web_Unsplash(http.Controller): attachment.generate_access_token() uploads.extend(attachment.read(['name', 'mimetype', 'checksum', 'res_id', 'res_model', 'access_token', 'url'])) + # Notifies Unsplash from an image download. (API requirement) + self._notify_download(value.get('download_url')) + return uploads - @http.route("/web_unsplash/get_client_id", type='json', auth="user") - def get_unsplash_client_id(self, **post): - if request.env.user._has_unsplash_key_rights(): - return request.env['ir.config_parameter'].sudo().get_param('unsplash.access_key') - raise werkzeug.exceptions.NotFound() + @http.route("/web_unsplash/fetch_images", type='json', auth="user") + def fetch_unsplash_images(self, **post): + access_key = self._get_access_key() + app_id = self.get_unsplash_app_id() + if not access_key or not app_id: + return {'error': 'key_not_found'} + post['client_id'] = access_key + response = requests.get('https://api.unsplash.com/search/photos/', params=url_encode(post)) + if response.status_code == requests.codes.ok: + return response.json() + else: + return {'error': response.status_code} @http.route("/web_unsplash/get_app_id", type='json', auth="public") def get_unsplash_app_id(self, **post): diff --git a/addons/web_unsplash/static/src/js/unsplash_image_widget.js b/addons/web_unsplash/static/src/js/unsplash_image_widget.js index d353694ddea..ab900d6a03c 100644 --- a/addons/web_unsplash/static/src/js/unsplash_image_widget.js +++ b/addons/web_unsplash/static/src/js/unsplash_image_widget.js @@ -88,10 +88,6 @@ ImageWidget.include({ res_id: self.options.res_id, } }).then(function (images) { - for (var img in self._unsplash.selectedImages) { - self.unsplashAPI.notifyDownload(self._unsplash.selectedImages[img].download_url); - } - _.each(images, function (image) { image.src = image.url; image.isDocument = !(/gif|jpe|jpg|png/.test(image.mimetype)); @@ -140,7 +136,7 @@ ImageWidget.include({ self.$('.unsplash_img_container').html(QWeb.render('web_unsplash.dialog.image.content', { rows: rows })); self._highlightSelectedImages(); }).fail(function (err) { - self.$('.unsplash_img_container').html(QWeb.render('web_unsplash.dialog.error.content', err)); + self.$('.unsplash_img_container').html(QWeb.render('web_unsplash.dialog.error.content', { status: err })); }).always(function () { self._toggleAttachmentContaines(false); }); diff --git a/addons/web_unsplash/static/src/js/unsplashapi.js b/addons/web_unsplash/static/src/js/unsplashapi.js index 0ceb2b8f8a7..a6ec5b75324 100644 --- a/addons/web_unsplash/static/src/js/unsplashapi.js +++ b/addons/web_unsplash/static/src/js/unsplashapi.js @@ -38,45 +38,15 @@ var UnsplashCore = Class.extend(Mixins.EventDispatcherMixin, ServicesMixin, { if (cachedData && (cachedData.images.length >= to || (cachedData.totalImages !== 0 && cachedData.totalImages < to))) { return $.when({ images: cachedData.images.slice(from, to), isMaxed: to > cachedData.totalImages }); } - return this._getAPIKey().then(function (clientID) { - if (!clientID) { - return $.Deferred().reject({ key_not_found: true }); - } - return self._fetchImages(query).then(function (cachedData) { - return { images: cachedData.images.slice(from, to), isMaxed: to > cachedData.totalImages }; - }); + return self._fetchImages(query).then(function (cachedData) { + return { images: cachedData.images.slice(from, to), isMaxed: to > cachedData.totalImages }; }); }, - /** - * Notifies Unsplash from an image download. (API requirement) - * - * @param {String} url url of the image to notify - */ - notifyDownload: function (url) { - $.get(url, { client_id: this.clientId }); - }, //-------------------------------------------------------------------------- // Private //-------------------------------------------------------------------------- - /** - * Checks and retrieves the unsplash API key - * - * @private - */ - _getAPIKey: function () { - var self = this; - if (this.clientId) { - return $.Deferred().resolve(self.clientId); - } - return this._rpc({ - route: '/web_unsplash/get_client_id', - }).then(function (res) { - self.clientId = res; - return res; - }); - }, /** * Fetches images from unsplash and stores it in cache * @@ -96,10 +66,15 @@ var UnsplashCore = Class.extend(Mixins.EventDispatcherMixin, ServicesMixin, { var payload = { query: query, page: cachedData.pageCached + 1, - client_id: this.clientId, per_page: 30, // max size from unsplash API }; - return $.get('https://api.unsplash.com/search/photos/', payload).then(function (result) { + return this._rpc({ + route: '/web_unsplash/fetch_images', + params: payload, + }).then(function (result) { + if (result.error) { + return $.Deferred().reject(result.error); + } cachedData.pageCached++; cachedData.images.push.apply(cachedData.images, result.results); cachedData.maxPages = result.total_pages; diff --git a/addons/web_unsplash/static/src/xml/unsplash_image_widget.xml b/addons/web_unsplash/static/src/xml/unsplash_image_widget.xml index 409c435884b..05202e073b2 100644 --- a/addons/web_unsplash/static/src/xml/unsplash_image_widget.xml +++ b/addons/web_unsplash/static/src/xml/unsplash_image_widget.xml @@ -50,7 +50,7 @@
- + Unsplash requires an access key and an application ID