Get ueeditor
Download UEditor source code from the official website. There is no UEditor in the downloaded source code all. JS file. You need to use grunt to package the source package into a deployment Version (including ueditor.all.js file)
- Install node js
- Global install grunt (NPM install - G grunt CLI)
- The command line switches the directory to the ueeditor directory (including the Gruntfile.js file)
- npm install installation dependency
- Execute the command grunt default, which will package the source file and generate ueditor all. JS file. After execution, a dist directory will be generated under the ueditor directory
- There is a utf8 PHP directory in dist, which is the deployment version. Modify and rename it ueditor
ueditor related requests to be processed by the server
Put the UEditor deployment version into the static directory of the project, and then introduce UEditor on the relevant pages to be used according to the instructions of the official website config. JS and ueeditor all. JS file, you can use most of the functions of ueeditor. Only uploading files, pictures, videos, online pictures and online files, which are related to uploading, are not easy to use. Because these functions need the support of the back-end server, we need to implement the response view function in our django project to process these requests:
- Request for obtaining backend configuration item information (the parameter carried in the request address is action=config)
- Upload picture request (the parameters carried by the request address can be seen from the specific value set by the backend configuration item. The default is: action=uploadimage)
- Upload video request (the parameters carried by the request address can be seen from the specific value set by the backend configuration item. The default is: action=uploadvideo)
- Upload attachment request (the parameters carried by the request address can be seen from the specific value set by the backend configuration item. The default is: action=uploadfile)
- List all picture requests (the parameters carried by the request address can be seen from the specific value set by the backend configuration item. The default is: action=listimage)
- List all attachment requests (the parameters carried by the request address are based on the specific value set by the backend configuration item. The default is: action=listfile)
- Request for uploading graffiti pictures (the parameters carried by the request address can be seen from the specific value set by the backend configuration item. The default is: action=uploadscrawl)
- The default value of the back-end configuration parameter is: chimage = action (the default value of the configuration parameter is chimage)
For uploading pictures, screenshots, videos, attachments and graffiti pictures, the JSON format data returned by the background server is as follows:
{ "state": "SUCCESS", // Status information. When successful, the return value is fixed as SUCCESS "url": "/ueditor/2_%E5%B9%BF%E5%91%8A%E6%8E%92%E6%9C%9F%E5%B9%B3%E5%8F%B0/%E6%9C%80%E6%96%B0%E7%89%A9%E6%96%99%E5%8D%95ID%E6%98%BE%E7%A4%BA%E9%94%99%E8%AF%AF001.png", "title": "Latest bill of materials ID Display error 001.png", // File name "original": "Latest bill of materials ID Display error 001.png" // Internal file name, which is generally the same as titile }
When capturing remote pictures, the JSON format data that the background server should return is as follows:
{ "state": "SUCCESS", "list": [ { "state": "SUCCESS", "url": "/ueditor/2_%E5%B9%BF%E5%91%8A%E6%8E%92%E6%9C%9F%E5%B9%B3%E5%8F%B0/sww.png", "size": 7200, "title": "sww.png", "original": "sww.png", "source": "http://seventest.cn/static/images/sww.png ", / / download address } ] }
List the pictures and files in the specified directory. The JSON format data that the background server should return is as follows:
{ "state": "SUCCESS", "list": [ { "url": "/ueditor/2_%E5%B9%BF%E5%91%8A%E6%8E%92%E6%9C%9F%E5%B9%B3%E5%8F%B0/del_image_01.png" }, { "url": "/ueditor/2_%E5%B9%BF%E5%91%8A%E6%8E%92%E6%9C%9F%E5%B9%B3%E5%8F%B0/image.png" }, { "url": "/ueditor/2_%E5%B9%BF%E5%91%8A%E6%8E%92%E6%9C%9F%E5%B9%B3%E5%8F%B0/test_picture_002.gif" }, { "url": "/ueditor/2_%E5%B9%BF%E5%91%8A%E6%8E%92%E6%9C%9F%E5%B9%B3%E5%8F%B0/%E6%9C%80%E6%96%B0%E7%89%A9%E6%96%99%E5%8D%95ID%E6%98%BE%E7%A4%BA%E9%94%99%E8%AF%AF001.png" }, { "url": "/ueditor/2_%E5%B9%BF%E5%91%8A%E6%8E%92%E6%9C%9F%E5%B9%B3%E5%8F%B0/%E6%B6%82%E9%B8%A6.png" } ], "start": 0, "total": 5 }
The django project handles the ueditor request code
The following is the relevant code for processing the above ueditor requests in the transfer test process management system I developed
-
settings.py configuration
-
Project routing configuration (urls.py)
# -*-Coding: UTF-8 - * - '' 'created on December 15, 2019 @author: siwenwei ''' from django.urls import re_path from . import views urlpatterns = [ re_path(r'^$', views.Index.as_view()), re_path(r'^login$', views.Login.as_view()), re_path(r'^logout$', views.Logout.as_view()), re_path(r'^userguide$', views.UserGuide.as_view()), re_path(r'^author$', views.Author.as_view()), re_path(r'^register$', views.Register.as_view()), re_path(r'^{}$'.format(views.Settings.suburl), views.Settings.as_view()), re_path(r'^{}$'.format(views.BaseData.suburl), views.BaseData.as_view()), re_path(r'^testproject/{}$'.format(views.Project.suburl), views.Project.as_view()), re_path(r'^user/list$', views.UserList.as_view()), re_path(r'^member/{}$'.format(views.Member.suburl), views.Member.as_view()), re_path(r'^flow/list$', views.FlowList.as_view()), re_path(r'^flow/{}$'.format(views.Flow.suburl), views.Flow.as_view()), re_path(r'^flow/node/list$', views.FlowNodes.as_view()), re_path(r'^flow/node/settings$', views.NodeSettings.as_view()), re_path(r'^flow/node/run$', views.NodeRunner.as_view()), re_path(r'^flow/node/file/{}$'.format(views.NodeFiles.suburl), views.NodeFiles.as_view()), re_path(r'^{}$'.format(views.UEditor.SERVER_URL['value']), views.UEditor.as_view()), # Handle ueditor's request to obtain server configuration, upload pictures, upload attachments, list all pictures, list all attachments, delete pictures, delete attachments, etc re_path(r'^{}/{}$'.format(views.UEditor.SERVER_URL['value'], views.Ueditor_FileServer.suburl), views.Ueditor_FileServer.as_view()), # Processing the request of ueditor to obtain various files is actually providing the service of obtaining static files]
- Handle various upload requests, image list and attachment list request views (ueditor.py)
#!/usr/bin/env python # -*- encoding: utf-8 -*- ''' @Author: Si Wenwei @Date: 2021/03/07 14:45:44 ''' import os import json import base64 from urllib.parse import quote from urllib.parse import unquote from urllib.request import urlopen from django.views import View from django.conf import settings from django.http import HttpResponse from django.http import JsonResponse from django.http import HttpResponseBadRequest from django.core.exceptions import ObjectDoesNotExist from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt from django.http import QueryDict from .. import models from ..utils.filesize import FileSize from ..utils.ueditor_path_formatter import UeditorPathFormatter @method_decorator(csrf_exempt, name='dispatch') class UEditor(View): ROOT_DIR = settings.UEDITOR_FILE_DIR SERVER_URL = {'key': 'serverUrl', 'value': 'ueditor', 'root_dir': ROOT_DIR} # Upload picture configuration item IMAGE = { "imageActionName": "uploadimage", # The name of the action to upload the picture "imageMaxSize": 20485760, # Upload size limit, unit B,10M "imageFieldName": "upfile", # *Submitted picture form name "imageUrlPrefix": "", "imagePathFormat": "", "imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], # Upload picture format display } # Graffiti picture upload configuration item SCRAWL = { "scrawlActionName": "uploadscrawl", # Name of action to upload graffiti "scrawlFieldName": "upfile", # Submitted picture form name "scrawlMaxSize": 10485760, # Upload size limit, unit B 10m "scrawlUrlPrefix": "", "scrawlPathFormat": "", } # Screenshot tool upload SNAPSCREEN = { "snapscreenActionName": "uploadimage", # The name of the action to upload the screenshot "snapscreenPathFormat": "", "snapscreenUrlPrefix": "", } # Grab remote picture configuration CATCHER = { "catcherLocalDomain": ["127.0.0.1", "localhost", "img.baidu.com"], "catcherPathFormat": "", "catcherActionName": "catchimage", # The action name of the remote image to be captured "catcherFieldName": "source", # Submitted picture list form name "catcherMaxSize": 10485760, # Upload size limit, unit B "catcherAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], # Capture picture format display "catcherUrlPrefix": "", } # Upload video configuration VIDEO = { "videoActionName": "uploadvideo", # The name of the action to upload the video "videoPathFormat": "", "videoFieldName": "upfile", # Name of submitted video form "videoMaxSize": 102400000, # Upload size limit, unit B, default 100MB "videoUrlPrefix": "", "videoAllowFiles": [".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg", ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"], # Upload video format display } # Upload file configuration __FILE_ALLOW_FILES = [ ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg", ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid", ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml" ] FILE = { "fileActionName": "uploadfile", # In the controller, the name of the action to upload the video "filePathFormat": "", "fileFieldName": "upfile", # File form name submitted "fileMaxSize": 204800000, # Upload size limit, unit B, 200MB "fileUrlPrefix": "", # File access path prefix "fileAllowFiles": __FILE_ALLOW_FILES, # Upload file format display } # List the pictures in the specified directory IMAGE_MANAGER = { "imageManagerActionName": "listimages", # The name of the action to perform image management "imageManagerListPath": "", "imageManagerListSize": 30, # Number of documents listed each time # File types listed "imageManagerAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], "imageManagerUrlPrefix": "", # Picture access path prefix } # Lists the files in the specified directory __FILE_MANAGER_ALLOW_FILES = [ ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tif", ".psd" ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg", ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid", ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml", ".exe", ".com", ".dll", ".msi" ] FILE_MANAGER = { "fileManagerActionName": "listfiles", # action name of executing file management "fileManagerListPath": "", "fileManagerUrlPrefix": "", "fileManagerListSize": 30, # Number of documents listed each time "fileManagerAllowFiles": __FILE_MANAGER_ALLOW_FILES # File types listed } DEFAULT_MAX_SIZE = 20485760 IMAGE_REMOVE = {"imageRemoveActionName": "removeimage"} FILE_REMOVE = {"fileRemoveActionName": "removefile"} SAVE_TO_SERVER = {"saveToServerActionName": "savecontent"} @property def upload_config(self): """Upload configuration item returned to the front end""" self.IMAGE.setdefault('imageActionName ', 'uploadimage') self.SCRAWL.setdefault("scrawlActionName", "uploadscrawl") self.SNAPSCREEN.setdefault("snapscreenActionName", "uploadimage") self.CATCHER.setdefault("catcherActionName", "catchimage") self.VIDEO.setdefault("videoActionName", "uploadvideo") self.FILE.setdefault("fileActionName", "uploadfile") self.IMAGE_MANAGER.setdefault("imageManagerActionName", "listimages") self.FILE_MANAGER.setdefault("fileManagerActionName", "listfiles") self.IMAGE_REMOVE.setdefault("imageRemoveActionName", "removeimage") self.FILE_REMOVE.setdefault("fileRemoveActionName", "removefile") self.SAVE_TO_SERVER.setdefault("saveToServerActionName", "savecontent") to_be_add_items = [self.IMAGE, self.SCRAWL, self.SNAPSCREEN, self.CATCHER] to_be_add_items.append(self.VIDEO) to_be_add_items.append(self.FILE) to_be_add_items.append(self.IMAGE_MANAGER) to_be_add_items.append(self.FILE_MANAGER) to_be_add_items.append(self.IMAGE_REMOVE) to_be_add_items.append(self.FILE_REMOVE) to_be_add_items.append(self.SAVE_TO_SERVER) items = {} for item in to_be_add_items: items.update(item) return items @property def action_views(self): """Configuration correspondence action View function for""" views = { 'config': self.get_ueditor_config, self.upload_config.get('imageActionName '): self.general_upload_file, self.upload_config.get("scrawlActionName"): self.upload_scrawl, self.upload_config.get("snapscreenActionName"): self.general_upload_file, self.upload_config.get("catcherActionName"): self.catch_remote_image, self.upload_config.get("videoActionName"): self.general_upload_file, self.upload_config.get("fileActionName"): self.general_upload_file, self.upload_config.get("imageManagerActionName"): self.list_images, self.upload_config.get("fileManagerActionName"): self.list_files, self.upload_config.get("imageRemoveActionName"): self.remove_file, self.upload_config.get("fileRemoveActionName"): self.remove_file, self.upload_config.get("saveToServerActionName"): self.save_ueditor_content, } return views @staticmethod def to_json(obj): return json.dumps(obj, ensure_ascii=False) @staticmethod def get_or_post(request): if request.method.upper() == 'get'.upper(): return request.GET elif request.method.upper() == 'post'.upper(): parts = request.get_full_path().split('?') query_params = parts[1] if len(parts) > 1 else '' qd = QueryDict(query_params) final_post = request.POST.copy() final_post.update(qd.copy()) return final_post else: return None def call_action_views(self, request, *args, **kwargs): params = self.get_or_post(request) action = params.get('action') action_view = self.action_views.get(action, None) if action_view: return action_view(request, *args, **kwargs) else: message = 'Not for{}Configure the corresponding view function'.format(action) return HttpResponseBadRequest(message) def create_full_file_path(self, subpath): """structure ueditor Upload storage directory Args: subpath: Sub path """ return os.path.join(self.ROOT_DIR, subpath) def get_ueditor_config(self, request, *args, **kwargs): """Return to configuration""" return HttpResponse(self.to_json(self.upload_config), content_type="application/javascript") def get(self, request, *args, **kwargs): """obtain ueditor Back end of URL address""" return self.call_action_views(request, *args, **kwargs) def post(self, request, *args, **kwargs): """obtain ueditor Back end of URL address""" return self.call_action_views(request, *args, **kwargs) def list_images(self, request, *args, **kwargs): params = self.get_or_post(request) allow_types_key = 'imageManagerAllowFiles' list_size_key = 'imageManagerListSize' list_path_key = 'imageManagerListPath' list_size = int(params.get('size', self.upload_config.get(list_size_key, 7))) list_start = int(params.get("start", 0)) listpath = self.upload_config.get(list_path_key, '') allow_types = self.upload_config.get(allow_types_key, '') subdirs = self._project_flow_node_dirname(params.get('project_id', ''), params.get('flow_pk', ''), params.get('node_id', '')) files = self.get_url_files(listpath, allow_types, listpath_dirs=subdirs) if (len(files) == 0): return_info = {"state": "No matching file found!", "list": [], "start": list_start, "total": 0} else: return_info = {"state": "SUCCESS", "list": files[list_start:list_start + list_size], "start": list_start, "total": len(files)} print(json.dumps(return_info)) return HttpResponse(json.dumps(return_info), content_type="application/javascript") def remove_file(self, request, *args, **kwargs): state = True msg = '' params = self.get_or_post(request) subdirs = self._project_flow_node_dirname(params.get('project_id', ''), params.get('flow_pk', ''), params.get('node_id', '')) suburlpath = unquote(params.get('path', '')) parts = suburlpath.split('/') root_dir = self.SERVER_URL['root_dir'] if parts: fpath = subdirs fpath.append(parts[-1]) filepath = os.path.join(root_dir, *fpath) try: if os.path.isfile(filepath): os.remove(filepath) except Exception as e: msg = str(e) state = False res = dict(state=state, msg=msg) dumps_params = dict(ensure_ascii=False) return JsonResponse(res, json_dumps_params=dumps_params) def list_files(self, request, *args, **kwargs): """List files""" params = self.get_or_post(request) allow_types_key = 'fileManagerAllowFiles' list_size_key = 'fileManagerListSize' list_path_key = 'fileManagerListPath' list_size = int(params.get('size', self.upload_config.get(list_size_key, 7))) list_start = int(params.get("start", 0)) listpath = self.upload_config.get(list_path_key, '') allow_types = self.upload_config.get(allow_types_key, '') subdirs = self._project_flow_node_dirname(params.get('project_id', ''), params.get('flow_pk', ''), params.get('node_id', '')) files = self.get_url_files(listpath, allow_types, listpath_dirs=subdirs) if (len(files) == 0): return_info = {"state": "No matching file found!", "list": [], "start": list_start, "total": 0} else: return_info = {"state": "SUCCESS", "list": files[list_start:list_start + list_size], "start": list_start, "total": len(files)} return HttpResponse(json.dumps(return_info), content_type="application/javascript") def get_url_files(self, listpath, allow_types=[], listpath_dirs=[]): urlsep = '/' listpath_dirs.extend(listpath.split(urlsep)) dirlist = listpath_dirs url_files = [] root_dir = self.SERVER_URL['root_dir'] rd_parts = root_dir.split(os.sep) plength = len(rd_parts) root_url = self.SERVER_URL['value'] if dirlist: dirpath = os.path.join(root_dir, os.sep.join(dirlist)) items = os.listdir(dirpath) for item in items: if os.path.isfile(os.path.join(dirpath, item)): name, ext = os.path.splitext(item) urlparts = dirpath.split(os.sep) urlparts.append(item) urlparts = urlparts[plength:] urlparts.insert(0, root_url) url = quote(urlsep.join(urlparts)) url = url if url.startswith(urlsep) else (urlsep + url) if allow_types: if ext in allow_types: url_files.append({"url": url}) else: url_files.append({"url": url}) return url_files def catch_remote_image(self, request, *args, **kwargs): """Remote capture, when catchRemoteImageEnable:true If the front-end inserts the picture address and the current web If it is not in the same domain, this function downloads the image from the remote to the local """ state = "SUCCESS" path_format_key = 'catcherPathFormat' params = self.get_or_post(request) allow_type = list(params.get("catcherAllowFiles", self.upload_config.get("catcherAllowFiles", ""))) # max_size = int(params.get("catcherMaxSize", self.upload_config.get("catcherMaxSize", 0))) remote_urls = params.getlist(self.upload_config['catcherFieldName'], []) catcher_infos = [] for remote_url in remote_urls: # Get the original name of the uploaded file remote_file_name = os.path.basename(remote_url) remote_original_name, remote_original_ext = os.path.splitext(remote_file_name) # Document type inspection if remote_original_ext in allow_type: path_format = params.get(path_format_key, self.upload_config.get(path_format_key, '')) formatter = UeditorPathFormatter() formatter.format(remote_original_name, path_format) subdirectories = self._project_flow_node_dirname(params.get('project_id', ''), params.get('flow_pk', ''), params.get('node_id', '')) formatter.set_url_path_prefix(*subdirectories) # Path composed of project process nodes full_file_path = self.create_full_file_path(formatter.save_subpath) self._create_directory(full_file_path) # Read remote picture file try: remote_image = urlopen(remote_url) # Write the captured file to the file try: f = open(full_file_path, 'wb') f.write(remote_image.read()) f.close() state = "SUCCESS" except Exception as E: state = u"Error writing captured picture file:%s" % E.message except Exception as E: state = u"Image capture error:%s" % E.message formatter.set_url_path_prefix(self.SERVER_URL['value']) # Add root path catcher_infos.append({ "state": state, "url": quote(formatter.url_path), "size": os.path.getsize(full_file_path), "title": os.path.basename(full_file_path), "original": remote_file_name, "source": remote_url }) return_info = {"state": "SUCCESS" if len(catcher_infos) > 0 else "ERROR", "list": catcher_infos} return HttpResponse(json.dumps(return_info, ensure_ascii=False), content_type="application/javascript") @classmethod def get_db_object(cls, model_klass, **db_fields): obj = None try: obj = model_klass.objects.get(**db_fields) except ObjectDoesNotExist: obj = None return obj def _project_flow_node_dirname(self, project_id=None, flow_id=None, node_id=None, sep='_'): dirname_list = [] if node_id: node = self.get_db_object(models.Node, id=node_id) dirname_list.append(sep.join([str(node.flow.project.id), node.flow.project.name])) dirname_list.append(sep.join([node.flow.number])) dirname_list.append(sep.join([node.name])) elif flow_id: flow = self.get_db_object(models.Flow, id=flow_id) dirname_list.append(sep.join([str(flow.project.id), flow.project.name])) dirname_list.append(sep.join([flow.number])) elif project_id: project = self.get_db_object(models.Project, id=project_id) dirname_list.append(sep.join([project_id, project.name])) else: pass return dirname_list def general_upload_file(self, request, *args, **kwargs): """Upload file""" state = "SUCCESS" params = self.get_or_post(request) action = params.get('action') if action == self.upload_config.get('imageActionName'): submit_field_key = 'imageFieldName' max_size_field = 'imageMaxSize' ext_field = 'imageAllowFiles' path_format_key = 'imagePathFormat' elif action == self.upload_config.get('fileActionName'): submit_field_key = 'fileFieldName' max_size_field = 'fileMaxSize' ext_field = 'fileAllowFiles' path_format_key = 'filePathFormat' elif action == self.upload_config.get('videoActionName'): submit_field_key = 'videoFieldName' max_size_field = 'videoMaxSize' ext_field = 'videoAllowFiles' path_format_key = 'videoPathFormat' else: return JsonResponse({'state': 'action Value transmission error'}) submit_field_name = params.get(submit_field_key, self.upload_config.get(submit_field_key, 'upfile')) submit_file = request.FILES.get(submit_field_name, None) if submit_file is None: return JsonResponse({'state': 'No files uploaded'}) submit_file_name = submit_file.name submit_file_size = submit_file.size submit_file_ext = os.path.splitext(submit_file_name)[1] support_file_exts = list(params.get(ext_field, self.upload_config.get(ext_field, ""))) if submit_file_ext not in support_file_exts: state = "The server only supports the following types of files:{},The actual upload is:{}".format(' | '.join(support_file_exts), submit_file_name) return JsonResponse({'state': state}) limit_size = int(params.get(max_size_field, self.upload_config.get(max_size_field, self.DEFAULT_MAX_SIZE))) asize = FileSize(submit_file_size) lsize = FileSize(limit_size) if asize > lsize: state = "Upload file size({})The maximum limit has been exceeded({})%s. ".format(asize.human_readable, lsize.human_readable) return JsonResponse({'state': state}) path_format = params.get(path_format_key, self.upload_config.get(path_format_key, '')) formatter = UeditorPathFormatter() formatter.format(submit_file_name, path_format) subdirectories = self._project_flow_node_dirname(params.get('project_id', ''), params.get('flow_pk', ''), params.get('node_id', '')) formatter.set_url_path_prefix(*subdirectories) # Path composed of project process nodes full_file_path = self.create_full_file_path(formatter.save_subpath) try: self._create_directory(full_file_path) with open(full_file_path, 'wb') as f: for chunk in submit_file.chunks(): f.write(chunk) except Exception as e: state = "Save file{}error: {}".format(submit_file_name, str(e)) formatter.set_url_path_prefix(self.SERVER_URL['value']) # Add root path res = dict(state=state, url=quote(formatter.url_path), title=submit_file_name, original=submit_file_name) dumps_params = dict(ensure_ascii=False) return JsonResponse(res, json_dumps_params=dumps_params) def _create_directory(self, path): target_dir = os.path.dirname(path) if not os.path.exists(target_dir): os.makedirs(target_dir) def upload_scrawl(self, request, *args, **kwargs): """Upload graffiti""" state = "SUCCESS" sfn = 'scrawlFieldName' max_size_field = 'scrawlMaxSize' scrawl_file_name = kwargs.get('scrawl_file_name', 'Graffiti.png') params = self.get_or_post(request) field_name = params.get(sfn, self.upload_config.get(sfn, 'upfile')) base64_content = params.get(field_name) content = base64.b64decode(base64_content) actual_size = len(content) limit_size = int(params.get(max_size_field, self.upload_config.get(max_size_field, 0))) asize = FileSize(actual_size) lsize = FileSize(limit_size) if asize > lsize: state = "Upload file size({})The maximum limit has been exceeded({})%s. ".format(asize.human_readable, lsize.human_readable) return JsonResponse({'state': state}) path_format = params.get('scrawlPathFormat', self.upload_config.get('scrawlPathFormat', '')) formatter = UeditorPathFormatter() formatter.format(scrawl_file_name, path_format) subdirectories = self._project_flow_node_dirname(params.get('project_id', ''), params.get('flow_pk', ''), params.get('node_id', '')) formatter.set_url_path_prefix(*subdirectories) # Path composed of project process nodes full_file_path = self.create_full_file_path(formatter.save_subpath) try: self._create_directory(full_file_path) with open(full_file_path, 'wb') as f: f.write(content) except Exception as e: state = "Error writing picture file: {}".format(str(e)) formatter.set_url_path_prefix(self.SERVER_URL['value']) # Add root path res = dict(state=state, url=quote(formatter.url_path), title=scrawl_file_name, original=scrawl_file_name) dumps_params = dict(ensure_ascii=False) return JsonResponse(res, json_dumps_params=dumps_params) def save_ueditor_content(self, request, *args, **kwargs): state = True msg = "" submit_datas = self.get_or_post(request) project_id = submit_datas.get('project_id', '') flow_id = submit_datas.get('flow_pk', '') node_id = submit_datas.get('node_id', '') ueditor_content = submit_datas.get("ueditor_content") node = self.get_db_object(models.Node, id=node_id) if node: if node.is_review_kind or node.is_env_kind or node.is_test_kind: r = self.get_db_object(models.Result, node=node, batch=node.batch) if r: r.doc = ueditor_content r.save() else: code, name = (-1, "No results yet") nr = models.Result(code=code, name=name, node=node, batch=node.batch, creator=request.user, doc=ueditor_content) nr.save() else: state = False msg = "node({})I won't support it".format(node.name) else: flow = self.get_db_object(models.Flow, id=flow_id) if flow: flow.doc = ueditor_content flow.save() else: project = self.get_db_object(models.Project, id=project_id) if project: project.doc = ueditor_content project.save() else: state = False # No one of the project process nodes can be found. I don't know where to save it msg = "error code: p{}f{}n{}".format(project_id, flow_id, node_id) res = dict(state=state, msg=msg) dumps_params = dict(ensure_ascii=False) return JsonResponse(res, json_dumps_params=dumps_params)
- Provide a service view for ueditor to obtain static files (ueditor_fileserver.py)
#!/usr/bin/env python # -*- encoding: utf-8 -*- ''' @Author: Si Wenwei @Date: 2021/03/07 14:47:32 ''' from django.views import View from django.conf import settings from django.views import static from django.http import HttpResponseRedirect from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt @method_decorator(csrf_exempt, name='dispatch') class Ueditor_FileServer(View): suburl_group_name = 'suburl' suburl = '(?P<{}>.+)'.format(suburl_group_name) redirect_url = "/login" @property def ueditor_file_dir(self): return settings.UEDITOR_FILE_DIR def download(self, request, *args, **kwargs): if not request.user.is_authenticated: return HttpResponseRedirect(self.redirect_url) sub_url = kwargs.get(self.suburl_group_name) document_root = self.ueditor_file_dir path = sub_url res = static.serve(request, path, document_root=document_root) return res def get(self, request, *args, **kwargs): return self.download(request, *args, **kwargs) def post(self, request, *args, **kwargs): return self.download(request, *args, **kwargs)
- Processing file size (filesize.py)
#!/usr/bin/env python # -*- encoding: utf-8 -*- ''' @Author: Si Wenwei @Date: 2021/03/07 14:48:18 ''' class FileSize(): SIZE_UNIT = {"Byte": 1, "KB": 1024, "MB": 1048576, "GB": 1073741824, "TB": 1099511627776} def __init__(self, size): self.size = int(FileSize.Format(size)) @staticmethod def Format(size): import re if isinstance(size, int): return size else: if not isinstance(size, str): return 0 else: oSize = size.lstrip().upper().replace(" ", "") pattern = re.compile(r"(\d*\.?(?=\d)\d*)(byte|kb|mb|gb|tb)", re.I) match = pattern.match(oSize) if match: m_size, m_unit = match.groups() if m_size.find(".") == -1: m_size = int(m_size) else: m_size = float(m_size) if m_unit != "BYTE": return m_size * FileSize.SIZE_UNIT[m_unit] else: return m_size else: return 0 # Returns a value in bytes @property def size(self): return self._size @size.setter def size(self, newsize): try: self._size = int(newsize) except Exception: self._size = 0 # Returns an automatic value with units @property def human_readable(self): if self.size < FileSize.SIZE_UNIT["KB"]: unit = "Byte" elif self.size < FileSize.SIZE_UNIT["MB"]: unit = "KB" elif self.size < FileSize.SIZE_UNIT["GB"]: unit = "MB" elif self.size < FileSize.SIZE_UNIT["TB"]: unit = "GB" else: unit = "TB" if (self.size % FileSize.SIZE_UNIT[unit]) == 0: return "%s%s" % ((self.size / FileSize.SIZE_UNIT[unit]), unit) else: return "%0.2f%s" % (round(float(self.size) / float(FileSize.SIZE_UNIT[unit]), 2), unit) def __str__(self): return self.human_readable # Add up def __add__(self, other): if isinstance(other, FileSize): return FileSize(other.size + self.size) else: return FileSize(FileSize(other).size + self.size) def __sub__(self, other): if isinstance(other, FileSize): return FileSize(self.size - other.size) else: return FileSize(self.size - FileSize(other).size) def __gt__(self, other): if isinstance(other, FileSize): if self.size > other.size: return True else: return False else: if self.size > FileSize(other).size: return True else: return False def __lt__(self, other): if isinstance(other, FileSize): if other.size > self.size: return True else: return False else: if FileSize(other).size > self.size: return True else: return False def __ge__(self, other): if isinstance(other, FileSize): if self.size >= other.size: return True else: return False else: if self.size >= FileSize(other).size: return True else: return False def __le__(self, other): if isinstance(other, FileSize): if other.size >= self.size: return True else: return False else: if FileSize(other).size >= self.size: return True else: return False
- Handle PathFormat related items in ueditor (ueditor_path_formatter.py)
#!/usr/bin/env python # -*- encoding: utf-8 -*- ''' @Author: Si Wenwei @Date: 2021/03/07 14:39:03 ''' import re import os import random import datetime class UeditorPathFormatter(object): def __init__(self, url_path_sep='/'): self.url_path_sep = url_path_sep self.url_path_prefix = None self.url_path = None def _replace(self, file_name, rand_prefix='rand:', dtime=datetime.datetime.now()): def wrapper(match_obj): ms = match_obj.group(0) if ms == '{filename}': repl = file_name elif ms == '{time}': repl = str(int(dtime.timestamp())) elif ms == '{yyyy}': repl = dtime.strftime('%Y') elif ms == '{yy}': repl = dtime.strftime('%y') elif ms == '{mm}': repl = dtime.strftime('%m') elif ms == '{dd}': repl = dtime.strftime('%d') elif ms == '{hh}': repl = dtime.strftime('%H') elif ms == '{ii}': repl = dtime.strftime('%M') elif ms == '{ss}': # datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f') # Date and time with microseconds repl = dtime.strftime('%S') else: ms_content = ms.lstrip("{").rstrip("}") if ms_content.startswith(rand_prefix): length = int(ms_content[len(rand_prefix):]) number = random.randint(1, int('9' * length)) fmt = '{:>0%sd}' % length repl = fmt.format(number) else: repl = ms return repl return wrapper def _check_path_format(self, path_format): pass def _check_file_name(self, file_name): pass def format(self, file_name, path_format, endswith_filename=True): """ # {filename} # It will be replaced by the file name [pay attention to the problem of garbled Chinese documents] # {rand:6} # Will be replaced by a random number, followed by the number of digits of the random number # {time} # Will be replaced with a timestamp # {yyyy} # Will be replaced with a four digit year # {yy} # Will be replaced by two digit years # {mm} # Will be replaced by two digit months # {dd} # Will be replaced with two digit dates # {hh} # Will be replaced by two hours # {ii} # Will be replaced by two minutes # {ss} # Will be replaced by two bits of seconds Args: file_name: File name (including extended name) eg: index.html path_format: ueditor Of related items PathFormat See http://fex.baidu.com/ueditor/#server-path endswith_filename: control path_format If it does not end with a file name, whether to automatically append the end of the file name, True - additional """ self.reset() parts = [ "\\{filename\\}", "\\{rand:\\d+\\}", "\\{time\\}", "\\{yyyy\\}", "\\{yy\\}", "\\{mm\\}", "\\{dd\\}", "\\{hh\\}", "\\{ii\\}", "\\{ss\\}", ] file_name_fmt = '{filename}' regex = '(' + '|'.join(parts) + ')' matcher = re.compile(regex) if endswith_filename and not path_format.endswith(file_name_fmt): path_format = '/'.join([path_format, file_name_fmt]) self.url_path = matcher.sub(self._replace(file_name), path_format) return self.url_path @property def save_subpath(self): try: p = self.url_path except AttributeError: raise AttributeError('Please call format method before calling save_subpath.') parts = p.split(self.url_path_sep) return os.path.join('', *parts) def set_url_path_prefix(self, *directories): self.url_path_prefix = self.url_path_sep.join(directories) if not self.url_path_prefix.startswith(self.url_path_sep): self.url_path_prefix = self.url_path_sep + self.url_path_prefix if self.url_path.startswith(self.url_path_sep): self.url_path = self.url_path_prefix + self.url_path else: self.url_path = self.url_path_prefix + self.url_path.lstrip(self.url_path_sep) def reset(self): self.url_path_prefix = None self.url_path = None if __name__ == '__main__': formatter = UeditorPathFormatter() formatter.format('index.html', "/ueditor/php/upload/image/{yyyy}{mm}{dd}/{time}/{rand:11}/{filename}") print(formatter.url_path) print(formatter.save_subpath)