{"id":13833587,"url":"https://github.com/jungsoft/uploadex","last_synced_at":"2025-04-09T07:07:36.181Z","repository":{"id":56221188,"uuid":"195479996","full_name":"jungsoft/uploadex","owner":"jungsoft","description":"Elixir library for handling uploads with Ecto, Phoenix and Absinthe","archived":false,"fork":false,"pushed_at":"2024-12-06T14:54:11.000Z","size":146,"stargazers_count":28,"open_issues_count":1,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-02T06:09:39.834Z","etag":null,"topics":["elixir","storage","upload"],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/uploadex","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jungsoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-06T00:17:53.000Z","updated_at":"2024-12-06T14:54:15.000Z","dependencies_parsed_at":"2024-01-15T18:45:32.984Z","dependency_job_id":"a412a22b-1112-4f06-9286-38b11570f0d9","html_url":"https://github.com/jungsoft/uploadex","commit_stats":null,"previous_names":["gabrielpra1/uploadex"],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jungsoft%2Fuploadex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jungsoft%2Fuploadex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jungsoft%2Fuploadex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jungsoft%2Fuploadex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jungsoft","download_url":"https://codeload.github.com/jungsoft/uploadex/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247994121,"owners_count":21030050,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elixir","storage","upload"],"created_at":"2024-08-04T12:00:51.418Z","updated_at":"2025-04-09T07:07:36.167Z","avatar_url":"https://github.com/jungsoft.png","language":"Elixir","readme":"# Uploadex\n\nUploadex is an Elixir library for handling uploads that integrates well with [Ecto](https://github.com/elixir-ecto/ecto), [Phoenix](https://github.com/phoenixframework/phoenix) and [Absinthe](https://github.com/absinthe-graphql/absinthe).\n\nDocumentation can be found at https://hexdocs.pm/uploadex.\n\n## Migrating from v2 to v3\n\n1. In you uploader, change `@behaviour Uploadex.Uploader` to `use Uploadex`\n1. Remove all `config :uploadex` from your configuration files\n1. Change all direct functions calls from `Uploadex.Resolver`, `Uploadex.Files` and `Uploadex` to your Uploader module\n\n## Installation\n\nThe package can be installed by adding `uploadex` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:uploadex, \"~\u003e 3.1.0\"},\n    # S3 dependencies(required for S3 storage only)\n    {:ex_aws, \"~\u003e 2.1\"},\n    {:ex_aws_s3, \"~\u003e 2.0.2\"},\n    {:sweet_xml, \"~\u003e 0.6\"},\n  ]\nend\n```\n\n## Usage\n\nFollow these steps to use Uploadex:\n\n### 1: Uploader\n\nThis library relies heavily on pattern matching for configuration, so the first step is to define your Uploader configuration module:\n\n```elixir\ndefmodule MyApp.Uploader do\n  @moduledoc false\n\n  use Uploadex,\n    repo: MyApp.Repo # only necessary if using the functions from Uploadex.Context\n\n  alias MyAppWeb.Endpoint\n\n  @impl true\n  def get_fields(%User{}), do: :photo\n  def get_fields(%Company{}), do: [:photo, :logo]\n\n  @impl true\n  def default_opts(Uploadex.FileStorage), do: [base_path: Path.join(:code.priv_dir(:my_app), \"static/\"), base_url: Endpoint.url()]\n  def default_opts(Uploadex.S3Storage), do: [bucket: \"my_bucket\", region: \"sa-east-1\", upload_opts: [acl: :public_read]]\n\n  @impl true\n  def storage(%User{id: id}, :photo), do: {Uploadex.FileStorage, directory: \"/uploads/users/#{id}\"}\n  def storage(%Company{id: id}, :photo), do: {Uploadex.S3Storage, directory: \"/thumbnails/#{id}\"}\n  def storage(%Company{}, :logo), do: {Uploadex.S3Storage, directory: \"/logos\"}\n\n  # Optional:\n  @impl true\n  def accepted_extensions(%User{}, :photo), do: ~w(.jpg .png)\n  def accepted_extensions(_any, _field), do: :any\nend\n```\n\nThis example shows the configuration for the [Uploadex.FileStorage](https://hexdocs.pm/uploadex/Uploadex.FileStorage.html#content) and [Uploadex.S3Storage](https://hexdocs.pm/uploadex/Uploadex.S3Storage.html#content) implementations, but you are free to implement your own [Storage](https://hexdocs.pm/uploadex/Uploadex.Storage.html#content).\n\n*Note: To avoid too much metaprogramming magic, the `use` in this module is very simple and, in fact, optional. If you wish to do so, you can just define the `@behaviour Uploadex.Uploader` instead of the `use` and then call all lower level modules directly, passing your Uploader module as argument. The `use` makes life much easier, though!*\n\n### 2: Ecto Migration\n\nA string field is required in the database to save the file reference.\nThe example below shows what would be needed to have a field to upload.\n\n```elixir\ndefmodule MyApp.Repo.Migrations.AddPhotoToUsers do\n  use Ecto.Migration\n\n  def change do\n    alter table(:users) do\n      add :photo, :string\n    end\n  end\nend\n```\n\n### 3: Schema\n\nIn your schema, use the Ecto Type [Uploadex.Upload](https://hexdocs.pm/uploadex/Uploadex.Upload.html#content):\n\n```elixir\nschema \"users\" do\n  field :name, :string\n  field :photo, Uploadex.Upload\nend\n\n# No special cast is needed, and casting does not have any side effects.\ndef create_changeset(%User{} = user, attrs) do\n  user\n  |\u003e cast(attrs, [:name, :photo])\nend\n```\n\n### 4: Configuration\n\nDepending on which features you are using, you may need extra configurations:\n\n#### S3 Configuration\n\nIf you are using the S3 adapter, add this to your configuration file. For more information access the [ex_aws_s3 documentation](https://github.com/ex-aws/ex_aws_s3):\n\n```elixir\nconfig :ex_aws, :s3,\n  access_key_id: \"key\",\n  secret_access_key: \"secret\",\n  region: \"us-east-1\",\n  host: \"localhost\",\n  port: \"9000\",\n  scheme: \"http://\"\n\nconfig :my_project, :uploads,\n  bucket: \"uploads\",\n  region: \"us-east-1\"\n```\n\n### 5: Enjoy!\n\nNow, you can use your defined Uploader to handle your records with their files!\n\nThe `use Uploadex` line in your Uploader module will import 3 groups of functions:\n\n#### Context\n\n  The highest level functions are context helpers (see [Context](https://hexdocs.pm/uploadex/Uploadex.Context.html) for more documentation), which will allow you to easily create, update and delete your records with associated files:\n\n  ```elixir\n  defmodule MyApp.Accounts do\n    alias MyApp.Accounts.User\n    alias MyApp.MyUploader\n\n    def create_user(attrs) do\n      %User{}\n      |\u003e User.create_changeset(attrs)\n      |\u003e MyUploader.create_with_file()\n    end\n\n    def update_user(%User{} = user, attrs) do\n      user\n      |\u003e User.update_changeset(attrs)\n      |\u003e MyUploader.update_with_file(user)\n    end\n\n    def delete_user(%User{} = user) do\n      MyUploader.delete_with_file(user)\n    end\n  end\n  ```\n\n#### Resolver\n\n  There are also functions to help you easily fetch the files in Absinthe schemas:\n\n  ```elixir\n  object :user do\n    field :photo_url, :string, resolve: MyUploader.get_file_url(:photo)\n  end\n\n  object :user do\n    field :photos, list_of(:string), resolve: MyUploader.get_files_url(:photos)\n  end\n  ```\n\n  See [Resolver](https://hexdocs.pm/uploadex/Uploadex.Resolver.html#content) for more documentation.\n\n#### Files\n\nIf you need more flexibility, you can use the lower-level functions defined in [Files](https://hexdocs.pm/uploadex/Uploadex.Files.html#content), which provide some extra functionalities, such as `get_temporary_file`, useful when the files are not publicly available.\n\nSome examples:\n\n```elixir\n{:ok, %User{}} = MyUploader.store_files(user)\n{:ok, %User{}} = MyUploader.delete_files(user)\n{:ok, %User{}} = MyUploader.delete_previous_files(user, user_after_change)\n{:ok, files} = MyUploader.get_files_url(user, :photos)\n```\n\n## Testing\n\nFor knowing how to test with Uploadex, check the hexdocs of the [Testing](https://hexdocs.pm/uploadex/Uploadex.Testing.html#content) module.\n\n## Motivation\n\nEven though there already exists a library for uploading files that integrates with ecto (https://github.com/stavro/arc_ecto), this library was created because:\n\n* arc_ecto does not support upload of binary files\n* Uploadex makes it easier to deal with records that contain files without having to manage those files manually on every operation\n* Using uploadex, the changeset operations have no side-effects and no special casting is needed\n* Uploadex offers more flexibility by allowing to define different storage configurations for each struct (or even each field in a struct) in the application\n* Uploadex does not rely on global configuration, which makes it easier to work in umbrella applications\n","funding_links":[],"categories":["Running the update"],"sub_categories":["By Popularity"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjungsoft%2Fuploadex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjungsoft%2Fuploadex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjungsoft%2Fuploadex/lists"}