diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 61a7393..0000000 --- a/.dockerignore +++ /dev/null @@ -1,45 +0,0 @@ -# This file excludes paths from the Docker build context. -# -# By default, Docker's build context includes all files (and folders) in the -# current directory. Even if a file isn't copied into the container it is still sent to -# the Docker daemon. -# -# There are multiple reasons to exclude files from the build context: -# -# 1. Prevent nested folders from being copied into the container (ex: exclude -# /assets/node_modules when copying /assets) -# 2. Reduce the size of the build context and improve build time (ex. /build, /deps, /doc) -# 3. Avoid sending files containing sensitive information -# -# More information on using .dockerignore is available here: -# https://docs.docker.com/engine/reference/builder/#dockerignore-file - -.dockerignore - -# Ignore git, but keep git HEAD and refs to access current commit hash if needed: -# -# $ cat .git/HEAD | awk '{print ".git/"$2}' | xargs cat -# d0b8727759e1e0e7aa3d41707d12376e373d5ecc -.git -!.git/HEAD -!.git/refs - -# Common development/test artifacts -/cover/ -/doc/ -/test/ -/tmp/ -.elixir_ls - -# Mix artifacts -/_build/ -/deps/ -*.ez - -# Generated on crash by the VM -erl_crash.dump - -# Static artifacts - These should be fetched and built inside the Docker image -/assets/node_modules/ -/priv/static/assets/ -/priv/static/cache_manifest.json diff --git a/.formatter.exs b/.formatter.exs deleted file mode 100644 index ef8840c..0000000 --- a/.formatter.exs +++ /dev/null @@ -1,6 +0,0 @@ -[ - import_deps: [:ecto, :ecto_sql, :phoenix], - subdirectories: ["priv/*/migrations"], - plugins: [Phoenix.LiveView.HTMLFormatter], - inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"] -] diff --git a/.gitignore b/.gitignore deleted file mode 100644 index f9a51dc..0000000 --- a/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# The directory Mix will write compiled artifacts to. -/_build/ - -# If you run "mix test --cover", coverage assets end up here. -/cover/ - -# The directory Mix downloads your dependencies sources to. -/deps/ - -# Where 3rd-party dependencies like ExDoc output generated docs. -/doc/ - -# Ignore .fetch files in case you like to edit your project deps locally. -/.fetch - -# If the VM crashes, it generates a dump, let's ignore it too. -erl_crash.dump - -# Also ignore archive artifacts (built via "mix archive.build"). -*.ez - -# Temporary files, for example, from tests. -/tmp/ - -# Ignore package tarball (built via "mix hex.build"). -potion-*.tar - -# Ignore assets that are produced by build tools. -/priv/static/assets/ - -# Ignore digested assets cache. -/priv/static/cache_manifest.json - -# In case you use Node.js/npm, you want to ignore these. -npm-debug.log -/assets/node_modules/ - -# Environment variables -.env - -docker-compose.yml diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 22f4752..0000000 --- a/Dockerfile +++ /dev/null @@ -1,99 +0,0 @@ -# Find eligible builder and runner images on Docker Hub. We use Ubuntu/Debian -# instead of Alpine to avoid DNS resolution issues in production. -# -# https://hub.docker.com/r/hexpm/elixir/tags?page=1&name=ubuntu -# https://hub.docker.com/_/ubuntu?tab=tags -# -# This file is based on these images: -# -# - https://hub.docker.com/r/hexpm/elixir/tags - for the build image -# - https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye-20241202-slim - for the release image -# - https://pkgs.org/ - resource for finding needed packages -# - Ex: hexpm/elixir:1.17.3-erlang-25.3.2.15-debian-bullseye-20241202-slim -# -ARG ELIXIR_VERSION=1.17.3 -ARG OTP_VERSION=25.3.2.15 -ARG DEBIAN_VERSION=bullseye-20241202-slim - -ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}" -ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}" - -FROM ${BUILDER_IMAGE} as builder - -# install build dependencies -RUN apt-get update -y && apt-get install -y build-essential git \ - && apt-get clean && rm -f /var/lib/apt/lists/*_* - -# prepare build dir -WORKDIR /app - -# install hex + rebar -RUN mix local.hex --force && \ - mix local.rebar --force - -# set build ENV -ENV MIX_ENV="prod" - -# install mix dependencies -COPY mix.exs mix.lock ./ -RUN mix deps.get --only $MIX_ENV -RUN mkdir config - -# copy compile-time config files before we compile dependencies -# to ensure any relevant config change will trigger the dependencies -# to be re-compiled. -COPY config/config.exs config/${MIX_ENV}.exs config/ -RUN mix deps.compile - -COPY priv priv - -COPY lib lib - -COPY assets assets - -# compile assets -RUN mix assets.deploy - -# Compile the release -RUN mix compile - -# Changes to config/runtime.exs don't require recompiling the code -COPY config/runtime.exs config/ - -COPY rel rel -RUN mix release - -# start a new build stage so that the final image will only contain -# the compiled release and other runtime necessities -FROM ${RUNNER_IMAGE} - -RUN apt-get update -y && \ - apt-get install -y libstdc++6 openssl libncurses5 locales ca-certificates \ - && apt-get clean && rm -f /var/lib/apt/lists/*_* - -# Set the locale -RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen - -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 - -WORKDIR "/app" -RUN chown nobody /app - -# set runner ENV -ENV MIX_ENV="prod" - -# Only copy the final release from the build stage -COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/potion ./ - -USER nobody - -# If using an environment that doesn't automatically reap zombie processes, it is -# advised to add an init process such as tini via `apt-get install` -# above and adding an entrypoint. See https://github.com/krallin/tini for details -# ENTRYPOINT ["/tini", "--"] - -EXPOSE 4000 - -CMD ["/app/bin/server"] diff --git a/README.md b/README.md deleted file mode 100644 index 43017b9..0000000 --- a/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Potion - -To start your Phoenix server: - - * Run `mix setup` to install and setup dependencies - * Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server` - -Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. - -Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). - -## Learn more - - * Official website: https://www.phoenixframework.org/ - * Guides: https://hexdocs.pm/phoenix/overview.html - * Docs: https://hexdocs.pm/phoenix - * Forum: https://elixirforum.com/c/phoenix-forum - * Source: https://github.com/phoenixframework/phoenix diff --git a/spec/TechnicalSpecification.md b/TechnicalSpecification.md similarity index 100% rename from spec/TechnicalSpecification.md rename to TechnicalSpecification.md diff --git a/assets/css/app.css b/assets/css/app.css deleted file mode 100644 index 378c8f9..0000000 --- a/assets/css/app.css +++ /dev/null @@ -1,5 +0,0 @@ -@import "tailwindcss/base"; -@import "tailwindcss/components"; -@import "tailwindcss/utilities"; - -/* This file is for your main application CSS */ diff --git a/assets/js/app.js b/assets/js/app.js deleted file mode 100644 index d5e278a..0000000 --- a/assets/js/app.js +++ /dev/null @@ -1,44 +0,0 @@ -// If you want to use Phoenix channels, run `mix help phx.gen.channel` -// to get started and then uncomment the line below. -// import "./user_socket.js" - -// You can include dependencies in two ways. -// -// The simplest option is to put them in assets/vendor and -// import them using relative paths: -// -// import "../vendor/some-package.js" -// -// Alternatively, you can `npm install some-package --prefix assets` and import -// them using a path starting with the package name: -// -// import "some-package" -// - -// Include phoenix_html to handle method=PUT/DELETE in forms and buttons. -import "phoenix_html" -// Establish Phoenix Socket and LiveView configuration. -import {Socket} from "phoenix" -import {LiveSocket} from "phoenix_live_view" -import topbar from "../vendor/topbar" - -let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") -let liveSocket = new LiveSocket("/live", Socket, { - longPollFallbackMs: 2500, - params: {_csrf_token: csrfToken} -}) - -// Show progress bar on live navigation and form submits -topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) -window.addEventListener("phx:page-loading-start", _info => topbar.show(300)) -window.addEventListener("phx:page-loading-stop", _info => topbar.hide()) - -// connect if there are any LiveViews on the page -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 - diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js deleted file mode 100644 index d33f807..0000000 --- a/assets/tailwind.config.js +++ /dev/null @@ -1,89 +0,0 @@ -// See the Tailwind configuration guide for advanced usage -// https://tailwindcss.com/docs/configuration - -const plugin = require("tailwindcss/plugin") -const fs = require("fs") -const path = require("path") - -module.exports = { - content: [ - "./js/**/*.js", - "../lib/potion_web.ex", - "../lib/potion_web/**/*.*ex" - ], - theme: { - extend: { - colors: { - background: { - 100: "#979ca1", - 200: "#717880", - 300: "#383D43", - 400: "#272B2E", - 500: "#1A1E21", - 600: "#0E1213", - }, - primary: { - 200: "#9e11f7", - 300: "#970af0", - 400: "#8a0bd9", - 500: "#6707a3", - 600: "#4a0575", - 700: "#2a0442", - }, - } - }, - }, - plugins: [ - require("@tailwindcss/forms"), - // Allows prefixing tailwind classes with LiveView classes to add rules - // only when LiveView classes are applied, for example: - // - //
- // - plugin(({ addVariant }) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])), - plugin(({ addVariant }) => addVariant("phx-submit-loading", [".phx-submit-loading&", ".phx-submit-loading &"])), - plugin(({ addVariant }) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"])), - - // Embeds Heroicons (https://heroicons.com) into your app.css bundle - // See your `CoreComponents.icon/1` for more information. - // - plugin(function({ matchComponents, theme }) { - let iconsDir = path.join(__dirname, "../deps/heroicons/optimized") - let values = {} - let icons = [ - ["", "/24/outline"], - ["-solid", "/24/solid"], - ["-mini", "/20/solid"], - ["-micro", "/16/solid"] - ] - icons.forEach(([suffix, dir]) => { - fs.readdirSync(path.join(iconsDir, dir)).forEach(file => { - let name = path.basename(file, ".svg") + suffix - values[name] = { name, fullPath: path.join(iconsDir, dir, file) } - }) - }) - matchComponents({ - "hero": ({ name, fullPath }) => { - let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "") - let size = theme("spacing.6") - if (name.endsWith("-mini")) { - size = theme("spacing.5") - } else if (name.endsWith("-micro")) { - size = theme("spacing.4") - } - return { - [`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`, - "-webkit-mask": `var(--hero-${name})`, - "mask": `var(--hero-${name})`, - "mask-repeat": "no-repeat", - "background-color": "currentColor", - "vertical-align": "middle", - "display": "inline-block", - "width": size, - "height": size - } - } - }, { values }) - }) - ] -} diff --git a/assets/vendor/topbar.js b/assets/vendor/topbar.js deleted file mode 100644 index 4195727..0000000 --- a/assets/vendor/topbar.js +++ /dev/null @@ -1,165 +0,0 @@ -/** - * @license MIT - * topbar 2.0.0, 2023-02-04 - * https://buunguyen.github.io/topbar - * Copyright (c) 2021 Buu Nguyen - */ -(function (window, document) { - "use strict"; - - // https://gist.github.com/paulirish/1579671 - (function () { - var lastTime = 0; - var vendors = ["ms", "moz", "webkit", "o"]; - for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { - window.requestAnimationFrame = - window[vendors[x] + "RequestAnimationFrame"]; - window.cancelAnimationFrame = - window[vendors[x] + "CancelAnimationFrame"] || - window[vendors[x] + "CancelRequestAnimationFrame"]; - } - if (!window.requestAnimationFrame) - window.requestAnimationFrame = function (callback, element) { - var currTime = new Date().getTime(); - var timeToCall = Math.max(0, 16 - (currTime - lastTime)); - var id = window.setTimeout(function () { - callback(currTime + timeToCall); - }, timeToCall); - lastTime = currTime + timeToCall; - return id; - }; - if (!window.cancelAnimationFrame) - window.cancelAnimationFrame = function (id) { - clearTimeout(id); - }; - })(); - - var canvas, - currentProgress, - showing, - progressTimerId = null, - fadeTimerId = null, - delayTimerId = null, - addEvent = function (elem, type, handler) { - if (elem.addEventListener) elem.addEventListener(type, handler, false); - else if (elem.attachEvent) elem.attachEvent("on" + type, handler); - else elem["on" + type] = handler; - }, - options = { - autoRun: true, - barThickness: 3, - barColors: { - 0: "rgba(26, 188, 156, .9)", - ".25": "rgba(52, 152, 219, .9)", - ".50": "rgba(241, 196, 15, .9)", - ".75": "rgba(230, 126, 34, .9)", - "1.0": "rgba(211, 84, 0, .9)", - }, - shadowBlur: 10, - shadowColor: "rgba(0, 0, 0, .6)", - className: null, - }, - repaint = function () { - canvas.width = window.innerWidth; - canvas.height = options.barThickness * 5; // need space for shadow - - var ctx = canvas.getContext("2d"); - ctx.shadowBlur = options.shadowBlur; - ctx.shadowColor = options.shadowColor; - - var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0); - for (var stop in options.barColors) - lineGradient.addColorStop(stop, options.barColors[stop]); - ctx.lineWidth = options.barThickness; - ctx.beginPath(); - ctx.moveTo(0, options.barThickness / 2); - ctx.lineTo( - Math.ceil(currentProgress * canvas.width), - options.barThickness / 2 - ); - ctx.strokeStyle = lineGradient; - ctx.stroke(); - }, - createCanvas = function () { - canvas = document.createElement("canvas"); - var style = canvas.style; - style.position = "fixed"; - style.top = style.left = style.right = style.margin = style.padding = 0; - style.zIndex = 100001; - style.display = "none"; - if (options.className) canvas.classList.add(options.className); - document.body.appendChild(canvas); - addEvent(window, "resize", repaint); - }, - topbar = { - config: function (opts) { - for (var key in opts) - if (options.hasOwnProperty(key)) options[key] = opts[key]; - }, - show: function (delay) { - if (showing) return; - if (delay) { - if (delayTimerId) return; - delayTimerId = setTimeout(() => topbar.show(), delay); - } else { - showing = true; - if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId); - if (!canvas) createCanvas(); - canvas.style.opacity = 1; - canvas.style.display = "block"; - topbar.progress(0); - if (options.autoRun) { - (function loop() { - progressTimerId = window.requestAnimationFrame(loop); - topbar.progress( - "+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2) - ); - })(); - } - } - }, - progress: function (to) { - if (typeof to === "undefined") return currentProgress; - if (typeof to === "string") { - to = - (to.indexOf("+") >= 0 || to.indexOf("-") >= 0 - ? currentProgress - : 0) + parseFloat(to); - } - currentProgress = to > 1 ? 1 : to; - repaint(); - return currentProgress; - }, - hide: function () { - clearTimeout(delayTimerId); - delayTimerId = null; - if (!showing) return; - showing = false; - if (progressTimerId != null) { - window.cancelAnimationFrame(progressTimerId); - progressTimerId = null; - } - (function loop() { - if (topbar.progress("+.1") >= 1) { - canvas.style.opacity -= 0.05; - if (canvas.style.opacity <= 0.05) { - canvas.style.display = "none"; - fadeTimerId = null; - return; - } - } - fadeTimerId = window.requestAnimationFrame(loop); - })(); - }, - }; - - if (typeof module === "object" && typeof module.exports === "object") { - module.exports = topbar; - } else if (typeof define === "function" && define.amd) { - define(function () { - return topbar; - }); - } else { - this.topbar = topbar; - } -}.call(this, window, document)); diff --git a/config/config.exs b/config/config.exs deleted file mode 100644 index 9682806..0000000 --- a/config/config.exs +++ /dev/null @@ -1,66 +0,0 @@ -# This file is responsible for configuring your application -# and its dependencies with the aid of the Config module. -# -# This configuration file is loaded before any dependency and -# is restricted to this project. - -# General application configuration -import Config - -config :potion, - ecto_repos: [Potion.Repo], - generators: [timestamp_type: :utc_datetime] - -# Configures the endpoint -config :potion, PotionWeb.Endpoint, - url: [host: "localhost"], - adapter: Bandit.PhoenixAdapter, - render_errors: [ - formats: [html: PotionWeb.ErrorHTML, json: PotionWeb.ErrorJSON], - layout: false - ], - pubsub_server: Potion.PubSub, - live_view: [signing_salt: "ANu80653"] - -# Configures the mailer -# -# By default it uses the "Local" adapter which stores the emails -# locally. You can see the emails in your browser, at "/dev/mailbox". -# -# For production it's recommended to configure a different adapter -# at the `config/runtime.exs`. -config :potion, Potion.Mailer, adapter: Swoosh.Adapters.Local - -# Configure esbuild (the version is required) -config :esbuild, - version: "0.17.11", - potion: [ - args: - ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*), - cd: Path.expand("../assets", __DIR__), - env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} - ] - -# Configure tailwind (the version is required) -config :tailwind, - version: "3.4.3", - potion: [ - args: ~w( - --config=tailwind.config.js - --input=css/app.css - --output=../priv/static/assets/app.css - ), - cd: Path.expand("../assets", __DIR__) - ] - -# Configures Elixir's Logger -config :logger, :console, - format: "$time $metadata[$level] $message\n", - metadata: [:request_id] - -# Use Jason for JSON parsing in Phoenix -config :phoenix, :json_library, Jason - -# Import environment specific config. This must remain at the bottom -# of this file so it overrides the configuration defined above. -import_config "#{config_env()}.exs" diff --git a/config/dev.exs b/config/dev.exs deleted file mode 100644 index bc5346a..0000000 --- a/config/dev.exs +++ /dev/null @@ -1,85 +0,0 @@ -import Config - -# Configure your database -config :potion, Potion.Repo, - username: System.get_env("DB_USERNAME") || "postgres", - password: System.get_env("DB_PASSWORD") || "postgres", - hostname: System.get_env("DB_HOSTNAME") || "localhost", - database: System.get_env("DB_DATABASE") || "potion_dev", - stacktrace: true, - show_sensitive_data_on_connection_error: true, - pool_size: 10 - -# For development, we disable any cache and enable -# debugging and code reloading. -# -# The watchers configuration can be used to run external -# watchers to your application. For example, we can use it -# to bundle .js and .css sources. -config :potion, PotionWeb.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], - check_origin: false, - code_reloader: true, - debug_errors: true, - secret_key_base: "aPeC2boibS77yIuu9VD8sf2sfALOcDssDM3xgLxniyiUEpDMlTO/QzO5LRFNPaIL", - watchers: [ - esbuild: {Esbuild, :install_and_run, [:potion, ~w(--sourcemap=inline --watch)]}, - tailwind: {Tailwind, :install_and_run, [:potion, ~w(--watch)]} - ] - -# ## SSL Support -# -# In order to use HTTPS in development, a self-signed -# certificate can be generated by running the following -# Mix task: -# -# mix phx.gen.cert -# -# Run `mix help phx.gen.cert` for more information. -# -# The `http:` config above can be replaced with: -# -# https: [ -# port: 4001, -# cipher_suite: :strong, -# keyfile: "priv/cert/selfsigned_key.pem", -# certfile: "priv/cert/selfsigned.pem" -# ], -# -# If desired, both `http:` and `https:` keys can be -# configured to run both http and https servers on -# different ports. - -# Watch static and templates for browser reloading. -config :potion, PotionWeb.Endpoint, - live_reload: [ - patterns: [ - ~r"priv/static/(?!uploads/).*(js|css|png|jpeg|jpg|gif|svg)$", - ~r"priv/gettext/.*(po)$", - ~r"lib/potion_web/(controllers|live|components)/.*(ex|heex)$" - ] - ] - -# Enable dev routes for dashboard and mailbox -config :potion, dev_routes: true - -# Do not include metadata nor timestamps in development logs -config :logger, :console, format: "[$level] $message\n" - -# Set a higher stacktrace during development. Avoid configuring such -# in production as building large stacktraces may be expensive. -config :phoenix, :stacktrace_depth, 20 - -# Initialize plugs at runtime for faster development compilation -config :phoenix, :plug_init_mode, :runtime - -config :phoenix_live_view, - # Include HEEx debug annotations as HTML comments in rendered markup - debug_heex_annotations: true, - # Enable helpful, but potentially expensive runtime checks - enable_expensive_runtime_checks: true - -# Disable swoosh api client as it is only required for production adapters. -config :swoosh, :api_client, false diff --git a/config/prod.exs b/config/prod.exs deleted file mode 100644 index 8a3cf30..0000000 --- a/config/prod.exs +++ /dev/null @@ -1,20 +0,0 @@ -import Config - -# Note we also include the path to a cache manifest -# containing the digested version of static files. This -# manifest is generated by the `mix assets.deploy` task, -# which you should run after static files are built and -# before starting your production server. -config :potion, PotionWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json" - -# Configures Swoosh API Client -config :swoosh, api_client: Swoosh.ApiClient.Finch, finch_name: Potion.Finch - -# Disable Swoosh Local Memory Storage -config :swoosh, local: false - -# Do not print debug messages in production -config :logger, level: :info - -# Runtime production configuration, including reading -# of environment variables, is done on config/runtime.exs. diff --git a/config/runtime.exs b/config/runtime.exs deleted file mode 100644 index 6a9c9e7..0000000 --- a/config/runtime.exs +++ /dev/null @@ -1,117 +0,0 @@ -import Config - -# config/runtime.exs is executed for all environments, including -# during releases. It is executed after compilation and before the -# system starts, so it is typically used to load production configuration -# and secrets from environment variables or elsewhere. Do not define -# any compile-time configuration in here, as it won't be applied. -# The block below contains prod specific runtime configuration. - -# ## Using releases -# -# If you use `mix release`, you need to explicitly enable the server -# by passing the PHX_SERVER=true when you start it: -# -# PHX_SERVER=true bin/potion start -# -# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` -# script that automatically sets the env var above. -if System.get_env("PHX_SERVER") do - config :potion, PotionWeb.Endpoint, server: true -end - -if config_env() == :prod do - database_url = - System.get_env("DATABASE_URL") || - raise """ - environment variable DATABASE_URL is missing. - For example: ecto://USER:PASS@HOST/DATABASE - """ - - maybe_ipv6 = if System.get_env("ECTO_IPV6") in ~w(true 1), do: [:inet6], else: [] - - config :potion, Potion.Repo, - # ssl: true, - url: database_url, - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), - socket_options: maybe_ipv6 - - # The secret key base is used to sign/encrypt cookies and other secrets. - # A default value is used in config/dev.exs and config/test.exs but you - # want to use a different value for prod and you most likely don't want - # to check this value into version control, so we use an environment - # variable instead. - secret_key_base = - System.get_env("SECRET_KEY_BASE") || - raise """ - environment variable SECRET_KEY_BASE is missing. - You can generate one by calling: mix phx.gen.secret - """ - - host = System.get_env("PHX_HOST") || "example.com" - port = String.to_integer(System.get_env("PORT") || "4000") - - config :potion, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY") - - config :potion, PotionWeb.Endpoint, - url: [host: host, port: 443, scheme: "https"], - http: [ - # Enable IPv6 and bind on all interfaces. - # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. - # See the documentation on https://hexdocs.pm/bandit/Bandit.html#t:options/0 - # for details about using IPv6 vs IPv4 and loopback vs public addresses. - ip: {0, 0, 0, 0, 0, 0, 0, 0}, - port: port - ], - secret_key_base: secret_key_base - - # ## SSL Support - # - # To get SSL working, you will need to add the `https` key - # to your endpoint configuration: - # - # config :potion, PotionWeb.Endpoint, - # https: [ - # ..., - # port: 443, - # cipher_suite: :strong, - # keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"), - # certfile: System.get_env("SOME_APP_SSL_CERT_PATH") - # ] - # - # The `cipher_suite` is set to `:strong` to support only the - # latest and more secure SSL ciphers. This means old browsers - # and clients may not be supported. You can set it to - # `:compatible` for wider support. - # - # `:keyfile` and `:certfile` expect an absolute path to the key - # and cert in disk or a relative path inside priv, for example - # "priv/ssl/server.key". For all supported SSL configuration - # options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1 - # - # We also recommend setting `force_ssl` in your config/prod.exs, - # ensuring no data is ever sent via http, always redirecting to https: - # - # config :potion, PotionWeb.Endpoint, - # force_ssl: [hsts: true] - # - # Check `Plug.SSL` for all available options in `force_ssl`. - - # ## Configuring the mailer - # - # In production you need to configure the mailer to use a different adapter. - # Also, you may need to configure the Swoosh API client of your choice if you - # are not using SMTP. Here is an example of the configuration: - # - # config :potion, Potion.Mailer, - # adapter: Swoosh.Adapters.Mailgun, - # api_key: System.get_env("MAILGUN_API_KEY"), - # domain: System.get_env("MAILGUN_DOMAIN") - # - # For this example you need include a HTTP client required by Swoosh API client. - # Swoosh supports Hackney and Finch out of the box: - # - # config :swoosh, :api_client, Swoosh.ApiClient.Hackney - # - # See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details. -end diff --git a/config/test.exs b/config/test.exs deleted file mode 100644 index 4acb56a..0000000 --- a/config/test.exs +++ /dev/null @@ -1,37 +0,0 @@ -import Config - -# Configure your database -# -# The MIX_TEST_PARTITION environment variable can be used -# to provide built-in test partitioning in CI environment. -# Run `mix help test` for more information. -config :potion, Potion.Repo, - username: "postgres", - password: "postgres", - hostname: "localhost", - database: "potion_test#{System.get_env("MIX_TEST_PARTITION")}", - pool: Ecto.Adapters.SQL.Sandbox, - pool_size: System.schedulers_online() * 2 - -# We don't run a server during test. If one is required, -# you can enable the server option below. -config :potion, PotionWeb.Endpoint, - http: [ip: {127, 0, 0, 1}, port: 4002], - secret_key_base: "eSsJTahs71n2rVSbmSy1qni0WZ0x/K3t9sCKftjAbTBUS3XuNBqbDIw/Dvxna4xL", - server: false - -# In test we don't send emails -config :potion, Potion.Mailer, adapter: Swoosh.Adapters.Test - -# Disable swoosh api client as it is only required for production adapters -config :swoosh, :api_client, false - -# Print only warnings and errors during test -config :logger, level: :warning - -# Initialize plugs at runtime for faster test compilation -config :phoenix, :plug_init_mode, :runtime - -# Enable helpful, but potentially expensive runtime checks -config :phoenix_live_view, - enable_expensive_runtime_checks: true diff --git a/lib/potion.ex b/lib/potion.ex deleted file mode 100644 index fec14a4..0000000 --- a/lib/potion.ex +++ /dev/null @@ -1,9 +0,0 @@ -defmodule Potion do - @moduledoc """ - Potion keeps the contexts that define your domain - and business logic. - - Contexts are also responsible for managing your data, regardless - if it comes from the database, an external API or others. - """ -end diff --git a/lib/potion/application.ex b/lib/potion/application.ex deleted file mode 100644 index e1e3529..0000000 --- a/lib/potion/application.ex +++ /dev/null @@ -1,36 +0,0 @@ -defmodule Potion.Application do - # See https://hexdocs.pm/elixir/Application.html - # for more information on OTP Applications - @moduledoc false - - use Application - - @impl true - def start(_type, _args) do - children = [ - PotionWeb.Telemetry, - Potion.Repo, - {DNSCluster, query: Application.get_env(:potion, :dns_cluster_query) || :ignore}, - {Phoenix.PubSub, name: Potion.PubSub}, - # Start the Finch HTTP client for sending emails - {Finch, name: Potion.Finch}, - # Start a worker by calling: Potion.Worker.start_link(arg) - # {Potion.Worker, arg}, - # Start to serve requests, typically the last entry - PotionWeb.Endpoint - ] - - # See https://hexdocs.pm/elixir/Supervisor.html - # for other strategies and supported options - opts = [strategy: :one_for_one, name: Potion.Supervisor] - Supervisor.start_link(children, opts) - end - - # Tell Phoenix to update the endpoint configuration - # whenever the application is updated. - @impl true - def config_change(changed, _new, removed) do - PotionWeb.Endpoint.config_change(changed, removed) - :ok - end -end diff --git a/lib/potion/mailer.ex b/lib/potion/mailer.ex deleted file mode 100644 index 22e67c0..0000000 --- a/lib/potion/mailer.ex +++ /dev/null @@ -1,3 +0,0 @@ -defmodule Potion.Mailer do - use Swoosh.Mailer, otp_app: :potion -end diff --git a/lib/potion/release.ex b/lib/potion/release.ex deleted file mode 100644 index b4ad916..0000000 --- a/lib/potion/release.ex +++ /dev/null @@ -1,28 +0,0 @@ -defmodule Potion.Release do - @moduledoc """ - Used for executing DB release tasks when run in production without Mix - installed. - """ - @app :potion - - def migrate do - load_app() - - for repo <- repos() do - {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true)) - end - end - - def rollback(repo, version) do - load_app() - {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version)) - end - - defp repos do - Application.fetch_env!(@app, :ecto_repos) - end - - defp load_app do - Application.load(@app) - end -end diff --git a/lib/potion/repo.ex b/lib/potion/repo.ex deleted file mode 100644 index 0b96713..0000000 --- a/lib/potion/repo.ex +++ /dev/null @@ -1,5 +0,0 @@ -defmodule Potion.Repo do - use Ecto.Repo, - otp_app: :potion, - adapter: Ecto.Adapters.Postgres -end diff --git a/lib/potion_web.ex b/lib/potion_web.ex deleted file mode 100644 index 494c2c4..0000000 --- a/lib/potion_web.ex +++ /dev/null @@ -1,116 +0,0 @@ -defmodule PotionWeb do - @moduledoc """ - The entrypoint for defining your web interface, such - as controllers, components, channels, and so on. - - This can be used in your application as: - - use PotionWeb, :controller - use PotionWeb, :html - - The definitions below will be executed for every controller, - component, etc, so keep them short and clean, focused - on imports, uses and aliases. - - Do NOT define functions inside the quoted expressions - below. Instead, define additional modules and import - those modules here. - """ - - def static_paths, do: ~w(assets fonts images favicon.ico robots.txt) - - def router do - quote do - use Phoenix.Router, helpers: false - - # Import common connection and controller functions to use in pipelines - import Plug.Conn - import Phoenix.Controller - import Phoenix.LiveView.Router - end - end - - def channel do - quote do - use Phoenix.Channel - end - end - - def controller do - quote do - use Phoenix.Controller, - formats: [:html, :json], - layouts: [html: PotionWeb.Layouts] - - use Gettext, backend: PotionWeb.Gettext - - import Plug.Conn - - unquote(verified_routes()) - end - end - - def live_view do - quote do - use Phoenix.LiveView, - layout: {PotionWeb.Layouts, :app} - - unquote(html_helpers()) - end - end - - def live_component do - quote do - use Phoenix.LiveComponent - - unquote(html_helpers()) - end - end - - def html do - quote do - use Phoenix.Component - - # Import convenience functions from controllers - import Phoenix.Controller, - only: [get_csrf_token: 0, view_module: 1, view_template: 1] - - # Include general helpers for rendering HTML - unquote(html_helpers()) - end - end - - defp html_helpers do - quote do - # Translation - use Gettext, backend: PotionWeb.Gettext - - # HTML escaping functionality - import Phoenix.HTML - # Core UI components - import PotionWeb.CoreComponents - - # Shortcut for generating JS commands - alias Phoenix.LiveView.JS - - # Routes generation with the ~p sigil - unquote(verified_routes()) - end - end - - def verified_routes do - quote do - use Phoenix.VerifiedRoutes, - endpoint: PotionWeb.Endpoint, - router: PotionWeb.Router, - statics: PotionWeb.static_paths() - end - end - - @doc """ - When used, dispatch to the appropriate controller/live_view/etc. - """ - defmacro __using__(which) when is_atom(which) do - apply(__MODULE__, which, []) - end -end diff --git a/lib/potion_web/components/core_components.ex b/lib/potion_web/components/core_components.ex deleted file mode 100644 index 244a817..0000000 --- a/lib/potion_web/components/core_components.ex +++ /dev/null @@ -1,676 +0,0 @@ -defmodule PotionWeb.CoreComponents do - @moduledoc """ - Provides core UI components. - - At first glance, this module may seem daunting, but its goal is to provide - core building blocks for your application, such as modals, tables, and - forms. The components consist mostly of markup and are well-documented - with doc strings and declarative assigns. You may customize and style - them in any way you want, based on your application growth and needs. - - The default components use Tailwind CSS, a utility-first CSS framework. - See the [Tailwind CSS documentation](https://tailwindcss.com) to learn - how to customize them or feel free to swap in another framework altogether. - - Icons are provided by [heroicons](https://heroicons.com). See `icon/1` for usage. - """ - use Phoenix.Component - use Gettext, backend: PotionWeb.Gettext - - alias Phoenix.LiveView.JS - - @doc """ - Renders a modal. - - ## Examples - - <.modal id="confirm-modal"> - This is a modal. - - - JS commands may be passed to the `:on_cancel` to configure - the closing/cancel event, for example: - - <.modal id="confirm" on_cancel={JS.navigate(~p"/posts")}> - This is another modal. - - - """ - attr :id, :string, required: true - attr :show, :boolean, default: false - attr :on_cancel, JS, default: %JS{} - slot :inner_block, required: true - - def modal(assigns) do - ~H""" - - """ - end - - def input(%{type: "select"} = assigns) do - ~H""" -
- <.label for={@id}>{@label} - - <.error :for={msg <- @errors}>{msg} -
- """ - end - - def input(%{type: "textarea"} = assigns) do - ~H""" -
- <.label for={@id}>{@label} - - <.error :for={msg <- @errors}>{msg} -
- """ - end - - # All other inputs text, datetime-local, url, password, etc. are handled here... - def input(assigns) do - ~H""" -
- <.label for={@id}>{@label} - - <.error :for={msg <- @errors}>{msg} -
- """ - end - - @doc """ - Renders a label. - """ - attr :for, :string, default: nil - slot :inner_block, required: true - - def label(assigns) do - ~H""" - - """ - end - - @doc """ - Generates a generic error message. - """ - slot :inner_block, required: true - - def error(assigns) do - ~H""" -

- <.icon name="hero-exclamation-circle-mini" class="mt-0.5 h-5 w-5 flex-none" /> - {render_slot(@inner_block)} -

- """ - end - - @doc """ - Renders a header with title. - """ - attr :class, :string, default: nil - - slot :inner_block, required: true - slot :subtitle - slot :actions - - def header(assigns) do - ~H""" -
-
-

- {render_slot(@inner_block)} -

-

- {render_slot(@subtitle)} -

-
-
{render_slot(@actions)}
-
- """ - end - - @doc ~S""" - Renders a table with generic styling. - - ## Examples - - <.table id="users" rows={@users}> - <:col :let={user} label="id">{user.id} - <:col :let={user} label="username">{user.username} - - """ - attr :id, :string, required: true - attr :rows, :list, required: true - attr :row_id, :any, default: nil, doc: "the function for generating the row id" - attr :row_click, :any, default: nil, doc: "the function for handling phx-click on each row" - - attr :row_item, :any, - default: &Function.identity/1, - doc: "the function for mapping each row before calling the :col and :action slots" - - slot :col, required: true do - attr :label, :string - end - - slot :action, doc: "the slot for showing user actions in the last table column" - - def table(assigns) do - assigns = - with %{rows: %Phoenix.LiveView.LiveStream{}} <- assigns do - assign(assigns, row_id: assigns.row_id || fn {id, _item} -> id end) - end - - ~H""" -
- - - - - - - - - - - - - -
{col[:label]} - {gettext("Actions")} -
-
- - - {render_slot(col, @row_item.(row))} - -
-
-
- - - {render_slot(action, @row_item.(row))} - -
-
-
- """ - end - - @doc """ - Renders a data list. - - ## Examples - - <.list> - <:item title="Title">{@post.title} - <:item title="Views">{@post.views} - - """ - slot :item, required: true do - attr :title, :string, required: true - end - - def list(assigns) do - ~H""" -
-
-
-
{item.title}
-
{render_slot(item)}
-
-
-
- """ - end - - @doc """ - Renders a back navigation link. - - ## Examples - - <.back navigate={~p"/posts"}>Back to posts - """ - attr :navigate, :any, required: true - slot :inner_block, required: true - - def back(assigns) do - ~H""" -
- <.link - navigate={@navigate} - class="text-sm font-semibold leading-6 text-zinc-900 hover:text-zinc-700" - > - <.icon name="hero-arrow-left-solid" class="h-3 w-3" /> - {render_slot(@inner_block)} - -
- """ - end - - @doc """ - Renders a [Heroicon](https://heroicons.com). - - Heroicons come in three styles – outline, solid, and mini. - By default, the outline style is used, but solid and mini may - be applied by using the `-solid` and `-mini` suffix. - - You can customize the size and colors of the icons by setting - width, height, and background color classes. - - Icons are extracted from the `deps/heroicons` directory and bundled within - your compiled app.css by the plugin in your `assets/tailwind.config.js`. - - ## Examples - - <.icon name="hero-x-mark-solid" /> - <.icon name="hero-arrow-path" class="ml-1 w-3 h-3 animate-spin" /> - """ - attr :name, :string, required: true - attr :class, :string, default: nil - - def icon(%{name: "hero-" <> _} = assigns) do - ~H""" - - """ - end - - ## JS Commands - - def show(js \\ %JS{}, selector) do - JS.show(js, - to: selector, - time: 300, - transition: - {"transition-all transform ease-out duration-300", - "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95", - "opacity-100 translate-y-0 sm:scale-100"} - ) - end - - def hide(js \\ %JS{}, selector) do - JS.hide(js, - to: selector, - time: 200, - transition: - {"transition-all transform ease-in duration-200", - "opacity-100 translate-y-0 sm:scale-100", - "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"} - ) - end - - def show_modal(js \\ %JS{}, id) when is_binary(id) do - js - |> JS.show(to: "##{id}") - |> JS.show( - to: "##{id}-bg", - time: 300, - transition: {"transition-all transform ease-out duration-300", "opacity-0", "opacity-100"} - ) - |> show("##{id}-container") - |> JS.add_class("overflow-hidden", to: "body") - |> JS.focus_first(to: "##{id}-content") - end - - def hide_modal(js \\ %JS{}, id) do - js - |> JS.hide( - to: "##{id}-bg", - transition: {"transition-all transform ease-in duration-200", "opacity-100", "opacity-0"} - ) - |> hide("##{id}-container") - |> JS.hide(to: "##{id}", transition: {"block", "block", "hidden"}) - |> JS.remove_class("overflow-hidden", to: "body") - |> JS.pop_focus() - end - - @doc """ - Translates an error message using gettext. - """ - def translate_error({msg, opts}) do - # When using gettext, we typically pass the strings we want - # to translate as a static argument: - # - # # Translate the number of files with plural rules - # dngettext("errors", "1 file", "%{count} files", count) - # - # However the error messages in our forms and APIs are generated - # dynamically, so we need to translate them by calling Gettext - # with our gettext backend as first argument. Translations are - # available in the errors.po file (as we use the "errors" domain). - if count = opts[:count] do - Gettext.dngettext(PotionWeb.Gettext, "errors", msg, msg, count, opts) - else - Gettext.dgettext(PotionWeb.Gettext, "errors", msg, opts) - end - end - - @doc """ - Translates the errors for a field from a keyword list of errors. - """ - def translate_errors(errors, field) when is_list(errors) do - for {^field, {msg, opts}} <- errors, do: translate_error({msg, opts}) - end -end diff --git a/lib/potion_web/components/layouts.ex b/lib/potion_web/components/layouts.ex deleted file mode 100644 index dfaf214..0000000 --- a/lib/potion_web/components/layouts.ex +++ /dev/null @@ -1,14 +0,0 @@ -defmodule PotionWeb.Layouts do - @moduledoc """ - This module holds different layouts used by your application. - - See the `layouts` directory for all templates available. - The "root" layout is a skeleton rendered as part of the - application router. The "app" layout is set as the default - layout on both `use PotionWeb, :controller` and - `use PotionWeb, :live_view`. - """ - use PotionWeb, :html - - embed_templates "layouts/*" -end diff --git a/lib/potion_web/components/layouts/app.html.heex b/lib/potion_web/components/layouts/app.html.heex deleted file mode 100644 index 3b3b607..0000000 --- a/lib/potion_web/components/layouts/app.html.heex +++ /dev/null @@ -1,32 +0,0 @@ -
-
-
- - - -

- v{Application.spec(:phoenix, :vsn)} -

-
- -
-
-
-
- <.flash_group flash={@flash} /> - {@inner_content} -
-
diff --git a/lib/potion_web/components/layouts/dashboard.html.heex b/lib/potion_web/components/layouts/dashboard.html.heex deleted file mode 100644 index a4fddb9..0000000 --- a/lib/potion_web/components/layouts/dashboard.html.heex +++ /dev/null @@ -1,206 +0,0 @@ -
- <.flash_group flash={@flash} /> - - - diff --git a/lib/potion_web/components/layouts/root.html.heex b/lib/potion_web/components/layouts/root.html.heex deleted file mode 100644 index fbc7046..0000000 --- a/lib/potion_web/components/layouts/root.html.heex +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - <.live_title default="Potion" suffix=" · Phoenix Framework"> - {assigns[:page_title]} - - - - - - {@inner_content} - - diff --git a/lib/potion_web/controllers/error_html.ex b/lib/potion_web/controllers/error_html.ex deleted file mode 100644 index 7c2e67a..0000000 --- a/lib/potion_web/controllers/error_html.ex +++ /dev/null @@ -1,24 +0,0 @@ -defmodule PotionWeb.ErrorHTML do - @moduledoc """ - This module is invoked by your endpoint in case of errors on HTML requests. - - See config/config.exs. - """ - use PotionWeb, :html - - # If you want to customize your error pages, - # uncomment the embed_templates/1 call below - # and add pages to the error directory: - # - # * lib/potion_web/controllers/error_html/404.html.heex - # * lib/potion_web/controllers/error_html/500.html.heex - # - # embed_templates "error_html/*" - - # The default is to render a plain text page based on - # the template name. For example, "404.html" becomes - # "Not Found". - def render(template, _assigns) do - Phoenix.Controller.status_message_from_template(template) - end -end diff --git a/lib/potion_web/controllers/error_json.ex b/lib/potion_web/controllers/error_json.ex deleted file mode 100644 index 30a74ed..0000000 --- a/lib/potion_web/controllers/error_json.ex +++ /dev/null @@ -1,21 +0,0 @@ -defmodule PotionWeb.ErrorJSON do - @moduledoc """ - This module is invoked by your endpoint in case of errors on JSON requests. - - See config/config.exs. - """ - - # If you want to customize a particular status code, - # you may add your own clauses, such as: - # - # def render("500.json", _assigns) do - # %{errors: %{detail: "Internal Server Error"}} - # end - - # By default, Phoenix returns the status message from - # the template name. For example, "404.json" becomes - # "Not Found". - def render(template, _assigns) do - %{errors: %{detail: Phoenix.Controller.status_message_from_template(template)}} - end -end diff --git a/lib/potion_web/controllers/page_controller.ex b/lib/potion_web/controllers/page_controller.ex deleted file mode 100644 index 04f339c..0000000 --- a/lib/potion_web/controllers/page_controller.ex +++ /dev/null @@ -1,38 +0,0 @@ -defmodule PotionWeb.PageController do - use PotionWeb, :controller - - def home(conn, _params) do - conn - |> assign(:current_page, :home) - |> put_layout(html: :dashboard) - |> render(:home) - end - - def favorites(conn, _params) do - conn - |> assign(:current_page, :favorites) - |> put_layout(html: :dashboard) - |> render(:favorites) - end - - def create(conn, _params) do - conn - |> assign(:current_page, :create) - |> put_layout(html: :dashboard) - |> render(:create) - end - - def list(conn, _params) do - conn - |> assign(:current_page, :list) - |> put_layout(html: :dashboard) - |> render(:list) - end - - def profile(conn, _params) do - conn - |> assign(:current_page, :profile) - |> put_layout(html: :dashboard) - |> render(:profile) - end -end diff --git a/lib/potion_web/controllers/page_html.ex b/lib/potion_web/controllers/page_html.ex deleted file mode 100644 index 022331e..0000000 --- a/lib/potion_web/controllers/page_html.ex +++ /dev/null @@ -1,10 +0,0 @@ -defmodule PotionWeb.PageHTML do - @moduledoc """ - This module contains pages rendered by PageController. - - See the `page_html` directory for all templates available. - """ - use PotionWeb, :html - - embed_templates "page_html/*" -end diff --git a/lib/potion_web/controllers/page_html/create.html.heex b/lib/potion_web/controllers/page_html/create.html.heex deleted file mode 100644 index a3195e3..0000000 --- a/lib/potion_web/controllers/page_html/create.html.heex +++ /dev/null @@ -1,738 +0,0 @@ - -
- - -
- - -
- - -
-

- Create Your Recipe -

-

- Share your culinary masterpieces with the world! Fill out the details below - to get started. -

-
- - -
-
-

- Recipe Details -

-

*Required

-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
- -