Ejemplo n.º 1
0
 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),
     )
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
    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})
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
 def get_name(self) -> str:
     """Get the name of the source (i.e. basename)."""
     return utf8_basename(self.file_path)
Ejemplo n.º 7
0
    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),
        )
Ejemplo n.º 8
0
    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),
        )