def render( self, request: HttpRequest, editing_context: SourceEditContext, extra_context: typing.Optional[dict] = None, ) -> HttpResponse: render_context = { "project": self.project, "has_edit_permission": self.has_permission(ProjectPermissionType.EDIT), "file_name": utf8_basename(editing_context.path), "file_directory": utf8_dirname(editing_context.path), "file_path": editing_context.path, "file_extension": editing_context.extension, "file_content": editing_context.content, "file_editable": editing_context.editable, "source": editing_context.source, "supports_commit_message": editing_context.supports_commit_message, } render_context.update(extra_context or {}) return render( request, "projects/source_open.html", self.get_render_context(render_context), )
def make_directory_entry(directory: str, source: Source): relative_path = strip_directory(source.path, directory) entry_type = determine_entry_type(source, relative_path) if entry_type == DirectoryEntryType.FILE: name = utf8_basename(relative_path) else: name = relative_path.split("/")[0] full_path = utf8_path_join(directory, name) return DirectoryListEntry(name, full_path, entry_type, source)
def post(self, request: HttpRequest, account_name: str, project_name: str) -> HttpResponse: # type: ignore project = self.get_project(request.user, account_name, project_name) body = json.loads(request.body) source_id = body["source_id"] source_path = body["source_path"] target_id = body["target_type"] target_name = body["target_name"] if "/" in target_name: raise ValueError("Target name can not contain /") if source_id: source = get_object_or_404(Source, project=project, pk=source_id) else: source = DiskSource() scf = make_source_content_facade(request.user, source_path, source, project) target_path = utf8_path_join(utf8_dirname(source_path), target_name) target_type = ConversionFormatId.from_id(target_id) try: self.source_convert(request, project, scf, target_path, target_name, target_type) except oauth2client.client.Error: return JsonResponse({ "success": False, "error": "Could not authenticate with your Google account." "Please try logging into Stencila Hub with " "your Google account to refresh the token.", }) except RuntimeError: return JsonResponse({ "success": False, "error": "Conversion of your document failed. Please check the Project Activity page for more " "information.", }) for message in scf.message_iterator(): messages.add_message(request, message.level, message.message) messages.success( request, "{} was converted.".format(utf8_basename(source_path))) return JsonResponse({"success": True})
def move_file(self, current_relative_path: str, new_relative_path: str) -> None: current_path = self.full_file_path(current_relative_path) new_path = self.full_file_path(new_relative_path) if utf8_isdir(new_path): # path moving to is a directory so actually move inside the path filename = utf8_basename(current_path) new_path = utf8_path_join(new_path, filename) if utf8_path_exists(new_path): raise OSError( "Can not move {} to {} as target file exists.".format( current_relative_path, new_relative_path ) ) utf8_makedirs(utf8_dirname(new_path), exist_ok=True) utf8_rename(current_path, new_path)
def do_conversion( self, project: Project, user: User, source_type: typing.Optional[ConversionFormatId], source_path: str, target_type: ConversionFormatId, target_path: typing.Optional[str] = None, standalone: bool = False, ) -> str: """ Perform a conversion (with Encoda). If `target_path` is not set then a `NamedTemporaryFile` is created and its path returned. The temporary file is not cleaned up. """ if not target_path: with tempfile.NamedTemporaryFile(delete=False) as temp_output: target_path = temp_output.name converter_input = ConverterIo(ConverterIoType.PATH, source_path, source_type) converter_output = ConverterIo(ConverterIoType.PATH, target_path, target_type) context = ConverterContext(standalone=standalone) source_type_desc = " from {}".format( source_type.name) if source_type else "" event = ProjectEvent.objects.create( event_type=ProjectEventType.CONVERT.name, project=project, user=logged_in_or_none(user), message="Conversion of {}{} to {}".format( utf8_basename(source_path), source_type_desc, target_type.name), ) convert_result = self.converter.convert(converter_input, converter_output, context) std_err = convert_result.stderr.decode("ascii") if std_err: try: # split on new line, decode JSOn event.log = list( map(json.loads, filter(lambda x: x, std_err.split("\n")))) except (TypeError, ValueError): event.log = {"stderr": std_err} event.finished = timezone.now() if convert_result.returncode != 0: event.success = False event.save() raise RuntimeError( "Convert process failed. Stderr is: {}".format(std_err)) event.success = True event.save() return target_path
def get_name(self) -> str: """Get the name of the source (i.e. basename).""" return utf8_basename(self.file_path)
def get( # type: ignore self, request: HttpRequest, account_name: str, project_name: str, path: str, ) -> HttpResponse: project = self.get_project(request.user, account_name, project_name) source = get_source(request.user, project, path) scf = make_source_content_facade(request.user, path, source, project) # the isinstance check is because Source might be a DiskSource which is not a subclass of Source pi, created = PublishedItem.objects.get_or_create( project=project, source_path=path, source=source if isinstance(source, Source) else None, snapshot=None, ) if created or scf.source_modification_time > pi.updated or not pi.path: try: self.convert_and_publish(request.user, project, pi, created, source, path, scf) except (NonFileError, UnknownMimeTypeError, RuntimeError) as e: filename = utf8_basename(path) directory = utf8_dirname(path) # by default, no message since the user might have just entered a bad URL message_format: typing.Optional[str] = None if isinstance(e, RuntimeError): message_format = ( "Unable to preview <em>{}</em> as it could not be converted to HTML. Please " "check the Project Activity page for more information." ) elif isinstance(e, UnknownMimeTypeError): message_format = "Unable to preview <em>{}</em> as its file type could not be determined." messages.error( request, "Unable to preview <em>{}</em> as its file type could not be determined." .format(escape(utf8_basename(path))), extra_tags="safe", ) if message_format: messages.error( request, message_format.format(escape(filename)), extra_tags="safe", ) if directory: return redirect("project_files_path", account_name, project, directory) return redirect("project_files", account_name, project_name) return published_item_render( request, pi, reverse( "file_source_download", args=(project.account.name, project.name, pi.source_path), ), "HTML Preview of {}".format(pi.source_path), )
def get( # type: ignore self, request: HttpRequest, account_name: str, project_name: str, version: int, path: str, ) -> HttpResponse: snapshot, file_path = self.get_snapshot_and_path( request, account_name, project_name, version, path) if file_path is None: raise TypeError( "Can't work with None path. But this won't happen unless path being passed is None." ) pi, created = PublishedItem.objects.get_or_create(project=self.project, snapshot=snapshot, source_path=path) published_path = utf8_path_join( generate_snapshot_publish_directory(settings.STORAGE_DIR, snapshot), "{}.html".format(pi.pk), ) if created or not pi.path: # don't bother checking modification time since snapshots shouldn't change try: source_type = conversion_format_from_path(file_path) self.do_conversion( snapshot.project, request.user, source_type, file_path, ConversionFormatId.html, published_path, False, ) pi.path = published_path pi.save() except Exception as e: if created: pi.delete() if not isinstance(e, (UnknownMimeTypeError, RuntimeError)): raise filename = escape(utf8_basename(path)) if isinstance(e, UnknownMimeTypeError): error_format = "Unable to preview <em>{}</em> as its file type could not be determined." else: error_format = ( "Unable to preview <em>{}</em> as it could not be converted to HTML. Please " "check the Project Activity page for more information." ) messages.error(request, error_format.format(filename), extra_tags="safe") dirname = utf8_dirname(path) redirect_args = [ snapshot.project.account.name, snapshot.project.name, snapshot.version_number, ] if dirname: redirect_args.append(dirname) redirect_view = "snapshot_files_path" else: redirect_view = "snapshot_files" return redirect(redirect_view, *redirect_args) project = self.project return published_item_render( request, pi, reverse( "api-snapshots-retrieve-file", args=( project.id, snapshot.number, pi.source_path, ), ), "HTML Preview of {}".format(pi.source_path), )