2019-05-22 14:12:11 +02:00
|
|
|
# Portions of this file are derived from Pleroma:
|
|
|
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
|
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
# Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/uploaders/local.ex
|
|
|
|
|
2020-01-26 21:36:50 +01:00
|
|
|
defmodule Mobilizon.Web.Upload.Uploader.Local do
|
2019-05-22 14:12:11 +02:00
|
|
|
@moduledoc """
|
|
|
|
Local uploader for files
|
|
|
|
"""
|
2019-09-08 00:05:54 +02:00
|
|
|
|
2020-01-26 21:36:50 +01:00
|
|
|
@behaviour Mobilizon.Web.Upload.Uploader
|
2019-05-22 14:12:11 +02:00
|
|
|
|
2019-09-08 00:05:54 +02:00
|
|
|
alias Mobilizon.Config
|
2020-10-26 10:53:56 +01:00
|
|
|
alias Mobilizon.Web.Upload
|
2019-09-08 00:05:54 +02:00
|
|
|
|
2020-10-25 12:00:00 +01:00
|
|
|
@impl true
|
2019-05-22 14:12:11 +02:00
|
|
|
def get_file(_) do
|
|
|
|
{:ok, {:static_dir, upload_path()}}
|
|
|
|
end
|
|
|
|
|
2020-10-25 12:00:00 +01:00
|
|
|
@impl true
|
2021-09-10 11:27:59 +02:00
|
|
|
@spec put_file(Upload.t()) ::
|
|
|
|
:ok | {:ok, {:file, String.t()}} | {:error, :tempfile_no_longer_exists}
|
2020-10-26 10:53:56 +01:00
|
|
|
def put_file(%Upload{path: path, tempfile: tempfile}) do
|
|
|
|
{path, file} = local_path(path)
|
2019-06-05 18:29:39 +02:00
|
|
|
result_file = Path.join(path, file)
|
2019-05-22 14:12:11 +02:00
|
|
|
|
2021-09-10 11:27:59 +02:00
|
|
|
if File.exists?(result_file) do
|
|
|
|
# If the resulting file already exists, it's because of the Dedupe filter
|
|
|
|
:ok
|
|
|
|
else
|
|
|
|
if File.exists?(tempfile) do
|
|
|
|
File.cp!(tempfile, result_file)
|
|
|
|
{:ok, {:file, result_file}}
|
|
|
|
else
|
|
|
|
{:error, :tempfile_no_longer_exists}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-10-26 10:53:56 +01:00
|
|
|
with {:result_exists, false} <- {:result_exists, File.exists?(result_file)},
|
|
|
|
{:temp_file_exists, true} <- {:temp_file_exists, File.exists?(tempfile)} do
|
|
|
|
File.cp!(tempfile, result_file)
|
|
|
|
else
|
|
|
|
{:result_exists, _} ->
|
|
|
|
# If the resulting file already exists, it's because of the Dedupe filter
|
|
|
|
:ok
|
2019-05-22 14:12:11 +02:00
|
|
|
|
2020-10-26 10:53:56 +01:00
|
|
|
{:temp_file_exists, _} ->
|
|
|
|
{:error, "Temporary file no longer exists"}
|
|
|
|
end
|
2019-05-22 14:12:11 +02:00
|
|
|
end
|
|
|
|
|
2020-10-25 12:00:00 +01:00
|
|
|
@impl true
|
2021-09-10 11:27:59 +02:00
|
|
|
@spec remove_file(String.t()) ::
|
|
|
|
{:ok, {:file, String.t()}}
|
|
|
|
| {:error, :folder_not_empty}
|
|
|
|
| {:error, :enofile}
|
|
|
|
| {:error, File.posix()}
|
2019-06-05 18:29:39 +02:00
|
|
|
def remove_file(path) do
|
2021-09-10 11:27:59 +02:00
|
|
|
{path, file} = local_path(path)
|
|
|
|
full_path = Path.join(path, file)
|
|
|
|
|
|
|
|
if File.exists?(full_path) do
|
|
|
|
do_remove_file(path, full_path)
|
2019-06-05 18:29:39 +02:00
|
|
|
else
|
2021-09-10 11:27:59 +02:00
|
|
|
{:error, :enofile}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
@spec do_remove_file(String.t(), String.t()) ::
|
|
|
|
{:ok, {:file, String.t()}}
|
|
|
|
| {:error, :folder_not_empty}
|
|
|
|
| {:error, File.posix()}
|
|
|
|
defp do_remove_file(path, full_path) do
|
|
|
|
case File.rm(full_path) do
|
|
|
|
:ok ->
|
|
|
|
case remove_folder(path) do
|
|
|
|
:ok ->
|
|
|
|
{:ok, {:file, path}}
|
|
|
|
|
|
|
|
{:error, err} ->
|
|
|
|
{:error, err}
|
|
|
|
end
|
|
|
|
|
|
|
|
{:error, err} ->
|
|
|
|
{:error, err}
|
2019-06-05 18:29:39 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-09-10 11:27:59 +02:00
|
|
|
@spec remove_folder(String.t()) :: :ok | {:error, :folder_not_empty} | {:error, File.posix()}
|
2019-06-05 18:29:39 +02:00
|
|
|
defp remove_folder(path) do
|
|
|
|
with {:subfolder, true} <- {:subfolder, path != upload_path()},
|
|
|
|
{:empty_folder, {:ok, [] = _files}} <- {:empty_folder, File.ls(path)} do
|
|
|
|
File.rmdir(path)
|
|
|
|
else
|
|
|
|
{:subfolder, _} -> :ok
|
2021-09-10 11:27:59 +02:00
|
|
|
{:empty_folder, _} -> {:error, :folder_not_empty}
|
2019-06-05 18:29:39 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-09-10 11:27:59 +02:00
|
|
|
@spec local_path(String.t()) :: {String.t(), String.t()}
|
2019-06-05 18:29:39 +02:00
|
|
|
defp local_path(path) do
|
|
|
|
case Enum.reverse(String.split(path, "/", trim: true)) do
|
|
|
|
[file] ->
|
|
|
|
{upload_path(), file}
|
|
|
|
|
|
|
|
[file | folders] ->
|
|
|
|
path = Path.join([upload_path()] ++ Enum.reverse(folders))
|
|
|
|
File.mkdir_p!(path)
|
|
|
|
{path, file}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-09-10 11:27:59 +02:00
|
|
|
@spec upload_path :: String.t()
|
2019-05-22 14:12:11 +02:00
|
|
|
def upload_path do
|
2019-09-08 00:05:54 +02:00
|
|
|
Config.get!([__MODULE__, :uploads])
|
2019-05-22 14:12:11 +02:00
|
|
|
end
|
|
|
|
end
|