From d66a8805d0289b6c1724ebff8bf52197e810cd40 Mon Sep 17 00:00:00 2001 From: HaimKortovich Date: Wed, 29 Apr 2026 12:18:52 -0500 Subject: [PATCH] dont use S3 directly allow to use any document url (document service agnostic) --- config/config.exs | 2 - config/dev.exs | 15 ----- config/runtime.exs | 15 ----- flake.nix | 2 +- lib/provider_service/aggregates/provider.ex | 31 ++++------ lib/provider_service/commands/provider.ex | 2 +- lib/provider_service/events/provider.ex | 4 +- .../projections/provider_projection.ex | 4 +- .../queries/provider_queries.ex | 4 +- lib/provider_service/s3.ex | 38 ------------ .../controllers/provider_controller.ex | 9 +-- .../controllers/template_controller.ex | 59 ++++++------------- lib/provider_service_web/query_helpers.ex | 34 +++++++++++ lib/provider_service_web/schemas/provider.ex | 30 ++-------- mix.exs | 9 +-- ops/chart/values.yaml | 16 ----- 16 files changed, 78 insertions(+), 196 deletions(-) delete mode 100644 lib/provider_service/s3.ex create mode 100644 lib/provider_service_web/query_helpers.ex diff --git a/config/config.exs b/config/config.exs index ac2d98b..70f0b9c 100644 --- a/config/config.exs +++ b/config/config.exs @@ -45,8 +45,6 @@ config :commanded_ecto_projections, config :flop, repo: ProviderService.Repo -config :provider_service, :s3_bucket, "provider-service" - # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{config_env()}.exs" diff --git a/config/dev.exs b/config/dev.exs index 6bb08ab..85806d8 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -17,16 +17,6 @@ config :provider_service, ProviderServiceWeb.Endpoint, debug_errors: true, secret_key_base: "localdevsecretkeybase1234567890localdevsecretkeybase1234567890xx" -config :ex_aws, - access_key_id: "minioadmin", - secret_access_key: "minioadmin", - region: "us-east-1" - -config :ex_aws, :s3, - scheme: "http://", - host: "localhost", - port: 9000 - config :provider_service, ProviderService.EventStore, serializer: Commanded.Serialization.JsonSerializer, username: "postgres", @@ -34,8 +24,3 @@ config :provider_service, ProviderService.EventStore, database: "provider_service_eventstore_dev", hostname: "localhost", pool_size: 10 - -config :provider_service, :s3_bucket, "provider-service" - -config :provider_service, - solicitation_service_url: "http://localhost:8081" diff --git a/config/runtime.exs b/config/runtime.exs index d6b1b1f..e897b2c 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -21,21 +21,6 @@ config :logger, level: logger_level config :logger, :console, format: {Logger.Formatter, :format} -s3_host = System.get_env("S3_HOST", "dev.s3.corredorconect.com") -s3_port = System.get_env("S3_PORT", "443") - -config :ex_aws, - access_key_id: System.get_env("AWS_ACCESS_KEY_ID"), - secret_access_key: System.get_env("AWS_SECRET_ACCESS_KEY"), - region: System.get_env("AWS_REGION", "us-east-1") - -config :ex_aws, :s3, - scheme: "https://", - host: s3_host, - port: s3_port - -config :provider_service, :s3_bucket, System.get_env("S3_BUCKET", "provider-service") - cors_origin = System.get_env("CORS_ORIGIN", "*") config :cors_plug, diff --git a/flake.nix b/flake.nix index a7300ee..582b73c 100644 --- a/flake.nix +++ b/flake.nix @@ -21,7 +21,7 @@ mixFodDeps = beamPackages.fetchMixDeps { inherit pname version; src = pkgs.lib.cleanSource ./.; - sha256 = "sha256-t6D0qjPNnAsYtHbwOCbuNBUwcrkvmmGf4/LeOIWgjyw="; + sha256 = "sha256-NMcH0z3ME4pCFXpKBK+GjBR6Fkv0wNeQcMlQFDxNLFo="; }; package = beamPackages.mixRelease { inherit pname version mixFodDeps; diff --git a/lib/provider_service/aggregates/provider.ex b/lib/provider_service/aggregates/provider.ex index a2a9ed0..bfef9c5 100644 --- a/lib/provider_service/aggregates/provider.ex +++ b/lib/provider_service/aggregates/provider.ex @@ -98,21 +98,16 @@ defmodule ProviderService.Aggregates.Provider do def execute(%__MODULE__{active: false}, %AddProviderTemplate{}), do: {:error, :provider_inactive} - def execute(%__MODULE__{} = agg, %AddProviderTemplate{} = cmd) do - existing = get_in(agg.templates, [cmd.policy_type, cmd.client_type]) || [] - version = length(existing) + 1 - - %ProviderTemplateAdded{ - provider_id: agg.provider_id, - template_id: cmd.template_id, - policy_type: cmd.policy_type, - client_type: cmd.client_type, - s3_key: cmd.s3_key, - fields: cmd.fields, - version: version, - added_at: DateTime.utc_now() - } - end + def execute(%__MODULE__{} = agg, %AddProviderTemplate{} = cmd) do + %ProviderTemplateAdded{ + provider_id: agg.provider_id, + template_id: cmd.template_id, + policy_type: cmd.policy_type, + client_type: cmd.client_type, + document_url: cmd.document_url, + added_at: DateTime.utc_now() + } + end def execute(%__MODULE__{} = agg, %ActivateProviderTemplate{} = cmd) do case find_template(agg, cmd.policy_type, cmd.client_type, cmd.template_id) do @@ -235,10 +230,8 @@ defmodule ProviderService.Aggregates.Provider do [ %{ template_id: e.template_id, - s3_key: e.s3_key, - fields: e.fields, - version: e.version, - active: true + document_url: e.document_url, + active: false } ] ) diff --git a/lib/provider_service/commands/provider.ex b/lib/provider_service/commands/provider.ex index 4e87f85..4868f2a 100644 --- a/lib/provider_service/commands/provider.ex +++ b/lib/provider_service/commands/provider.ex @@ -16,7 +16,7 @@ defmodule ProviderService.Commands do end defmodule AddProviderTemplate do - defstruct [:provider_id, :template_id, :policy_type, :s3_key, :fields, :client_type] + defstruct [:provider_id, :template_id, :policy_type, :document_url, :client_type] end defmodule ActivateProviderTemplate do diff --git a/lib/provider_service/events/provider.ex b/lib/provider_service/events/provider.ex index 28dd88f..931a31c 100644 --- a/lib/provider_service/events/provider.ex +++ b/lib/provider_service/events/provider.ex @@ -25,9 +25,7 @@ defmodule ProviderService.Events do :provider_id, :template_id, :policy_type, - :s3_key, - :fields, - :version, + :document_url, :added_at, :client_type ] diff --git a/lib/provider_service/projections/provider_projection.ex b/lib/provider_service/projections/provider_projection.ex index 5b6161d..028db82 100644 --- a/lib/provider_service/projections/provider_projection.ex +++ b/lib/provider_service/projections/provider_projection.ex @@ -76,9 +76,7 @@ defmodule ProviderService.Projections.ProviderProjection do template = %{ "template_id" => e.template_id, "client_type" => e.client_type, - "s3_key" => e.s3_key, - "fields" => e.fields || [], - "version" => e.version, + "document_url" => e.document_url, "active" => false } diff --git a/lib/provider_service/queries/provider_queries.ex b/lib/provider_service/queries/provider_queries.ex index 12d9cc0..18188d1 100644 --- a/lib/provider_service/queries/provider_queries.ex +++ b/lib/provider_service/queries/provider_queries.ex @@ -1,9 +1,11 @@ defmodule ProviderService.Queries.ProviderQueries do + import Ecto.Query alias ProviderService.Projections.Provider alias ProviderService.Repo def list_providers(params \\ %{}) do - Flop.validate_and_run(Provider, params, for: Provider) + base = from(p in Provider) + Flop.validate_and_run(base, params, for: Provider) end def get_provider(provider_id) do diff --git a/lib/provider_service/s3.ex b/lib/provider_service/s3.ex deleted file mode 100644 index 8a4cd6f..0000000 --- a/lib/provider_service/s3.ex +++ /dev/null @@ -1,38 +0,0 @@ -defmodule ProviderService.S3 do - @bucket Application.compile_env(:provider_service, :s3_bucket) - - def presigned_upload_url(s3_key) do - {:ok, url} = - ExAws.Config.new(:s3) - |> ExAws.S3.presigned_url(:put, @bucket, s3_key, - expires_in: 900, - query_params: [{"Content-Type", "application/pdf"}] - ) - - url - end - - def presigned_download_url(s3_key) do - {:ok, url} = - ExAws.Config.new(:s3) - |> ExAws.S3.presigned_url(:get, @bucket, s3_key, expires_in: 3600) - - url - end - - def delete(s3_key) do - ExAws.S3.delete_object(@bucket, s3_key) - |> ExAws.request() - end - - def upload(local_path, s3_key) do - local_path - |> File.read!() - |> then(&ExAws.S3.put_object(@bucket, s3_key, &1, content_type: "application/pdf")) - |> ExAws.request() - |> case do - {:ok, _} -> :ok - {:error, e} -> {:error, inspect(e)} - end - end -end diff --git a/lib/provider_service_web/controllers/provider_controller.ex b/lib/provider_service_web/controllers/provider_controller.ex index 8381d5b..2aa4fe3 100644 --- a/lib/provider_service_web/controllers/provider_controller.ex +++ b/lib/provider_service_web/controllers/provider_controller.ex @@ -13,16 +13,11 @@ defmodule ProviderServiceWeb.ProviderController do } alias ProviderServiceWeb.Schemas.Provider, as: PS + alias ProviderServiceWeb.QueryHelpers operation(:index, summary: "List providers", - parameters: [ - "page[number]": [in: :query, type: :integer, required: false], - "page[size]": [in: :query, type: :integer, required: false], - "filters[0][field]": [in: :query, type: :string, required: false], - "filters[0][op]": [in: :query, type: :string, required: false], - "filters[0][value]": [in: :query, type: :string, required: false] - ], + parameters: QueryHelpers.flop([:active, :search], [:name, :inserted_at]), responses: [ ok: {"Provider list", "application/json", PS.ProviderListResponse} ] diff --git a/lib/provider_service_web/controllers/template_controller.ex b/lib/provider_service_web/controllers/template_controller.ex index 74a1dba..1b0cce0 100644 --- a/lib/provider_service_web/controllers/template_controller.ex +++ b/lib/provider_service_web/controllers/template_controller.ex @@ -13,7 +13,6 @@ defmodule ProviderServiceWeb.TemplateController do RemoveProviderTemplate } - alias ProviderService.S3 alias ProviderServiceWeb.Schemas.Provider, as: PS operation(:index, @@ -37,65 +36,41 @@ defmodule ProviderServiceWeb.TemplateController do end operation(:upload_template, - summary: "Upload solicitation template", - description: "Upload a fillable PDF. Fields are auto-discovered via solicitation_service.", + summary: "Register template by document URL", + description: "Register a template document URL for a provider.", parameters: [ provider_id: [in: :path, type: :string, required: true] ], request_body: - {"Multipart PDF upload", "multipart/form-data", PS.UploadTemplateRequest, required: true}, + {"Document URL payload", "application/json", PS.UploadTemplateRequest, required: true}, responses: [ created: {"Template registered", "application/json", PS.UploadTemplateResponse} ] ) def upload_template(conn, %{"provider_id" => provider_id} = params) do - # %Plug.Upload{} - upload = params["file"] + document_url = params["document_url"] policy_type = params["policy_type"] client_type = params["client_type"] template_id = Ecto.UUID.generate() - s3_key = "templates/#{provider_id}/#{policy_type}/#{client_type}/#{template_id}.pdf" - # Upload to S3/MinIO - case S3.upload(upload.path, s3_key) do + cmd = %AddProviderTemplate{ + provider_id: provider_id, + template_id: template_id, + client_type: client_type, + policy_type: policy_type, + document_url: document_url + } + + case ProviderService.CommandedApp.dispatch(cmd) do :ok -> - # Discover AcroForm fields via solicitation_service - fields = discover_fields(s3_key) - - cmd = %AddProviderTemplate{ - provider_id: provider_id, - template_id: template_id, - client_type: client_type, - policy_type: policy_type, - s3_key: s3_key, - fields: fields - } - - case ProviderService.CommandedApp.dispatch(cmd) do - :ok -> - conn - |> put_status(:created) - |> json(%{template_id: template_id, s3_key: s3_key, fields: fields}) - - {:error, reason} -> - conn |> put_status(:unprocessable_entity) |> json(%{error: reason}) - end + conn + |> put_status(:created) + |> json(%{template_id: template_id, document_url: document_url}) {:error, reason} -> - conn - |> put_status(:internal_server_error) - |> json(%{error: "S3 upload failed: #{reason}"}) - end - end - - defp discover_fields(s3_key) do - url = Application.get_env(:provider_service, :solicitation_service_url) - - case Req.get("#{url}/api/solicitations/templates/fields", params: [s3_key: s3_key]) do - {:ok, %{status: 200, body: %{"fields" => fields}}} -> fields - _ -> [] + conn |> put_status(:unprocessable_entity) |> json(%{error: reason}) end end diff --git a/lib/provider_service_web/query_helpers.ex b/lib/provider_service_web/query_helpers.ex new file mode 100644 index 0000000..440b874 --- /dev/null +++ b/lib/provider_service_web/query_helpers.ex @@ -0,0 +1,34 @@ +defmodule ProviderServiceWeb.QueryHelpers do + @moduledoc false + + alias OpenApiSpex.Schema + + @filter_count 3 + + def flop(filter_fields, order_fields, other \\ []) do + [ + page: [in: :query, schema: %Schema{type: :number, default: 1}], + page_size: [in: :query, schema: %Schema{type: :number, default: 20}], + order_by: [ + in: :query, + schema: %Schema{type: :array, items: %Schema{type: :string, enum: order_fields}} + ], + order_directions: [ + in: :query, + schema: %Schema{type: :array, items: %Schema{type: :string, enum: ["asc", "desc"]}} + ] + ] ++ build_filter_params(filter_fields) ++ other + end + + defp build_filter_params(fields) do + for i <- 0..(@filter_count - 1) do + [ + {:"filters[#{i}][field]", [in: :query, schema: %Schema{type: :string, enum: fields}]}, + {:"filters[#{i}][op]", + [in: :query, schema: %Schema{type: :string, enum: Flop.Filter.allowed_operators(:all)}]}, + {:"filters[#{i}][value]", [in: :query, schema: %Schema{type: :string}]} + ] + end + |> List.flatten() + end +end diff --git a/lib/provider_service_web/schemas/provider.ex b/lib/provider_service_web/schemas/provider.ex index e4162e1..136bc77 100644 --- a/lib/provider_service_web/schemas/provider.ex +++ b/lib/provider_service_web/schemas/provider.ex @@ -18,22 +18,6 @@ defmodule ProviderServiceWeb.Schemas.Provider do }) end - defmodule TemplateField do - require OpenApiSpex - - OpenApiSpex.schema(%{ - title: "TemplateField", - type: :object, - properties: %{ - field: %Schema{type: :string, example: "beneficiary_name"}, - label: %Schema{type: :string, example: "Beneficiary Name"}, - type: %Schema{type: :string, enum: ["string", "date", "number", "select", "boolean"]}, - required: %Schema{type: :boolean}, - options: %Schema{type: :array, items: %Schema{type: :string}, nullable: true} - } - }) - end - defmodule Template do require OpenApiSpex @@ -44,9 +28,7 @@ defmodule ProviderServiceWeb.Schemas.Provider do template_id: %Schema{type: :string, format: :uuid}, policy_type: %Schema{type: :string, enum: ["car", "life", "fire"]}, client_type: %Schema{type: :string, enum: ["natural", "juridico"]}, - s3_key: %Schema{type: :string}, - version: %Schema{type: :integer}, - fields: %Schema{type: :array, items: TemplateField}, + document_url: %Schema{type: :string}, active: %Schema{type: :boolean} } }) @@ -98,12 +80,11 @@ defmodule ProviderServiceWeb.Schemas.Provider do OpenApiSpex.schema(%{ title: "UploadTemplateRequest", type: :object, - required: [:file, :policy_type, :client_type], + required: [:document_url, :policy_type, :client_type], properties: %{ - file: %Schema{ + document_url: %Schema{ type: :string, - format: :binary, - description: "Fillable PDF (AcroForm)" + description: "URL to the uploaded document" }, policy_type: %Schema{ type: :string, @@ -127,8 +108,7 @@ defmodule ProviderServiceWeb.Schemas.Provider do type: :object, properties: %{ template_id: %Schema{type: :string, format: :uuid}, - s3_key: %Schema{type: :string}, - fields: %Schema{type: :array, items: TemplateField} + document_url: %Schema{type: :string} } }) end diff --git a/mix.exs b/mix.exs index 233f07d..9a3d475 100644 --- a/mix.exs +++ b/mix.exs @@ -46,14 +46,7 @@ defmodule ProviderService.MixProject do {:open_api_spex, "~> 3.21"}, # Pagination - {:flop, "~> 0.26"}, - - # AWS S3 - {:ex_aws, "~> 2.5"}, - {:ex_aws_s3, "~> 2.5"}, - {:hackney, "~> 1.20"}, - {:req, "~> 0.5"}, - {:sweet_xml, "~> 0.7"} + {:flop, "~> 0.26"} ] end diff --git a/ops/chart/values.yaml b/ops/chart/values.yaml index 0af738c..29aba4e 100644 --- a/ops/chart/values.yaml +++ b/ops/chart/values.yaml @@ -43,22 +43,6 @@ controllers: value: "*" PHX_HOST: "0.0.0.0" PHX_SERVER: "true" - S3_HOST: - value: "dev.s3.corredorconect.com" - S3_BUCKET: - value: "provider-service" - AWS_REGION: - value: "us-east-1" - AWS_ACCESS_KEY_ID: - valueFrom: - secretKeyRef: - name: '{{ include "bjw-s.common.lib.chart.names.fullname" $ }}-s3-credentials' - key: rootAccessKeyId - AWS_SECRET_ACCESS_KEY: - valueFrom: - secretKeyRef: - name: '{{ include "bjw-s.common.lib.chart.names.fullname" $ }}-s3-credentials' - key: rootSecretAccessKey RELEASE_COOKIE: valueFrom: secretKeyRef: