Files
odoo_source/addons/web_unsplash/controllers/main.py
T
Samuel Degueldre 807ac81144 [IMP] web_editor, *: set image alt automatically, remove useless alts
*: website, web_unplash

The html alt attribute is supposed to contain a description of an
image's content (an alternative to the visual representation), a lot of
snippets contained alt attributes that were not descriptive of their
content, and would as such be counter-productive in terms of
accessibility. This commit removes those.

Previously, the alt attribute on img tags had to be set manually by the
user through the editor. This commit makes use of the description field
on ir.attachment to store image description, and sets the alt attribute
on images to that description when choosing an image from the media
dialog.

task-2091417
closes odoo/odoo#45174

Related: odoo/enterprise#9520
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
2020-03-30 11:07:10 +00:00

150 lines
5.9 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import base64
import logging
import mimetypes
import requests
import werkzeug.utils
from odoo import http, tools, _
from odoo.http import request
from odoo.tools.mimetypes import guess_mimetype
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
# ------------------------------------------------------
@http.route('/web_unsplash/attachment/add', type='json', auth='user', methods=['POST'])
def save_unsplash_url(self, unsplashurls=None, **kwargs):
"""
unsplashurls = {
image_id1: {
url: image_url,
download_url: download_url,
},
image_id2: {
url: image_url,
download_url: download_url,
},
.....
}
"""
def slugify(s):
''' Keeps only alphanumeric characters, hyphens and spaces from a string.
The string will also be truncated to 1024 characters max.
:param s: the string to be filtered
:return: the sanitized string
'''
return "".join([c for c in s if c.isalnum() or c in list("- ")])[:1024]
if not unsplashurls:
return []
uploads = []
Attachments = request.env['ir.attachment']
query = kwargs.get('query', '')
query = slugify(query)
res_model = kwargs.get('res_model', 'ir.ui.view')
if res_model != 'ir.ui.view' and kwargs.get('res_id'):
res_id = int(kwargs['res_id'])
else:
res_id = None
for key, value in unsplashurls.items():
url = value.get('url')
try:
if not url.startswith('https://images.unsplash.com/'):
logger.exception("ERROR: Unknown Unsplash URL!: " + url)
raise Exception(_("ERROR: Unknown Unsplash URL!"))
req = requests.get(url)
if req.status_code != requests.codes.ok:
continue
# get mime-type of image url because unsplash url dosn't contains mime-types in url
image_base64 = base64.b64encode(req.content)
except requests.exceptions.ConnectionError as e:
logger.exception("Connection Error: " + str(e))
continue
except requests.exceptions.Timeout as e:
logger.exception("Timeout: " + str(e))
continue
image_base64 = tools.image_process(image_base64, verify_resolution=True)
mimetype = guess_mimetype(base64.b64decode(image_base64))
# append image extension in name
query += mimetypes.guess_extension(mimetype) or ''
# /unsplash/5gR788gfd/lion
url_frags = ['unsplash', key, query]
attachment = Attachments.create({
'name': '_'.join(url_frags),
'url': '/' + '/'.join(url_frags),
'mimetype': mimetype,
'datas': image_base64,
'public': res_model == 'ir.ui.view',
'res_id': res_id,
'res_model': res_model,
'description': value.get('description'),
})
attachment.generate_access_token()
uploads.append(attachment._get_media_info())
# Notifies Unsplash from an image download. (API requirement)
self._notify_download(value.get('download_url'))
return uploads
@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):
return request.env['ir.config_parameter'].sudo().get_param('unsplash.app_id')
@http.route("/web_unsplash/save_unsplash", type='json', auth="user")
def save_unsplash(self, **post):
if request.env.user._has_unsplash_key_rights():
request.env['ir.config_parameter'].sudo().set_param('unsplash.app_id', post.get('appId'))
request.env['ir.config_parameter'].sudo().set_param('unsplash.access_key', post.get('key'))
return True
raise werkzeug.exceptions.NotFound()