From 5fe58c2494cd8473fa84de9b4bb1eed5aa7c6f40 Mon Sep 17 00:00:00 2001 From: MICHAELMUNAVU83 Date: Tue, 23 Jan 2024 11:30:24 +0300 Subject: [PATCH 1/4] added lib files --- .DS_Store | Bin 6148 -> 8196 bytes assets/js/app.js | 54 +- config/dev.exs | 2 +- config/test.exs | 3 + lib/.DS_Store | Bin 0 -> 6148 bytes lib/elixir_conf_africa/.DS_Store | Bin 0 -> 6148 bytes lib/elixir_conf_africa/accounts.ex | 386 +++++++++++++ lib/elixir_conf_africa/accounts/user.ex | 147 +++++ .../accounts/user_notifier.ex | 79 +++ lib/elixir_conf_africa/accounts/user_token.ex | 179 ++++++ lib/elixir_conf_africa/emails.ex | 41 ++ lib/elixir_conf_africa/events.ex | 139 ----- lib/elixir_conf_africa/events/event.ex | 24 - lib/elixir_conf_africa/paystack.ex | 107 ++++ lib/elixir_conf_africa/ticket_types.ex | 30 +- .../ticket_types/ticket_type.ex | 16 +- lib/elixir_conf_africa/tickets.ex | 151 ++++++ lib/elixir_conf_africa/tickets/ticket.ex | 52 ++ lib/elixir_conf_africa_web.ex | 9 + lib/elixir_conf_africa_web/.DS_Store | Bin 0 -> 6148 bytes .../components/core_components.ex | 4 +- .../components/layouts/admin.html.heex | 50 ++ .../components/layouts/app.html.heex | 18 + .../components/layouts/root.html.heex | 47 ++ .../user_confirmation_controller.ex | 56 ++ .../controllers/user_confirmation_html.ex | 5 + .../user_confirmation_html/edit.html.heex | 14 + .../user_confirmation_html/new.html.heex | 20 + .../user_registration_controller.ex | 30 ++ .../controllers/user_registration_html.ex | 5 + .../user_registration_html/new.html.heex | 25 + .../user_reset_password_controller.ex | 58 ++ .../controllers/user_reset_password_html.ex | 5 + .../user_reset_password_html/edit.html.heex | 29 + .../user_reset_password_html/new.html.heex | 20 + .../controllers/user_session_controller.ex | 29 + .../controllers/user_session_html.ex | 5 + .../user_session_html/new.html.heex | 31 ++ .../controllers/user_settings_controller.ex | 74 +++ .../controllers/user_settings_html.ex | 5 + .../user_settings_html/edit.html.heex | 63 +++ lib/elixir_conf_africa_web/live/.DS_Store | Bin 0 -> 6148 bytes .../live/event_live/form_component.ex | 95 ---- .../live/event_live/index.ex | 40 +- .../live/event_live/index.html.heex | 98 ++-- .../live/event_live/show.ex | 27 - .../live/event_live/show.html.heex | 58 -- .../live/home_live/index.ex | 25 +- .../live/home_live/index.html.heex | 154 +----- .../live/paid_ticket_live/index.ex | 36 ++ .../live/paid_ticket_live/index.html.heex | 41 ++ .../live/refunded_ticket_live/index.ex | 24 + .../live/refunded_ticket_live/index.html.heex | 33 ++ .../live/success_live/index.ex | 75 +++ .../live/success_live/index.html.heex | 34 ++ .../live/ticket_live/form_component.ex | 83 +++ .../live/ticket_live/form_component.html.heex | 40 ++ .../live/ticket_live/show.ex | 21 + .../live/ticket_live/show.html.heex | 57 ++ .../live/ticket_type_live/form_component.ex | 43 +- .../ticket_type_live/form_component.html.heex | 17 + .../live/ticket_type_live/index.ex | 18 +- .../live/ticket_type_live/index.html.heex | 83 +-- .../live/ticket_type_live/show.ex | 21 - .../live/ticket_type_live/show.html.heex | 34 -- .../live/transaction_live/index.ex | 23 + .../live/transaction_live/index.html.heex | 34 ++ .../live/unpaid_ticket_live/index.ex | 62 +++ .../live/unpaid_ticket_live/index.html.heex | 63 +++ .../live/user_live/index.ex | 27 + .../live/user_live/index.html.heex | 65 +++ lib/elixir_conf_africa_web/router.ex | 69 ++- lib/elixir_conf_africa_web/user_auth.ex | 239 ++++++++ mix.exs | 6 +- mix.lock | 14 + priv/.DS_Store | Bin 6148 -> 6148 bytes priv/gettext/errors.pot | 27 +- .../20231004111407_create_events.exs | 16 - .../20231006152547_create_ticket_types.exs | 21 - ...0231123072523_create_users_auth_tables.exs | 29 + .../20231130131216_create_ticket_types.exs | 16 + .../20231130142704_create_ticket.exs | 23 + priv/repo/seeds.exs | 152 +----- priv/static/.DS_Store | Bin 6148 -> 6148 bytes priv/static/images/.DS_Store | Bin 0 -> 8196 bytes priv/static/images/background.png | Bin 0 -> 250137 bytes priv/static/images/calendar.svg | 4 - priv/static/images/call.svg | 3 + priv/static/images/elixirconflogo.png | Bin 0 -> 2946 bytes priv/static/images/logo.svg | 6 - priv/static/images/phoenix.png | Bin 0 -> 13900 bytes priv/static/images/profile.svg | 4 + priv/static/images/purple-elixir-conf.png | Bin 0 -> 4493 bytes priv/static/images/sms.svg | 4 + priv/static/images/visa.png | Bin 0 -> 4468 bytes priv/static/images/visa.svg | 10 - test/elixir_conf_africa/accounts_test.exs | 508 ++++++++++++++++++ .../user_confirmation_controller_test.exs | 122 +++++ .../user_registration_controller_test.exs | 55 ++ .../user_reset_password_controller_test.exs | 123 +++++ .../user_session_controller_test.exs | 99 ++++ .../user_settings_controller_test.exs | 145 +++++ .../elixir_conf_africa_web/user_auth_test.exs | 272 ++++++++++ test/support/conn_case.ex | 26 + test/support/fixtures/accounts_fixtures.ex | 31 ++ 105 files changed, 4484 insertions(+), 983 deletions(-) create mode 100644 lib/.DS_Store create mode 100644 lib/elixir_conf_africa/.DS_Store create mode 100644 lib/elixir_conf_africa/accounts.ex create mode 100644 lib/elixir_conf_africa/accounts/user.ex create mode 100644 lib/elixir_conf_africa/accounts/user_notifier.ex create mode 100644 lib/elixir_conf_africa/accounts/user_token.ex create mode 100644 lib/elixir_conf_africa/emails.ex delete mode 100644 lib/elixir_conf_africa/events.ex delete mode 100644 lib/elixir_conf_africa/events/event.ex create mode 100644 lib/elixir_conf_africa/paystack.ex create mode 100644 lib/elixir_conf_africa/tickets.ex create mode 100644 lib/elixir_conf_africa/tickets/ticket.ex create mode 100644 lib/elixir_conf_africa_web/.DS_Store create mode 100644 lib/elixir_conf_africa_web/components/layouts/admin.html.heex create mode 100644 lib/elixir_conf_africa_web/controllers/user_confirmation_controller.ex create mode 100644 lib/elixir_conf_africa_web/controllers/user_confirmation_html.ex create mode 100644 lib/elixir_conf_africa_web/controllers/user_confirmation_html/edit.html.heex create mode 100644 lib/elixir_conf_africa_web/controllers/user_confirmation_html/new.html.heex create mode 100644 lib/elixir_conf_africa_web/controllers/user_registration_controller.ex create mode 100644 lib/elixir_conf_africa_web/controllers/user_registration_html.ex create mode 100644 lib/elixir_conf_africa_web/controllers/user_registration_html/new.html.heex create mode 100644 lib/elixir_conf_africa_web/controllers/user_reset_password_controller.ex create mode 100644 lib/elixir_conf_africa_web/controllers/user_reset_password_html.ex create mode 100644 lib/elixir_conf_africa_web/controllers/user_reset_password_html/edit.html.heex create mode 100644 lib/elixir_conf_africa_web/controllers/user_reset_password_html/new.html.heex create mode 100644 lib/elixir_conf_africa_web/controllers/user_session_controller.ex create mode 100644 lib/elixir_conf_africa_web/controllers/user_session_html.ex create mode 100644 lib/elixir_conf_africa_web/controllers/user_session_html/new.html.heex create mode 100644 lib/elixir_conf_africa_web/controllers/user_settings_controller.ex create mode 100644 lib/elixir_conf_africa_web/controllers/user_settings_html.ex create mode 100644 lib/elixir_conf_africa_web/controllers/user_settings_html/edit.html.heex create mode 100644 lib/elixir_conf_africa_web/live/.DS_Store delete mode 100644 lib/elixir_conf_africa_web/live/event_live/form_component.ex delete mode 100644 lib/elixir_conf_africa_web/live/event_live/show.ex delete mode 100644 lib/elixir_conf_africa_web/live/event_live/show.html.heex create mode 100644 lib/elixir_conf_africa_web/live/paid_ticket_live/index.ex create mode 100644 lib/elixir_conf_africa_web/live/paid_ticket_live/index.html.heex create mode 100644 lib/elixir_conf_africa_web/live/refunded_ticket_live/index.ex create mode 100644 lib/elixir_conf_africa_web/live/refunded_ticket_live/index.html.heex create mode 100644 lib/elixir_conf_africa_web/live/success_live/index.ex create mode 100644 lib/elixir_conf_africa_web/live/success_live/index.html.heex create mode 100644 lib/elixir_conf_africa_web/live/ticket_live/form_component.ex create mode 100644 lib/elixir_conf_africa_web/live/ticket_live/form_component.html.heex create mode 100644 lib/elixir_conf_africa_web/live/ticket_live/show.ex create mode 100644 lib/elixir_conf_africa_web/live/ticket_live/show.html.heex create mode 100644 lib/elixir_conf_africa_web/live/ticket_type_live/form_component.html.heex delete mode 100644 lib/elixir_conf_africa_web/live/ticket_type_live/show.ex delete mode 100644 lib/elixir_conf_africa_web/live/ticket_type_live/show.html.heex create mode 100644 lib/elixir_conf_africa_web/live/transaction_live/index.ex create mode 100644 lib/elixir_conf_africa_web/live/transaction_live/index.html.heex create mode 100644 lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.ex create mode 100644 lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.html.heex create mode 100644 lib/elixir_conf_africa_web/live/user_live/index.ex create mode 100644 lib/elixir_conf_africa_web/live/user_live/index.html.heex create mode 100644 lib/elixir_conf_africa_web/user_auth.ex delete mode 100644 priv/repo/migrations/20231004111407_create_events.exs delete mode 100644 priv/repo/migrations/20231006152547_create_ticket_types.exs create mode 100644 priv/repo/migrations/20231123072523_create_users_auth_tables.exs create mode 100644 priv/repo/migrations/20231130131216_create_ticket_types.exs create mode 100644 priv/repo/migrations/20231130142704_create_ticket.exs create mode 100644 priv/static/images/.DS_Store create mode 100644 priv/static/images/background.png delete mode 100755 priv/static/images/calendar.svg create mode 100644 priv/static/images/call.svg create mode 100644 priv/static/images/elixirconflogo.png delete mode 100644 priv/static/images/logo.svg create mode 100644 priv/static/images/phoenix.png create mode 100644 priv/static/images/profile.svg create mode 100644 priv/static/images/purple-elixir-conf.png create mode 100644 priv/static/images/sms.svg create mode 100644 priv/static/images/visa.png delete mode 100644 priv/static/images/visa.svg create mode 100644 test/elixir_conf_africa/accounts_test.exs create mode 100644 test/elixir_conf_africa_web/controllers/user_confirmation_controller_test.exs create mode 100644 test/elixir_conf_africa_web/controllers/user_registration_controller_test.exs create mode 100644 test/elixir_conf_africa_web/controllers/user_reset_password_controller_test.exs create mode 100644 test/elixir_conf_africa_web/controllers/user_session_controller_test.exs create mode 100644 test/elixir_conf_africa_web/controllers/user_settings_controller_test.exs create mode 100644 test/elixir_conf_africa_web/user_auth_test.exs create mode 100644 test/support/fixtures/accounts_fixtures.ex diff --git a/.DS_Store b/.DS_Store index 14f7fcd070f258c7be63463beed07207d0e49718..241a5ddc8302daa6945afede71bf99c55d8282f3 100644 GIT binary patch delta 271 zcmZoMXmOBWU|?W$DortDU;r^WfEYvza8E20o2aMAD7Z0TH}hr%jz7$c**Q2SHn1=X zPUc~eXH1=}!=lZ28A!@(E@2U1WOSU|%4*HHe)2(9H6|w6$uC(|#k+w9>HP--Ad7*4 znIVTElObvHTDE=;69aP{1!Dul$=s}t!cd8_;G(>o{JeCaQpU;BY>GfjY}xdImgKSl z%}fVU5+J?o#+H^k3WgSwxmcYhx3XISEj_@l#>3zU)W!(0Zu18b5$1^vJc7(%iy0)i hfwU{gTbl(rzB5ne7xA3z&%?pN2=Ot)=6Iet%m6IyLh%3q delta 206 zcmZp1XfcprU|?W$DortDU=RQ@Ie-{Mvv5r;6q~50$jHAjU^g=(|70Ekc}B;{Is)2^ z>w%=q<`Mw`Mn>7mt%BB!-IEUrsxdMCoXjsIHu=9GKW{qF0KNZUz`!tBKv)r|(@0n! zs540zs8Dutm+X`@8GqF%~F*^r`ATv-12n4u+ge%BN c8w topbar.show(300)) -window.addEventListener("phx:page-loading-stop", _info => topbar.hide()) +topbar.config({ barColors: { 0: "#29d" }, shadowColor: "rgba(0, 0, 0, .3)" }); +window.addEventListener("phx:page-loading-start", (info) => topbar.show()); +window.addEventListener("phx:page-loading-stop", (info) => topbar.hide()); // connect if there are any LiveViews on the page -liveSocket.connect() +liveSocket.connect(); // expose liveSocket on window for web console debug logs and latency simulation: // >> liveSocket.enableDebug() // >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session // >> liveSocket.disableLatencySim() -window.liveSocket = liveSocket - +window.liveSocket = liveSocket; diff --git a/config/dev.exs b/config/dev.exs index 3c89e9b..5ea99cf 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -19,7 +19,7 @@ config :elixir_conf_africa, ElixirConfAfrica.Repo, config :elixir_conf_africa, ElixirConfAfricaWeb.Endpoint, # Binding to loopback ipv4 address prevents access from other machines. # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. - http: [ip: {127, 0, 0, 1}, port: 4000], + http: [ip: {127, 0, 0, 1}, port: 4100], check_origin: false, code_reloader: true, debug_errors: true, diff --git a/config/test.exs b/config/test.exs index 4dbe051..21b19df 100644 --- a/config/test.exs +++ b/config/test.exs @@ -1,5 +1,8 @@ import Config +# Only in tests, remove the complexity from the password hashing algorithm +config :bcrypt_elixir, :log_rounds, 1 + # Configure your database # # The MIX_TEST_PARTITION environment variable can be used diff --git a/lib/.DS_Store b/lib/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0dbdda63540c5c07e09e71859be26593cfecda3e GIT binary patch literal 6148 zcmeHK&2AGh5FWPyoFGJmD3k+|FWjPPLn{!6N=qn*-jEi-0Z_Wzq;#e2x=J?PmJqae zo&a8g=imu=9QejIKWU1T3Kc=+k;dP6JTt5PytdawBs!yBo2W@d63SR>pgBQ!oOMPP zoQDU6sgcrvy0lH2@|kGw@C(7Txq9V6od2eXyM0P;Rx~zAb z%j5A{aKEKigZ8AQ#t-fWEw#3KZ!)RNn|Ipln_GKFZ^myY?>?B z2t0@ed8YH%i04{M^N>y}h&r66Uc5*4uhid|t5TOr#3j?U=+mFnI#fsF z#);E=``DDAdq(0uX?gjK>ie>u0nfny%K+~W3d$HdtSp+X1C6-?0Bdj?fz7`MoTD6u z4l9cofe4!lw5h^fF@#NrU%9x@VP(;#lW><0;hrqq4MmuzqrNiXBtnb6^$d6hrWshY z-6o&^kAHvvpHA{U&wyv(TrnVO8_`AwujJ0wnU~|URzbI*EF4!^G%0A@acm4eikG2A ZFs9f5h7K!>@Id^JfT6)Ro`Jv0z&DLv^=kkC literal 0 HcmV?d00001 diff --git a/lib/elixir_conf_africa/.DS_Store b/lib/elixir_conf_africa/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..83f37be5e98987c542bef119b49cc8219f3ba784 GIT binary patch literal 6148 zcmeHKO-lnY5PhQsD}wasMaVBG_z$+F9z6R8v~>>)t1D8$KDY>J{rMbusGI*8yyqSzQ6Hn_zW9frz4f6=9DKjoSq`Se`( z*ZLnYM~j!Me%P%0Va+%tX~8ysGob|>JWZ;tl-5&~@ViPzz+SWm3B>-_kw+U^%CTmU!Yyw9| z_E5xAiJmG^Vu+{HUm~sv934F!62*ta%pb*z*z6p?SU99{Oq~oQ1G@}p?Ms>I`G3h@ zrds4%NUCHY8ThXZ$YgcBTJr1SZ2k6~de#=U8#Wb<8`YrD-nj(uMfZ_2>-7GjHshMW V(NRZHzoirNB4C81N(O#`fp;~2HP-+D literal 0 HcmV?d00001 diff --git a/lib/elixir_conf_africa/accounts.ex b/lib/elixir_conf_africa/accounts.ex new file mode 100644 index 0000000..72eff1a --- /dev/null +++ b/lib/elixir_conf_africa/accounts.ex @@ -0,0 +1,386 @@ +defmodule ElixirConfAfrica.Accounts do + @moduledoc """ + The Accounts context. + """ + + import Ecto.Query, warn: false + alias ElixirConfAfrica.Repo + + alias ElixirConfAfrica.Accounts.{User, UserToken, UserNotifier} + + ## Database getters + + @doc """ + Gets a user by email. + + ## Examples + + iex> get_user_by_email("foo@example.com") + %User{} + + iex> get_user_by_email("unknown@example.com") + nil + + """ + + def get_user_by_email(email) when is_binary(email) do + Repo.get_by(User, email: email) + end + + @doc """ + Lists all users apart from the current user. + """ + + def list_users_apart_from_current_user(current_user) do + from(u in User, + where: u.id != ^current_user.id, + order_by: u.email, + select: u + ) + |> Repo.all() + end + + def list_users do + Repo.all(User) + end + + @doc """ + Updates a user role. + + """ + def update_user_role(%User{} = user, role) do + user + |> User.role_changeset(%{role: role}) + |> Repo.update() + end + + def delete_user_session_token(token) do + Repo.delete_all(UserToken.token_and_context_query(token, "session")) + :ok + end + + @doc """ + Gets a user by email and password. + + ## Examples + + iex> get_user_by_email_and_password("foo@example.com", "correct_password") + %User{} + + iex> get_user_by_email_and_password("foo@example.com", "invalid_password") + nil + + """ + def get_user_by_email_and_password(email, password) + when is_binary(email) and is_binary(password) do + user = Repo.get_by(User, email: email) + if User.valid_password?(user, password), do: user + end + + @doc """ + Gets a single user. + + Raises `Ecto.NoResultsError` if the User does not exist. + + ## Examples + + iex> get_user!(123) + %User{} + + iex> get_user!(456) + ** (Ecto.NoResultsError) + + """ + def get_user!(id), do: Repo.get!(User, id) + + ## User registration + + @doc """ + Registers a user. + + ## Examples + + iex> register_user(%{field: value}) + {:ok, %User{}} + + iex> register_user(%{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def register_user(attrs) do + %User{} + |> User.registration_changeset(attrs) + |> Repo.insert() + end + + @doc """ + Returns an `%Ecto.Changeset{}` for tracking user changes. + + ## Examples + + iex> change_user_registration(user) + %Ecto.Changeset{data: %User{}} + + """ + def change_user_registration(%User{} = user, attrs \\ %{}) do + User.registration_changeset(user, attrs, hash_password: false) + end + + ## Settings + + @doc """ + Returns an `%Ecto.Changeset{}` for changing the user email. + + ## Examples + + iex> change_user_email(user) + %Ecto.Changeset{data: %User{}} + + """ + def change_user_email(user, attrs \\ %{}) do + User.email_changeset(user, attrs) + end + + @doc """ + Emulates that the email will change without actually changing + it in the database. + + ## Examples + + iex> apply_user_email(user, "valid password", %{email: ...}) + {:ok, %User{}} + + iex> apply_user_email(user, "invalid password", %{email: ...}) + {:error, %Ecto.Changeset{}} + + """ + def apply_user_email(user, password, attrs) do + user + |> User.email_changeset(attrs) + |> User.validate_current_password(password) + |> Ecto.Changeset.apply_action(:update) + end + + @doc """ + Updates the user email using the given token. + + If the token matches, the user email is updated and the token is deleted. + The confirmed_at date is also updated to the current time. + """ + def update_user_email(user, token) do + context = "change:#{user.email}" + + with {:ok, query} <- UserToken.verify_change_email_token_query(token, context), + %UserToken{sent_to: email} <- Repo.one(query), + {:ok, _} <- Repo.transaction(user_email_multi(user, email, context)) do + :ok + else + _ -> :error + end + end + + defp user_email_multi(user, email, context) do + changeset = + user + |> User.email_changeset(%{email: email}) + |> User.confirm_changeset() + + Ecto.Multi.new() + |> Ecto.Multi.update(:user, changeset) + |> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, [context])) + end + + @doc """ + Delivers the update email instructions to the given user. + + ## Examples + + iex> deliver_update_email_instructions(user, current_email, &Routes.user_update_email_url(conn, :edit, &1)) + {:ok, %{to: ..., body: ...}} + + """ + def deliver_update_email_instructions(%User{} = user, current_email, update_email_url_fun) + when is_function(update_email_url_fun, 1) do + {encoded_token, user_token} = UserToken.build_email_token(user, "change:#{current_email}") + + Repo.insert!(user_token) + UserNotifier.deliver_update_email_instructions(user, update_email_url_fun.(encoded_token)) + end + + @doc """ + Returns an `%Ecto.Changeset{}` for changing the user password. + + ## Examples + + iex> change_user_password(user) + %Ecto.Changeset{data: %User{}} + + """ + def change_user_password(user, attrs \\ %{}) do + User.password_changeset(user, attrs, hash_password: false) + end + + @doc """ + Updates the user password. + + ## Examples + + iex> update_user_password(user, "valid password", %{password: ...}) + {:ok, %User{}} + + iex> update_user_password(user, "invalid password", %{password: ...}) + {:error, %Ecto.Changeset{}} + + """ + def update_user_password(user, password, attrs) do + changeset = + user + |> User.password_changeset(attrs) + |> User.validate_current_password(password) + + Ecto.Multi.new() + |> Ecto.Multi.update(:user, changeset) + |> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, :all)) + |> Repo.transaction() + |> case do + {:ok, %{user: user}} -> {:ok, user} + {:error, :user, changeset, _} -> {:error, changeset} + end + end + + ## Session + + @doc """ + Generates a session token. + """ + def generate_user_session_token(user) do + {token, user_token} = UserToken.build_session_token(user) + Repo.insert!(user_token) + token + end + + @doc """ + Gets the user with the given signed token. + """ + def get_user_by_session_token(token) do + {:ok, query} = UserToken.verify_session_token_query(token) + Repo.one(query) + end + + @doc """ + Deletes the signed token with the given context. + """ + def delete_session_token(token) do + Repo.delete_all(UserToken.token_and_context_query(token, "session")) + :ok + end + + ## Confirmation + + @doc """ + Delivers the confirmation email instructions to the given user. + + ## Examples + + iex> deliver_user_confirmation_instructions(user, &Routes.user_confirmation_url(conn, :edit, &1)) + {:ok, %{to: ..., body: ...}} + + iex> deliver_user_confirmation_instructions(confirmed_user, &Routes.user_confirmation_url(conn, :edit, &1)) + {:error, :already_confirmed} + + """ + def deliver_user_confirmation_instructions(%User{} = user, confirmation_url_fun) + when is_function(confirmation_url_fun, 1) do + if user.confirmed_at do + {:error, :already_confirmed} + else + {encoded_token, user_token} = UserToken.build_email_token(user, "confirm") + Repo.insert!(user_token) + UserNotifier.deliver_confirmation_instructions(user, confirmation_url_fun.(encoded_token)) + end + end + + @doc """ + Confirms a user by the given token. + + If the token matches, the user account is marked as confirmed + and the token is deleted. + """ + def confirm_user(token) do + with {:ok, query} <- UserToken.verify_email_token_query(token, "confirm"), + %User{} = user <- Repo.one(query), + {:ok, %{user: user}} <- Repo.transaction(confirm_user_multi(user)) do + {:ok, user} + else + _ -> :error + end + end + + defp confirm_user_multi(user) do + Ecto.Multi.new() + |> Ecto.Multi.update(:user, User.confirm_changeset(user)) + |> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, ["confirm"])) + end + + ## Reset password + + @doc """ + Delivers the reset password email to the given user. + + ## Examples + + iex> deliver_user_reset_password_instructions(user, &Routes.user_reset_password_url(conn, :edit, &1)) + {:ok, %{to: ..., body: ...}} + + """ + def deliver_user_reset_password_instructions(%User{} = user, reset_password_url_fun) + when is_function(reset_password_url_fun, 1) do + {encoded_token, user_token} = UserToken.build_email_token(user, "reset_password") + Repo.insert!(user_token) + UserNotifier.deliver_reset_password_instructions(user, reset_password_url_fun.(encoded_token)) + end + + @doc """ + Gets the user by reset password token. + + ## Examples + + iex> get_user_by_reset_password_token("validtoken") + %User{} + + iex> get_user_by_reset_password_token("invalidtoken") + nil + + """ + def get_user_by_reset_password_token(token) do + with {:ok, query} <- UserToken.verify_email_token_query(token, "reset_password"), + %User{} = user <- Repo.one(query) do + user + else + _ -> nil + end + end + + @doc """ + Resets the user password. + + ## Examples + + iex> reset_user_password(user, %{password: "new long password", password_confirmation: "new long password"}) + {:ok, %User{}} + + iex> reset_user_password(user, %{password: "valid", password_confirmation: "not the same"}) + {:error, %Ecto.Changeset{}} + + """ + def reset_user_password(user, attrs) do + Ecto.Multi.new() + |> Ecto.Multi.update(:user, User.password_changeset(user, attrs)) + |> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, :all)) + |> Repo.transaction() + |> case do + {:ok, %{user: user}} -> {:ok, user} + {:error, :user, changeset, _} -> {:error, changeset} + end + end +end diff --git a/lib/elixir_conf_africa/accounts/user.ex b/lib/elixir_conf_africa/accounts/user.ex new file mode 100644 index 0000000..0bdf005 --- /dev/null +++ b/lib/elixir_conf_africa/accounts/user.ex @@ -0,0 +1,147 @@ +defmodule ElixirConfAfrica.Accounts.User do + use Ecto.Schema + import Ecto.Changeset + + schema "users" do + field :email, :string + field :password, :string, virtual: true, redact: true + field :hashed_password, :string, redact: true + field :confirmed_at, :naive_datetime + field :role, :string, default: "user" + + timestamps() + end + + @doc """ + A user changeset for registration. + + It is important to validate the length of both email and password. + Otherwise databases may truncate the email without warnings, which + could lead to unpredictable or insecure behaviour. Long passwords may + also be very expensive to hash for certain algorithms. + + ## Options + + * `:hash_password` - Hashes the password so it can be stored securely + in the database and ensures the password field is cleared to prevent + leaks in the logs. If password hashing is not needed and clearing the + password field is not desired (like when using this changeset for + validations on a LiveView form), this option can be set to `false`. + Defaults to `true`. + """ + def registration_changeset(user, attrs, opts \\ []) do + user + |> cast(attrs, [:email, :password, :role]) + |> validate_email() + |> validate_password(opts) + end + + def role_changeset(user, attrs) do + user + |> cast(attrs, [:role]) + |> validate_inclusion(:role, ["user", "admin", "scanner"]) + end + + defp validate_email(changeset) do + changeset + |> validate_required([:email]) + |> validate_format(:email, ~r/^[^\s]+@[^\s]+$/, message: "must have the @ sign and no spaces") + |> validate_length(:email, max: 160) + |> unsafe_validate_unique(:email, ElixirConfAfrica.Repo) + |> unique_constraint(:email) + end + + defp validate_password(changeset, opts) do + changeset + |> validate_required([:password]) + |> validate_length(:password, min: 6, max: 72) + # |> validate_format(:password, ~r/[a-z]/, message: "at least one lower case character") + # |> validate_format(:password, ~r/[A-Z]/, message: "at least one upper case character") + # |> validate_format(:password, ~r/[!?@#$%^&*_0-9]/, message: "at least one digit or punctuation character") + |> maybe_hash_password(opts) + end + + defp maybe_hash_password(changeset, opts) do + hash_password? = Keyword.get(opts, :hash_password, true) + password = get_change(changeset, :password) + + if hash_password? && password && changeset.valid? do + changeset + # If using Bcrypt, then further validate it is at most 72 bytes long + |> validate_length(:password, max: 72, count: :bytes) + |> put_change(:hashed_password, Bcrypt.hash_pwd_salt(password)) + |> delete_change(:password) + else + changeset + end + end + + @doc """ + A user changeset for changing the email. + + It requires the email to change otherwise an error is added. + """ + def email_changeset(user, attrs) do + user + |> cast(attrs, [:email]) + |> validate_email() + |> case do + %{changes: %{email: _}} = changeset -> changeset + %{} = changeset -> add_error(changeset, :email, "did not change") + end + end + + @doc """ + A user changeset for changing the password. + + ## Options + + * `:hash_password` - Hashes the password so it can be stored securely + in the database and ensures the password field is cleared to prevent + leaks in the logs. If password hashing is not needed and clearing the + password field is not desired (like when using this changeset for + validations on a LiveView form), this option can be set to `false`. + Defaults to `true`. + """ + def password_changeset(user, attrs, opts \\ []) do + user + |> cast(attrs, [:password]) + |> validate_confirmation(:password, message: "does not match password") + |> validate_password(opts) + end + + @doc """ + Confirms the account by setting `confirmed_at`. + """ + def confirm_changeset(user) do + now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + change(user, confirmed_at: now) + end + + @doc """ + Verifies the password. + + If there is no user or the user doesn't have a password, we call + `Bcrypt.no_user_verify/0` to avoid timing attacks. + """ + def valid_password?(%ElixirConfAfrica.Accounts.User{hashed_password: hashed_password}, password) + when is_binary(hashed_password) and byte_size(password) > 0 do + Bcrypt.verify_pass(password, hashed_password) + end + + def valid_password?(_, _) do + Bcrypt.no_user_verify() + false + end + + @doc """ + Validates the current password otherwise adds an error to the changeset. + """ + def validate_current_password(changeset, password) do + if valid_password?(changeset.data, password) do + changeset + else + add_error(changeset, :current_password, "is not valid") + end + end +end diff --git a/lib/elixir_conf_africa/accounts/user_notifier.ex b/lib/elixir_conf_africa/accounts/user_notifier.ex new file mode 100644 index 0000000..c487d79 --- /dev/null +++ b/lib/elixir_conf_africa/accounts/user_notifier.ex @@ -0,0 +1,79 @@ +defmodule ElixirConfAfrica.Accounts.UserNotifier do + import Swoosh.Email + + alias ElixirConfAfrica.Mailer + + # Delivers the email using the application mailer. + defp deliver(recipient, subject, body) do + email = + new() + |> to(recipient) + |> from({"Elixirconf", "contact@example.com"}) + |> subject(subject) + |> text_body(body) + + with {:ok, _metadata} <- Mailer.deliver(email) do + {:ok, email} + end + end + + @doc """ + Deliver instructions to confirm account. + """ + def deliver_confirmation_instructions(user, url) do + deliver(user.email, "Confirmation instructions", """ + + ============================== + + Hi #{user.email}, + + You can confirm your account by visiting the URL below: + + #{url} + + If you didn't create an account with us, please ignore this. + + ============================== + """) + end + + @doc """ + Deliver instructions to reset a user password. + """ + def deliver_reset_password_instructions(user, url) do + deliver(user.email, "Reset password instructions", """ + + ============================== + + Hi #{user.email}, + + You can reset your password by visiting the URL below: + + #{url} + + If you didn't request this change, please ignore this. + + ============================== + """) + end + + @doc """ + Deliver instructions to update a user email. + """ + def deliver_update_email_instructions(user, url) do + deliver(user.email, "Update email instructions", """ + + ============================== + + Hi #{user.email}, + + You can change your email by visiting the URL below: + + #{url} + + If you didn't request this change, please ignore this. + + ============================== + """) + end +end diff --git a/lib/elixir_conf_africa/accounts/user_token.ex b/lib/elixir_conf_africa/accounts/user_token.ex new file mode 100644 index 0000000..972baab --- /dev/null +++ b/lib/elixir_conf_africa/accounts/user_token.ex @@ -0,0 +1,179 @@ +defmodule ElixirConfAfrica.Accounts.UserToken do + use Ecto.Schema + import Ecto.Query + alias ElixirConfAfrica.Accounts.UserToken + + @hash_algorithm :sha256 + @rand_size 32 + + # It is very important to keep the reset password token expiry short, + # since someone with access to the email may take over the account. + @reset_password_validity_in_days 1 + @confirm_validity_in_days 7 + @change_email_validity_in_days 7 + @session_validity_in_days 60 + + schema "users_tokens" do + field :token, :binary + field :context, :string + field :sent_to, :string + belongs_to :user, ElixirConfAfrica.Accounts.User + + timestamps(updated_at: false) + end + + @doc """ + Generates a token that will be stored in a signed place, + such as session or cookie. As they are signed, those + tokens do not need to be hashed. + + The reason why we store session tokens in the database, even + though Phoenix already provides a session cookie, is because + Phoenix' default session cookies are not persisted, they are + simply signed and potentially encrypted. This means they are + valid indefinitely, unless you change the signing/encryption + salt. + + Therefore, storing them allows individual user + sessions to be expired. The token system can also be extended + to store additional data, such as the device used for logging in. + You could then use this information to display all valid sessions + and devices in the UI and allow users to explicitly expire any + session they deem invalid. + """ + def build_session_token(user) do + token = :crypto.strong_rand_bytes(@rand_size) + {token, %UserToken{token: token, context: "session", user_id: user.id}} + end + + @doc """ + Checks if the token is valid and returns its underlying lookup query. + + The query returns the user found by the token, if any. + + The token is valid if it matches the value in the database and it has + not expired (after @session_validity_in_days). + """ + def verify_session_token_query(token) do + query = + from token in token_and_context_query(token, "session"), + join: user in assoc(token, :user), + where: token.inserted_at > ago(@session_validity_in_days, "day"), + select: user + + {:ok, query} + end + + @doc """ + Builds a token and its hash to be delivered to the user's email. + + The non-hashed token is sent to the user email while the + hashed part is stored in the database. The original token cannot be reconstructed, + which means anyone with read-only access to the database cannot directly use + the token in the application to gain access. Furthermore, if the user changes + their email in the system, the tokens sent to the previous email are no longer + valid. + + Users can easily adapt the existing code to provide other types of delivery methods, + for example, by phone numbers. + """ + def build_email_token(user, context) do + build_hashed_token(user, context, user.email) + end + + defp build_hashed_token(user, context, sent_to) do + token = :crypto.strong_rand_bytes(@rand_size) + hashed_token = :crypto.hash(@hash_algorithm, token) + + {Base.url_encode64(token, padding: false), + %UserToken{ + token: hashed_token, + context: context, + sent_to: sent_to, + user_id: user.id + }} + end + + @doc """ + Checks if the token is valid and returns its underlying lookup query. + + The query returns the user found by the token, if any. + + The given token is valid if it matches its hashed counterpart in the + database and the user email has not changed. This function also checks + if the token is being used within a certain period, depending on the + context. The default contexts supported by this function are either + "confirm", for account confirmation emails, and "reset_password", + for resetting the password. For verifying requests to change the email, + see `verify_change_email_token_query/2`. + """ + def verify_email_token_query(token, context) do + case Base.url_decode64(token, padding: false) do + {:ok, decoded_token} -> + hashed_token = :crypto.hash(@hash_algorithm, decoded_token) + days = days_for_context(context) + + query = + from token in token_and_context_query(hashed_token, context), + join: user in assoc(token, :user), + where: token.inserted_at > ago(^days, "day") and token.sent_to == user.email, + select: user + + {:ok, query} + + :error -> + :error + end + end + + defp days_for_context("confirm"), do: @confirm_validity_in_days + defp days_for_context("reset_password"), do: @reset_password_validity_in_days + + @doc """ + Checks if the token is valid and returns its underlying lookup query. + + The query returns the user found by the token, if any. + + This is used to validate requests to change the user + email. It is different from `verify_email_token_query/2` precisely because + `verify_email_token_query/2` validates the email has not changed, which is + the starting point by this function. + + The given token is valid if it matches its hashed counterpart in the + database and if it has not expired (after @change_email_validity_in_days). + The context must always start with "change:". + """ + def verify_change_email_token_query(token, "change:" <> _ = context) do + case Base.url_decode64(token, padding: false) do + {:ok, decoded_token} -> + hashed_token = :crypto.hash(@hash_algorithm, decoded_token) + + query = + from token in token_and_context_query(hashed_token, context), + where: token.inserted_at > ago(@change_email_validity_in_days, "day") + + {:ok, query} + + :error -> + :error + end + end + + @doc """ + Returns the token struct for the given token value and context. + """ + def token_and_context_query(token, context) do + from UserToken, where: [token: ^token, context: ^context] + end + + @doc """ + Gets all tokens for the given user for the given contexts. + """ + def user_and_contexts_query(user, :all) do + from t in UserToken, where: t.user_id == ^user.id + end + + def user_and_contexts_query(user, [_ | _] = contexts) do + from t in UserToken, where: t.user_id == ^user.id and t.context in ^contexts + end +end diff --git a/lib/elixir_conf_africa/emails.ex b/lib/elixir_conf_africa/emails.ex new file mode 100644 index 0000000..73437b2 --- /dev/null +++ b/lib/elixir_conf_africa/emails.ex @@ -0,0 +1,41 @@ +defmodule ElixirConfAfrica.Emails do + @moduledoc """ + The Emails module is responsible for all the interactions with the Sendgrid API + """ + + @doc """ + Delivers a ticket by email + """ + + def deliver_ticket_by_email(email, url) do + header = [ + {"Authorization", + "Bearer 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"}, + {"Content-Type", "application/json"}, + {"Accept", "application/json"} + ] + + body = %{ + "from" => %{ + "email" => "Mche " + }, + "personalizations" => [ + %{ + "to" => [ + %{"email" => email} + ], + "dynamic_template_data" => %{ + "url" => url + } + } + ], + "template_id" => "d-0b163cbd94794e5ca1757b26b38f76dc" + } + + HTTPoison.post( + "https://api.sendgrid.com/v3/mail/send", + Jason.encode!(body), + header + ) + end +end diff --git a/lib/elixir_conf_africa/events.ex b/lib/elixir_conf_africa/events.ex deleted file mode 100644 index 65431c0..0000000 --- a/lib/elixir_conf_africa/events.ex +++ /dev/null @@ -1,139 +0,0 @@ -defmodule ElixirConfAfrica.Events do - @moduledoc """ - The Events context. - """ - - import Ecto.Query, warn: false - - alias ElixirConfAfrica.Events.Event - alias ElixirConfAfrica.Repo - alias ElixirConfAfrica.TicketTypes.TicketType - - @doc """ - Returns the list of events. - - ## Examples - - iex> list_events() - [%Event{}, ...] - - """ - @spec list_events() :: list() - def list_events do - Repo.all(from e in Event, order_by: [desc: e.id]) - end - - @doc """ - Returns the elixir conf event together with all its ticket types - """ - @spec get_event_with_ticket_types_by_event_name(String.t()) :: Event.t() - def get_event_with_ticket_types_by_event_name(event_name) do - query = - from event in Event, - join: ticket_types in assoc(event, :ticket_types), - where: event.name == ^event_name, - preload: [ticket_types: ticket_types] - - Repo.one(query) - end - - @doc """ - Get totals number of available tickets for a given event - """ - @spec get_total_number_of_available_tickets(String.t()) :: Event.t() - def get_total_number_of_available_tickets(event_name) do - query = - from t in TicketType, - join: e in Event, - on: t.event_id == e.id and e.name == ^event_name, - select: sum(t.number) - - Repo.one(query) - end - - @doc """ - Gets a single event. - - Raises `Ecto.NoResultsError` if the Event does not exist. - - ## Examples - - iex> get_event!(123) - %Event{} - - iex> get_event!(456) - ** (Ecto.NoResultsError) - - """ - @spec get_event!(non_neg_integer()) :: Event.t() | Ecto.NoResultsError - def get_event!(id), do: Repo.get!(Event, id) - - @doc """ - Creates a event. - - ## Examples - - iex> create_event(%{field: value}) - {:ok, %Event{}} - - iex> create_event(%{field: bad_value}) - {:error, %Ecto.Changeset{}} - - """ - @spec create_event(map()) :: {:ok, Event.t()} | {:error, Ecto.Changeset.t()} - def create_event(attrs \\ %{}) do - %Event{} - |> Event.changeset(attrs) - |> Repo.insert() - end - - @doc """ - Updates a event. - - ## Examples - - iex> update_event(event, %{field: new_value}) - {:ok, %Event{}} - - iex> update_event(event, %{field: bad_value}) - {:error, %Ecto.Changeset{}} - - """ - @spec update_event(Event.t(), map()) :: {:ok, Event.t()} | {:error, Ecto.Changeset.t()} - def update_event(%Event{} = event, attrs) do - event - |> Event.changeset(attrs) - |> Repo.update() - end - - @doc """ - Deletes a event. - - ## Examples - - iex> delete_event(event) - {:ok, %Event{}} - - iex> delete_event(event) - {:error, %Ecto.Changeset{}} - - """ - @spec delete_event(Event.t()) :: {:ok, Event.t()} | {:error, Ecto.Changeset.t()} - def delete_event(%Event{} = event) do - Repo.delete(event) - end - - @doc """ - Returns an `%Ecto.Changeset{}` for tracking event changes. - - ## Examples - - iex> change_event(event) - %Ecto.Changeset{data: %Event{}} - - """ - @spec change_event(Event.t(), map()) :: Ecto.Changeset.t() - def change_event(%Event{} = event, attrs \\ %{}) do - Event.changeset(event, attrs) - end -end diff --git a/lib/elixir_conf_africa/events/event.ex b/lib/elixir_conf_africa/events/event.ex deleted file mode 100644 index 92731df..0000000 --- a/lib/elixir_conf_africa/events/event.ex +++ /dev/null @@ -1,24 +0,0 @@ -defmodule ElixirConfAfrica.Events.Event do - @moduledoc false - use TypedEctoSchema - import Ecto.Changeset - - typed_schema "events" do - field :name, :string - field :description, :string - field :location, :string - field :event_type, :string - field :start_date, :naive_datetime - field :end_date, :naive_datetime - has_many :ticket_types, ElixirConfAfrica.TicketTypes.TicketType - - timestamps() - end - - @doc false - def changeset(event, attrs) do - event - |> cast(attrs, [:name, :event_type, :location, :description, :start_date, :end_date]) - |> validate_required([:name, :event_type, :location, :description, :start_date, :end_date]) - end -end diff --git a/lib/elixir_conf_africa/paystack.ex b/lib/elixir_conf_africa/paystack.ex new file mode 100644 index 0000000..8c6fa64 --- /dev/null +++ b/lib/elixir_conf_africa/paystack.ex @@ -0,0 +1,107 @@ +defmodule ElixirConfAfrica.Paystack do + @moduledoc """ + The Paystack module is responsible for all the interactions with the Paystack API + """ + defp api_url(), do: "https://api.paystack.co/transaction/initialize" + + defp paystack_headers(), + do: [ + { + "Content-Type", + "application/json" + }, + { + "Authorization", + "Bearer #{api_key()}" + } + ] + + @doc """ + Initializes a transaction with Paystack and returns the transaction reference and a url to redirect to + + """ + def initialize(email, amount) do + api_url = api_url() + + amount = amount * 100 + + paystack_body = + %{ + "email" => email, + "amount" => amount, + "callback_url" => "http://localhost:5800/success" + } + |> Jason.encode!() + + case HTTPoison.post(api_url, paystack_body, paystack_headers()) do + {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> + body + |> Jason.decode!() + |> Map.get("data") + + {:error, %HTTPoison.Error{reason: reason}} -> + reason + end + end + + @doc """ + Verifies a transaction with Paystack and returns the transaction details + + """ + def test_verification(transaction_reference) do + paystack_headers = paystack_headers() + + url = "https://api.paystack.co/transaction/verify/#{transaction_reference}" + + case HTTPoison.get(url, paystack_headers) do + {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> + body + |> Jason.decode!() + |> Map.get("data") + + {:error, %HTTPoison.Error{reason: reason}} -> + reason + end + end + + @doc """ + Lists all transactions made + + """ + def list_transactions do + get_transactions() + |> Enum.map(fn transaction -> + %{ + "reference" => transaction["reference"], + "amount" => transaction["amount"], + "status" => transaction["status"], + "currency" => transaction["currency"], + "paid_at" => transaction["paid_at"], + "email" => transaction["customer"]["email"], + "bank" => transaction["authorization"]["bank"] + } + end) + end + + defp get_transactions do + url = "https://api.paystack.co/transaction" + + case HTTPoison.get(url, paystack_headers()) do + {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> + body + |> Jason.decode!() + |> Map.get("data") + + {:error, %HTTPoison.Error{reason: reason}} -> + reason + end + end + + defp api_key do + if Mix.env() == :test do + "sk_test_46828225be64577ea7523018d51bb119d00d4e40" + else + "sk_test_46828225be64577ea7523018d51bb119d00d4e40" + end + end +end diff --git a/lib/elixir_conf_africa/ticket_types.ex b/lib/elixir_conf_africa/ticket_types.ex index cccb8ad..e0b6098 100644 --- a/lib/elixir_conf_africa/ticket_types.ex +++ b/lib/elixir_conf_africa/ticket_types.ex @@ -7,6 +7,7 @@ defmodule ElixirConfAfrica.TicketTypes do alias ElixirConfAfrica.Repo alias ElixirConfAfrica.TicketTypes.TicketType + alias ElixirConfAfrica.Tickets.Ticket @doc """ Returns the list of ticket_types. @@ -17,11 +18,32 @@ defmodule ElixirConfAfrica.TicketTypes do [%TicketType{}, ...] """ - @spec list_ticket_types() :: list() def list_ticket_types do Repo.all(TicketType) end + @doc """ + Returns the list of ticket_types with the remaining tickets. + + + """ + + def list_ticket_types_with_remaining_tickets do + from(tick in TicketType, + left_join: t in Ticket, + on: t.ticket_type_id == tick.id and t.is_paid == true and t.is_refunded == false, + group_by: tick.id, + select: %{ + id: tick.id, + name: tick.name, + remaining_tickets: coalesce(tick.number - count(t.id), 0), + description: tick.description, + price: tick.price + } + ) + |> Repo.all() + end + @doc """ Gets a single ticket_type. @@ -36,7 +58,6 @@ defmodule ElixirConfAfrica.TicketTypes do ** (Ecto.NoResultsError) """ - @spec get_ticket_type!(non_neg_integer()) :: TicketType.t() | Ecto.NoResultsError def get_ticket_type!(id), do: Repo.get!(TicketType, id) @doc """ @@ -51,7 +72,6 @@ defmodule ElixirConfAfrica.TicketTypes do {:error, %Ecto.Changeset{}} """ - @spec create_ticket_type(map()) :: {:ok, TicketType.t()} | {:error, Ecto.Changeset.t()} def create_ticket_type(attrs \\ %{}) do %TicketType{} |> TicketType.changeset(attrs) @@ -70,8 +90,6 @@ defmodule ElixirConfAfrica.TicketTypes do {:error, %Ecto.Changeset{}} """ - @spec update_ticket_type(TicketType.t(), map()) :: - {:ok, TicketType.t()} | {:error, Ecto.Changeset.t()} def update_ticket_type(%TicketType{} = ticket_type, attrs) do ticket_type |> TicketType.changeset(attrs) @@ -90,7 +108,6 @@ defmodule ElixirConfAfrica.TicketTypes do {:error, %Ecto.Changeset{}} """ - @spec delete_ticket_type(TicketType.t()) :: {:ok, TicketType.t()} | {:error, Ecto.Changeset.t()} def delete_ticket_type(%TicketType{} = ticket_type) do Repo.delete(ticket_type) end @@ -104,7 +121,6 @@ defmodule ElixirConfAfrica.TicketTypes do %Ecto.Changeset{data: %TicketType{}} """ - @spec change_ticket_type(TicketType.t(), map()) :: Ecto.Changeset.t() def change_ticket_type(%TicketType{} = ticket_type, attrs \\ %{}) do TicketType.changeset(ticket_type, attrs) end diff --git a/lib/elixir_conf_africa/ticket_types/ticket_type.ex b/lib/elixir_conf_africa/ticket_types/ticket_type.ex index c89aa01..489196e 100644 --- a/lib/elixir_conf_africa/ticket_types/ticket_type.ex +++ b/lib/elixir_conf_africa/ticket_types/ticket_type.ex @@ -1,15 +1,13 @@ defmodule ElixirConfAfrica.TicketTypes.TicketType do - @moduledoc false - - use TypedEctoSchema + use Ecto.Schema import Ecto.Changeset - typed_schema "ticket_types" do + schema "ticket_types" do field :name, :string field :description, :string - field :price, :decimal + field :price, :integer field :number, :integer - belongs_to :event, ElixirConfAfrica.Events.Event + has_many :tickets, ElixirConfAfrica.Tickets.Ticket timestamps() end @@ -17,8 +15,8 @@ defmodule ElixirConfAfrica.TicketTypes.TicketType do @doc false def changeset(ticket_type, attrs) do ticket_type - |> cast(attrs, [:event_id, :name, :description, :price, :number]) - |> validate_required([:event_id, :name, :description, :price, :number]) - |> foreign_key_constraint(:event_id) + |> cast(attrs, [:name, :description, :price, :number]) + |> validate_required([:name, :description, :price, :number]) + |> unique_constraint(:name) end end diff --git a/lib/elixir_conf_africa/tickets.ex b/lib/elixir_conf_africa/tickets.ex new file mode 100644 index 0000000..1d034eb --- /dev/null +++ b/lib/elixir_conf_africa/tickets.ex @@ -0,0 +1,151 @@ +defmodule ElixirConfAfrica.Tickets do + @moduledoc """ + The Tickets context. + """ + + import Ecto.Query, warn: false + alias ElixirConfAfrica.Repo + + alias ElixirConfAfrica.Tickets.Ticket + + @doc """ + Returns the list of ticket. + + ## Examples + + iex> list_ticket() + [%Ticket{}, ...] + + """ + def list_ticket do + Repo.all(Ticket) + end + + @doc """ + Gets a single ticket by ticketid. + + """ + + def get_ticket_by_ticketid!(ticketid), + do: Repo.get_by!(Ticket, ticketid: ticketid) |> Repo.preload(:ticket_type) + + @doc """ + List paid tickets. + + """ + def list_paid_tickets do + from(t in Ticket, + where: t.is_paid == true and t.is_refunded == false, + select: t + ) + |> Repo.all() + |> Repo.preload(:ticket_type) + end + + @doc """ + List refunded tickets. + + """ + def list_refunded_tickets do + from(t in Ticket, + where: t.is_refunded == true, + select: t + ) + |> Repo.all() + |> Repo.preload(:ticket_type) + end + + @doc """ + List unpaid tickets. + + """ + def list_unpaid_tickets do + from(t in Ticket, + where: t.is_paid == false and t.is_refunded == false, + select: t + ) + |> Repo.all() + |> Repo.preload(:ticket_type) + end + + @doc """ + Gets a single ticket. + + Raises `Ecto.NoResultsError` if the Ticket does not exist. + + ## Examples + + iex> get_ticket!(123) + %Ticket{} + + iex> get_ticket!(456) + ** (Ecto.NoResultsError) + + """ + def get_ticket!(id), do: Repo.get!(Ticket, id) + + @doc """ + Creates a ticket. + + ## Examples + + iex> create_ticket(%{field: value}) + {:ok, %Ticket{}} + + iex> create_ticket(%{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def create_ticket(attrs \\ %{}) do + %Ticket{} + |> Ticket.changeset(attrs) + |> Repo.insert() + end + + @doc """ + Updates a ticket. + + ## Examples + + iex> update_ticket(ticket, %{field: new_value}) + {:ok, %Ticket{}} + + iex> update_ticket(ticket, %{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def update_ticket(%Ticket{} = ticket, attrs) do + ticket + |> Ticket.changeset(attrs) + |> Repo.update() + end + + @doc """ + Deletes a ticket. + + ## Examples + + iex> delete_ticket(ticket) + {:ok, %Ticket{}} + + iex> delete_ticket(ticket) + {:error, %Ecto.Changeset{}} + + """ + def delete_ticket(%Ticket{} = ticket) do + Repo.delete(ticket) + end + + @doc """ + Returns an `%Ecto.Changeset{}` for tracking ticket changes. + + ## Examples + + iex> change_ticket(ticket) + %Ecto.Changeset{data: %Ticket{}} + + """ + def change_ticket(%Ticket{} = ticket, attrs \\ %{}) do + Ticket.changeset(ticket, attrs) + end +end diff --git a/lib/elixir_conf_africa/tickets/ticket.ex b/lib/elixir_conf_africa/tickets/ticket.ex new file mode 100644 index 0000000..e967d42 --- /dev/null +++ b/lib/elixir_conf_africa/tickets/ticket.ex @@ -0,0 +1,52 @@ +defmodule ElixirConfAfrica.Tickets.Ticket do + use Ecto.Schema + import Ecto.Changeset + + schema "tickets" do + field :name, :string + field :email, :string + field :ticketid, :string + field :quantity, :integer + field :cost, :integer + belongs_to :ticket_type, ElixirConfAfrica.TicketTypes.TicketType + field :is_paid, :boolean, default: false + field :is_refunded, :boolean, default: false + field :phone_number, :string + field :is_scanned, :boolean, default: false + field :email_sent, :boolean, default: true + + timestamps() + end + + @doc false + def changeset(ticket, attrs) do + ticket + |> cast(attrs, [ + :name, + :email, + :ticketid, + :quantity, + :ticket_type_id, + :cost, + :is_paid, + :is_scanned, + :is_refunded, + :phone_number, + :email_sent + ]) + |> validate_required([ + :name, + :email, + :ticketid, + :quantity, + :ticket_type_id, + :cost, + :is_paid, + :is_refunded, + :is_scanned, + :email_sent + ]) + |> unique_constraint(:ticketid) + |> validate_format(:email, ~r/^[^\s]+@[^\s]+$/, message: "must have the @ sign and no spaces") + end +end diff --git a/lib/elixir_conf_africa_web.ex b/lib/elixir_conf_africa_web.ex index 5afb506..076758a 100644 --- a/lib/elixir_conf_africa_web.ex +++ b/lib/elixir_conf_africa_web.ex @@ -58,6 +58,15 @@ defmodule ElixirConfAfricaWeb do end end + def admin_live_view do + quote do + use Phoenix.LiveView, + layout: {ElixirConfAfricaWeb.Layouts, :admin} + + unquote(html_helpers()) + end + end + def live_component do quote do use Phoenix.LiveComponent diff --git a/lib/elixir_conf_africa_web/.DS_Store b/lib/elixir_conf_africa_web/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..806010c5fc4e1337e2bcb4b101679748d53962d1 GIT binary patch literal 6148 zcmeHK&2G~`5T0#Q>bODVfJ84yzHp1GgjS#)kU}Vj-jIUe04TK^tFh$Rk?l0JAt-mA z01mtY&%qP$ES%t**(FMx^okJLv39@l?tK3FX1(hrBGno9TSRpta!?p6E~*X2{an^; z%e2&hO0JPoLLo{)`C7DXunJfO{xt>o+jZ%jQX0|-_2Tb;FlOY zqCMg8m!5$Y;|Ss9CDyk!7S9fSxl<(b!~uBkS6S+QiRID-q6!>{MZJmhsl=(^i6XkB zuypO8H^l{$d}QADdoYTlyl6ImsIBeF&aGX?aUJ)z`>s1kC*8s?#(Brj-tgHAzZe9@ zf0?H7!uNw$Q8?+O=3CGLrF(QR~vbp^krUEcs#sf^2IL=6UE6}X4Ghm z1%wAw4-9_B!KOROKw0MPAmI^slkz}Roc85NoLV!(#@Vw{SOu&CR)LZNJU@6SjBSH+ zjWTthk}UwRf@U%J{JX#$&tTi&TqAm5N>hQFs>~KcX*$|H6W2C4*Qn{F%;rOxJ1et8 zQF3=&-;;1sZH>0J3RneJ71-9Nbzc9U-@N}{CD}8pfK}kXQb1Ksx+fjHl382VUXIsV t59JJnjpODTg@Vc~$Kvo(ypJM=K93z>+u&RyT444^KxD9$Rp75G@EgM++bRG6 literal 0 HcmV?d00001 diff --git a/lib/elixir_conf_africa_web/components/core_components.ex b/lib/elixir_conf_africa_web/components/core_components.ex index 7c0e312..cf43e38 100644 --- a/lib/elixir_conf_africa_web/components/core_components.ex +++ b/lib/elixir_conf_africa_web/components/core_components.ex @@ -225,9 +225,9 @@ defmodule ElixirConfAfricaWeb.CoreComponents do + + + + <%= @inner_content %> diff --git a/lib/elixir_conf_africa_web/components/layouts/root.html.heex b/lib/elixir_conf_africa_web/components/layouts/root.html.heex index d60757a..fa99b53 100644 --- a/lib/elixir_conf_africa_web/components/layouts/root.html.heex +++ b/lib/elixir_conf_africa_web/components/layouts/root.html.heex @@ -10,8 +10,55 @@ + + +
    + <%= if @current_user do %> +
  • + <%= @current_user.email %> +
  • +
  • + <.link + href={~p"/users/settings"} + class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700" + > + Settings + +
  • +
  • + <.link + href={~p"/users/log_out"} + method="delete" + class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700" + > + Log out + +
  • + <% else %> +
  • + <.link + href={~p"/users/register"} + class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700" + > + Register + +
  • +
  • + <.link + href={~p"/users/log_in"} + class="text-[0.8125rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700" + > + Log in + +
  • + <% end %> +
<%= @inner_content %> diff --git a/lib/elixir_conf_africa_web/controllers/user_confirmation_controller.ex b/lib/elixir_conf_africa_web/controllers/user_confirmation_controller.ex new file mode 100644 index 0000000..de26636 --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_confirmation_controller.ex @@ -0,0 +1,56 @@ +defmodule ElixirConfAfricaWeb.UserConfirmationController do + use ElixirConfAfricaWeb, :controller + + alias ElixirConfAfrica.Accounts + + def new(conn, _params) do + render(conn, :new) + end + + def create(conn, %{"user" => %{"email" => email}}) do + if user = Accounts.get_user_by_email(email) do + Accounts.deliver_user_confirmation_instructions( + user, + &url(~p"/users/confirm/#{&1}") + ) + end + + conn + |> put_flash( + :info, + "If your email is in our system and it has not been confirmed yet, " <> + "you will receive an email with instructions shortly." + ) + |> redirect(to: ~p"/") + end + + def edit(conn, %{"token" => token}) do + render(conn, :edit, token: token) + end + + # Do not log in the user after confirmation to avoid a + # leaked token giving the user access to the account. + def update(conn, %{"token" => token}) do + case Accounts.confirm_user(token) do + {:ok, _} -> + conn + |> put_flash(:info, "User confirmed successfully.") + |> redirect(to: ~p"/") + + :error -> + # If there is a current user and the account was already confirmed, + # then odds are that the confirmation link was already visited, either + # by some automation or by the user themselves, so we redirect without + # a warning message. + case conn.assigns do + %{current_user: %{confirmed_at: confirmed_at}} when not is_nil(confirmed_at) -> + redirect(conn, to: ~p"/") + + %{} -> + conn + |> put_flash(:error, "User confirmation link is invalid or it has expired.") + |> redirect(to: ~p"/") + end + end + end +end diff --git a/lib/elixir_conf_africa_web/controllers/user_confirmation_html.ex b/lib/elixir_conf_africa_web/controllers/user_confirmation_html.ex new file mode 100644 index 0000000..2f95938 --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_confirmation_html.ex @@ -0,0 +1,5 @@ +defmodule ElixirConfAfricaWeb.UserConfirmationHTML do + use ElixirConfAfricaWeb, :html + + embed_templates "user_confirmation_html/*" +end diff --git a/lib/elixir_conf_africa_web/controllers/user_confirmation_html/edit.html.heex b/lib/elixir_conf_africa_web/controllers/user_confirmation_html/edit.html.heex new file mode 100644 index 0000000..f320cf7 --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_confirmation_html/edit.html.heex @@ -0,0 +1,14 @@ +
+ <.header class="text-center">Confirm account + + <.simple_form for={@conn.params["user"]} as={:user} action={~p"/users/confirm/#{@token}"}> + <:actions> + <.button class="w-full">Confirm my account + + + +

+ <.link href={~p"/users/register"}>Register + | <.link href={~p"/users/log_in"}>Log in +

+
diff --git a/lib/elixir_conf_africa_web/controllers/user_confirmation_html/new.html.heex b/lib/elixir_conf_africa_web/controllers/user_confirmation_html/new.html.heex new file mode 100644 index 0000000..cb29e0b --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_confirmation_html/new.html.heex @@ -0,0 +1,20 @@ +
+ <.header class="text-center"> + No confirmation instructions received? + <:subtitle>We'll send a new confirmation link to your inbox + + + <.simple_form :let={f} for={@conn.params["user"]} as={:user} action={~p"/users/confirm"}> + <.input field={f[:email]} type="email" placeholder="Email" required /> + <:actions> + <.button phx-disable-with="Sending..." class="w-full"> + Resend confirmation instructions + + + + +

+ <.link href={~p"/users/register"}>Register + | <.link href={~p"/users/log_in"}>Log in +

+
diff --git a/lib/elixir_conf_africa_web/controllers/user_registration_controller.ex b/lib/elixir_conf_africa_web/controllers/user_registration_controller.ex new file mode 100644 index 0000000..aa6a09b --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_registration_controller.ex @@ -0,0 +1,30 @@ +defmodule ElixirConfAfricaWeb.UserRegistrationController do + use ElixirConfAfricaWeb, :controller + + alias ElixirConfAfrica.Accounts + alias ElixirConfAfrica.Accounts.User + alias ElixirConfAfricaWeb.UserAuth + + def new(conn, _params) do + changeset = Accounts.change_user_registration(%User{}) + render(conn, :new, changeset: changeset) + end + + def create(conn, %{"user" => user_params}) do + case Accounts.register_user(user_params) do + {:ok, user} -> + {:ok, _} = + Accounts.deliver_user_confirmation_instructions( + user, + &url(~p"/users/confirm/#{&1}") + ) + + conn + |> put_flash(:info, "User created successfully.") + |> UserAuth.log_in_user(user) + + {:error, %Ecto.Changeset{} = changeset} -> + render(conn, :new, changeset: changeset) + end + end +end diff --git a/lib/elixir_conf_africa_web/controllers/user_registration_html.ex b/lib/elixir_conf_africa_web/controllers/user_registration_html.ex new file mode 100644 index 0000000..dc05280 --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_registration_html.ex @@ -0,0 +1,5 @@ +defmodule ElixirConfAfricaWeb.UserRegistrationHTML do + use ElixirConfAfricaWeb, :html + + embed_templates "user_registration_html/*" +end diff --git a/lib/elixir_conf_africa_web/controllers/user_registration_html/new.html.heex b/lib/elixir_conf_africa_web/controllers/user_registration_html/new.html.heex new file mode 100644 index 0000000..a06b058 --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_registration_html/new.html.heex @@ -0,0 +1,25 @@ +
+ <.header class="text-center"> + Register for an account + <:subtitle> + Already registered? + <.link navigate={~p"/users/log_in"} class="font-semibold text-brand hover:underline"> + Sign in + + to your account now. + + + + <.simple_form :let={f} for={@changeset} action={~p"/users/register"}> + <.error :if={@changeset.action == :insert}> + Oops, something went wrong! Please check the errors below. + + + <.input field={f[:email]} type="email" label="Email" required /> + <.input field={f[:password]} type="password" label="Password" required /> + + <:actions> + <.button phx-disable-with="Creating account..." class="w-full">Create an account + + +
diff --git a/lib/elixir_conf_africa_web/controllers/user_reset_password_controller.ex b/lib/elixir_conf_africa_web/controllers/user_reset_password_controller.ex new file mode 100644 index 0000000..9b4da39 --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_reset_password_controller.ex @@ -0,0 +1,58 @@ +defmodule ElixirConfAfricaWeb.UserResetPasswordController do + use ElixirConfAfricaWeb, :controller + + alias ElixirConfAfrica.Accounts + + plug :get_user_by_reset_password_token when action in [:edit, :update] + + def new(conn, _params) do + render(conn, :new) + end + + def create(conn, %{"user" => %{"email" => email}}) do + if user = Accounts.get_user_by_email(email) do + Accounts.deliver_user_reset_password_instructions( + user, + &url(~p"/users/reset_password/#{&1}") + ) + end + + conn + |> put_flash( + :info, + "If your email is in our system, you will receive instructions to reset your password shortly." + ) + |> redirect(to: ~p"/") + end + + def edit(conn, _params) do + render(conn, :edit, changeset: Accounts.change_user_password(conn.assigns.user)) + end + + # Do not log in the user after reset password to avoid a + # leaked token giving the user access to the account. + def update(conn, %{"user" => user_params}) do + case Accounts.reset_user_password(conn.assigns.user, user_params) do + {:ok, _} -> + conn + |> put_flash(:info, "Password reset successfully.") + |> redirect(to: ~p"/users/log_in") + + {:error, changeset} -> + render(conn, :edit, changeset: changeset) + end + end + + defp get_user_by_reset_password_token(conn, _opts) do + %{"token" => token} = conn.params + + if user = Accounts.get_user_by_reset_password_token(token) do + conn |> assign(:user, user) |> assign(:token, token) + else + conn + |> put_flash(:error, "Reset password link is invalid or it has expired.") + |> redirect(to: ~p"/") + |> halt() + end + end +end diff --git a/lib/elixir_conf_africa_web/controllers/user_reset_password_html.ex b/lib/elixir_conf_africa_web/controllers/user_reset_password_html.ex new file mode 100644 index 0000000..cadaa71 --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_reset_password_html.ex @@ -0,0 +1,5 @@ +defmodule ElixirConfAfricaWeb.UserResetPasswordHTML do + use ElixirConfAfricaWeb, :html + + embed_templates "user_reset_password_html/*" +end diff --git a/lib/elixir_conf_africa_web/controllers/user_reset_password_html/edit.html.heex b/lib/elixir_conf_africa_web/controllers/user_reset_password_html/edit.html.heex new file mode 100644 index 0000000..b8be4ce --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_reset_password_html/edit.html.heex @@ -0,0 +1,29 @@ +
+ <.header class="text-center"> + Reset Password + + + <.simple_form :let={f} for={@changeset} action={~p"/users/reset_password/#{@token}"}> + <.error :if={@changeset.action}> + Oops, something went wrong! Please check the errors below. + + + <.input field={f[:password]} type="password" label="New Password" required /> + <.input + field={f[:password_confirmation]} + type="password" + label="Confirm new password" + required + /> + <:actions> + <.button phx-disable-with="Resetting..." class="w-full"> + Reset password + + + + +

+ <.link href={~p"/users/register"}>Register + | <.link href={~p"/users/log_in"}>Log in +

+
diff --git a/lib/elixir_conf_africa_web/controllers/user_reset_password_html/new.html.heex b/lib/elixir_conf_africa_web/controllers/user_reset_password_html/new.html.heex new file mode 100644 index 0000000..cc36db4 --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_reset_password_html/new.html.heex @@ -0,0 +1,20 @@ +
+ <.header class="text-center"> + Forgot your password? + <:subtitle>We'll send a password reset link to your inbox + + + <.simple_form :let={f} for={@conn.params["user"]} as={:user} action={~p"/users/reset_password"}> + <.input field={f[:email]} type="email" placeholder="Email" required /> + <:actions> + <.button phx-disable-with="Sending..." class="w-full"> + Send password reset instructions + + + + +

+ <.link href={~p"/users/register"}>Register + | <.link href={~p"/users/log_in"}>Log in +

+
diff --git a/lib/elixir_conf_africa_web/controllers/user_session_controller.ex b/lib/elixir_conf_africa_web/controllers/user_session_controller.ex new file mode 100644 index 0000000..3373d08 --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_session_controller.ex @@ -0,0 +1,29 @@ +defmodule ElixirConfAfricaWeb.UserSessionController do + use ElixirConfAfricaWeb, :controller + + alias ElixirConfAfrica.Accounts + alias ElixirConfAfricaWeb.UserAuth + + def new(conn, _params) do + render(conn, :new, error_message: nil) + end + + def create(conn, %{"user" => user_params}) do + %{"email" => email, "password" => password} = user_params + + if user = Accounts.get_user_by_email_and_password(email, password) do + conn + |> put_flash(:info, "Welcome back!") + |> UserAuth.log_in_user(user, user_params) + else + # In order to prevent user enumeration attacks, don't disclose whether the email is registered. + render(conn, :new, error_message: "Invalid email or password") + end + end + + def delete(conn, _params) do + conn + |> put_flash(:info, "Logged out successfully.") + |> UserAuth.log_out_user() + end +end diff --git a/lib/elixir_conf_africa_web/controllers/user_session_html.ex b/lib/elixir_conf_africa_web/controllers/user_session_html.ex new file mode 100644 index 0000000..5391143 --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_session_html.ex @@ -0,0 +1,5 @@ +defmodule ElixirConfAfricaWeb.UserSessionHTML do + use ElixirConfAfricaWeb, :html + + embed_templates "user_session_html/*" +end diff --git a/lib/elixir_conf_africa_web/controllers/user_session_html/new.html.heex b/lib/elixir_conf_africa_web/controllers/user_session_html/new.html.heex new file mode 100644 index 0000000..28c2467 --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_session_html/new.html.heex @@ -0,0 +1,31 @@ +
+ <.header class="text-center"> + Sign in to account + <:subtitle> + Don't have an account? + <.link navigate={~p"/users/register"} class="font-semibold text-brand hover:underline"> + Sign up + + for an account now. + + + + <.simple_form :let={f} for={@conn.params["user"]} as={:user} action={~p"/users/log_in"}> + <.error :if={@error_message}><%= @error_message %> + + <.input field={f[:email]} type="email" label="Email" required /> + <.input field={f[:password]} type="password" label="Password" required /> + + <:actions :let={f}> + <.input field={f[:remember_me]} type="checkbox" label="Keep me logged in" /> + <.link href={~p"/users/reset_password"} class="text-sm font-semibold"> + Forgot your password? + + + <:actions> + <.button phx-disable-with="Signing in..." class="w-full"> + Sign in + + + +
diff --git a/lib/elixir_conf_africa_web/controllers/user_settings_controller.ex b/lib/elixir_conf_africa_web/controllers/user_settings_controller.ex new file mode 100644 index 0000000..9c7d79d --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_settings_controller.ex @@ -0,0 +1,74 @@ +defmodule ElixirConfAfricaWeb.UserSettingsController do + use ElixirConfAfricaWeb, :controller + + alias ElixirConfAfrica.Accounts + alias ElixirConfAfricaWeb.UserAuth + + plug :assign_email_and_password_changesets + + def edit(conn, _params) do + render(conn, :edit) + end + + def update(conn, %{"action" => "update_email"} = params) do + %{"current_password" => password, "user" => user_params} = params + user = conn.assigns.current_user + + case Accounts.apply_user_email(user, password, user_params) do + {:ok, applied_user} -> + Accounts.deliver_update_email_instructions( + applied_user, + user.email, + &url(~p"/users/settings/confirm_email/#{&1}") + ) + + conn + |> put_flash( + :info, + "A link to confirm your email change has been sent to the new address." + ) + |> redirect(to: ~p"/users/settings") + + {:error, changeset} -> + render(conn, :edit, email_changeset: changeset) + end + end + + def update(conn, %{"action" => "update_password"} = params) do + %{"current_password" => password, "user" => user_params} = params + user = conn.assigns.current_user + + case Accounts.update_user_password(user, password, user_params) do + {:ok, user} -> + conn + |> put_flash(:info, "Password updated successfully.") + |> put_session(:user_return_to, ~p"/users/settings") + |> UserAuth.log_in_user(user) + + {:error, changeset} -> + render(conn, :edit, password_changeset: changeset) + end + end + + def confirm_email(conn, %{"token" => token}) do + case Accounts.update_user_email(conn.assigns.current_user, token) do + :ok -> + conn + |> put_flash(:info, "Email changed successfully.") + |> redirect(to: ~p"/users/settings") + + :error -> + conn + |> put_flash(:error, "Email change link is invalid or it has expired.") + |> redirect(to: ~p"/users/settings") + end + end + + defp assign_email_and_password_changesets(conn, _opts) do + user = conn.assigns.current_user + + conn + |> assign(:email_changeset, Accounts.change_user_email(user)) + |> assign(:password_changeset, Accounts.change_user_password(user)) + end +end diff --git a/lib/elixir_conf_africa_web/controllers/user_settings_html.ex b/lib/elixir_conf_africa_web/controllers/user_settings_html.ex new file mode 100644 index 0000000..93a42fd --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_settings_html.ex @@ -0,0 +1,5 @@ +defmodule ElixirConfAfricaWeb.UserSettingsHTML do + use ElixirConfAfricaWeb, :html + + embed_templates "user_settings_html/*" +end diff --git a/lib/elixir_conf_africa_web/controllers/user_settings_html/edit.html.heex b/lib/elixir_conf_africa_web/controllers/user_settings_html/edit.html.heex new file mode 100644 index 0000000..915c3fd --- /dev/null +++ b/lib/elixir_conf_africa_web/controllers/user_settings_html/edit.html.heex @@ -0,0 +1,63 @@ +<.header class="text-center"> + Account Settings + <:subtitle>Manage your account email address and password settings + + +
+
+ <.simple_form :let={f} for={@email_changeset} action={~p"/users/settings"} id="update_email"> + <.error :if={@email_changeset.action}> + Oops, something went wrong! Please check the errors below. + + + <.input field={f[:action]} type="hidden" name="action" value="update_email" /> + + <.input field={f[:email]} type="email" label="Email" required /> + <.input + field={f[:current_password]} + name="current_password" + type="password" + label="Current Password" + required + id="current_password_for_email" + /> + <:actions> + <.button phx-disable-with="Changing...">Change Email + + +
+
+ <.simple_form + :let={f} + for={@password_changeset} + action={~p"/users/settings"} + id="update_password" + > + <.error :if={@password_changeset.action}> + Oops, something went wrong! Please check the errors below. + + + <.input field={f[:action]} type="hidden" name="action" value="update_password" /> + + <.input field={f[:password]} type="password" label="New password" required /> + <.input + field={f[:password_confirmation]} + type="password" + label="Confirm new password" + required + /> + + <.input + field={f[:current_password]} + name="current_password" + type="password" + label="Current password" + id="current_password_for_password" + required + /> + <:actions> + <.button phx-disable-with="Changing...">Change Password + + +
+
diff --git a/lib/elixir_conf_africa_web/live/.DS_Store b/lib/elixir_conf_africa_web/live/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..efd35b9cfda4816866ddf293ce4cf69a43f0c6f9 GIT binary patch literal 6148 zcmeHKOHRWu5Pbt(^n*}@Sg@&-6CiPeP?ZI14ghUZ1fn#kO_A7T&mFh|=VJwLY^zGz zMk*Urp_yvtIkulYepT!kfDD$|1rPyf(-m7?hApP;>Kk?tYLq8#j2tse=mi!Vy{*C& zFa`Ea0eyG7NRi_iFN~}A_j;PA<7qx-yKWAb^z(0LECC%nIL-vOnBozynA924Ut>fZ zf5e^{83i%L6ZeXuk^i;EKgFE=@3CZ#8B05k<1+uKWPZfGY024Bjw{wlAx zQ`WlbDl1xJ6?mf#&8od`;m@htjG2y@vnr?mQbX3Fs#WJdaeDnqc~wk~D~feE#)3J| zn`Tw5Y78b}w)YC~%vNjnJX$mbOaW71rGV}aFKv# z1S~zWg(jX#^i&B~4Doc<$Dv;mu=MEZkZ}2sFtdakin!T1e(btK5|0*50aKu^z@dMP z^!&eSzW>)r_GAi}0{=<@X$^0N11>3?ts9Hevo@yR(bcqH>CsUb!g1^hdK910ov|&} W0x=0#dSngFJ_MW$7EFOZRp1AA1*;eU literal 0 HcmV?d00001 diff --git a/lib/elixir_conf_africa_web/live/event_live/form_component.ex b/lib/elixir_conf_africa_web/live/event_live/form_component.ex deleted file mode 100644 index 504822e..0000000 --- a/lib/elixir_conf_africa_web/live/event_live/form_component.ex +++ /dev/null @@ -1,95 +0,0 @@ -defmodule ElixirConfAfricaWeb.EventLive.FormComponent do - use ElixirConfAfricaWeb, :live_component - - alias ElixirConfAfrica.Events - - @impl true - def render(assigns) do - ~H""" -
- <.header> - <%= @title %> - <:subtitle>Use this form to manage event records in your database. - - - <.simple_form - for={@form} - id="event-form" - phx-target={@myself} - phx-change="validate" - phx-submit="save" - > - <.input field={@form[:name]} type="text" label="Name" /> - <.input field={@form[:event_type]} type="text" label="Event type" /> - <.input field={@form[:location]} type="text" label="Location" /> - <.input field={@form[:description]} type="text" label="Description" /> - <.input field={@form[:start_date]} type="datetime-local" label="Start date" /> - <.input field={@form[:end_date]} type="datetime-local" label="End date" /> - <:actions> - <.button phx-disable-with="Saving...">Save Event - - -
- """ - end - - @impl true - def update(%{event: event} = assigns, socket) do - changeset = Events.change_event(event) - - {:ok, - socket - |> assign(assigns) - |> assign_form(changeset)} - end - - @impl true - def handle_event("validate", %{"event" => event_params}, socket) do - changeset = - socket.assigns.event - |> Events.change_event(event_params) - |> Map.put(:action, :validate) - - {:noreply, assign_form(socket, changeset)} - end - - def handle_event("save", %{"event" => event_params}, socket) do - save_event(socket, socket.assigns.action, event_params) - end - - defp save_event(socket, :edit, event_params) do - case Events.update_event(socket.assigns.event, event_params) do - {:ok, event} -> - notify_parent({:saved, event}) - - {:noreply, - socket - |> put_flash(:info, "Event updated successfully") - |> push_patch(to: socket.assigns.patch)} - - {:error, %Ecto.Changeset{} = changeset} -> - {:noreply, assign_form(socket, changeset)} - end - end - - defp save_event(socket, :new, event_params) do - case Events.create_event(event_params) do - {:ok, event} -> - notify_parent({:saved, event}) - - {:noreply, - socket - |> put_flash(:info, "Event created successfully") - |> push_patch(to: socket.assigns.patch)} - - {:error, %Ecto.Changeset{} = changeset} -> - {:noreply, assign_form(socket, changeset)} - end - end - - defp assign_form(socket, %Ecto.Changeset{} = changeset) do - assign(socket, :form, to_form(changeset)) - end - - defp notify_parent(msg), do: send(self(), {__MODULE__, msg}) -end diff --git a/lib/elixir_conf_africa_web/live/event_live/index.ex b/lib/elixir_conf_africa_web/live/event_live/index.ex index 91803fc..4601a44 100644 --- a/lib/elixir_conf_africa_web/live/event_live/index.ex +++ b/lib/elixir_conf_africa_web/live/event_live/index.ex @@ -1,12 +1,11 @@ defmodule ElixirConfAfricaWeb.EventLive.Index do use ElixirConfAfricaWeb, :live_view - - alias ElixirConfAfrica.Events - alias ElixirConfAfrica.Events.Event - + alias ElixirConfAfrica.TicketTypes + alias ElixirConfAfrica.Tickets.Ticket @impl true def mount(_params, _session, socket) do - {:ok, stream(socket, :events, Events.list_events())} + ticket_types = TicketTypes.list_ticket_types_with_remaining_tickets() + {:ok, assign(socket, :ticket_types, ticket_types)} end @impl true @@ -14,34 +13,17 @@ defmodule ElixirConfAfricaWeb.EventLive.Index do {:noreply, apply_action(socket, socket.assigns.live_action, params)} end - defp apply_action(socket, :edit, %{"id" => id}) do - socket - |> assign(:page_title, "Edit Event") - |> assign(:event, Events.get_event!(id)) - end - - defp apply_action(socket, :new, _params) do - socket - |> assign(:page_title, "New Event") - |> assign(:event, %Event{}) - end - defp apply_action(socket, :index, _params) do socket - |> assign(:page_title, "Listing Events") - |> assign(:event, nil) - end - - @impl true - def handle_info({ElixirConfAfricaWeb.EventLive.FormComponent, {:saved, event}}, socket) do - {:noreply, stream_insert(socket, :events, event)} + |> assign(:page_title, "ElixirConf Africa 2024") end - @impl true - def handle_event("delete", %{"id" => id}, socket) do - event = Events.get_event!(id) - {:ok, _} = Events.delete_event(event) + defp apply_action(socket, :ticket, params) do + ticket_type = TicketTypes.get_ticket_type!(params["ticket_type_id"]) - {:noreply, stream_delete(socket, :events, event)} + socket + |> assign(:page_title, "#{ticket_type.name} Ticket") + |> assign(:ticket_type, ticket_type) + |> assign(:ticket, %Ticket{}) end end diff --git a/lib/elixir_conf_africa_web/live/event_live/index.html.heex b/lib/elixir_conf_africa_web/live/event_live/index.html.heex index 4b14fe0..742c613 100644 --- a/lib/elixir_conf_africa_web/live/event_live/index.html.heex +++ b/lib/elixir_conf_africa_web/live/event_live/index.html.heex @@ -1,51 +1,63 @@ -<.header> - Listing Events - <:actions> - <.link patch={~p"/events/new"}> - <.button>New Event - - - - -<.table - id="events" - rows={@streams.events} - row_click={fn {_id, event} -> JS.navigate(~p"/events/#{event}") end} -> - <:col :let={{_id, event}} label="Name"><%= event.name %> - <:col :let={{_id, event}} label="Event type"><%= event.event_type %> - <:col :let={{_id, event}} label="Location"><%= event.location %> - <:col :let={{_id, event}} label="Description"><%= event.description %> - <:col :let={{_id, event}} label="Start date"><%= event.start_date %> - <:col :let={{_id, event}} label="End date"><%= event.end_date %> - <:action :let={{_id, event}}> -
- <.link navigate={~p"/events/#{event}"}>Show -
- <.link patch={~p"/events/#{event}/edit"}>Edit - - <:action :let={{id, event}}> - <.link - phx-click={JS.push("delete", value: %{id: event.id}) |> hide("##{id}")} - data-confirm="Are you sure?" - > - Delete - - - - <.modal - :if={@live_action in [:new, :edit]} - id="event-modal" + :if={@live_action in [:ticket]} + id="buy-ticket-modal" show - on_cancel={JS.patch(~p"/events")} + on_cancel={JS.patch(~p"/event")} > <.live_component - module={ElixirConfAfricaWeb.EventLive.FormComponent} - id={@event.id || :new} + module={ElixirConfAfricaWeb.TicketLive.FormComponent} + id={:new} title={@page_title} action={@live_action} - event={@event} - patch={~p"/events"} + ticket_type={@ticket_type} + ticket={@ticket} + patch={~p"/event"} /> + +
+ ElixirConf Africa 2024 +
+ +
+
+
+
+

Available Tickets

+ +
+ <%= for ticket_type <- @ticket_types do %> +
+
+

<%= ticket_type.name %>

+

+ <%= ticket_type.remaining_tickets %> Tickets Remaining +

+
+

+ <%= ticket_type.description %> +

+
+

KSH <%= ticket_type.price %>

+
+ <.link + navigate={~p"/event/#{ticket_type.id}/buy"} + id="buy-#{ticket_type.id}-tickets" + > + + +
+
+
+ <% end %> +
+
+
+
+
diff --git a/lib/elixir_conf_africa_web/live/event_live/show.ex b/lib/elixir_conf_africa_web/live/event_live/show.ex deleted file mode 100644 index 1372982..0000000 --- a/lib/elixir_conf_africa_web/live/event_live/show.ex +++ /dev/null @@ -1,27 +0,0 @@ -defmodule ElixirConfAfricaWeb.EventLive.Show do - use ElixirConfAfricaWeb, :live_view - - alias ElixirConfAfrica.Events - alias ElixirConfAfrica.Repo - - @impl true - def mount(_params, _session, socket) do - {:ok, socket} - end - - @impl true - def handle_params(%{"id" => id}, _, socket) do - event = - id - |> Events.get_event!() - |> Repo.preload(:ticket_types) - - {:noreply, - socket - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:event, event)} - end - - defp page_title(:show), do: "Show Event" - defp page_title(:edit), do: "Edit Event" -end diff --git a/lib/elixir_conf_africa_web/live/event_live/show.html.heex b/lib/elixir_conf_africa_web/live/event_live/show.html.heex deleted file mode 100644 index 2be9944..0000000 --- a/lib/elixir_conf_africa_web/live/event_live/show.html.heex +++ /dev/null @@ -1,58 +0,0 @@ -<.header> - Event <%= @event.id %> - <:subtitle>This is a event record from your database. - <:actions> - <.link patch={~p"/events/#{@event}/show/edit"} phx-click={JS.push_focus()}> - <.button>Edit event - - - - -<.list> - <:item title="Name"><%= @event.name %> - <:item title="Event type"><%= @event.event_type %> - <:item title="Location"><%= @event.location %> - <:item title="Description"><%= @event.description %> - <:item title="Start date"><%= @event.start_date %> - <:item title="End date"><%= @event.end_date %> - -
-<.header>Event Ticket Types - -<.table id="ticket_types" rows={@event.ticket_types}> - <:col :let={ticket_type} label="Name"><%= ticket_type.name %> - <:col :let={ticket_type} label="Description"><%= ticket_type.description %> - <:col :let={ticket_type} label="Price"><%= ticket_type.price %> - <:action :let={ticket_type}> -
- <.link navigate={~p"/ticket_types/#{ticket_type}"}>Show -
- <.link navigate={~p"/ticket_types/#{ticket_type}/edit"}>Edit - - <:action :let={ticket_type}> - <.link - phx-click={JS.push("delete", value: %{id: ticket_type.id}) |> hide("##{ticket_type.id}")} - data-confirm="Are you sure?" - > - Delete - - - - -<.back navigate={~p"/events"}>Back to events - -<.modal - :if={@live_action == :edit} - id="event-modal" - show - on_cancel={JS.patch(~p"/events/#{@event}")} -> - <.live_component - module={ElixirConfAfricaWeb.EventLive.FormComponent} - id={@event.id} - title={@page_title} - action={@live_action} - event={@event} - patch={~p"/events/#{@event}"} - /> - diff --git a/lib/elixir_conf_africa_web/live/home_live/index.ex b/lib/elixir_conf_africa_web/live/home_live/index.ex index 1291b04..fc61708 100644 --- a/lib/elixir_conf_africa_web/live/home_live/index.ex +++ b/lib/elixir_conf_africa_web/live/home_live/index.ex @@ -1,24 +1,17 @@ defmodule ElixirConfAfricaWeb.HomeLive.Index do use ElixirConfAfricaWeb, :live_view - alias ElixirConfAfrica.Events - + @impl true def mount(_params, _session, socket) do - # these value are more static and we should find away of display this data to home page - event_name = "ElixirConf Africa #{get_current_year()}" - - event = - Events.get_event_with_ticket_types_by_event_name(event_name) - - available_ticket = Events.get_total_number_of_available_tickets(event_name) + {:ok, socket} + end - {:ok, - socket - |> assign(:event, event)} - |> assign(available_ticket: available_ticket) + @impl true + def handle_params(params, _url, socket) do + {:noreply, apply_action(socket, socket.assigns.live_action, params)} end - defp get_current_year do - %{year: year} = DateTime.utc_now() - year + defp apply_action(socket, :index, _params) do + socket + |> assign(:page_title, "ElixirConf Africa") end end diff --git a/lib/elixir_conf_africa_web/live/home_live/index.html.heex b/lib/elixir_conf_africa_web/live/home_live/index.html.heex index cec095a..022f5e6 100644 --- a/lib/elixir_conf_africa_web/live/home_live/index.html.heex +++ b/lib/elixir_conf_africa_web/live/home_live/index.html.heex @@ -1,143 +1,25 @@ -
-
- -
- -
-

Logout

- -
-
-
-
- ElixirConf Africa 2024 -
-
- -
-
- -
- Backend Engineer at Wezacare Solutions -
- -
-
- -

Attending

-
-
- -

June 19 2024 | June 23 2024

-
-
-
-

- Details -

-

- Cart -

-

- Payment +

+ Elixir Conf 2024

-

- Payment Details +

+ Dive deep into Elixir through interactive workshops led by experienced mentors, providing practical experience and enhancing your understanding of the language.

-
-
- -<%!-- navbar --%> - -
-
-
-
-

- Event Information -

-
-
-

Start Date

-

<%= @event.start_date %>

-
-
-

End Date

-

<%= @event.start_date %>

-
-
-

Event Type

-

<%= @event.event_type %>

-
-
-

Available Tickets

-

<%= @available_tickets %>

-
-
-
-

Location

-

<%= @event.location %>

-
-
-

Hosted by

-

Elixir Conf Africa

-
-
-
-

Available Tickets

- -
- <%= for ticket_type <- @event.ticket_types do %> -
-
-

<%= ticket_type.name %>

-

<%= ticket_type.number %>Tickets

-
-

- <%= ticket_type.description %> -

-
-

KSH <%= ticket_type.price %>

-
- - -
-
-
- <% end %> -
-
+

+

+ <.link navigate={~p"/event"}> + +
diff --git a/lib/elixir_conf_africa_web/live/paid_ticket_live/index.ex b/lib/elixir_conf_africa_web/live/paid_ticket_live/index.ex new file mode 100644 index 0000000..e5e48c1 --- /dev/null +++ b/lib/elixir_conf_africa_web/live/paid_ticket_live/index.ex @@ -0,0 +1,36 @@ +defmodule ElixirConfAfricaWeb.PaidTicketLive.Index do + use ElixirConfAfricaWeb, :admin_live_view + + alias ElixirConfAfrica.Tickets + alias ElixirConfAfrica.Emails + + @impl true + def mount(_params, _session, socket) do + {:ok, assign(socket, :ticket_collection, list_paid_tickets())} + end + + @impl true + def handle_params(params, _url, socket) do + {:noreply, apply_action(socket, socket.assigns.live_action, params)} + end + + defp apply_action(socket, :index, _params) do + socket + |> assign(:page_title, "Listing Paid Tickets") + end + + @impl true + + def handle_event("send_email", %{"ticketid" => ticketid}, socket) do + ticket = Tickets.get_ticket_by_ticketid!(ticketid) + Emails.deliver_ticket_by_email(ticket.email, "localhost:4900/tickets/#{ticket.ticketid}") + + {:noreply, + socket + |> put_flash(:info, "Ticket sent successfully")} + end + + defp list_paid_tickets do + Tickets.list_paid_tickets() + end +end diff --git a/lib/elixir_conf_africa_web/live/paid_ticket_live/index.html.heex b/lib/elixir_conf_africa_web/live/paid_ticket_live/index.html.heex new file mode 100644 index 0000000..04ec952 --- /dev/null +++ b/lib/elixir_conf_africa_web/live/paid_ticket_live/index.html.heex @@ -0,0 +1,41 @@ +
+

Listing Paid Tickets

+
+ + + + + + + + + + + + + + + <%= for ticket <- @ticket_collection do %> + + + + + + + + + + <% end %> + +
NameEmailTicket idQuantityAmountTypeEmail Action
<%= ticket.name %><%= ticket.email %><%= ticket.ticketid %><%= ticket.quantity %><%= ticket.cost %> KSH /=<%= ticket.ticket_type.name %> +
+ +
+
diff --git a/lib/elixir_conf_africa_web/live/refunded_ticket_live/index.ex b/lib/elixir_conf_africa_web/live/refunded_ticket_live/index.ex new file mode 100644 index 0000000..6c639e7 --- /dev/null +++ b/lib/elixir_conf_africa_web/live/refunded_ticket_live/index.ex @@ -0,0 +1,24 @@ +defmodule ElixirConfAfricaWeb.RefundedTicketLive.Index do + use ElixirConfAfricaWeb, :admin_live_view + + alias ElixirConfAfrica.Tickets + + @impl true + def mount(_params, _session, socket) do + {:ok, assign(socket, :ticket_collection, list_refunded_tickets())} + end + + @impl true + def handle_params(params, _url, socket) do + {:noreply, apply_action(socket, socket.assigns.live_action, params)} + end + + defp apply_action(socket, :index, _params) do + socket + |> assign(:page_title, "Listing Refunded Tickets") + end + + defp list_refunded_tickets do + Tickets.list_refunded_tickets() + end +end diff --git a/lib/elixir_conf_africa_web/live/refunded_ticket_live/index.html.heex b/lib/elixir_conf_africa_web/live/refunded_ticket_live/index.html.heex new file mode 100644 index 0000000..199f01d --- /dev/null +++ b/lib/elixir_conf_africa_web/live/refunded_ticket_live/index.html.heex @@ -0,0 +1,33 @@ +
+

Listing Refunded Tickets

+
+ + + + + + + + + + + + + + <%= for ticket <- @ticket_collection do %> + + + + + + + + + <% end %> + +
NameEmailTicket idQuantityAmountType
<%= ticket.name %><%= ticket.email %><%= ticket.ticketid %><%= ticket.quantity %><%= ticket.cost %> KSH /=<%= ticket.ticket_type.name %>
diff --git a/lib/elixir_conf_africa_web/live/success_live/index.ex b/lib/elixir_conf_africa_web/live/success_live/index.ex new file mode 100644 index 0000000..791d7da --- /dev/null +++ b/lib/elixir_conf_africa_web/live/success_live/index.ex @@ -0,0 +1,75 @@ +defmodule ElixirConfAfricaWeb.SuccessLive.Index do + use ElixirConfAfricaWeb, :live_view + + alias ElixirConfAfrica.Tickets + + alias ElixirConfAfrica.Emails + alias ElixirConfAfrica.Paystack + + def mount(params, _session, socket) do + Paystack.test_verification(params["trxref"]) + + case Paystack.test_verification(params["trxref"]) do + # handle mpesa payments + %{"status" => "success", "authorization" => %{"mobile_money_number" => phone_number}} -> + ticket = Tickets.get_ticket_by_ticketid!(params["trxref"]) + + case ticket.email_sent do + true -> + deliver_ticket_by_email(ticket.email, ticket.ticketid) + + {:ok, _ticket} = + Tickets.update_ticket(ticket, %{is_paid: true, phone_number: phone_number}) + + false -> + {:ok, _ticket} = + Tickets.update_ticket(ticket, %{ + is_paid: true, + email_sent: true, + phone_number: phone_number + }) + end + + {:ok, + socket + |> assign(:success, true) + |> assign(:ticket, ticket)} + + # handle card payments + %{"status" => "success"} -> + ticket = Tickets.get_ticket_by_ticketid!(params["trxref"]) + + case ticket.email_sent do + true -> + deliver_ticket_by_email(ticket.email, ticket.ticketid) + {:ok, _ticket} = Tickets.update_ticket(ticket, %{is_paid: true}) + + false -> + {:ok, _ticket} = Tickets.update_ticket(ticket, %{is_paid: true, email_sent: true}) + end + + {:ok, + socket + |> assign(:success, true) + |> assign(:ticket, ticket)} + + %{"status" => "failed"} -> + {:ok, + socket + |> assign(:success, false)} + + %{"status" => "abandoned"} -> + {:ok, + socket + |> assign(:success, false)} + end + end + + def deliver_ticket_by_email(email, ticketid) do + {:ok, _} = + Emails.deliver_ticket_by_email( + email, + "http://5.189.162.107:3200/tickets/#{ticketid}" + ) + end +end diff --git a/lib/elixir_conf_africa_web/live/success_live/index.html.heex b/lib/elixir_conf_africa_web/live/success_live/index.html.heex new file mode 100644 index 0000000..a9fbddf --- /dev/null +++ b/lib/elixir_conf_africa_web/live/success_live/index.html.heex @@ -0,0 +1,34 @@ +
+ <%= if @success == true do %> +
+ +

+ Payment Successful +

+

+ Thank you for your purchase , we have sent you your ticket via email , you can also view it here +

+ <.link navigate={~p"/tickets/#{@ticket.ticketid}"}> + + +
+ <% else %> +
+ +

+ Payment Unsuccessful +

+

+ Payment was unsuccessful , go back to the tickets and purchase +

+ <.link navigate={~p"/event"}> + + +
+ <% end %> +
diff --git a/lib/elixir_conf_africa_web/live/ticket_live/form_component.ex b/lib/elixir_conf_africa_web/live/ticket_live/form_component.ex new file mode 100644 index 0000000..5b2c05c --- /dev/null +++ b/lib/elixir_conf_africa_web/live/ticket_live/form_component.ex @@ -0,0 +1,83 @@ +defmodule ElixirConfAfricaWeb.TicketLive.FormComponent do + use ElixirConfAfricaWeb, :live_component + + alias ElixirConfAfrica.Tickets + alias ElixirConfAfrica.Paystack + + @impl true + def update(%{ticket: ticket} = assigns, socket) do + changeset = Tickets.change_ticket(ticket) + + {:ok, + socket + |> assign(assigns) + |> assign_form(changeset)} + end + + @impl true + def handle_event("validate", %{"ticket" => ticket_params}, socket) do + changeset = + socket.assigns.ticket + |> Tickets.change_ticket(ticket_params) + |> Map.put(:action, :validate) + + {:noreply, assign_form(socket, changeset)} + end + + def handle_event("save", %{"ticket" => ticket_params}, socket) do + save_ticket(socket, socket.assigns.action, ticket_params) + end + + defp save_ticket(socket, :edit, ticket_params) do + case Tickets.update_ticket(socket.assigns.ticket, ticket_params) do + {:ok, _ticket} -> + {:noreply, + socket + |> put_flash(:info, "Ticket updated successfully") + |> push_redirect(to: socket.assigns.return_to)} + + {:error, %Ecto.Changeset{} = changeset} -> + {:noreply, assign(socket, :changeset, changeset)} + end + end + + defp save_ticket(socket, :new, ticket_params) do + case Tickets.create_ticket(ticket_params) do + {:ok, _ticket} -> + {:noreply, + socket + |> put_flash(:info, "Ticket created successfully") + |> push_redirect(to: socket.assigns.return_to)} + + {:error, %Ecto.Changeset{} = changeset} -> + {:noreply, assign(socket, changeset: changeset)} + end + end + + defp save_ticket(socket, :ticket, ticket_params) do + cost = socket.assigns.ticket_type.price * String.to_integer(ticket_params["quantity"]) + + paystack_initailization = + Paystack.initialize(ticket_params["email"], cost) + + new_ticket_params = + ticket_params + |> Map.put("ticket_type_id", socket.assigns.ticket_type.id) + |> Map.put("ticketid", paystack_initailization["reference"]) + |> Map.put("cost", cost) + + case Tickets.create_ticket(new_ticket_params) do + {:ok, _ticket} -> + {:noreply, + socket + |> redirect(external: paystack_initailization["authorization_url"])} + + {:error, %Ecto.Changeset{} = changeset} -> + {:noreply, assign(socket, changeset: changeset)} + end + end + + defp assign_form(socket, %Ecto.Changeset{} = changeset) do + assign(socket, :form, to_form(changeset)) + end +end diff --git a/lib/elixir_conf_africa_web/live/ticket_live/form_component.html.heex b/lib/elixir_conf_africa_web/live/ticket_live/form_component.html.heex new file mode 100644 index 0000000..5df2bc2 --- /dev/null +++ b/lib/elixir_conf_africa_web/live/ticket_live/form_component.html.heex @@ -0,0 +1,40 @@ +
+ <.simple_form + for={@form} + id="event-form" + phx-target={@myself} + phx-change="validate" + phx-submit="save" + > +

+ <%= @ticket_type.name %> Ticket - <%= @ticket_type.price %> KSH /= +

+ +

+ Your ticket and payment details will be sent to your email address you will input below. +

+ +
+
+ <.input field={@form[:name]} type="text" label="Name" /> +
+
+
+ <.input field={@form[:email]} type="text" label="Email" /> +
+
+ <.input field={@form[:quantity]} type="number" label="Quantity of Tickets" /> +
+ + <:actions> +
+ <.button + phx-disable-with="Proceeding.." + class="w-[100%] flex justify-center items-center bg-[#AD3989]" + > + Proceed to Payment + +
+ + +
diff --git a/lib/elixir_conf_africa_web/live/ticket_live/show.ex b/lib/elixir_conf_africa_web/live/ticket_live/show.ex new file mode 100644 index 0000000..edbae33 --- /dev/null +++ b/lib/elixir_conf_africa_web/live/ticket_live/show.ex @@ -0,0 +1,21 @@ +defmodule ElixirConfAfricaWeb.TicketLive.Show do + use ElixirConfAfricaWeb, :live_view + + alias ElixirConfAfrica.Tickets + + @impl true + def mount(_params, _session, socket) do + {:ok, socket} + end + + @impl true + def handle_params(%{"ticketid" => ticketid}, _, socket) do + {:noreply, + socket + |> assign(:page_title, page_title(socket.assigns.live_action)) + |> assign(:ticket, Tickets.get_ticket_by_ticketid!(ticketid))} + end + + defp page_title(:show), do: "Show Ticket" + defp page_title(:edit), do: "Edit Ticket" +end diff --git a/lib/elixir_conf_africa_web/live/ticket_live/show.html.heex b/lib/elixir_conf_africa_web/live/ticket_live/show.html.heex new file mode 100644 index 0000000..e553953 --- /dev/null +++ b/lib/elixir_conf_africa_web/live/ticket_live/show.html.heex @@ -0,0 +1,57 @@ +
+ ElixirConf Africa 2024 +
+ +
+
+

+ +

+
+
+ +

+ Elixir Safari +

+
+
+

+ Elixir Safari +

+
+
+
+

Name:

+

<%= @ticket.name %>

+
+
+ <%= @ticket.email %> +
+
+
+

20th June 2024

+

+

20th June 2024

+
+
+
+

+ Ticket Value +

+

+ <%= @ticket.ticket_type.name %> +

+
+
+
+
+
+ +
+
+
+
+
diff --git a/lib/elixir_conf_africa_web/live/ticket_type_live/form_component.ex b/lib/elixir_conf_africa_web/live/ticket_type_live/form_component.ex index b4219ce..1e4e4c8 100644 --- a/lib/elixir_conf_africa_web/live/ticket_type_live/form_component.ex +++ b/lib/elixir_conf_africa_web/live/ticket_type_live/form_component.ex @@ -3,35 +3,6 @@ defmodule ElixirConfAfricaWeb.TicketTypeLive.FormComponent do alias ElixirConfAfrica.TicketTypes - @impl true - def render(assigns) do - ~H""" -
- <.header> - <%= @title %> - <:subtitle>Use this form to manage ticket_type records in your database. - - - <.simple_form - for={@form} - id="ticket_type-form" - phx-target={@myself} - phx-change="validate" - phx-submit="save" - > - <.input field={@form[:event_id]} type="number" label="Event ID" /> - <.input field={@form[:name]} type="text" label="Name" /> - <.input field={@form[:number]} type="number" label="Number" /> - <.input field={@form[:description]} type="text" label="Description" /> - <.input field={@form[:price]} type="number" label="Price" step="any" /> - <:actions> - <.button phx-disable-with="Saving...">Save Ticket type - - -
- """ - end - @impl true def update(%{ticket_type: ticket_type} = assigns, socket) do changeset = TicketTypes.change_ticket_type(ticket_type) @@ -58,37 +29,31 @@ defmodule ElixirConfAfricaWeb.TicketTypeLive.FormComponent do defp save_ticket_type(socket, :edit, ticket_type_params) do case TicketTypes.update_ticket_type(socket.assigns.ticket_type, ticket_type_params) do - {:ok, ticket_type} -> - notify_parent({:saved, ticket_type}) - + {:ok, _ticket_type} -> {:noreply, socket |> put_flash(:info, "Ticket type updated successfully") |> push_patch(to: socket.assigns.patch)} {:error, %Ecto.Changeset{} = changeset} -> - {:noreply, assign_form(socket, changeset)} + {:noreply, assign(socket, :changeset, changeset)} end end defp save_ticket_type(socket, :new, ticket_type_params) do case TicketTypes.create_ticket_type(ticket_type_params) do - {:ok, ticket_type} -> - notify_parent({:saved, ticket_type}) - + {:ok, _ticket_type} -> {:noreply, socket |> put_flash(:info, "Ticket type created successfully") |> push_patch(to: socket.assigns.patch)} {:error, %Ecto.Changeset{} = changeset} -> - {:noreply, assign_form(socket, changeset)} + {:noreply, assign(socket, changeset: changeset)} end end defp assign_form(socket, %Ecto.Changeset{} = changeset) do assign(socket, :form, to_form(changeset)) end - - defp notify_parent(msg), do: send(self(), {__MODULE__, msg}) end diff --git a/lib/elixir_conf_africa_web/live/ticket_type_live/form_component.html.heex b/lib/elixir_conf_africa_web/live/ticket_type_live/form_component.html.heex new file mode 100644 index 0000000..339796a --- /dev/null +++ b/lib/elixir_conf_africa_web/live/ticket_type_live/form_component.html.heex @@ -0,0 +1,17 @@ +
+ <.simple_form + for={@form} + id="ticket_type-form" + phx-target={@myself} + phx-change="validate" + phx-submit="save" + > + <.input field={@form[:name]} type="text" label="Name" /> + <.input field={@form[:number]} type="number" label="Number" /> + <.input field={@form[:description]} type="text" label="Description" /> + <.input field={@form[:price]} type="number" label="Price" step="any" /> + <:actions> + <.button phx-disable-with="Saving...">Save Ticket type + + +
diff --git a/lib/elixir_conf_africa_web/live/ticket_type_live/index.ex b/lib/elixir_conf_africa_web/live/ticket_type_live/index.ex index 259c2be..6285f3b 100644 --- a/lib/elixir_conf_africa_web/live/ticket_type_live/index.ex +++ b/lib/elixir_conf_africa_web/live/ticket_type_live/index.ex @@ -1,12 +1,12 @@ defmodule ElixirConfAfricaWeb.TicketTypeLive.Index do - use ElixirConfAfricaWeb, :live_view + use ElixirConfAfricaWeb, :admin_live_view alias ElixirConfAfrica.TicketTypes alias ElixirConfAfrica.TicketTypes.TicketType @impl true def mount(_params, _session, socket) do - {:ok, stream(socket, :ticket_types, TicketTypes.list_ticket_types())} + {:ok, assign(socket, :ticket_types, list_ticket_types())} end @impl true @@ -32,19 +32,15 @@ defmodule ElixirConfAfricaWeb.TicketTypeLive.Index do |> assign(:ticket_type, nil) end - @impl true - def handle_info( - {ElixirConfAfricaWeb.TicketTypeLive.FormComponent, {:saved, ticket_type}}, - socket - ) do - {:noreply, stream_insert(socket, :ticket_types, ticket_type)} - end - @impl true def handle_event("delete", %{"id" => id}, socket) do ticket_type = TicketTypes.get_ticket_type!(id) {:ok, _} = TicketTypes.delete_ticket_type(ticket_type) - {:noreply, stream_delete(socket, :ticket_types, ticket_type)} + {:noreply, assign(socket, :ticket_types, list_ticket_types())} + end + + defp list_ticket_types do + TicketTypes.list_ticket_types() end end diff --git a/lib/elixir_conf_africa_web/live/ticket_type_live/index.html.heex b/lib/elixir_conf_africa_web/live/ticket_type_live/index.html.heex index ced7f9b..2b8ec1c 100644 --- a/lib/elixir_conf_africa_web/live/ticket_type_live/index.html.heex +++ b/lib/elixir_conf_africa_web/live/ticket_type_live/index.html.heex @@ -1,39 +1,13 @@ -<.header> - Listing Ticket types - <:actions> - <.link patch={~p"/ticket_types/new"}> - <.button>New Ticket type - - - - -<.table - id="ticket_types" - rows={@streams.ticket_types} - row_click={fn {_id, ticket_type} -> JS.navigate(~p"/ticket_types/#{ticket_type}") end} -> - <:col :let={{_id, ticket_type}} label="Name"><%= ticket_type.name %> - <:col :let={{_id, ticket_type}} label="Number"><%= ticket_type.number %> - <:col :let={{_id, ticket_type}} label="Event ID"> - <.link navigate={~p"/events/#{ticket_type.event_id}"}><%= ticket_type.event_id %> - - <:col :let={{_id, ticket_type}} label="Description"><%= ticket_type.description %> - <:col :let={{_id, ticket_type}} label="Price"><%= ticket_type.price %> - <:action :let={{_id, ticket_type}}> -
- <.link navigate={~p"/ticket_types/#{ticket_type}"}>Show -
- <.link patch={~p"/ticket_types/#{ticket_type}/edit"}>Edit - - <:action :let={{id, ticket_type}}> - <.link - phx-click={JS.push("delete", value: %{id: ticket_type.id}) |> hide("##{id}")} - data-confirm="Are you sure?" - > - Delete - - - +
+ <.header> + Listing Ticket types + <:actions> + <.link patch={~p"/ticket_types/new"}> + <.button>New Ticket type + + + +
<.modal :if={@live_action in [:new, :edit]} @@ -50,3 +24,40 @@ patch={~p"/ticket_types"} /> + + + + + + + + + + + + <%= for ticket_type <- @ticket_types do %> + + + + + + + + <% end %> + +
NameDescriptionPriceActions
<%= ticket_type.name %><%= ticket_type.description %><%= ticket_type.price %> +
+ <.link patch={~p"/ticket_types/#{ticket_type}/edit"}>Edit + + + <.link + phx-click={ + JS.push("delete", value: %{id: ticket_type.id}) |> hide("##{ticket_type.id}") + } + data-confirm="Are you sure?" + > + Delete + + +
+
diff --git a/lib/elixir_conf_africa_web/live/ticket_type_live/show.ex b/lib/elixir_conf_africa_web/live/ticket_type_live/show.ex deleted file mode 100644 index c07f168..0000000 --- a/lib/elixir_conf_africa_web/live/ticket_type_live/show.ex +++ /dev/null @@ -1,21 +0,0 @@ -defmodule ElixirConfAfricaWeb.TicketTypeLive.Show do - use ElixirConfAfricaWeb, :live_view - - alias ElixirConfAfrica.TicketTypes - - @impl true - def mount(_params, _session, socket) do - {:ok, socket} - end - - @impl true - def handle_params(%{"id" => id}, _, socket) do - {:noreply, - socket - |> assign(:page_title, page_title(socket.assigns.live_action)) - |> assign(:ticket_type, TicketTypes.get_ticket_type!(id))} - end - - defp page_title(:show), do: "Show Ticket type" - defp page_title(:edit), do: "Edit Ticket type" -end diff --git a/lib/elixir_conf_africa_web/live/ticket_type_live/show.html.heex b/lib/elixir_conf_africa_web/live/ticket_type_live/show.html.heex deleted file mode 100644 index 9ec7ed1..0000000 --- a/lib/elixir_conf_africa_web/live/ticket_type_live/show.html.heex +++ /dev/null @@ -1,34 +0,0 @@ -<.header> - Ticket type <%= @ticket_type.id %> - <:subtitle>This is a ticket_type record from your database. - <:actions> - <.link patch={~p"/ticket_types/#{@ticket_type}/show/edit"} phx-click={JS.push_focus()}> - <.button>Edit ticket_type - - - - -<.list> - <:item title="Name"><%= @ticket_type.name %> - <:item title="Number"><%= @ticket_type.number %> - <:item title="Description"><%= @ticket_type.description %> - <:item title="Price"><%= @ticket_type.price %> - - -<.back navigate={~p"/ticket_types"}>Back to ticket_types - -<.modal - :if={@live_action == :edit} - id="ticket_type-modal" - show - on_cancel={JS.patch(~p"/ticket_types/#{@ticket_type}")} -> - <.live_component - module={ElixirConfAfricaWeb.TicketTypeLive.FormComponent} - id={@ticket_type.id} - title={@page_title} - action={@live_action} - ticket_type={@ticket_type} - patch={~p"/ticket_types/#{@ticket_type}"} - /> - diff --git a/lib/elixir_conf_africa_web/live/transaction_live/index.ex b/lib/elixir_conf_africa_web/live/transaction_live/index.ex new file mode 100644 index 0000000..97894cf --- /dev/null +++ b/lib/elixir_conf_africa_web/live/transaction_live/index.ex @@ -0,0 +1,23 @@ +defmodule ElixirConfAfricaWeb.TransactionLive.Index do + use ElixirConfAfricaWeb, :admin_live_view + + alias ElixirConfAfrica.Paystack + + @impl true + def mount(_params, _session, socket) do + {:ok, socket} + end + + @impl true + def handle_params(params, _url, socket) do + {:noreply, apply_action(socket, socket.assigns.live_action, params)} + end + + defp apply_action(socket, :index, _params) do + transctions = Paystack.list_transactions() + + socket + |> assign(:transactions, transctions) + |> assign(:page_title, "Listing Transactions") + end +end diff --git a/lib/elixir_conf_africa_web/live/transaction_live/index.html.heex b/lib/elixir_conf_africa_web/live/transaction_live/index.html.heex new file mode 100644 index 0000000..c0ac271 --- /dev/null +++ b/lib/elixir_conf_africa_web/live/transaction_live/index.html.heex @@ -0,0 +1,34 @@ +
+

Listing Transactions

+
+ + + + + + + + + + + + + + + + <%= for transaction <- @transactions do %> + + + + + + + + + + + <% end %> + +
ReferenceAmountStatusCurrencyEmailBank + Paid At +
<%= transaction["reference"] %><%= transaction["amount"] %><%= transaction["status"] %><%= transaction["currency"] %><%= transaction["email"] %><%= transaction["bank"] %><%= transaction["paid_at"] %>
diff --git a/lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.ex b/lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.ex new file mode 100644 index 0000000..b97c157 --- /dev/null +++ b/lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.ex @@ -0,0 +1,62 @@ +defmodule ElixirConfAfricaWeb.UnPaidTicketLive.Index do + use ElixirConfAfricaWeb, :admin_live_view + + alias ElixirConfAfrica.Tickets + + alias ElixirConfAfrica.Paystack + alias ElixirConfAfrica.Emails + @impl true + def mount(_params, _session, socket) do + {:ok, assign(socket, :ticket_collection, list_unpaid_tickets())} + end + + @impl true + def handle_params(params, _url, socket) do + {:noreply, apply_action(socket, socket.assigns.live_action, params)} + end + + @impl true + def handle_event("update_and_send_ticket", %{"ticketid" => ticketid}, socket) do + ticket = Tickets.get_ticket_by_ticketid!(ticketid) + Emails.deliver_ticket_by_email(ticket.email, "localhost:4900/tickets/#{ticket.ticketid}") + {:ok, _ticket} = Tickets.update_ticket(ticket, %{is_paid: true, email_sent: true}) + + {:noreply, + socket + |> assign(:ticket_collection, list_unpaid_tickets()) + |> put_flash(:info, "Ticket sent successfully")} + end + + defp apply_action(socket, :index, _params) do + socket + |> assign(:page_title, "Listing UnPaid Tickets") + end + + defp list_unpaid_tickets do + Tickets.list_unpaid_tickets() + |> Enum.map(fn ticket -> + %{ + id: ticket.id, + name: ticket.name, + email: ticket.email, + quantity: ticket.quantity, + phone_number: ticket.phone_number, + cost: ticket.cost, + ticketid: ticket.ticketid, + ticket_type_id: ticket.ticket_type_id, + is_paid: ticket.is_paid, + is_refunded: ticket.is_refunded, + ticket_type: ticket.ticket_type, + payment_status: check_payment_status(ticket.ticketid) + } + end) + end + + defp check_payment_status(ticketid) do + case Paystack.test_verification(ticketid) do + %{"status" => "success"} -> "incorrect" + %{"status" => "failed"} -> "correct" + _ -> "correct" + end + end +end diff --git a/lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.html.heex b/lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.html.heex new file mode 100644 index 0000000..9489184 --- /dev/null +++ b/lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.html.heex @@ -0,0 +1,63 @@ +
+

Listing Unpaid Tickets

+
+ + + + + + + + + + + + + + + + <%= for ticket <- @ticket_collection do %> + + + + + + + + + + + + + <% end %> + +
NameEmailTicket idQuantityAmountTypeStatus + Action +
<%= ticket.name %><%= ticket.email %><%= ticket.ticketid %><%= ticket.quantity %><%= ticket.cost %> KSH /=<%= ticket.ticket_type.name %> + <%= if ticket.payment_status == "correct" do %> +
+ Correct +
+ <% else %> +
+ Incorrect +
+ <% end %> +
+ <%= if ticket.payment_status == "incorrect" do %> +
+ +
+ <% end %> +
diff --git a/lib/elixir_conf_africa_web/live/user_live/index.ex b/lib/elixir_conf_africa_web/live/user_live/index.ex new file mode 100644 index 0000000..72e2116 --- /dev/null +++ b/lib/elixir_conf_africa_web/live/user_live/index.ex @@ -0,0 +1,27 @@ +defmodule ElixirConfAfricaWeb.UserLive.Index do + use ElixirConfAfricaWeb, :admin_live_view + + alias ElixirConfAfrica.Accounts + + def mount(_params, session, socket) do + current_user = Accounts.get_user_by_session_token(session["user_token"]) + + users = + Accounts.list_users_apart_from_current_user(current_user) + + {:ok, + socket + |> assign(:users, users) + |> assign(:current_user, current_user)} + end + + def handle_event("change_role", %{"role" => role, "email" => email}, socket) do + user = Accounts.get_user_by_email(email) + {:ok, _user} = Accounts.update_user_role(user, role) + + {:noreply, + socket + |> put_flash(:info, "User role changed successfully") + |> assign(:users, Accounts.list_users_apart_from_current_user(socket.assigns.current_user))} + end +end diff --git a/lib/elixir_conf_africa_web/live/user_live/index.html.heex b/lib/elixir_conf_africa_web/live/user_live/index.html.heex new file mode 100644 index 0000000..645d3e5 --- /dev/null +++ b/lib/elixir_conf_africa_web/live/user_live/index.html.heex @@ -0,0 +1,65 @@ +
+
+

Listing Users

+
+ + + + + + + + + + + + + <%= for user <- @users do %> + + + + + + + + + <% end %> + +
EmailRoleAdmin actionUser actionScanner action
<%= user.email %><%= user.role %> + <%= if user.role != "admin" do %> + + <% end %> + + <%= if user.role != "user" do %> + + <% end %> + + <%= if user.role != "scanner" do %> + + <% end %> +
+
diff --git a/lib/elixir_conf_africa_web/router.ex b/lib/elixir_conf_africa_web/router.ex index b538e48..e87face 100644 --- a/lib/elixir_conf_africa_web/router.ex +++ b/lib/elixir_conf_africa_web/router.ex @@ -1,6 +1,8 @@ defmodule ElixirConfAfricaWeb.Router do use ElixirConfAfricaWeb, :router + import ElixirConfAfricaWeb.UserAuth + pipeline :browser do plug :accepts, ["html"] plug :fetch_session @@ -8,6 +10,7 @@ defmodule ElixirConfAfricaWeb.Router do plug :put_root_layout, html: {ElixirConfAfricaWeb.Layouts, :root} plug :protect_from_forgery plug :put_secure_browser_headers + plug :fetch_current_user end pipeline :api do @@ -15,25 +18,30 @@ defmodule ElixirConfAfricaWeb.Router do end scope "/", ElixirConfAfricaWeb do - pipe_through :browser - - get "/", PageController, :home + pipe_through [:browser, :require_authenticated_admin] + live "/ticket_types", TicketTypeLive.Index, :index + live "/ticket_types/new", TicketTypeLive.Index, :new + live "/ticket_types/:id/edit", TicketTypeLive.Index, :edit - live "/home", HomeLive.Index, :index + live "/tickets/paid", PaidTicketLive.Index, :index - live "/events", EventLive.Index, :index - live "/events/new", EventLive.Index, :new - live "/events/:id/edit", EventLive.Index, :edit + live "/tickets/refunded", RefundedTicketLive.Index, :index + live "/tickets/unpaid", UnPaidTicketLive.Index, :index + live "/tickets/new", TicketLive.Index, :new + live "/tickets/:id/edit", TicketLive.Index, :edit - live "/events/:id", EventLive.Show, :show - live "/events/:id/show/edit", EventLive.Show, :edit + live "/transactions", TransactionLive.Index, :index + live "/users", UserLive.Index, :index + end - live "/ticket_types", TicketTypeLive.Index, :index - live "/ticket_types/new", TicketTypeLive.Index, :new - live "/ticket_types/:id/edit", TicketTypeLive.Index, :edit + scope "/", ElixirConfAfricaWeb do + pipe_through :browser - live "/ticket_types/:id", TicketTypeLive.Show, :show - live "/ticket_types/:id/show/edit", TicketTypeLive.Show, :edit + live "/", HomeLive.Index, :index + live "/event", EventLive.Index, :index + live "/event/:ticket_type_id/buy", EventLive.Index, :ticket + live "/success", SuccessLive.Index, :index + live "/tickets/:ticketid", TicketLive.Show, :show end # Other scopes may use custom stacks. @@ -57,4 +65,37 @@ defmodule ElixirConfAfricaWeb.Router do forward "/mailbox", Plug.Swoosh.MailboxPreview end end + + ## Authentication routes + + scope "/", ElixirConfAfricaWeb do + pipe_through [:browser, :redirect_if_user_is_authenticated] + + get "/users/register", UserRegistrationController, :new + post "/users/register", UserRegistrationController, :create + get "/users/log_in", UserSessionController, :new + post "/users/log_in", UserSessionController, :create + get "/users/reset_password", UserResetPasswordController, :new + post "/users/reset_password", UserResetPasswordController, :create + get "/users/reset_password/:token", UserResetPasswordController, :edit + put "/users/reset_password/:token", UserResetPasswordController, :update + end + + scope "/", ElixirConfAfricaWeb do + pipe_through [:browser, :require_authenticated_user] + + get "/users/settings", UserSettingsController, :edit + put "/users/settings", UserSettingsController, :update + get "/users/settings/confirm_email/:token", UserSettingsController, :confirm_email + end + + scope "/", ElixirConfAfricaWeb do + pipe_through [:browser] + + delete "/users/log_out", UserSessionController, :delete + get "/users/confirm", UserConfirmationController, :new + post "/users/confirm", UserConfirmationController, :create + get "/users/confirm/:token", UserConfirmationController, :edit + post "/users/confirm/:token", UserConfirmationController, :update + end end diff --git a/lib/elixir_conf_africa_web/user_auth.ex b/lib/elixir_conf_africa_web/user_auth.ex new file mode 100644 index 0000000..2235ca7 --- /dev/null +++ b/lib/elixir_conf_africa_web/user_auth.ex @@ -0,0 +1,239 @@ +defmodule ElixirConfAfricaWeb.UserAuth do + use ElixirConfAfricaWeb, :verified_routes + + import Plug.Conn + import Phoenix.Controller + + alias ElixirConfAfrica.Accounts + + # Make the remember me cookie valid for 60 days. + # If you want bump or reduce this value, also change + # the token expiry itself in UserToken. + @max_age 60 * 60 * 24 * 60 + @remember_me_cookie "_elixir_conf_africa_web_user_remember_me" + @remember_me_options [sign: true, max_age: @max_age, same_site: "Lax"] + + @doc """ + Logs the user in. + + It renews the session ID and clears the whole session + to avoid fixation attacks. See the renew_session + function to customize this behaviour. + + It also sets a `:live_socket_id` key in the session, + so LiveView sessions are identified and automatically + disconnected on log out. The line can be safely removed + if you are not using LiveView. + """ + def log_in_user(conn, user, params \\ %{}) do + token = Accounts.generate_user_session_token(user) + user_return_to = get_session(conn, :user_return_to) + + conn + |> renew_session() + |> put_token_in_session(token) + |> maybe_write_remember_me_cookie(token, params) + |> redirect(to: user_return_to || signed_in_path(conn)) + end + + defp maybe_write_remember_me_cookie(conn, token, %{"remember_me" => "true"}) do + put_resp_cookie(conn, @remember_me_cookie, token, @remember_me_options) + end + + defp maybe_write_remember_me_cookie(conn, _token, _params) do + conn + end + + # This function renews the session ID and erases the whole + # session to avoid fixation attacks. If there is any data + # in the session you may want to preserve after log in/log out, + # you must explicitly fetch the session data before clearing + # and then immediately set it after clearing, for example: + # + # defp renew_session(conn) do + # preferred_locale = get_session(conn, :preferred_locale) + # + # conn + # |> configure_session(renew: true) + # |> clear_session() + # |> put_session(:preferred_locale, preferred_locale) + # end + # + defp renew_session(conn) do + conn + |> configure_session(renew: true) + |> clear_session() + end + + @doc """ + Logs the user out. + + It clears all session data for safety. See renew_session. + """ + def log_out_user(conn) do + user_token = get_session(conn, :user_token) + user_token && Accounts.delete_user_session_token(user_token) + + if live_socket_id = get_session(conn, :live_socket_id) do + ElixirConfAfricaWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{}) + end + + conn + |> renew_session() + |> delete_resp_cookie(@remember_me_cookie) + |> redirect(to: ~p"/") + end + + @doc """ + Authenticates the user by looking into the session + and remember me token. + """ + def fetch_current_user(conn, _opts) do + {user_token, conn} = ensure_user_token(conn) + user = user_token && Accounts.get_user_by_session_token(user_token) + assign(conn, :current_user, user) + end + + defp ensure_user_token(conn) do + if token = get_session(conn, :user_token) do + {token, conn} + else + conn = fetch_cookies(conn, signed: [@remember_me_cookie]) + + if token = conn.cookies[@remember_me_cookie] do + {token, put_token_in_session(conn, token)} + else + {nil, conn} + end + end + end + + @doc """ + Handles mounting and authenticating the current_user in LiveViews. + + ## `on_mount` arguments + + * `:mount_current_user` - Assigns current_user + to socket assigns based on user_token, or nil if + there's no user_token or no matching user. + + * `:ensure_authenticated` - Authenticates the user from the session, + and assigns the current_user to socket assigns based + on user_token. + Redirects to login page if there's no logged user. + + * `:redirect_if_user_is_authenticated` - Authenticates the user from the session. + Redirects to signed_in_path if there's a logged user. + + ## Examples + + Use the `on_mount` lifecycle macro in LiveViews to mount or authenticate + the current_user: + + defmodule ElixirConfAfricaWeb.PageLive do + use ElixirConfAfricaWeb, :live_view + + on_mount {ElixirConfAfricaWeb.UserAuth, :mount_current_user} + ... + end + + Or use the `live_session` of your router to invoke the on_mount callback: + + live_session :authenticated, on_mount: [{ElixirConfAfricaWeb.UserAuth, :ensure_authenticated}] do + live "/profile", ProfileLive, :index + end + """ + def on_mount(:mount_current_user, _params, session, socket) do + {:cont, mount_current_user(socket, session)} + end + + def on_mount(:ensure_authenticated, _params, session, socket) do + socket = mount_current_user(socket, session) + + if socket.assigns.current_user do + {:cont, socket} + else + socket = + socket + |> Phoenix.LiveView.put_flash(:error, "You must log in to access this page.") + |> Phoenix.LiveView.redirect(to: ~p"/users/log_in") + + {:halt, socket} + end + end + + def on_mount(:redirect_if_user_is_authenticated, _params, session, socket) do + socket = mount_current_user(socket, session) + + if socket.assigns.current_user do + {:halt, Phoenix.LiveView.redirect(socket, to: signed_in_path(socket))} + else + {:cont, socket} + end + end + + defp mount_current_user(socket, session) do + Phoenix.Component.assign_new(socket, :current_user, fn -> + if user_token = session["user_token"] do + Accounts.get_user_by_session_token(user_token) + end + end) + end + + @doc """ + Used for routes that require the user to not be authenticated. + """ + def redirect_if_user_is_authenticated(conn, _opts) do + if conn.assigns[:current_user] do + conn + |> redirect(to: signed_in_path(conn)) + |> halt() + else + conn + end + end + + @doc """ + Used for routes that require the user to be authenticated. + + If you want to enforce the user email is confirmed before + they use the application at all, here would be a good place. + """ + def require_authenticated_user(conn, _opts) do + if conn.assigns[:current_user] do + conn + else + conn + |> put_flash(:error, "You must log in to access this page.") + |> maybe_store_return_to() + |> redirect(to: ~p"/users/log_in") + |> halt() + end + end + + def require_authenticated_admin(conn, _opts) do + if conn.assigns[:current_user] && conn.assigns[:current_user].role == "admin" do + conn + else + conn + |> put_flash(:error, "You must log in and be authenticated to access this page.") + |> maybe_store_return_to() + |> redirect(to: ~p"/users/log_in") + |> halt() + end + end + + defp put_token_in_session(conn, token) do + conn + |> put_session(:user_token, token) + |> put_session(:live_socket_id, "users_sessions:#{Base.url_encode64(token)}") + end + + defp maybe_store_return_to(%{method: "GET"} = conn) do + put_session(conn, :user_return_to, current_path(conn)) + end + + defp maybe_store_return_to(conn), do: conn + + defp signed_in_path(_conn), do: ~p"/" +end diff --git a/mix.exs b/mix.exs index 70b1b76..06071da 100644 --- a/mix.exs +++ b/mix.exs @@ -43,6 +43,7 @@ defmodule ElixirConfAfrica.MixProject do # Type `mix help deps` for examples and options. defp deps do [ + {:bcrypt_elixir, "~> 3.0"}, {:phoenix, "~> 1.7.7"}, {:phoenix_ecto, "~> 4.4"}, {:ecto_sql, "~> 3.10"}, @@ -65,7 +66,10 @@ defmodule ElixirConfAfrica.MixProject do {:credo, "~> 1.7", only: :dev, runtime: false}, {:excoveralls, "~> 0.18.0", only: :test}, {:faker, "~> 0.17.0", only: [:dev, :test], runtime: false}, - {:typed_ecto_schema, "~> 0.4.1"} + {:typed_ecto_schema, "~> 0.4.1"}, + {:ex_machina, "~> 2.7.0"}, + {:httpoison, "~> 2.1"}, + {:styler, "~> 0.11", only: [:dev, :test], runtime: false}, ] end diff --git a/mix.lock b/mix.lock index 48bb7e3..46b7965 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,9 @@ %{ + "bcrypt_elixir": {:hex, :bcrypt_elixir, "3.1.0", "0b110a9a6c619b19a7f73fa3004aa11d6e719a67e672d1633dc36b6b2290a0f7", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2ad2acb5a8bc049e8d5aa267802631912bb80d5f4110a178ae7999e69dca1bf7"}, "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, "castore": {:hex, :castore, "1.0.4", "ff4d0fb2e6411c0479b1d965a814ea6d00e51eb2f58697446e9c41a97d940b28", [:mix], [], "hexpm", "9418c1b8144e11656f0be99943db4caf04612e3eaecefb5dae9a2a87565584f8"}, + "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, + "comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"}, "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, @@ -10,8 +13,10 @@ "dialyxir": {:hex, :dialyxir, "1.4.2", "764a6e8e7a354f0ba95d58418178d486065ead1f69ad89782817c296d0d746a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "516603d8067b2fd585319e4b13d3674ad4f314a5902ba8130cd97dc902ce6bbd"}, "ecto": {:hex, :ecto, "3.11.0", "ff8614b4e70a774f9d39af809c426def80852048440e8785d93a6e91f48fec00", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7769dad267ef967310d6e988e92d772659b11b09a0c015f101ce0fff81ce1f81"}, "ecto_sql": {:hex, :ecto_sql, "3.11.0", "c787b24b224942b69c9ff7ab9107f258ecdc68326be04815c6cce2941b6fad1c", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "77aa3677169f55c2714dda7352d563002d180eb33c0dc29cd36d39c0a1a971f5"}, + "elixir_make": {:hex, :elixir_make, "0.7.8", "505026f266552ee5aabca0b9f9c229cbb496c689537c9f922f3eb5431157efc7", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "7a71945b913d37ea89b06966e1342c85cfe549b15e6d6d081e8081c493062c07"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"}, + "ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"}, "excoveralls": {:hex, :excoveralls, "0.18.0", "b92497e69465dc51bc37a6422226ee690ab437e4c06877e836f1c18daeb35da9", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1109bb911f3cb583401760be49c02cbbd16aed66ea9509fc5479335d284da60b"}, "expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"}, "faker": {:hex, :faker, "0.17.0", "671019d0652f63aefd8723b72167ecdb284baf7d47ad3a82a15e9b8a6df5d1fa", [:mix], [], "hexpm", "a7d4ad84a93fd25c5f5303510753789fc2433ff241bf3b4144d3f6f291658a6a"}, @@ -19,12 +24,18 @@ "finch": {:hex, :finch, "0.16.0", "40733f02c89f94a112518071c0a91fe86069560f5dbdb39f9150042f44dcfb1a", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f660174c4d519e5fec629016054d60edd822cdfe2b7270836739ac2f97735ec5"}, "floki": {:hex, :floki, "0.35.2", "87f8c75ed8654b9635b311774308b2760b47e9a579dabf2e4d5f1e1d42c39e0b", [:mix], [], "hexpm", "6b05289a8e9eac475f644f09c2e4ba7e19201fd002b89c28c1293e7bd16773d9"}, "gettext": {:hex, :gettext, "0.23.1", "821e619a240e6000db2fc16a574ef68b3bd7fe0167ccc264a81563cc93e67a31", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "19d744a36b809d810d610b57c27b934425859d158ebd56561bc41f7eeb8795db"}, + "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, + "httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, + "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mint": {:hex, :mint, "1.5.1", "8db5239e56738552d85af398798c80648db0e90f343c8469f6c6d8898944fb6f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4a63e1e76a7c3956abd2c72f370a0d0aecddc3976dea5c27eccbecfa5e7d5b1e"}, "nimble_options": {:hex, :nimble_options, "1.0.2", "92098a74df0072ff37d0c12ace58574d26880e522c22801437151a159392270e", [:mix], [], "hexpm", "fd12a8db2021036ce12a309f26f564ec367373265b53e25403f0ee697380f1b8"}, "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"}, + "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "phoenix": {:hex, :phoenix, "1.7.10", "02189140a61b2ce85bb633a9b6fd02dff705a5f1596869547aeb2b2b95edd729", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "cf784932e010fd736d656d7fead6a584a4498efefe5b8227e9f383bf15bb79d0"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.3", "86e9878f833829c3f66da03d75254c155d91d72a201eb56ae83482328dc7ca93", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "d36c401206f3011fefd63d04e8ef626ec8791975d9d107f9a0817d426f61ac07"}, "phoenix_html": {:hex, :phoenix_html, "3.3.3", "380b8fb45912b5638d2f1d925a3771b4516b9a78587249cabe394e0a5d579dc9", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "923ebe6fec6e2e3b3e569dfbdc6560de932cd54b000ada0208b5f45024bdd76c"}, @@ -38,12 +49,15 @@ "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, "postgrex": {:hex, :postgrex, "0.17.3", "c92cda8de2033a7585dae8c61b1d420a1a1322421df84da9a82a6764580c503d", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "946cf46935a4fdca7a81448be76ba3503cff082df42c6ec1ff16a4bdfbfb098d"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, + "styler": {:hex, :styler, "0.11.6", "ad4c5fc1ff72b93107ecb251f595b316c6d97604b742f3473aa036888592b270", [:mix], [], "hexpm", "0b0b9936e91b01a7a9fd7239902581ed1cb5515254357126429a37d1bb3d0078"}, "swoosh": {:hex, :swoosh, "1.14.1", "d8813699ba410509008dd3dfdb2df057e3fce367d45d5e6d76b146a7c9d559cd", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "87da72260b4351678f96aec61db5c2acc8a88cda2cf2c4f534eb4c9c461350c7"}, "tailwind": {:hex, :tailwind, "0.2.2", "9e27288b568ede1d88517e8c61259bc214a12d7eed271e102db4c93fcca9b2cd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "ccfb5025179ea307f7f899d1bb3905cd0ac9f687ed77feebc8f67bdca78565c4"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"}, "typed_ecto_schema": {:hex, :typed_ecto_schema, "0.4.1", "a373ca6f693f4de84cde474a67467a9cb9051a8a7f3f615f1e23dc74b75237fa", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm", "85c6962f79d35bf543dd5659c6adc340fd2480cacc6f25d2cc2933ea6e8fcb3b"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, "websock_adapter": {:hex, :websock_adapter, "0.5.5", "9dfeee8269b27e958a65b3e235b7e447769f66b5b5925385f5a569269164a210", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b977ba4a01918acbf77045ff88de7f6972c2a009213c515a445c48f224ffce9"}, } diff --git a/priv/.DS_Store b/priv/.DS_Store index 517548bf78ff52c1bb56d50b32103d32c63c544e..4625c3d03db9c2c39d0525da3987c2c62b4042c8 100644 GIT binary patch delta 20 bcmZoMXffEJ%gk - datetime = Faker.DateTime.forward(Enum.random(1..30)) - - event = - %Event{ - name: Faker.Lorem.sentence(), - event_type: Faker.Lorem.sentence(1), - location: Faker.Address.En.street_address(), - description: Faker.Lorem.paragraph(), - start_date: - datetime - |> NaiveDateTime.truncate(:second), - end_date: - datetime - |> NaiveDateTime.truncate(:second) - |> NaiveDateTime.add(Enum.random(1..5), :day) - } - |> Repo.insert!() - - Enum.each(Enum.shuffle(ticket_types_names), fn type -> - %TicketType{ - event_id: event.id, - name: type, - description: Faker.Lorem.sentence(), - price: 0.0 + Enum.random(20..500), - number: Enum.random(100..500) - } - |> Repo.insert!() - end) -end) - -# Almost random seed -datetime = Faker.DateTime.forward(Enum.random(1..30)) - -event = - %Event{ - name: "ElixirConf 2024", - event_type: "Conference", - location: "Nairobi", - description: "A very long and BEAMy description of some interestingly scary concept", - start_date: - datetime - |> NaiveDateTime.truncate(:second), - end_date: - datetime - |> NaiveDateTime.truncate(:second) - |> NaiveDateTime.add(Enum.random(1..5), :day) - } - |> Repo.insert!() - -Enum.each(Enum.shuffle(ticket_types_names), fn type -> - %TicketType{ - event_id: event.id, - name: type, - description: Faker.Lorem.sentence(), - price: 0.0 + Enum.random(20..500), - number: Enum.random(100..500) - } - |> Repo.insert!() -end) - -datetime = Faker.DateTime.forward(Enum.random(1..30)) - -%Event{ - name: "BEAM: The Perfect Fit for Networks", - event_type: "Webinar", - location: "Zoom", - description: "A very long and BEAMy description of some interestingly scary concept", - start_date: - datetime - |> NaiveDateTime.truncate(:second), - end_date: - datetime - |> NaiveDateTime.truncate(:second) - |> NaiveDateTime.add(Enum.random(1..5), :day) -} -|> Repo.insert!() - -Enum.each(Enum.shuffle(ticket_types_names), fn type -> - %TicketType{ - event_id: event.id, - name: type, - description: Faker.Lorem.sentence(), - price: 0.0 + Enum.random(20..500), - number: Enum.random(100..500) - } - |> Repo.insert!() -end) - -datetime = Faker.DateTime.forward(Enum.random(1..30)) - -%Event{ - name: "Learn You Some Erlang", - event_type: "Webinar", - location: "Somewhere Crazy", - description: "A very long and BEAMy description of some interestingly scary concept", - start_date: NaiveDateTime.truncate(datetime, :second), - end_date: - datetime - |> NaiveDateTime.truncate(:second) - |> NaiveDateTime.add(Enum.random(1..5), :day) -} -|> Repo.insert!() - -Enum.each(Enum.shuffle(ticket_types_names), fn type -> - %TicketType{ - event_id: event.id, - name: type, - description: Faker.Lorem.sentence(), - price: 0.0 + Enum.random(20..500), - number: Enum.random(100..500) - } - |> Repo.insert!() -end) - -datetime = Faker.DateTime.forward(Enum.random(1..30)) - -%Event{ - name: "Who Supervises The Supervisor", - event_type: "Webinar", - location: "Who Knows?", - description: "A very long and BEAMy description of some interestingly scary concept", - start_date: - datetime - |> NaiveDateTime.truncate(:second), - end_date: - datetime - |> NaiveDateTime.truncate(:second) - |> NaiveDateTime.add(Enum.random(1..5), :day) -} -|> Repo.insert!() - -Enum.each(Enum.shuffle(ticket_types_names), fn type -> - %TicketType{ - event_id: event.id, - name: type, - description: Faker.Lorem.sentence(), - price: 0.0 + Enum.random(20..500), - number: Enum.random(100..500) - } - |> Repo.insert!() -end) diff --git a/priv/static/.DS_Store b/priv/static/.DS_Store index 4e12eda7b6e91b326d5565ca25b0fc41b9c10c26..479134f277fbdb2b178a471ce07d7afd1ee103c6 100644 GIT binary patch delta 556 zcmZoMXfc=|#>B!ku~2NHo+2ar#(>?7iytsEF|u#wVbWz}H@39YQ82Wa?7-|_pP5`% zkd%|3#K6FKHmM*dv$({-;J$zWBNHspufDoF}pwyH& zs8Bsndq`ygP>~3lBKM-y)I6|({%L8&sU;Ce?8tZl{^I1K{G6PC{Nl`#%>2B_nBt85 za?g^~T+h6;e4v$OnW^Re1t6*7u+*YrAdR6XA~Lb4z9=y-J=Li)HYYJDHOD{CDZiv7 zKNqAFWL$E7UO-VQ$f$@+ARFWxW%~~dV4&>a4P$6P7y=B+5C#K-vO}-~n9U&q6N1u= zA$j?Eshph34gnyM7$D|g&}MLC@MQ>N$Y!Wwn8+}fVI{+Eh7$~T8QwGeWMpTQWK?3* zW;9{6WwdAXU<_moVoYYtV9aF9f*8rf2%#Bdp){0YES_A?JbyDg2R{ceEo{EX{GE9+ Szlb9TP&pGw$>s==HOv4ILXfNg delta 80 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�BE?4H6BAas`CnyGV;DtgdbiN0RB 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

-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%0D2d2M2oSJ?d+ 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 yeHWV4l)wiZmtvY&!+v~&gxh8e&cnzScK - - - diff --git a/priv/static/images/call.svg b/priv/static/images/call.svg new file mode 100644 index 0000000..2669aee --- /dev/null +++ b/priv/static/images/call.svg @@ -0,0 +1,3 @@ + + + diff --git a/priv/static/images/elixirconflogo.png b/priv/static/images/elixirconflogo.png new file mode 100644 index 0000000000000000000000000000000000000000..6de70d41663c30b01e443c86ac49f1da13f32e66 GIT binary patch literal 2946 zcmV-|3w`v7P))w3`q!;AYY{*5=lbx-n-p9bH`jJ^B(iE0=o3=wf35sd+(e%bLZZ3 z&OLWT5=bC{1QJLffpZ8;&I6QESK<(~ENhR{5|GgphZf*&$f=ZX5b*BoyRdu(pd>4> zymRUpOGVc8+4#f;sU_-c;GuH@IQ-Bk+5~&_(=#gX>@5H^*pJ9~=a(Li?-a{DR?0Q+-a4Faqojj$t?f=7HmA}MP6uxX7kS*$SgODCLCD{57Wo`F z7WH?^7T@~p4MBW@z8l8vJG1Tgk}C2GE>V&2AClYU?kUU545~oA;i#G_wSlVXYTNj@ zr;T#CT3tQ^+^0DQycWzi%AVIR>&Qtn>i2@2%|ABU?=af_LzjK1+x-&U1D*nVfdz&> zWt8KgH(k+C@NK#_quc^B!A;<&U`WfQOuGKIuC|K}9f#A>f_Y%6?iaeZxnOI3&u!qF zV6ma&AzeoPE=oUlRkkZ84k$ZJAYS!oI~H7_Z1+u^0AJC(3hZQD4+i^#>%i5@p1@UD z(m8v|>o;Yky5)xo2Hsaum^r-qd19T;AMm6q%IqMufvVeqx6~+Grptb2bOt+dxGuj~ ze=G+%${rZQjIv|KGj|v=_PBJOq^ds&-Fbr@M66uI$N49099b`I4KSX`b6@ z;-hXo_HP?|#pzuGC+yw()08uwd2mE(MgD*(?s7N$#&~yWCB2v;@nZovPi(hI9iD}p z>&15I*XcG}!SOmyJR2zEYJE<({~>s*RKFiruZtL~L=)h+Pv{Y(KH!~VyH_G#Y&W)A zYFBvLuA}`g~bg6f{ zZg~w{B6bKNTK62y|GC<7#m{fa0Ug@5ZCh1Hqv{1N4+I1MH5(-!;nCE0)bPQ=g!M=3U<$)m6z9HW`5y|FK^%8u!f%h8IfF;pZSc$z&Tyj#)4i@a0Pcj7tu=a zC1{oI2j7wSuo4`_d>lxt7cn0v{*&ch#a?I-Tnr3{yw9}G3Zx5s*=XO>L&iq%Ild!T ziR zgU!L4;PO~*F$y-gc0`Jea}Mez;t#Ej^8&~$^Juf(IBzcAy14cK*f?ju$F*yOkIU!W zqA!`Wr?qdSZ1?-FF6YGUqhiFeG2po+H}daUrIrc=mUf!Ze)jI&U9dlOV0c;@2fK`D z-+nFpOxc{g-8a;@F&Nv!_)VuQK}YVBx(8zl?nsy&)miK~&-}Q42BF(R{1Y6l&zZSr z%<)pRoB6TyU@>FLXvywmR?5GEYcr!376b)LiXxRmc5h?i_Gegae){ z!?EB&vE4IQwexV#c(LD+N#Ze5y%WFz`Zqbp!1KAce2u#;LGIM&ncxbk zLxe9(Y2GkYk?U1=sH9|V%aqh#mFyX^t6pWKmlX-89yuOf7fYVsftP!h`X5OgGantv z)CZUJ&SGK)2FjoGs%x>>19}*)xq<(Z)E-RP&~kF%FipaN^K(rvFa<-G&6t)82o5~D zeWoNBKPJnWVZj1jcdjwScup+O}E3A;LjvY&v z<*mFWxgvCNJ&C+(UAO40f4!V{SF7y2-+Zxu^&!@R&W1Htj0^NRx4F38Rl6*>R9QX7 zTHNPld~`TQQx1Oq?a~AHFlWVy##qMuW2I^p1l`?GgQ9l{E!P`3^p8hX{uE+}aHiPds*{q_qV^)u**XcmuwYqt1DvDlVkvYeT; zCD>7g`h1(%iOMya{DAYF)B#fu=;%lE^PR*rW0oC;KIS5V|My*{&)16w^iKwKmmEyo zGGl&_D_0Jr6Iv&xVm9i5DteK@EwHz7WJo}3!c0C_@cbW;sfR-2F>F8A&|$5IDrTQD z@ODpwvjq(wWO_5Q4@8IDB^RjyM@Uyk~1rh@

KSH <%= ticket_type.price %>

<.link - navigate={~p"/event/#{ticket_type.id}/buy"} - id="buy-#{ticket_type.id}-tickets" + patch={~p"/event/#{ticket_type.id}/buy"} + id={"buy-#{ticket_type.id}-tickets"} >
diff --git a/lib/elixir_conf_africa_web/live/ticket_live/form_component.html.heex b/lib/elixir_conf_africa_web/live/ticket_live/form_component.html.heex index 5df2bc2..40b6905 100644 --- a/lib/elixir_conf_africa_web/live/ticket_live/form_component.html.heex +++ b/lib/elixir_conf_africa_web/live/ticket_live/form_component.html.heex @@ -1,7 +1,7 @@
<.simple_form for={@form} - id="event-form" + id="ticket-form" phx-target={@myself} phx-change="validate" phx-submit="save" diff --git a/lib/elixir_conf_africa_web/live/ticket_type_live/form_component.ex b/lib/elixir_conf_africa_web/live/ticket_type_live/form_component.ex index 1e4e4c8..e5e2354 100644 --- a/lib/elixir_conf_africa_web/live/ticket_type_live/form_component.ex +++ b/lib/elixir_conf_africa_web/live/ticket_type_live/form_component.ex @@ -33,7 +33,7 @@ defmodule ElixirConfAfricaWeb.TicketTypeLive.FormComponent do {:noreply, socket |> put_flash(:info, "Ticket type updated successfully") - |> push_patch(to: socket.assigns.patch)} + |> push_redirect(to: socket.assigns.patch)} {:error, %Ecto.Changeset{} = changeset} -> {:noreply, assign(socket, :changeset, changeset)} @@ -46,7 +46,7 @@ defmodule ElixirConfAfricaWeb.TicketTypeLive.FormComponent do {:noreply, socket |> put_flash(:info, "Ticket type created successfully") - |> push_patch(to: socket.assigns.patch)} + |> push_redirect(to: socket.assigns.patch)} {:error, %Ecto.Changeset{} = changeset} -> {:noreply, assign(socket, changeset: changeset)} diff --git a/lib/elixir_conf_africa_web/live/ticket_type_live/index.html.heex b/lib/elixir_conf_africa_web/live/ticket_type_live/index.html.heex index 2b8ec1c..3d2653a 100644 --- a/lib/elixir_conf_africa_web/live/ticket_type_live/index.html.heex +++ b/lib/elixir_conf_africa_web/live/ticket_type_live/index.html.heex @@ -3,7 +3,7 @@ Listing Ticket types <:actions> <.link patch={~p"/ticket_types/new"}> - <.button>New Ticket type + <.button>New Ticket Type @@ -43,7 +43,12 @@
- <.link patch={~p"/ticket_types/#{ticket_type}/edit"}>Edit + <.link + id={"ticket_types-#{ticket_type.id}"} + patch={~p"/ticket_types/#{ticket_type}/edit"} + > + Edit + <.link diff --git a/lib/elixir_conf_africa_web/user_auth.ex b/lib/elixir_conf_africa_web/user_auth.ex index 2235ca7..89ec6e3 100644 --- a/lib/elixir_conf_africa_web/user_auth.ex +++ b/lib/elixir_conf_africa_web/user_auth.ex @@ -1,4 +1,5 @@ defmodule ElixirConfAfricaWeb.UserAuth do + @moduledoc false use ElixirConfAfricaWeb, :verified_routes import Plug.Conn diff --git a/mix.exs b/mix.exs index 06071da..bb2f687 100644 --- a/mix.exs +++ b/mix.exs @@ -69,7 +69,7 @@ defmodule ElixirConfAfrica.MixProject do {:typed_ecto_schema, "~> 0.4.1"}, {:ex_machina, "~> 2.7.0"}, {:httpoison, "~> 2.1"}, - {:styler, "~> 0.11", only: [:dev, :test], runtime: false}, + {:styler, "~> 0.11", only: [:dev, :test], runtime: false} ] end diff --git a/test/.DS_Store b/test/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..dd0df7da06fc565bb7ea74e70fb32971fa87cf4e GIT binary patch literal 6148 zcmeHK&2G~`5T0!V-2|aV2+>}U_QEZy99mIvKr*2{^oC>v2SBOaq{Nc(Mz(_sA;|YW zL3s(DgD2o|;M*U5;((N1P*m+$GvEHqjO}l|yIvwx zuNI5P(4FsEP+BraROVxw<7+fd;=J&@Z)|P7aqapB=Plm4*?Jv}WEm7;G0A&j_EOcJ zhQ%ndEOJ{oBj6o zbh_v5cf_vOopr?Y;eD?o_I4l4W=+0zulwle`0e`-(~q-H7y9*xVS&@KY4Im~Mqw!e z-vwEk$n*{TRjxbBkd7fJ;TP4&|AP2G$-h*tt2zjmBB3@I8Bf5wV{%zp*0E;~v8?;22mP2Gsf>pbCA9l|j99 z!000Yuz_YRD68KC6(cPA7Au43fiM#aG@;BMF_;NQyRd$~#mb-wCuR>H%-)&V6AIIJ zM}DE*iTMVdbqqKL<{4Nw)wbII5C47spAT|1$ADwtN-@A12f;xPuVnYug_l!%t$-dw ql_ - Accounts.deliver_user_update_email_instructions(user, "current@example.com", url) + Accounts.deliver_update_email_instructions(user, "current@example.com", url) end) {:ok, token} = Base.url_decode64(token, padding: false) @@ -200,7 +200,7 @@ defmodule ElixirConfAfrica.AccountsTest do token = extract_user_token(fn url -> - Accounts.deliver_user_update_email_instructions(%{user | email: email}, user.email, url) + Accounts.deliver_update_email_instructions(%{user | email: email}, user.email, url) end) %{user: user, token: token, email: email} @@ -262,12 +262,12 @@ defmodule ElixirConfAfrica.AccountsTest do test "validates password", %{user: user} do {:error, changeset} = Accounts.update_user_password(user, valid_user_password(), %{ - password: "not valid", + password: "poor", password_confirmation: "another" }) assert %{ - password: ["should be at least 12 character(s)"], + password: ["should be at least 6 character(s)"], password_confirmation: ["does not match password"] } = errors_on(changeset) end @@ -353,11 +353,11 @@ defmodule ElixirConfAfrica.AccountsTest do end end - describe "delete_user_session_token/1" do + describe "delete_session_token/1" do test "deletes the token" do user = user_fixture() token = Accounts.generate_user_session_token(user) - assert Accounts.delete_user_session_token(token) == :ok + assert Accounts.delete_session_token(token) == :ok refute Accounts.get_user_by_session_token(token) end end @@ -471,12 +471,12 @@ defmodule ElixirConfAfrica.AccountsTest do test "validates password", %{user: user} do {:error, changeset} = Accounts.reset_user_password(user, %{ - password: "not valid", + password: "poor", password_confirmation: "another" }) assert %{ - password: ["should be at least 12 character(s)"], + password: ["should be at least 6 character(s)"], password_confirmation: ["does not match password"] } = errors_on(changeset) end @@ -500,7 +500,27 @@ defmodule ElixirConfAfrica.AccountsTest do end end - describe "inspect/2 for the User module" do + describe "update a user role/2" do + setup do + %{user: user_fixture()} + end + + test "you can update a user's role" do + {:ok, user} = Accounts.register_user(valid_user_attributes()) + assert user.role == "user" + {:ok, user} = Accounts.update_user_role(user, "admin") + assert user.role == "admin" + end + + test "you can only give the roles 'user' , 'admin' or 'scanner'" do + {:ok, user} = Accounts.register_user(valid_user_attributes()) + assert user.role == "user" + {:error, _} = Accounts.update_user_role(user, "not a role") + assert user.role == "user" + end + end + + describe "inspect/2" do test "does not include password" do refute inspect(%User{password: "123456"}) =~ "password: \"123456\"" end diff --git a/test/elixir_conf_africa/events_test.exs b/test/elixir_conf_africa/events_test.exs deleted file mode 100644 index db27efe..0000000 --- a/test/elixir_conf_africa/events_test.exs +++ /dev/null @@ -1,110 +0,0 @@ -defmodule ElixirConfAfrica.EventsTest do - use ElixirConfAfrica.DataCase - - alias ElixirConfAfrica.Events - - describe "events" do - import ElixirConfAfrica.Factory - alias ElixirConfAfrica.Events.Event - - @invalid_attrs %{ - name: nil, - description: nil, - location: nil, - event_type: nil, - start_date: nil, - end_date: nil - } - setup do - event = insert!(:elixir_conf_event) - [event: event] - end - - test "list_events/0 returns all events", %{event: event} do - assert Events.list_events() == [event] - end - - test "get_event!/1 returns the event with given id", %{event: event} do - assert Events.get_event!(event.id) == event - end - - test "get_event_with_ticket_types_by_event_name/1 returns the elixir conf event with ticket types", - %{event: event} do - ticket_type = - insert!(:elixir_conf_ticket_type, event_id: event.id) - - event_with_ticket_types = ElixirConfAfrica.Repo.preload(event, :ticket_types) - assert event = Events.get_event_with_ticket_types_by_event_name(event.name) - - assert event_with_ticket_types.ticket_types == [ticket_type] - assert event == event_with_ticket_types - end - - test "create_event/1 with valid data creates a event" do - valid_attrs = %{ - name: "some name", - description: "some description", - location: "some location", - event_type: "some event_type", - start_date: ~N[2023-10-05 06:18:00], - end_date: ~N[2023-10-05 06:18:00] - } - - assert {:ok, %Event{} = event} = Events.create_event(valid_attrs) - assert event.name == "some name" - assert event.description == "some description" - assert event.location == "some location" - assert event.event_type == "some event_type" - assert event.start_date == ~N[2023-10-05 06:18:00] - assert event.end_date == ~N[2023-10-05 06:18:00] - end - - test "create_event/1 with invalid data returns error changeset" do - assert {:error, %Ecto.Changeset{}} = Events.create_event(@invalid_attrs) - end - - test "update_event/2 with valid data updates the event", %{event: event} do - update_attrs = %{ - name: "some updated name", - description: "some updated description", - location: "some updated location", - event_type: "some updated event_type", - start_date: ~N[2023-10-06 06:18:00], - end_date: ~N[2023-10-06 06:18:00] - } - - assert {:ok, %Event{} = event} = Events.update_event(event, update_attrs) - assert event.name == "some updated name" - assert event.description == "some updated description" - assert event.location == "some updated location" - assert event.event_type == "some updated event_type" - assert event.start_date == ~N[2023-10-06 06:18:00] - assert event.end_date == ~N[2023-10-06 06:18:00] - end - - test "update_event/2 with invalid data returns error changeset", %{event: event} do - assert {:error, %Ecto.Changeset{}} = Events.update_event(event, @invalid_attrs) - assert event == Events.get_event!(event.id) - end - - test "delete_event/1 deletes the event", %{event: event} do - assert {:ok, %Event{}} = Events.delete_event(event) - assert_raise Ecto.NoResultsError, fn -> Events.get_event!(event.id) end - end - - test "change_event/1 returns a event changeset", %{event: event} do - assert %Ecto.Changeset{} = Events.change_event(event) - end - - test "get_total_number_of_available_tickets/1 returns total number of tickets", %{ - event: event - } do - %{number: number} = insert!(:elixir_conf_ticket_type, event_id: event.id) - %{number: number1} = insert!(:elixir_conf_ticket_type, event_id: event.id) - total_number_of_available_tickets = number1 + number - - assert Events.get_total_number_of_available_tickets(event.name) == - total_number_of_available_tickets - end - end -end diff --git a/test/elixir_conf_africa/paystack_test.exs b/test/elixir_conf_africa/paystack_test.exs new file mode 100644 index 0000000..992e269 --- /dev/null +++ b/test/elixir_conf_africa/paystack_test.exs @@ -0,0 +1,43 @@ +defmodule ElixirConfAfrica.PaystackTest do + use ElixirConfAfrica.DataCase + alias ElixirConfAfrica.Paystack + + describe "Paystack initialization , transaction verification and getting all transactions" do + setup do + [email: "michaelmunavu83@gmail.com", amount: 1000] + end + + test "initialize/2 with a valid email and amount returns a map with a authorization url , transaction reference and access code", + %{email: email, amount: amount} do + assert %{ + "access_code" => _, + "authorization_url" => _, + "reference" => _ + } = + Paystack.initialize(email, amount) + end + + test "list_transactions/0 returns a list of transactions for that account and gets structured", + %{email: email, amount: amount} do + Paystack.initialize(email, amount) + assert Paystack.list_transactions() != [] + end + + test "test_verification/1 returns a map with the transaction details", %{ + email: email, + amount: amount + } do + %{ + "access_code" => _, + "authorization_url" => _, + "reference" => reference + } = + Paystack.initialize(email, amount) + + assert %{ + "amount" => _amount, + "reference" => _reference + } = Paystack.test_verification(reference) + end + end +end diff --git a/test/elixir_conf_africa/ticket_types_test.exs b/test/elixir_conf_africa/ticket_types_test.exs index f62cd18..6aa866c 100644 --- a/test/elixir_conf_africa/ticket_types_test.exs +++ b/test/elixir_conf_africa/ticket_types_test.exs @@ -1,82 +1,91 @@ defmodule ElixirConfAfrica.TicketTypesTest do use ElixirConfAfrica.DataCase - alias ElixirConfAfrica.TicketTypes + alias ElixirConfAfrica.Factory describe "ticket_types" do alias ElixirConfAfrica.TicketTypes.TicketType + alias ElixirConfAfrica.TicketTypes - import ElixirConfAfrica.Factory - @invalid_attrs %{name: nil, description: nil, price: nil, number: nil} - setup do - event = insert!(:elixir_conf_event) - ticket_type = insert!(:elixir_conf_ticket_type, event_id: event.id) - %{ticket_type: ticket_type, event: event} - end + @invalid_attrs %{name: nil, description: nil, price: nil} + + test "list_ticket_types/0 returns all ticket_types" do + ticket_type = Factory.insert(:ticket_type) - test "list_ticket_types/0 returns all ticket_types", %{ticket_type: ticket_type} do - assert [^ticket_type] = TicketTypes.list_ticket_types() + assert TicketTypes.list_ticket_types() == [ticket_type] end - test "get_ticket_type!/1 returns the ticket_type with given id", %{ticket_type: ticket_type} do - assert ^ticket_type = TicketTypes.get_ticket_type!(ticket_type.id) + test "get_ticket_type!/1 returns the ticket_type with given id" do + ticket_type = Factory.insert(:ticket_type) + assert TicketTypes.get_ticket_type!(ticket_type.id) == ticket_type end - test "create_ticket_type/1 with valid data creates a ticket_type", %{event: event} do - valid_attrs = %{ - event_id: event.id, - name: "some name", - description: "some description", - price: "120.5", - number: "357" - } + test "create_ticket_type/1 with valid data creates a ticket_type" do + valid_attrs = %{name: "some name", description: "some description", price: 42, number: 49} assert {:ok, %TicketType{} = ticket_type} = TicketTypes.create_ticket_type(valid_attrs) assert ticket_type.name == "some name" assert ticket_type.description == "some description" - assert ticket_type.price == Decimal.new("120.5") + assert ticket_type.price == 42 end test "create_ticket_type/1 with invalid data returns error changeset" do assert {:error, %Ecto.Changeset{}} = TicketTypes.create_ticket_type(@invalid_attrs) end - test "update_ticket_type/2 with valid data updates the ticket_type", %{ - ticket_type: ticket_type - } do + test "update_ticket_type/2 with valid data updates the ticket_type" do + ticket_type = Factory.insert(:ticket_type) + update_attrs = %{ name: "some updated name", description: "some updated description", - price: "456.7", - number: "579" + price: 43, + number: 49 } - assert {:ok, %TicketType{} = update_ticket_type} = + assert {:ok, %TicketType{} = ticket_type} = TicketTypes.update_ticket_type(ticket_type, update_attrs) - refute ticket_type == update_ticket_type - assert update_ticket_type.name == "some updated name" - assert update_ticket_type.description == "some updated description" - assert update_ticket_type.price == Decimal.new("456.7") - assert update_ticket_type.number == 579 + assert ticket_type.name == "some updated name" + assert ticket_type.description == "some updated description" + assert ticket_type.price == 43 end - test "update_ticket_type/2 with invalid data returns error changeset", %{ - ticket_type: ticket_type - } do + test "update_ticket_type/2 with invalid data returns error changeset" do + ticket_type = Factory.insert(:ticket_type) + assert {:error, %Ecto.Changeset{}} = TicketTypes.update_ticket_type(ticket_type, @invalid_attrs) - assert ^ticket_type = TicketTypes.get_ticket_type!(ticket_type.id) + assert ticket_type == TicketTypes.get_ticket_type!(ticket_type.id) end - test "delete_ticket_type/1 deletes the ticket_type", %{ticket_type: ticket_type} do + test "delete_ticket_type/1 deletes the ticket_type" do + ticket_type = Factory.insert(:ticket_type) assert {:ok, %TicketType{}} = TicketTypes.delete_ticket_type(ticket_type) assert_raise Ecto.NoResultsError, fn -> TicketTypes.get_ticket_type!(ticket_type.id) end end - test "change_ticket_type/1 returns a ticket_type changeset", %{ticket_type: ticket_type} do + test "change_ticket_type/1 returns a ticket_type changeset" do + ticket_type = Factory.insert(:ticket_type) assert %Ecto.Changeset{} = TicketTypes.change_ticket_type(ticket_type) end + + test "list_ticket_types_with_remaining_tickets/0 returns all ticket_types with the remaining tickets available" do + ticket_type = Factory.insert(:ticket_type, number: 10) + + Factory.insert(:ticket, ticket_type_id: ticket_type.id, is_paid: true) + + assert TicketTypes.list_ticket_types_with_remaining_tickets() == + [ + %{ + id: ticket_type.id, + name: ticket_type.name, + remaining_tickets: 9, + description: ticket_type.description, + price: ticket_type.price + } + ] + end end end diff --git a/test/elixir_conf_africa/tickets_test.exs b/test/elixir_conf_africa/tickets_test.exs new file mode 100644 index 0000000..1a56961 --- /dev/null +++ b/test/elixir_conf_africa/tickets_test.exs @@ -0,0 +1,149 @@ +defmodule ElixirConfAfrica.TicketsTest do + use ElixirConfAfrica.DataCase + + alias ElixirConfAfrica.Tickets + alias ElixirConfAfrica.Factory + alias ElixirConfAfrica.Tickets.Ticket + + describe "ticket" do + @invalid_attrs %{name: nil, email: nil, ticketid: nil, quantity: nil} + + setup do + ticket_type = Factory.insert(:ticket_type, number: 10) + + ticket = + Factory.insert(:ticket, + ticket_type_id: ticket_type.id, + is_paid: true, + is_refunded: false, + cost: 400 + ) + + unpaid_ticket = + Factory.insert(:ticket, + ticket_type_id: ticket_type.id, + is_paid: false, + is_refunded: false, + cost: 400 + ) + + refunded_ticket = + Factory.insert(:ticket, + ticket_type_id: ticket_type.id, + is_paid: true, + is_refunded: true, + cost: 400 + ) + + [ + ticket_type: ticket_type, + ticket: ticket, + unpaid_ticket: unpaid_ticket, + refunded_ticket: refunded_ticket + ] + end + + test "list_ticket/0 returns all ticket", %{ + ticket: ticket, + unpaid_ticket: unpaid_ticket, + refunded_ticket: refunded_ticket + } do + assert Tickets.list_ticket() == [ticket, unpaid_ticket, refunded_ticket] + end + + test "list_paid_tickets/0 returns all paid tickets that are not refunded", %{ + ticket: ticket, + ticket_type: ticket_type + } do + assert Tickets.list_paid_tickets() == [ + ticket |> Map.put(:ticket_type, ticket_type) + ] + end + + test "list_unpaid_tickets/0 returns all unpaid tickets that are not refunded", %{ + unpaid_ticket: unpaid_ticket, + ticket_type: ticket_type + } do + assert Tickets.list_unpaid_tickets() == [ + unpaid_ticket |> Map.put(:ticket_type, ticket_type) + ] + end + + test "list_refunded_tickets/0 returns all refunded tickets that are paid", %{ + refunded_ticket: refunded_ticket, + ticket_type: ticket_type + } do + assert Tickets.list_refunded_tickets() == [ + refunded_ticket |> Map.put(:ticket_type, ticket_type) + ] + end + + test "get_ticket!/1 returns the ticket with given id", %{ticket: ticket} do + assert Tickets.get_ticket!(ticket.id) == ticket + end + + test "get_ticket_by_ticketid!/1 returns the ticket with given ticketid", %{ + ticket: ticket, + ticket_type: ticket_type + } do + assert Tickets.get_ticket_by_ticketid!(ticket.ticketid) == + ticket |> Map.put(:ticket_type, ticket_type) + end + + test "create_ticket/1 with valid data creates a ticket", %{ + ticket_type: ticket_type + } do + valid_attrs = %{ + name: "some name", + email: "email@gmail.com", + ticketid: "some ticketid", + quantity: 42, + ticket_type_id: ticket_type.id, + cost: 200 + } + + assert {:ok, %Ticket{} = ticket} = Tickets.create_ticket(valid_attrs) + assert ticket.name == "some name" + assert ticket.email == "email@gmail.com" + assert ticket.ticketid == "some ticketid" + assert ticket.quantity == 42 + end + + test "create_ticket/1 with invalid data returns error changeset" do + assert {:error, %Ecto.Changeset{}} = Tickets.create_ticket(@invalid_attrs) + end + + test "update_ticket/2 with valid data updates the ticket", %{ + ticket_type: ticket_type, + ticket: ticket + } do + update_attrs = %{ + name: "some updated name", + email: "someemail@gmail.com", + ticketid: "some updated ticketid", + quantity: 43, + cost: 200, + ticket_type_id: ticket_type.id + } + + assert {:ok, %Ticket{} = ticket} = Tickets.update_ticket(ticket, update_attrs) + assert ticket.name == "some updated name" + assert ticket.email == "someemail@gmail.com" + assert ticket.ticketid == "some updated ticketid" + assert ticket.quantity == 43 + end + + test "update_ticket/2 with invalid data returns error changeset", %{ticket: ticket} do + assert {:error, %Ecto.Changeset{}} = Tickets.update_ticket(ticket, @invalid_attrs) + assert ticket == Tickets.get_ticket!(ticket.id) + end + + test "delete_ticket/1 deletes the ticket", %{ticket: ticket} do + assert {:ok, %Ticket{}} = Tickets.delete_ticket(ticket) + end + + test "change_ticket/1 returns a ticket changeset", %{ticket: ticket} do + assert %Ecto.Changeset{} = Tickets.change_ticket(ticket) + end + end +end diff --git a/test/elixir_conf_africa_web/.DS_Store b/test/elixir_conf_africa_web/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..51293b8fe9130a6efda46c976027336209932586 GIT binary patch literal 6148 zcmeHK&2G~`5S~p_*rY;42#H>h_QEZy99n@mAeqn}dP6dT1EADyEMm!cE8A&+kjk&o zz68&~6Yx0j?GJ%A^j0B2GtulfJ3BMhe(UUdiAW5m;{j2Rh$PfttApk@V#bZGNXvWH zfx^}(NmGtrO65v4JN`xn%-U_xA=a&+8msnm{i^+3A11j@5Mf@AC(x~LR$vjevCbJC zQ+grp^JQ_#tUB`bz9dI^R@Fi9RkYUH>({PJ*_GWJ-8a!h&!Rf6r`0enUzy&sxSk~5 zey(-CwBzJOmd-}K+fQ{-$61k>@)YD>I**cLMkg_8?qu%Cxz7ss` ztLMWOP}W0cL<1xOxWsrY1M8zBE^4 z2AF|=oB^{xD5$~EW8=_n9cb(o0N94x3T*SSXmXUt&|~8eBM{+Ifi6|}D~53C@GBn| zdTboJbQ1pZA^ektzo7{GbktWioJ8o5TV{Y6IM2YE>-Nm~zjyil|9lenm;q+szhXeN zcca}QrsU7omC2d2RzVM-Moe7eaG3(b9>s_?NAV`q3jE3#z|dpk5FQAB2v{1pVFvyv G1K$DHpL#j~ literal 0 HcmV?d00001 diff --git a/test/elixir_conf_africa_web/controllers/page_controller_test.exs b/test/elixir_conf_africa_web/controllers/page_controller_test.exs deleted file mode 100644 index 566dd2b..0000000 --- a/test/elixir_conf_africa_web/controllers/page_controller_test.exs +++ /dev/null @@ -1,8 +0,0 @@ -defmodule ElixirConfAfricaWeb.PageControllerTest do - use ElixirConfAfricaWeb.ConnCase - - test "GET /", %{conn: conn} do - conn = get(conn, ~p"/") - assert html_response(conn, 200) =~ "Peace of mind from prototype to production" - end -end diff --git a/test/elixir_conf_africa_web/controllers/user_registration_controller_test.exs b/test/elixir_conf_africa_web/controllers/user_registration_controller_test.exs index 35d689c..0c6bd7b 100644 --- a/test/elixir_conf_africa_web/controllers/user_registration_controller_test.exs +++ b/test/elixir_conf_africa_web/controllers/user_registration_controller_test.exs @@ -43,13 +43,13 @@ defmodule ElixirConfAfricaWeb.UserRegistrationControllerTest do test "render errors for invalid data", %{conn: conn} do conn = post(conn, ~p"/users/register", %{ - "user" => %{"email" => "with spaces", "password" => "too short"} + "user" => %{"email" => "with spaces", "password" => "short"} }) response = html_response(conn, 200) assert response =~ "Register" assert response =~ "must have the @ sign and no spaces" - assert response =~ "should be at least 12 character" + assert response =~ "should be at least 6 character" end end end diff --git a/test/elixir_conf_africa_web/controllers/user_reset_password_controller_test.exs b/test/elixir_conf_africa_web/controllers/user_reset_password_controller_test.exs index 6b30b2e..dd0b968 100644 --- a/test/elixir_conf_africa_web/controllers/user_reset_password_controller_test.exs +++ b/test/elixir_conf_africa_web/controllers/user_reset_password_controller_test.exs @@ -104,7 +104,7 @@ defmodule ElixirConfAfricaWeb.UserResetPasswordControllerTest do conn = put(conn, ~p"/users/reset_password/#{token}", %{ "user" => %{ - "password" => "too short", + "password" => "short", "password_confirmation" => "does not match" } }) diff --git a/test/elixir_conf_africa_web/controllers/user_settings_controller_test.exs b/test/elixir_conf_africa_web/controllers/user_settings_controller_test.exs index 28a478e..933a188 100644 --- a/test/elixir_conf_africa_web/controllers/user_settings_controller_test.exs +++ b/test/elixir_conf_africa_web/controllers/user_settings_controller_test.exs @@ -48,14 +48,14 @@ defmodule ElixirConfAfricaWeb.UserSettingsControllerTest do "action" => "update_password", "current_password" => "invalid", "user" => %{ - "password" => "too short", + "password" => "short", "password_confirmation" => "does not match" } }) response = html_response(old_password_conn, 200) assert response =~ "Settings" - assert response =~ "should be at least 12 character(s)" + assert response =~ "should be at least 6 character(s)" assert response =~ "does not match password" assert response =~ "is not valid" @@ -102,7 +102,7 @@ defmodule ElixirConfAfricaWeb.UserSettingsControllerTest do token = extract_user_token(fn url -> - Accounts.deliver_user_update_email_instructions(%{user | email: email}, user.email, url) + Accounts.deliver_update_email_instructions(%{user | email: email}, user.email, url) end) %{token: token, email: email} diff --git a/test/elixir_conf_africa_web/live/event_live_test.exs b/test/elixir_conf_africa_web/live/event_live_test.exs index 23da999..9983554 100644 --- a/test/elixir_conf_africa_web/live/event_live_test.exs +++ b/test/elixir_conf_africa_web/live/event_live_test.exs @@ -2,129 +2,118 @@ defmodule ElixirConfAfricaWeb.EventLiveTest do use ElixirConfAfricaWeb.ConnCase import Phoenix.LiveViewTest - import ElixirConfAfrica.Factory + alias ElixirConfAfrica.Factory - @create_attrs %{ + @valid_attributes %{ name: "some name", - description: "some description", - location: "some location", - event_type: "some event_type", - start_date: "2023-10-05T06:18:00", - end_date: "2023-10-05T06:18:00" + email: "michaelmunavu83@gmail.com", + quantity: 2 } - @update_attrs %{ - name: "some updated name", - description: "some updated description", - location: "some updated location", - event_type: "some updated event_type", - start_date: "2023-10-06T06:18:00", - end_date: "2023-10-06T06:18:00" - } - @invalid_attrs %{ + + @invalid_attributes %{ name: nil, - description: nil, - location: nil, - event_type: nil, - start_date: nil, - end_date: nil + email: nil, + quantity: 2 } - setup do - event = insert!(:elixir_conf_event) - %{event: event} - end - - describe "Index" do - test "lists all events", %{conn: conn, event: event} do - {:ok, _index_live, html} = live(conn, ~p"/events") - - assert html =~ "Listing Events" - assert html =~ event.name + describe "Event" do + setup do + ticket_type1 = Factory.insert(:ticket_type, number: 10, name: "Early Bird", price: 400) + ticket_type2 = Factory.insert(:ticket_type, number: 10, name: "Advanced", price: 500) + + Factory.insert(:ticket, + ticket_type_id: ticket_type1.id, + is_paid: false, + is_refunded: false, + cost: 400 + ) + + Factory.insert(:ticket, + ticket_type_id: ticket_type2.id, + is_paid: true, + is_refunded: false, + cost: 400 + ) + + Factory.insert(:ticket, + ticket_type_id: ticket_type1.id, + is_paid: true, + is_refunded: false, + cost: 400 + ) + + Factory.insert(:ticket, + ticket_type_id: ticket_type2.id, + is_paid: true, + is_refunded: true, + cost: 400 + ) + + %{ticket_type1: ticket_type1, ticket_type2: ticket_type2} end - test "saves new event", %{conn: conn} do - {:ok, index_live, _html} = live(conn, ~p"/events") - - assert index_live |> element("a", "New Event") |> render_click() =~ - "New Event" - - assert_patch(index_live, ~p"/events/new") + test "You can see available tickets with their remaining quantity", %{ + conn: conn, + ticket_type1: ticket_type1, + ticket_type2: ticket_type2 + } do + {:ok, _index_live, html} = live(conn, ~p"/event") + + assert html =~ ticket_type1.name + assert html =~ ticket_type2.name + assert html =~ "9" + assert html =~ "8" + end - assert index_live - |> form("#event-form", event: @invalid_attrs) - |> render_change() =~ "can't be blank" + test "once you click on get ticket for a particular ticket type , a form popups where you add your details", + %{ + conn: conn, + ticket_type1: ticket_type1 + } do + {:ok, index_live, _html} = live(conn, ~p"/event") - assert index_live - |> form("#event-form", event: @create_attrs) - |> render_submit() + index_live + |> element("#buy-#{ticket_type1.id}-tickets", "Get") + |> render_click() - assert_patch(index_live, ~p"/events") + assert_patch(index_live, ~p"/event/#{ticket_type1.id}/buy") - html = render(index_live) - assert html =~ "Event created successfully" - assert html =~ "some name" + assert has_element?(index_live, "#ticket-form") end - test "updates event in listing", %{conn: conn, event: event} do - {:ok, index_live, _html} = live(conn, ~p"/events") + test "adding invalid data on the form renders errors", + %{ + conn: conn, + ticket_type1: ticket_type1 + } do + {:ok, index_live, _html} = live(conn, ~p"/event") - assert index_live |> element("#events-#{event.id} a", "Edit") |> render_click() =~ - "Edit Event" + index_live + |> element("#buy-#{ticket_type1.id}-tickets", "Get") + |> render_click() - assert_patch(index_live, ~p"/events/#{event}/edit") + {:ok, index_live, _html} = + live(conn, ~p"/event/#{ticket_type1.id}/buy") assert index_live - |> form("#event-form", event: @invalid_attrs) + |> form("#ticket-form", ticket: @invalid_attributes) |> render_change() =~ "can't be blank" - - assert index_live - |> form("#event-form", event: @update_attrs) - |> render_submit() - - assert_patch(index_live, ~p"/events") - - html = render(index_live) - assert html =~ "Event updated successfully" - assert html =~ "some updated name" - end - - test "deletes event in listing", %{conn: conn, event: event} do - {:ok, index_live, _html} = live(conn, ~p"/events") - - assert index_live |> element("#events-#{event.id} a", "Delete") |> render_click() - refute has_element?(index_live, "#events-#{event.id}") end - end - - describe "Show" do - test "displays event", %{conn: conn, event: event} do - {:ok, _show_live, html} = live(conn, ~p"/events/#{event}") - - assert html =~ "Show Event" - assert html =~ event.name - end - - test "updates event within modal", %{conn: conn, event: event} do - {:ok, show_live, _html} = live(conn, ~p"/events/#{event}") - - assert show_live |> element("a", "Edit") |> render_click() =~ - "Edit Event" - - assert_patch(show_live, ~p"/events/#{event}/show/edit") - - assert show_live - |> form("#event-form", event: @invalid_attrs) - |> render_change() =~ "can't be blank" - assert show_live - |> form("#event-form", event: @update_attrs) - |> render_submit() + test "adding valid data on the form redirects to the event page", + %{ + conn: conn, + ticket_type1: ticket_type1 + } do + {:ok, index_live, _html} = live(conn, ~p"/event") - assert_patch(show_live, ~p"/events/#{event}") + index_live + |> element("#buy-#{ticket_type1.id}-tickets", "Get") + |> render_click() - html = render(show_live) - assert html =~ "Event updated successfully" - assert html =~ "some updated name" + index_live + |> form("#ticket-form", ticket: @valid_attributes) + |> render_submit() end end end diff --git a/test/elixir_conf_africa_web/live/home_live_test.exs b/test/elixir_conf_africa_web/live/home_live_test.exs new file mode 100644 index 0000000..391500c --- /dev/null +++ b/test/elixir_conf_africa_web/live/home_live_test.exs @@ -0,0 +1,21 @@ +defmodule ElixirConfAfricaWeb.HomeLiveTest do + use ElixirConfAfricaWeb.ConnCase + + import Phoenix.LiveViewTest + + describe "Home" do + test "There is a button to buy tickets", %{conn: conn} do + {:ok, _index_live, html} = live(conn, ~p"/") + + assert html =~ "Buy Tickets" + end + + test "once clicked, the button takes you to the event page", %{conn: conn} do + {:ok, index_live, _html} = live(conn, ~p"/") + + index_live |> element("a", "Buy Tickets") |> render_click() |> follow_redirect(conn) + + assert_redirect(index_live, ~p"/event") + end + end +end diff --git a/test/elixir_conf_africa_web/live/paid_ticket_live_test.exs b/test/elixir_conf_africa_web/live/paid_ticket_live_test.exs new file mode 100644 index 0000000..a169038 --- /dev/null +++ b/test/elixir_conf_africa_web/live/paid_ticket_live_test.exs @@ -0,0 +1,67 @@ +defmodule ElixirConfAfricaWeb.PaidTicketLiveTest do + use ElixirConfAfricaWeb.ConnCase + + import Phoenix.LiveViewTest + alias ElixirConfAfrica.Factory + + describe "Paid Tickets Tests" do + setup %{conn: conn} do + # sign up first + conn = + post(conn, ~p"/users/register", + method: :create, + user: %{email: "admin@gmail.com", password: "123456", role: "admin"} + ) + + ticket_type = Factory.insert(:ticket_type, name: "some name", price: 400) + + paid_ticket = + Factory.insert(:ticket, + is_paid: true, + is_refunded: false, + name: "some paid name", + ticket_type_id: ticket_type.id + ) + + unpaid_ticket = + Factory.insert(:ticket, + is_paid: false, + is_refunded: false, + name: "some unpaid name", + ticket_type_id: ticket_type.id + ) + + [ + paid_ticket: paid_ticket, + unpaid_ticket: unpaid_ticket, + conn: conn + ] + end + + test "you see the paid tickets on /tickets/paid", %{ + conn: conn, + paid_ticket: paid_ticket, + unpaid_ticket: unpaid_ticket + } do + {:ok, _index_live, html} = live(conn, ~p"/tickets/paid") + + assert html =~ "Listing Paid Tickets" + assert html =~ paid_ticket.name + refute html =~ unpaid_ticket.name + end + + test "you see a button on each record that sends a ticket email", %{ + conn: conn, + paid_ticket: paid_ticket + } do + {:ok, index_live, html} = live(conn, ~p"/tickets/paid") + + assert html =~ "Listing Paid Tickets" + assert html =~ paid_ticket.name + + assert index_live + |> element("#send-email-#{paid_ticket.id}", "Send Email") + |> render_click() =~ "Ticket sent successfully" + end + end +end diff --git a/test/elixir_conf_africa_web/live/refunded_ticket_live_test.exs b/test/elixir_conf_africa_web/live/refunded_ticket_live_test.exs new file mode 100644 index 0000000..847cf73 --- /dev/null +++ b/test/elixir_conf_africa_web/live/refunded_ticket_live_test.exs @@ -0,0 +1,53 @@ +defmodule ElixirConfAfricaWeb.RefundedTicketLiveTest do + use ElixirConfAfricaWeb.ConnCase + + import Phoenix.LiveViewTest + alias ElixirConfAfrica.Factory + + describe "Refunded Tickets Tests" do + setup %{conn: conn} do + # sign up first + conn = + post(conn, ~p"/users/register", + method: :create, + user: %{email: "admin@gmail.com", password: "123456", role: "admin"} + ) + + ticket_type = Factory.insert(:ticket_type, name: "some name", price: 400) + + paid_ticket = + Factory.insert(:ticket, + is_paid: true, + is_refunded: false, + name: "some paid name", + ticket_type_id: ticket_type.id + ) + + refunded_ticket = + Factory.insert(:ticket, + is_paid: true, + is_refunded: true, + name: "some refunded name", + ticket_type_id: ticket_type.id + ) + + [ + paid_ticket: paid_ticket, + refunded_ticket: refunded_ticket, + conn: conn + ] + end + + test "you see the refunded tickets on /tickets/refunded", %{ + conn: conn, + paid_ticket: paid_ticket, + refunded_ticket: refunded_ticket + } do + {:ok, _index_live, html} = live(conn, ~p"/tickets/refunded") + + assert html =~ "Listing Refunded Tickets" + assert html =~ refunded_ticket.name + refute html =~ paid_ticket.name + end + end +end diff --git a/test/elixir_conf_africa_web/live/success_live_test.exs b/test/elixir_conf_africa_web/live/success_live_test.exs new file mode 100644 index 0000000..ba94b5e --- /dev/null +++ b/test/elixir_conf_africa_web/live/success_live_test.exs @@ -0,0 +1,55 @@ +defmodule ElixirConfAfricaWeb.SuccessLiveTest do + use ElixirConfAfricaWeb.ConnCase + + import Phoenix.LiveViewTest + alias ElixirConfAfrica.Factory + alias ElixirConfAfrica.Paystack + + describe "Tests the Success Redirect URL that you are redirected to" do + setup do + ticket_type = Factory.insert(:ticket_type, name: "some name", price: 400) + + %{"reference" => reference} = + Paystack.initialize("michaelmunavu83@gmail.com", 400) + + Factory.insert(:ticket, + is_paid: true, + is_refunded: false, + name: "some paid name", + ticket_type_id: ticket_type.id, + ticketid: reference + ) + + [ + reference: reference + ] + end + + test "you see a button to go back to the tickets page if the payment is not successful", %{ + reference: reference, + conn: conn + } do + {:ok, _index_live, html} = + live(conn, ~p"/success?trxref=#{reference}") + + assert html =~ "Payment was unsuccessful , go back to the tickets and purchase" + assert html =~ "Back to Tickets Page" + end + + test "the button for tickets page takes you back to the tickets page", %{ + reference: reference, + conn: conn + } do + {:ok, index_live, _html} = + live(conn, ~p"/success?trxref=#{reference}") + + {:ok, _index_live, html} = + index_live + |> element("a", "Back to Tickets Page") + |> render_click() + |> follow_redirect(conn) + + assert html =~ "Available Tickets" + end + end +end diff --git a/test/elixir_conf_africa_web/live/ticket_show_live_test.exs b/test/elixir_conf_africa_web/live/ticket_show_live_test.exs new file mode 100644 index 0000000..f316f49 --- /dev/null +++ b/test/elixir_conf_africa_web/live/ticket_show_live_test.exs @@ -0,0 +1,38 @@ +defmodule ElixirConfAfricaWeb.TicketShowLiveTest do + use ElixirConfAfricaWeb.ConnCase + + import Phoenix.LiveViewTest + alias ElixirConfAfrica.Factory + + describe "Tests The Ticket Show Page" do + setup do + ticket_type = Factory.insert(:ticket_type, name: "some name", price: 400) + + ticket = + Factory.insert(:ticket, + is_paid: true, + is_refunded: false, + name: "some paid name", + ticket_type_id: ticket_type.id, + ticketid: "some-ticket-id" + ) + + [ + ticket: ticket + ] + end + + test "you see the ticket details on /tickets/:id", %{ticket: ticket, conn: conn} do + {:ok, _index_live, html} = live(conn, ~p"/tickets/#{ticket.ticketid}") + + assert html =~ ticket.name + assert html =~ ticket.email + end + + test "you see a qr code on the ticket show page", %{ticket: ticket, conn: conn} do + {:ok, index_live, _html} = live(conn, ~p"/tickets/#{ticket.ticketid}") + + assert has_element?(index_live, "#qrcode") + end + end +end diff --git a/test/elixir_conf_africa_web/live/ticket_type_live_test.exs b/test/elixir_conf_africa_web/live/ticket_type_live_test.exs index ee47ce3..e2be8ef 100644 --- a/test/elixir_conf_africa_web/live/ticket_type_live_test.exs +++ b/test/elixir_conf_africa_web/live/ticket_type_live_test.exs @@ -2,29 +2,34 @@ defmodule ElixirConfAfricaWeb.TicketTypeLiveTest do use ElixirConfAfricaWeb.ConnCase import Phoenix.LiveViewTest - import ElixirConfAfrica.Factory - @create_attrs %{ - name: "some name", - description: "some description", - price: "120.5", - number: "357" - } + alias ElixirConfAfrica.Factory + @update_attrs %{ name: "some updated name", description: "some updated description", - price: "456.7", - number: "579" + price: 43, + number: 50 } - @invalid_attrs %{name: nil, description: nil, price: nil, number: nil} - - setup do - event = insert!(:elixir_conf_event) - ticket_type = insert!(:elixir_conf_ticket_type, event_id: event.id) - %{ticket_type: ticket_type, event: event} - end + @invalid_attrs %{name: nil, description: nil, price: nil} describe "Index" do + setup %{conn: conn} do + # sign up first + conn = + post(conn, ~p"/users/register", + method: :create, + user: %{email: "admin@gmail.com", password: "123456", role: "admin"} + ) + + ticket_type = Factory.insert(:ticket_type) + + [ + ticket_type: ticket_type, + conn: conn + ] + end + test "lists all ticket_types", %{conn: conn, ticket_type: ticket_type} do {:ok, _index_live, html} = live(conn, ~p"/ticket_types") @@ -32,11 +37,11 @@ defmodule ElixirConfAfricaWeb.TicketTypeLiveTest do assert html =~ ticket_type.name end - test "saves new ticket_type", %{conn: conn, event: event} do + test "saves new ticket_type", %{conn: conn} do {:ok, index_live, _html} = live(conn, ~p"/ticket_types") - assert index_live |> element("a", "New Ticket type") |> render_click() =~ - "New Ticket type" + assert index_live |> element("a", "New Ticket Type") |> render_click() =~ + "New Ticket Type" assert_patch(index_live, ~p"/ticket_types/new") @@ -44,24 +49,28 @@ defmodule ElixirConfAfricaWeb.TicketTypeLiveTest do |> form("#ticket_type-form", ticket_type: @invalid_attrs) |> render_change() =~ "can't be blank" - assert index_live - |> form("#ticket_type-form", - ticket_type: Map.merge(@create_attrs, %{event_id: event.id}) - ) - |> render_submit() - - assert_patch(index_live, ~p"/ticket_types") + {:ok, _, html} = + index_live + |> form("#ticket_type-form", + ticket_type: %{ + name: "early bird", + description: "some description", + price: 42, + number: 49 + } + ) + |> render_submit() + |> follow_redirect(conn, ~p"/ticket_types") - html = render(index_live) assert html =~ "Ticket type created successfully" - assert html =~ "some name" + assert html =~ "early bird" end test "updates ticket_type in listing", %{conn: conn, ticket_type: ticket_type} do {:ok, index_live, _html} = live(conn, ~p"/ticket_types") - assert index_live |> element("#ticket_types-#{ticket_type.id} a", "Edit") |> render_click() =~ - "Edit Ticket type" + assert index_live |> element("#ticket_types-#{ticket_type.id}", "Edit") |> render_click() =~ + "Edit" assert_patch(index_live, ~p"/ticket_types/#{ticket_type}/edit") @@ -69,13 +78,12 @@ defmodule ElixirConfAfricaWeb.TicketTypeLiveTest do |> form("#ticket_type-form", ticket_type: @invalid_attrs) |> render_change() =~ "can't be blank" - assert index_live - |> form("#ticket_type-form", ticket_type: @update_attrs) - |> render_submit() - - assert_patch(index_live, ~p"/ticket_types") + {:ok, _, html} = + index_live + |> form("#ticket_type-form", ticket_type: @update_attrs) + |> render_submit() + |> follow_redirect(conn, ~p"/ticket_types") - html = render(index_live) assert html =~ "Ticket type updated successfully" assert html =~ "some updated name" end @@ -83,43 +91,8 @@ defmodule ElixirConfAfricaWeb.TicketTypeLiveTest do test "deletes ticket_type in listing", %{conn: conn, ticket_type: ticket_type} do {:ok, index_live, _html} = live(conn, ~p"/ticket_types") - assert index_live - |> element("#ticket_types-#{ticket_type.id} a", "Delete") - |> render_click() - - refute has_element?(index_live, "#ticket_types-#{ticket_type.id}") - end - end - - describe "Show" do - test "displays ticket_type", %{conn: conn, ticket_type: ticket_type} do - {:ok, _show_live, html} = live(conn, ~p"/ticket_types/#{ticket_type}") - - assert html =~ "Show Ticket type" - assert html =~ ticket_type.name - end - - test "updates ticket_type within modal", %{conn: conn, ticket_type: ticket_type} do - {:ok, show_live, _html} = live(conn, ~p"/ticket_types/#{ticket_type}") - - assert show_live |> element("a", "Edit") |> render_click() =~ - "Edit Ticket type" - - assert_patch(show_live, ~p"/ticket_types/#{ticket_type}/show/edit") - - assert show_live - |> form("#ticket_type-form", ticket_type: @invalid_attrs) - |> render_change() =~ "can't be blank" - - assert show_live - |> form("#ticket_type-form", ticket_type: @update_attrs) - |> render_submit() - - assert_patch(show_live, ~p"/ticket_types/#{ticket_type}") - - html = render(show_live) - assert html =~ "Ticket type updated successfully" - assert html =~ "some updated name" + assert index_live |> element("#ticket_type-#{ticket_type.id} a", "Delete") |> render_click() + refute has_element?(index_live, "#ticket_type-#{ticket_type.id}") end end end diff --git a/test/elixir_conf_africa_web/live/transaction_live_test.exs b/test/elixir_conf_africa_web/live/transaction_live_test.exs new file mode 100644 index 0000000..cc2e753 --- /dev/null +++ b/test/elixir_conf_africa_web/live/transaction_live_test.exs @@ -0,0 +1,42 @@ +defmodule ElixirConfAfricaWeb.TransactionLiveTest do + use ElixirConfAfricaWeb.ConnCase + + import Phoenix.LiveViewTest + + alias ElixirConfAfrica.Paystack + + describe "This page lists all transactions made" do + setup %{conn: conn} do + # sign up first + conn = + post(conn, ~p"/users/register", + method: :create, + user: %{email: "admin@gmail.com", password: "123456", role: "admin"} + ) + + %{"reference" => reference1} = + Paystack.initialize("michaelmunavu83@gmail.com", 400) + + %{"reference" => reference2} = + Paystack.initialize("michaelmunavu83@gmail.com", 400) + + [ + reference1: reference1, + reference2: reference2, + conn: conn + ] + end + + test "on /transactions , you see all the transactions made", %{ + conn: conn, + reference1: reference1, + reference2: reference2 + } do + {:ok, _index_live, html} = live(conn, ~p"/transactions") + + assert html =~ "Listing Transactions" + assert html =~ reference1 + assert html =~ reference2 + end + end +end diff --git a/test/elixir_conf_africa_web/live/unpaid_ticket_live_test.exs b/test/elixir_conf_africa_web/live/unpaid_ticket_live_test.exs new file mode 100644 index 0000000..d15448b --- /dev/null +++ b/test/elixir_conf_africa_web/live/unpaid_ticket_live_test.exs @@ -0,0 +1,62 @@ +defmodule ElixirConfAfricaWeb.UnpaidTicketLiveTest do + use ElixirConfAfricaWeb.ConnCase + + import Phoenix.LiveViewTest + alias ElixirConfAfrica.Factory + alias ElixirConfAfrica.Paystack + + describe "Unpaid Tickets Tests" do + setup %{conn: conn} do + # sign up first + conn = + post(conn, ~p"/users/register", + method: :create, + user: %{email: "admin@gmail.com", password: "123456", role: "admin"} + ) + + ticket_type = Factory.insert(:ticket_type, name: "some name", price: 400) + + %{"reference" => reference} = + Paystack.initialize("michaelmunavu83@gmail.com", 400) + + paid_ticket = + Factory.insert(:ticket, + is_paid: true, + is_refunded: false, + name: "some paid name", + ticketid: reference, + ticket_type_id: ticket_type.id + ) + + %{"reference" => reference} = + Paystack.initialize("michaelmunavu83@gmail.com", 400) + + unpaid_ticket = + Factory.insert(:ticket, + is_paid: false, + is_refunded: false, + name: "some unpaid name", + ticketid: reference, + ticket_type_id: ticket_type.id + ) + + [ + paid_ticket: paid_ticket, + unpaid_ticket: unpaid_ticket, + conn: conn + ] + end + + test "you see the unpaid tickets on /tickets/unpaid", %{ + conn: conn, + paid_ticket: paid_ticket, + unpaid_ticket: unpaid_ticket + } do + {:ok, _index_live, html} = live(conn, ~p"/tickets/unpaid") + + assert html =~ "Listing Unpaid Tickets" + assert html =~ unpaid_ticket.name + refute html =~ paid_ticket.name + end + end +end diff --git a/test/elixir_conf_africa_web/live/user_live_test.exs b/test/elixir_conf_africa_web/live/user_live_test.exs new file mode 100644 index 0000000..d13c2ad --- /dev/null +++ b/test/elixir_conf_africa_web/live/user_live_test.exs @@ -0,0 +1,83 @@ +defmodule ElixirConfAfricaWeb.UserLiveTest do + use ElixirConfAfricaWeb.ConnCase + + import Phoenix.LiveViewTest + + alias ElixirConfAfrica.Factory + + describe "System Users Page" do + setup %{conn: conn} do + # sign up first + conn = + post(conn, ~p"/users/register", + method: :create, + user: %{email: "admin@gmail.com", password: "123456", role: "admin"} + ) + + user_1 = + Factory.insert(:user, email: "test1@gmail.com", hashed_password: "123456", role: "user") + + scanner_1 = + Factory.insert(:user, + email: "test2@gmail.com", + hashed_password: "123456", + role: "scanner" + ) + + admin_1 = + Factory.insert(:user, email: "admin2@gmail.com", hashed_password: "123456", role: "admin") + + [ + conn: conn, + user_1: user_1, + scanner_1: scanner_1, + admin_1: admin_1 + ] + end + + test "on /users you see all users apart from the current user", %{ + conn: conn, + user_1: user_1, + scanner_1: scanner_1, + admin_1: admin_1 + } do + {:ok, _index_live, html} = live(conn, ~p"/users") + + assert html =~ "Listing Users" + assert html =~ user_1.email + assert html =~ scanner_1.email + assert html =~ admin_1.email + end + + test "for admin users , you can only see a button to make the user a normal user or scanner and not to make them an admin", + %{ + conn: conn, + admin_1: admin_1 + } do + {:ok, index_live, _html} = live(conn, ~p"/users") + + assert has_element?(index_live, "#make-user-#{admin_1.id}") + assert has_element?(index_live, "#make-scanner-#{admin_1.id}") + refute has_element?(index_live, "#make-admin-#{admin_1.id}") + end + + test "you can change a users role when you click a button", %{ + conn: conn, + admin_1: admin_1 + } do + {:ok, index_live, _html} = live(conn, ~p"/users") + + assert has_element?(index_live, "#role-#{admin_1.id}", admin_1.role) + + html = + index_live + |> element("#make-user-#{admin_1.id}") + |> render_click() + + assert html =~ "User role changed successfully" + + assert has_element?(index_live, "#role-#{admin_1.id}", "user") + refute has_element?(index_live, "#role-#{admin_1.id}", admin_1.role) + end + end +end diff --git a/test/support/factory.ex b/test/support/factory.ex index 8fc7e86..f5da8a3 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -1,32 +1,33 @@ defmodule ElixirConfAfrica.Factory do @moduledoc false - alias ElixirConfAfrica.Repo + use ExMachina.Ecto, repo: ElixirConfAfrica.Repo - def build(:elixir_conf_event) do - %ElixirConfAfrica.Events.Event{ - name: "ElixirConf Africa 2024", - description: "description", - location: "location", - event_type: "event_type", - start_date: ~N[2023-10-05 06:18:00], - end_date: ~N[2023-10-05 06:18:00] - } - end + alias ElixirConfAfrica.Tickets.Ticket + alias ElixirConfAfrica.TicketTypes.TicketType + alias ElixirConfAfrica.Accounts.User - def build(:elixir_conf_ticket_type) do - %ElixirConfAfrica.TicketTypes.TicketType{ + def ticket_type_factory do + %TicketType{ name: "some name", description: "some description", - price: Decimal.new("120.5"), - number: 357 + price: 42, + number: 49 } end - def build(factory_name, attributes) do - factory_name |> build() |> struct!(attributes) + def ticket_factory do + %Ticket{ + ticketid: Integer.to_string(System.unique_integer([:positive])), + email: sequence(:email, fn n -> "email-#{n}@example" end), + cost: 400, + quantity: 1 + } end - def insert!(factory_name, attributes \\ []) do - factory_name |> build(attributes) |> Repo.insert!() + def user_factory do + %User{ + email: "some email", + password: "some password" + } end end From 0191be1f1ab30a5bf84a74b3f6fa869d836abe45 Mon Sep 17 00:00:00 2001 From: MICHAELMUNAVU83 Date: Tue, 23 Jan 2024 13:22:47 +0300 Subject: [PATCH 3/4] Fixed credo issues --- lib/elixir_conf_africa/accounts.ex | 15 ++++++--------- lib/elixir_conf_africa/ticket_types.ex | 25 +++++++++++++------------ lib/elixir_conf_africa/tickets.ex | 25 +++++++++++-------------- 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/lib/elixir_conf_africa/accounts.ex b/lib/elixir_conf_africa/accounts.ex index 72eff1a..ec7b802 100644 --- a/lib/elixir_conf_africa/accounts.ex +++ b/lib/elixir_conf_africa/accounts.ex @@ -32,16 +32,13 @@ defmodule ElixirConfAfrica.Accounts do """ def list_users_apart_from_current_user(current_user) do - from(u in User, - where: u.id != ^current_user.id, - order_by: u.email, - select: u + Repo.all( + from(u in User, + where: u.id != ^current_user.id, + order_by: u.email, + select: u + ) ) - |> Repo.all() - end - - def list_users do - Repo.all(User) end @doc """ diff --git a/lib/elixir_conf_africa/ticket_types.ex b/lib/elixir_conf_africa/ticket_types.ex index e0b6098..07d7ea0 100644 --- a/lib/elixir_conf_africa/ticket_types.ex +++ b/lib/elixir_conf_africa/ticket_types.ex @@ -29,19 +29,20 @@ defmodule ElixirConfAfrica.TicketTypes do """ def list_ticket_types_with_remaining_tickets do - from(tick in TicketType, - left_join: t in Ticket, - on: t.ticket_type_id == tick.id and t.is_paid == true and t.is_refunded == false, - group_by: tick.id, - select: %{ - id: tick.id, - name: tick.name, - remaining_tickets: coalesce(tick.number - count(t.id), 0), - description: tick.description, - price: tick.price - } + Repo.all( + from(tick in TicketType, + left_join: t in Ticket, + on: t.ticket_type_id == tick.id and t.is_paid == true and t.is_refunded == false, + group_by: tick.id, + select: %{ + id: tick.id, + name: tick.name, + remaining_tickets: coalesce(tick.number - count(t.id), 0), + description: tick.description, + price: tick.price + } + ) ) - |> Repo.all() end @doc """ diff --git a/lib/elixir_conf_africa/tickets.ex b/lib/elixir_conf_africa/tickets.ex index 1d034eb..492983a 100644 --- a/lib/elixir_conf_africa/tickets.ex +++ b/lib/elixir_conf_africa/tickets.ex @@ -26,18 +26,19 @@ defmodule ElixirConfAfrica.Tickets do """ - def get_ticket_by_ticketid!(ticketid), - do: Repo.get_by!(Ticket, ticketid: ticketid) |> Repo.preload(:ticket_type) + def get_ticket_by_ticketid!(ticketid) do + Ticket + |> Repo.get_by!(ticketid: ticketid) + |> Repo.preload(:ticket_type) + end @doc """ List paid tickets. """ def list_paid_tickets do - from(t in Ticket, - where: t.is_paid == true and t.is_refunded == false, - select: t - ) + Ticket + |> where([t], t.is_paid == true and t.is_refunded == false) |> Repo.all() |> Repo.preload(:ticket_type) end @@ -47,10 +48,8 @@ defmodule ElixirConfAfrica.Tickets do """ def list_refunded_tickets do - from(t in Ticket, - where: t.is_refunded == true, - select: t - ) + Ticket + |> where([t], t.is_refunded == true) |> Repo.all() |> Repo.preload(:ticket_type) end @@ -60,10 +59,8 @@ defmodule ElixirConfAfrica.Tickets do """ def list_unpaid_tickets do - from(t in Ticket, - where: t.is_paid == false and t.is_refunded == false, - select: t - ) + Ticket + |> where([t], t.is_paid == false and t.is_refunded == false) |> Repo.all() |> Repo.preload(:ticket_type) end From 0bbc80473478b9c26ccb81b8a5dfbb2f97409764 Mon Sep 17 00:00:00 2001 From: MICHAELMUNAVU83 Date: Tue, 23 Jan 2024 13:36:42 +0300 Subject: [PATCH 4/4] Added code readability --- lib/elixir_conf_africa/accounts.ex | 3 +-- lib/elixir_conf_africa/paystack.ex | 4 ++-- lib/elixir_conf_africa/ticket_types.ex | 2 +- lib/elixir_conf_africa_web/live/event_live/index.ex | 3 ++- lib/elixir_conf_africa_web/live/paid_ticket_live/index.ex | 2 +- lib/elixir_conf_africa_web/live/ticket_live/form_component.ex | 3 +-- lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.ex | 2 +- test/elixir_conf_africa/ticket_types_test.exs | 2 +- test/elixir_conf_africa/tickets_test.exs | 2 +- test/elixir_conf_africa_web/user_auth_test.exs | 2 +- test/support/factory.ex | 3 +-- 11 files changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/elixir_conf_africa/accounts.ex b/lib/elixir_conf_africa/accounts.ex index ec7b802..cbc2b77 100644 --- a/lib/elixir_conf_africa/accounts.ex +++ b/lib/elixir_conf_africa/accounts.ex @@ -4,10 +4,9 @@ defmodule ElixirConfAfrica.Accounts do """ import Ecto.Query, warn: false + alias ElixirConfAfrica.Accounts.{User, UserNotifier, UserToken} alias ElixirConfAfrica.Repo - alias ElixirConfAfrica.Accounts.{User, UserToken, UserNotifier} - ## Database getters @doc """ diff --git a/lib/elixir_conf_africa/paystack.ex b/lib/elixir_conf_africa/paystack.ex index 8c6fa64..6b7a870 100644 --- a/lib/elixir_conf_africa/paystack.ex +++ b/lib/elixir_conf_africa/paystack.ex @@ -2,9 +2,9 @@ defmodule ElixirConfAfrica.Paystack do @moduledoc """ The Paystack module is responsible for all the interactions with the Paystack API """ - defp api_url(), do: "https://api.paystack.co/transaction/initialize" + defp api_url, do: "https://api.paystack.co/transaction/initialize" - defp paystack_headers(), + defp paystack_headers, do: [ { "Content-Type", diff --git a/lib/elixir_conf_africa/ticket_types.ex b/lib/elixir_conf_africa/ticket_types.ex index 07d7ea0..0432c77 100644 --- a/lib/elixir_conf_africa/ticket_types.ex +++ b/lib/elixir_conf_africa/ticket_types.ex @@ -6,8 +6,8 @@ defmodule ElixirConfAfrica.TicketTypes do import Ecto.Query, warn: false alias ElixirConfAfrica.Repo - alias ElixirConfAfrica.TicketTypes.TicketType alias ElixirConfAfrica.Tickets.Ticket + alias ElixirConfAfrica.TicketTypes.TicketType @doc """ Returns the list of ticket_types. diff --git a/lib/elixir_conf_africa_web/live/event_live/index.ex b/lib/elixir_conf_africa_web/live/event_live/index.ex index 4601a44..a9667da 100644 --- a/lib/elixir_conf_africa_web/live/event_live/index.ex +++ b/lib/elixir_conf_africa_web/live/event_live/index.ex @@ -1,7 +1,8 @@ defmodule ElixirConfAfricaWeb.EventLive.Index do use ElixirConfAfricaWeb, :live_view - alias ElixirConfAfrica.TicketTypes + alias ElixirConfAfrica.Tickets.Ticket + alias ElixirConfAfrica.TicketTypes @impl true def mount(_params, _session, socket) do ticket_types = TicketTypes.list_ticket_types_with_remaining_tickets() diff --git a/lib/elixir_conf_africa_web/live/paid_ticket_live/index.ex b/lib/elixir_conf_africa_web/live/paid_ticket_live/index.ex index e5e48c1..ca7f5bd 100644 --- a/lib/elixir_conf_africa_web/live/paid_ticket_live/index.ex +++ b/lib/elixir_conf_africa_web/live/paid_ticket_live/index.ex @@ -1,8 +1,8 @@ defmodule ElixirConfAfricaWeb.PaidTicketLive.Index do use ElixirConfAfricaWeb, :admin_live_view - alias ElixirConfAfrica.Tickets alias ElixirConfAfrica.Emails + alias ElixirConfAfrica.Tickets @impl true def mount(_params, _session, socket) do diff --git a/lib/elixir_conf_africa_web/live/ticket_live/form_component.ex b/lib/elixir_conf_africa_web/live/ticket_live/form_component.ex index 5b2c05c..c95c94c 100644 --- a/lib/elixir_conf_africa_web/live/ticket_live/form_component.ex +++ b/lib/elixir_conf_africa_web/live/ticket_live/form_component.ex @@ -1,8 +1,7 @@ defmodule ElixirConfAfricaWeb.TicketLive.FormComponent do use ElixirConfAfricaWeb, :live_component - - alias ElixirConfAfrica.Tickets alias ElixirConfAfrica.Paystack + alias ElixirConfAfrica.Tickets @impl true def update(%{ticket: ticket} = assigns, socket) do diff --git a/lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.ex b/lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.ex index b97c157..8fcab0c 100644 --- a/lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.ex +++ b/lib/elixir_conf_africa_web/live/unpaid_ticket_live/index.ex @@ -1,10 +1,10 @@ defmodule ElixirConfAfricaWeb.UnPaidTicketLive.Index do use ElixirConfAfricaWeb, :admin_live_view + alias ElixirConfAfrica.Emails alias ElixirConfAfrica.Tickets alias ElixirConfAfrica.Paystack - alias ElixirConfAfrica.Emails @impl true def mount(_params, _session, socket) do {:ok, assign(socket, :ticket_collection, list_unpaid_tickets())} diff --git a/test/elixir_conf_africa/ticket_types_test.exs b/test/elixir_conf_africa/ticket_types_test.exs index 6aa866c..237c419 100644 --- a/test/elixir_conf_africa/ticket_types_test.exs +++ b/test/elixir_conf_africa/ticket_types_test.exs @@ -4,8 +4,8 @@ defmodule ElixirConfAfrica.TicketTypesTest do alias ElixirConfAfrica.Factory describe "ticket_types" do - alias ElixirConfAfrica.TicketTypes.TicketType alias ElixirConfAfrica.TicketTypes + alias ElixirConfAfrica.TicketTypes.TicketType @invalid_attrs %{name: nil, description: nil, price: nil} diff --git a/test/elixir_conf_africa/tickets_test.exs b/test/elixir_conf_africa/tickets_test.exs index 1a56961..f5948e8 100644 --- a/test/elixir_conf_africa/tickets_test.exs +++ b/test/elixir_conf_africa/tickets_test.exs @@ -1,8 +1,8 @@ defmodule ElixirConfAfrica.TicketsTest do use ElixirConfAfrica.DataCase - alias ElixirConfAfrica.Tickets alias ElixirConfAfrica.Factory + alias ElixirConfAfrica.Tickets alias ElixirConfAfrica.Tickets.Ticket describe "ticket" do diff --git a/test/elixir_conf_africa_web/user_auth_test.exs b/test/elixir_conf_africa_web/user_auth_test.exs index 4751396..d6d70d2 100644 --- a/test/elixir_conf_africa_web/user_auth_test.exs +++ b/test/elixir_conf_africa_web/user_auth_test.exs @@ -1,9 +1,9 @@ defmodule ElixirConfAfricaWeb.UserAuthTest do use ElixirConfAfricaWeb.ConnCase, async: true - alias Phoenix.LiveView alias ElixirConfAfrica.Accounts alias ElixirConfAfricaWeb.UserAuth + alias Phoenix.LiveView import ElixirConfAfrica.AccountsFixtures @remember_me_cookie "_elixir_conf_africa_web_user_remember_me" diff --git a/test/support/factory.ex b/test/support/factory.ex index f5da8a3..f9f02d8 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -1,10 +1,9 @@ defmodule ElixirConfAfrica.Factory do @moduledoc false use ExMachina.Ecto, repo: ElixirConfAfrica.Repo - + alias ElixirConfAfrica.Accounts.User alias ElixirConfAfrica.Tickets.Ticket alias ElixirConfAfrica.TicketTypes.TicketType - alias ElixirConfAfrica.Accounts.User def ticket_type_factory do %TicketType{