diff --git a/mfr/core/utils.py b/mfr/core/utils.py index 079f88457..9f7803909 100644 --- a/mfr/core/utils.py +++ b/mfr/core/utils.py @@ -1,6 +1,10 @@ +from time import time +from os.path import getctime + from stevedore import driver from mfr.core import exceptions +from mfr.extensions import settings as ext_settings def make_provider(name, request, url): @@ -97,6 +101,7 @@ def make_renderer(name, metadata, file_path, url, assets_url, export_url): } ) + def sizeof_fmt(num, suffix='B'): if abs(num) < 1000: return '%3.0f%s' % (num, suffix) @@ -106,3 +111,33 @@ def sizeof_fmt(num, suffix='B'): return '%3.1f%s%s' % (num, unit, suffix) num /= 1000.0 return '%.1f%s%s' % (num, 'Y', suffix) + + +def file_expired(path: str, ttl: int) -> bool: + """Helper method that checks if a file's last change time has expired ttl. + + :param path: the path of the file + :param ttl: the expiration time in seconds + :return: True if expired, False otherwise + """ + + if (time() - getctime(path)) >= ttl: + return True + return False + + +def get_full_file_ext(file_ext: str, file_name: str) -> str: + """Helper method that checks if a secondary extension exists for a file + with a compressed extension as primary. If so, returns the full extension. + + :param metadata_ext: the file's primary extension + :param metadata_name: the file name that may contain a secondary extension + :return: the file's full extension + """ + + compressed_ext = ext_settings.COMPRESSED_EXT + if file_ext in compressed_ext.keys(): + secondary_ext = '.{}'.format(file_name.split('.')[-1]) + if secondary_ext in compressed_ext[file_ext]: + return secondary_ext + file_ext + return file_ext diff --git a/mfr/extensions/papaya/__init__.py b/mfr/extensions/papaya/__init__.py new file mode 100644 index 000000000..4b3a4eba1 --- /dev/null +++ b/mfr/extensions/papaya/__init__.py @@ -0,0 +1 @@ +from .render import PapayaRenderer # noqa diff --git a/mfr/extensions/papaya/render.py b/mfr/extensions/papaya/render.py new file mode 100644 index 000000000..e3d23f3e2 --- /dev/null +++ b/mfr/extensions/papaya/render.py @@ -0,0 +1,43 @@ +import os +import shutil + +from mako.lookup import TemplateLookup + +from mfr.core import utils +from mfr.core import extension +from mfr.extensions import settings as ext_settings +from mfr.extensions.papaya import settings as papaya_settings + + +class PapayaRenderer(extension.BaseRenderer): + + data_dir = papaya_settings.DATA_DIR + data_ttl = papaya_settings.DATA_TTL + comp_ext = ext_settings.COMPRESSED_EXT + + TEMPLATE = TemplateLookup( + directories=[ + os.path.join(os.path.dirname(__file__), 'templates') + ]).get_template('viewer.mako') + + def render(self): + self.remove_old_files() + file_name = os.path.basename(self.file_path) + file_ext = utils.get_full_file_ext(self.metadata.ext, self.metadata.name) + file_name = file_name + file_ext + shutil.copyfile(self.file_path, self.data_dir + file_name) + return self.TEMPLATE.render(base=self.assets_url, file_name=file_name) + + def remove_old_files(self): + + for data_file in os.listdir(self.data_dir): + if utils.file_expired(self.data_dir + data_file, self.data_ttl): + os.unlink(self.data_dir + data_file) + + @property + def file_required(self): + return True + + @property + def cache_result(self): + return True diff --git a/mfr/extensions/papaya/settings.py b/mfr/extensions/papaya/settings.py new file mode 100644 index 000000000..384940a9b --- /dev/null +++ b/mfr/extensions/papaya/settings.py @@ -0,0 +1,8 @@ +from mfr import settings + +config = settings.child('PAPAYA_EXTENSION_CONFIG') + +# Directory to temporarily store papaya image files +DATA_DIR = 'mfr/extensions/papaya/static/data/' +# Files older then this many seconds will be deleted from DATA_DIR at the beginning of each render. +DATA_TTL = 300 diff --git a/mfr/extensions/papaya/static/README-papaya.txt b/mfr/extensions/papaya/static/README-papaya.txt new file mode 100644 index 000000000..83045ba29 --- /dev/null +++ b/mfr/extensions/papaya/static/README-papaya.txt @@ -0,0 +1,7 @@ +Currently using a custom built papaya.js with option to remove the ability to open new files from the users desktop. + +https://github.com/TomBaxter/Papaya/tree/feature/noNewFiles + +I have sent them a PR, hopefully they bite. + +https://github.com/rii-mango/Papaya/pull/101 diff --git a/mfr/extensions/papaya/static/data/.gitkeep b/mfr/extensions/papaya/static/data/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/mfr/extensions/papaya/static/papaya.css b/mfr/extensions/papaya/static/papaya.css new file mode 100644 index 000000000..c9e3dd8ab --- /dev/null +++ b/mfr/extensions/papaya/static/papaya.css @@ -0,0 +1 @@ +.papaya{width:90%;height:90%;margin:25px auto;background-color:black;font-family:sans-serif}.papaya:before{position:relative;content:"Papaya requires JavaScript...";display:block;top:45%;color:red;margin:0 auto;font-size:18px;font-family:sans-serif}.papaya-fullscreen{height:100%}.papaya-toolbar{text-align:left;box-sizing:content-box;position:relative}.papaya-toolbar ul{margin:0;list-style:none}.papaya-toolbar input[type=file]{text-align:right;display:none}.papaya-kiosk-controls{position:relative;margin:5px auto;list-style:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.papaya-kiosk-controls ul{list-style:none}.papaya-kiosk-controls button{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;background-color:lightgray}.papaya-control-increment{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;width:25px;text-align:center;vertical-align:middle;padding:0;margin-left:auto;margin-right:auto;line-height:16px;box-sizing:border-box;font-family:"Courier New",Courier,monospace}.papaya-main-increment{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;width:25px;text-align:center;font-family:"Courier New",Courier,monospace;background-color:lightgray;vertical-align:middle;padding:0;margin-left:auto;margin-right:auto;box-sizing:border-box;outline:0}.papaya-main-decrement{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;width:25px;text-align:center;font-family:"Courier New",Courier,monospace;background-color:lightgray;vertical-align:middle;padding:0;margin-left:auto;margin-right:auto;box-sizing:border-box;outline:0}.papaya-main-swap{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;background-color:lightgray;outline:0}.papaya-main-goto-center{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;background-color:lightgray;outline:0}.papaya-main-goto-origin{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;background-color:lightgray;outline:0}.papaya-slider-slice{padding:0 5px;display:inline}.papaya-slider-slice span{font-size:14px;font-family:sans-serif;vertical-align:middle}.papaya-slider-slice button{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;vertical-align:middle;font-size:14px;height:25px;background-color:lightgray}.papaya-controlbar-label{color:#000}.papaya-menu{width:220px;background:#222;z-index:100;position:absolute;border:solid 2px darkgray;padding:4px;margin:0}.papaya-menu li{font-size:12px;font-family:sans-serif;padding:4px 2px;color:#b5cbd3;cursor:pointer;list-style-type:none}.papaya-menu-label{font-size:14px;font-family:sans-serif;font-weight:bold;padding:2px 8px;cursor:pointer;vertical-align:text-bottom}.papaya-menu-titlebar{font-size:16px;font-family:sans-serif;padding:3px 8px 0 8px;cursor:default;vertical-align:text-bottom;color:white}.papaya-menu-icon{margin-left:5px}.papaya-menu-icon img{box-sizing:content-box}.papaya-menu-hovering{background-color:#444}.papaya-menu-spacer{height:8px}.papaya-menu-unselectable{-moz-user-select:-moz-none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;-webkit-user-drag:none;user-drag:none}.papaya-menu-button-hovering{background-color:#DDD}.papaya-menu-filechooser{cursor:pointer;width:200px;display:inline-block;font-weight:normal}.papaya-menu-input{width:38px;margin-right:5px;color:black}li .papaya-menu-slider{vertical-align:middle;text-align:center;display:inline;width:120px;padding:0;margin:0}.papaya-dialog{min-width:400px;max-width:500px;height:500px;background:#222;position:absolute;z-index:100;border:solid 2px darkgray;padding:6px;font-size:14px;font-family:sans-serif;color:#b5cbd3;box-sizing:content-box;line-height:1.45}.papaya-dialog-content{margin:20px;height:415px;color:#dedede;overflow:auto;-ms-overflow-style:-ms-autohiding-scrollbar}.papaya-dialog-content-nowrap{white-space:nowrap}.papaya-dialog-content table{margin:0 auto}.papaya-dialog-content-label{text-align:right;padding:5px;color:#b5cbd3}.papaya-dialog-content-control{text-align:left;padding:5px}.papaya-dialog-content-help{text-align:right;padding:5px;color:lightgray;font-size:12px}.papaya-dialog-title{color:#b5cbd3;font-weight:bold;font-size:16px}.papaya-dialog-button{text-align:right;box-sizing:content-box;height:22px}.papaya-dialog-button button{box-sizing:content-box;color:black;font-size:11px}.papaya-dialog-background{position:fixed;top:0;left:0;background-color:#fff;width:100%;height:100%;opacity:.5}.papaya-dialog-stopscroll{height:100%;overflow:hidden}.checkForJS{width:90%;height:90%;margin:25px auto;background-color:black}.checkForJS:before{position:relative;content:"Papaya requires JavaScript...";display:block;top:45%;color:red;margin:0 auto;font-size:18px;font-family:sans-serif;text-align:center}.papaya-utils-unsupported{width:90%;height:90%;margin:25px auto;background-color:black}.papaya-utils-unsupported-message{position:relative;display:block;top:45%;color:red;margin:0 auto;font-size:18px;font-family:sans-serif;text-align:center}.papaya-viewer{line-height:1;font-family:sans-serif}.papaya-viewer div,.papaya-viewer canvas{margin:0;padding:0;border:0;font:inherit;font-size:100%;vertical-align:baseline;font-family:sans-serif}.papaya-viewer canvas{cursor:crosshair} \ No newline at end of file diff --git a/mfr/extensions/papaya/static/papaya.js b/mfr/extensions/papaya/static/papaya.js new file mode 100644 index 000000000..9134fc0d6 --- /dev/null +++ b/mfr/extensions/papaya/static/papaya.js @@ -0,0 +1,2108 @@ +var PAPAYA_BUILD_NUM="1431",papayaLoadableImages=[]; +(function(c,a){function d(c){var a=c.length,b=r.type(c);return r.isWindow(c)?!1:1===c.nodeType&&a?!0:"array"===b||"function"!==b&&(0===a||"number"===typeof a&&0a;a+=2)"margin"===b&&(g+=r.css(c,b+ya[a],!0,d)),e?("content"===b&&(g-=r.css(c,"padding"+ya[a],!0,d)),"margin"!==b&&(g-=r.css(c,"border"+ +ya[a]+"Width",!0,d))):(g+=r.css(c,"padding"+ya[a],!0,d),"padding"!==b&&(g+=r.css(c,"border"+ya[a]+"Width",!0,d)));return g}function D(c,a,b){var e=!0,d="width"===a?c.offsetWidth:c.offsetHeight,g=ja(c),l=r.support.boxSizing&&"border-box"===r.css(c,"boxSizing",!1,g);if(0>=d||null==d){d=Oa(c,a,g);if(0>d||null==d)d=c.style[a];if(wb.test(d))return d;e=l&&(r.support.boxSizingReliable||d===c.style[a]);d=parseFloat(d)||0}return d+y(c,a,b||(l?"border":"content"),e,g)+"px"}function u(c){var a=S,b=xb[c];b|| +(b=n(c,a),"none"!==b&&b||(wa=(wa||r(""),setTimeout(function(){try{b.location.href,e=!0}catch(a){console.log(a)}e?b.setTimeout("window.close()",100):b.close();d(e)},100);else if("Firefox"===papaya.utilities.PlatformUtils.browser){try{f=$("