Skip to content

Commit

Permalink
Merge branch 'release/0.3.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Flo0807 committed Jun 13, 2024
2 parents 04cb27b + 5d7620d commit 4831e9e
Show file tree
Hide file tree
Showing 39 changed files with 1,540 additions and 947 deletions.
119 changes: 1 addition & 118 deletions .credo.exs
Original file line number Diff line number Diff line change
Expand Up @@ -16,124 +16,7 @@
parse_timeout: 5000,
color: true,
checks: %{
enabled: [
#
## Consistency Checks
#
{Credo.Check.Consistency.ExceptionNames, []},
{Credo.Check.Consistency.LineEndings, []},
{Credo.Check.Consistency.MultiAliasImportRequireUse, []},
{Credo.Check.Consistency.ParameterPatternMatching, []},
{Credo.Check.Consistency.SpaceAroundOperators, []},
{Credo.Check.Consistency.SpaceInParentheses, []},
{Credo.Check.Consistency.TabsOrSpaces, []},
{Credo.Check.Consistency.UnusedVariableNames, []},

#
## Design Checks
#
{Credo.Check.Design.AliasUsage, [priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]},
{Credo.Check.Design.DuplicatedCode, []},
{Credo.Check.Design.SkipTestWithoutComment, []},
{Credo.Check.Design.TagFIXME, []},
{Credo.Check.Design.TagTODO, [exit_status: 0]},

#
## Readability Checks
#
{Credo.Check.Readability.AliasOrder, []},
{Credo.Check.Readability.BlockPipe, []},
{Credo.Check.Readability.FunctionNames, []},
{Credo.Check.Readability.ImplTrue, []},
{Credo.Check.Readability.LargeNumbers, []},
{Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]},
{Credo.Check.Readability.ModuleAttributeNames, []},
{Credo.Check.Readability.ModuleDoc, []},
{Credo.Check.Readability.ModuleNames, []},
{Credo.Check.Readability.MultiAlias, []},
{Credo.Check.Readability.NestedFunctionCalls, []},
{Credo.Check.Readability.ParenthesesInCondition, []},
{Credo.Check.Readability.ParenthesesOnZeroArityDefs, []},
{Credo.Check.Readability.PipeIntoAnonymousFunctions, []},
{Credo.Check.Readability.PredicateFunctionNames, []},
{Credo.Check.Readability.PreferImplicitTry, []},
{Credo.Check.Readability.RedundantBlankLines, []},
{Credo.Check.Readability.Semicolons, []},
{Credo.Check.Readability.SeparateAliasRequire, []},
{Credo.Check.Readability.SingleFunctionToBlockPipe, []},
{Credo.Check.Readability.SpaceAfterCommas, []},
{Credo.Check.Readability.StrictModuleLayout, []},
{Credo.Check.Readability.StringSigils, []},
{Credo.Check.Readability.TrailingBlankLine, []},
{Credo.Check.Readability.TrailingWhiteSpace, []},
{Credo.Check.Readability.UnnecessaryAliasExpansion, []},
{Credo.Check.Readability.VariableNames, []},
{Credo.Check.Readability.WithCustomTaggedTuple, []},
{Credo.Check.Readability.WithSingleClause, []},

#
## Refactoring Opportunities
#
{Credo.Check.Refactor.AppendSingleItem, []},
{Credo.Check.Refactor.Apply, []},
{Credo.Check.Refactor.CondStatements, []},
{Credo.Check.Refactor.CyclomaticComplexity, []},
{Credo.Check.Refactor.DoubleBooleanNegation, []},
{Credo.Check.Refactor.FilterFilter, []},
{Credo.Check.Refactor.FilterReject, []},
{Credo.Check.Refactor.FunctionArity, []},
{Credo.Check.Refactor.IoPuts, []},
{Credo.Check.Refactor.LongQuoteBlocks, []},
{Credo.Check.Refactor.MapInto, false},
{Credo.Check.Refactor.MapJoin, []},
{Credo.Check.Refactor.MapMap, []},
{Credo.Check.Refactor.MatchInCondition, []},
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
{Credo.Check.Refactor.NegatedConditionsWithElse, []},
{Credo.Check.Refactor.NegatedIsNil, []},
{Credo.Check.Refactor.Nesting, []},
{Credo.Check.Refactor.PipeChainStart, [excluded_argument_types: [:atom, :credo_type_error]]},
{Credo.Check.Refactor.RedundantWithClauseResult, []},
{Credo.Check.Refactor.RejectFilter, []},
{Credo.Check.Refactor.RejectReject, []},
{Credo.Check.Refactor.UnlessWithElse, []},
{Credo.Check.Refactor.VariableRebinding, []},
{Credo.Check.Refactor.WithClauses, []},

#
## Warnings
#
{Credo.Check.Warning.ApplicationConfigInModuleAttribute, []},
{Credo.Check.Warning.BoolOperationOnSameValues, []},
{Credo.Check.Warning.ExpensiveEmptyEnumCheck, []},
{Credo.Check.Warning.IExPry, []},
{Credo.Check.Warning.IoInspect, []},
{Credo.Check.Warning.LazyLogging, false},
{Credo.Check.Warning.MapGetUnsafePass, []},
{Credo.Check.Warning.MixEnv, []},
{Credo.Check.Warning.OperationOnSameValues, []},
{Credo.Check.Warning.OperationWithConstantResult, []},
{Credo.Check.Warning.RaiseInsideRescue, []},
{Credo.Check.Warning.SpecWithStruct, []},
{Credo.Check.Warning.UnsafeExec, []},
{Credo.Check.Warning.UnsafeToAtom, []},
{Credo.Check.Warning.UnusedEnumOperation, []},
{Credo.Check.Warning.UnusedFileOperation, []},
{Credo.Check.Warning.UnusedKeywordOperation, []},
{Credo.Check.Warning.UnusedListOperation, []},
{Credo.Check.Warning.UnusedPathOperation, []},
{Credo.Check.Warning.UnusedRegexOperation, []},
{Credo.Check.Warning.UnusedStringOperation, []},
{Credo.Check.Warning.UnusedTupleOperation, []},
{Credo.Check.Warning.WrongTestFileExtension, []}
],
disabled: [
{Credo.Check.Refactor.ABCSize, []},
{Credo.Check.Readability.AliasAs, []},
{Credo.Check.Readability.SinglePipe, []},
{Credo.Check.Readability.Specs, []},
{Credo.Check.Refactor.ModuleDependencies, []}
]
disabled: []
}
}
]
Expand Down
20 changes: 3 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,6 @@ jobs:
run: |
mix gettext.extract --check-up-to-date
- name: Publish package on hex.pm
if: github.event_name == 'release'
env:
HEX_API_KEY: ${{ secrets.HEX_API_KEY }}
run: mix hex.publish --yes

publish:
needs: test
if: github.event_name == 'release'
Expand Down Expand Up @@ -156,7 +150,8 @@ jobs:
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_TESTING }}

- name: Build container
- name: Build and push container
id: docker
uses: docker/build-push-action@v5
with:
push: true
Expand All @@ -168,7 +163,7 @@ jobs:
build-args: |
MIX_ENV=test
outputs:
image: ${{ steps.meta.outputs.tags }}
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_TESTING }}@${{ steps.docker.outputs.digest }}

lint-demo:
needs: build-testing
Expand All @@ -187,15 +182,6 @@ jobs:
run: |
apk add --no-cache tar
- name: Restore the plts cache
uses: actions/cache@v4
id: plts-cache
with:
path: /opt/app/demo/priv/plts
key: ${{ runner.os }}-demo-plts-mixlockhash-${{ hashFiles(format('{0}{1}', github.workspace, '/opt/app/demo/mix.lock')) }}
restore-keys: |
${{ runner.os }}-demo-plts-
- name: lint:credo
working-directory: /opt/app/demo
run: |
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Stage: builder
########################################################################

FROM hexpm/elixir:1.16.2-erlang-26.2.2-alpine-3.19.1 as builder
FROM hexpm/elixir:1.16.3-erlang-26.2.5-alpine-3.20.0 as builder

ENV MIX_HOME=/opt/mix \
HEX_HOME=/opt/hex \
Expand Down Expand Up @@ -71,7 +71,7 @@ RUN mix do deps.get, deps.compile, assets.deploy, sentry.package_source_code, re
# Stage: runtime
########################################################################

FROM alpine:3.19.1 as runtime
FROM alpine:3.20.0 as runtime

ENV APP_HOME=/opt/app
WORKDIR $APP_HOME
Expand Down
4 changes: 3 additions & 1 deletion demo/lib/demo/product.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule Demo.Product do
field(:name, :string)
field(:quantity, :integer)
field(:manufacturer, :string)
field(:images, {:array, :string})

field(:price, Backpex.Ecto.Amount.Type,
currency: :EUR,
Expand All @@ -24,7 +25,7 @@ defmodule Demo.Product do
end

@required_fields ~w[name quantity manufacturer price]a
@optional_fields ~w[]a
@optional_fields ~w[images]a

def changeset(product, attrs, _metadata \\ []) do
product
Expand All @@ -35,5 +36,6 @@ defmodule Demo.Product do
drop_param: :suppliers_delete
)
|> validate_required(@required_fields)
|> validate_length(:images, max: 2)
end
end
9 changes: 8 additions & 1 deletion demo/lib/demo/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ defmodule Demo.User do
field(:age, :integer)
field(:role, Ecto.Enum, values: [:user, :admin])
field(:permissions, {:array, :string})
field(:avatar, :string, default: "")
field(:avatar, :string)
field(:deleted_at, :utc_datetime)

has_many(:posts, Post, on_replace: :nilify)
Expand Down Expand Up @@ -59,6 +59,13 @@ defmodule Demo.User do
drop_param: :web_links_delete
)
|> validate_required(@required_fields)
|> validate_change(:avatar, fn
:avatar, "too_many_files" ->
[avatar: "has to be exactly one"]

:avatar, _avatar ->
[]
end)
end

@required_fields ~w[label url]a
Expand Down
5 changes: 4 additions & 1 deletion demo/lib/demo_web/item_actions/soft_delete.ex
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ defmodule DemoWeb.ItemActions.SoftDelete do

socket =
try do
{:ok, _items} = Backpex.Resource.update_all(socket.assigns, items, [set: [deleted_at: datetime]], "deleted")
%{assigns: %{repo: repo, schema: schema, pubsub: pubsub}} = socket

{:ok, _items} =
Backpex.Resource.update_all(items, repo, schema, [set: [deleted_at: datetime]], "deleted", pubsub)

socket
|> clear_flash()
Expand Down
10 changes: 8 additions & 2 deletions demo/lib/demo_web/live/post_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ defmodule DemoWeb.PostLive do
def filters do
[
category_id: %{
module: DemoWeb.Filters.PostCategorySelect
module: DemoWeb.Filters.PostCategorySelect,
label: "Category"
},
user_id: %{
module: DemoWeb.Filters.PostUserMultiSelect
module: DemoWeb.Filters.PostUserMultiSelect,
label: "Users"
},
likes: %{
module: DemoWeb.Filters.PostLikeRange,
label: "Likes",
presets: [
%{
label: "Over 100",
Expand All @@ -40,6 +43,7 @@ defmodule DemoWeb.PostLive do
},
inserted_at: %{
module: DemoWeb.Filters.DateTimeRange,
label: "Created at",
presets: [
%{
label: "Last 7 Days",
Expand Down Expand Up @@ -72,6 +76,7 @@ defmodule DemoWeb.PostLive do
},
published: %{
module: DemoWeb.Filters.PostPublished,
label: "Published?",
default: ["published"],
presets: [
%{
Expand Down Expand Up @@ -147,6 +152,7 @@ defmodule DemoWeb.PostLive do
full_name: fragment("concat(?, ' ', ?)", user.first_name, user.last_name)
})
end,
index_editable: true,
searchable: true,
live_resource: DemoWeb.UserLive
},
Expand Down
78 changes: 77 additions & 1 deletion demo/lib/demo_web/live/product_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,40 @@ defmodule DemoWeb.ProductLive do
def filters do
[
quantity: %{
module: DemoWeb.Filters.ProductQuantityRange
module: DemoWeb.Filters.ProductQuantityRange,
label: "Quantity"
}
]
end

@impl Backpex.LiveResource
def fields do
[
images: %{
module: Backpex.Fields.Upload,
label: "Images",
upload_key: :images,
accept: ~w(.jpg .jpeg .png),
max_entries: 2,
max_file_size: 512_000,
put_upload_change: &put_upload_change/6,
consume_upload: &consume_upload/4,
remove_uploads: &remove_uploads/3,
list_existing_files: &list_existing_files/1,
render: fn
%{value: value} = assigns when is_list(value) ->
~H"""
<div>
<img :for={img <- @value} class="h-10 w-auto" src={file_url(img)} />
</div>
"""

assigns ->
~H"<p><%= Backpex.HTML.pretty_value(@value) %></p>"
end,
except: [:index, :resource_action],
align: :center
},
name: %{
module: Backpex.Fields.Text,
label: "Name",
Expand Down Expand Up @@ -87,4 +113,54 @@ defmodule DemoWeb.ProductLive do
}
]
end

defp list_existing_files(%{images: images} = _item) when is_list(images), do: images
defp list_existing_files(_item), do: []

defp put_upload_change(_socket, change, item, uploaded_entries, removed_entries, action) do
existing_files = list_existing_files(item) -- removed_entries

new_entries =
case action do
:validate ->
elem(uploaded_entries, 1)

:insert ->
elem(uploaded_entries, 0)
end

files = existing_files ++ Enum.map(new_entries, fn entry -> file_name(entry) end)

Map.put(change, "images", files)
end

# sobelow_skip ["Traversal"]
defp consume_upload(_socket, _item, %{path: path} = _meta, entry) do
file_name = file_name(entry)
dest = Path.join([:code.priv_dir(:demo), "static", upload_dir(), file_name])

File.cp!(path, dest)

{:ok, file_url(file_name)}
end

# sobelow_skip ["Traversal"]
defp remove_uploads(_socket, _item, removed_entries) do
for file <- removed_entries do
path = Path.join([:code.priv_dir(:demo), "static", upload_dir(), file])
File.rm!(path)
end
end

defp file_url(file_name) do
static_path = Path.join([upload_dir(), file_name])
Phoenix.VerifiedRoutes.static_url(DemoWeb.Endpoint, "/" <> static_path)
end

defp file_name(entry) do
[ext | _] = MIME.extensions(entry.client_type)
"#{entry.uuid}.#{ext}"
end

defp upload_dir, do: Path.join(["uploads", "product", "images"])
end
Loading

0 comments on commit 4831e9e

Please sign in to comment.