From 77e3c1cc0fcf9b2436904c132c802bf3bd5770d1 Mon Sep 17 00:00:00 2001 From: n Date: Tue, 14 Apr 2026 23:57:16 +0100 Subject: [PATCH 1/2] git rm -rf "old files" #330 --- assets/css/app.css | 5 - assets/js/app.js | 190 ------ assets/js/user_socket.js | 13 - assets/tailwind.config.js | 26 - assets/vendor/topbar.js | 167 ----- config/config.exs | 55 -- config/dev.exs | 75 --- config/prod.exs | 18 - config/runtime.exs | 97 --- config/test.exs | 27 - lib/chat.ex | 9 - lib/chat/application.ex | 37 -- lib/chat/message.ex | 26 - lib/chat/release.ex | 28 - lib/chat/repo.ex | 5 - lib/chat_web.ex | 111 ---- lib/chat_web/channels/room_channel.ex | 74 --- lib/chat_web/channels/user_socket.ex | 44 -- lib/chat_web/components/core_components.ex | 617 ------------------ lib/chat_web/components/layouts.ex | 5 - lib/chat_web/components/layouts/app.html.heex | 55 -- .../components/layouts/root.html.heex | 41 -- lib/chat_web/controllers/auth_controller.ex | 14 - lib/chat_web/controllers/error_html.ex | 19 - lib/chat_web/controllers/error_json.ex | 15 - lib/chat_web/controllers/page_controller.ex | 9 - lib/chat_web/controllers/page_html.ex | 9 - .../controllers/page_html/home.html.heex | 62 -- lib/chat_web/endpoint.ex | 49 -- lib/chat_web/presence.ex | 5 - lib/chat_web/router.ex | 32 - lib/chat_web/telemetry.ex | 92 --- mix.exs | 87 --- mix.lock | 50 -- priv/repo/migrations/.formatter.exs | 4 - .../20221012115654_create_messages.exs | 12 - priv/repo/seeds.exs | 11 - rel/overlays/bin/migrate | 3 - rel/overlays/bin/migrate.bat | 1 - rel/overlays/bin/server | 3 - rel/overlays/bin/server.bat | 2 - test/chat_web/channels/room_channel_test.exs | 40 -- .../controllers/auth_controller_test.exs | 36 - test/chat_web/controllers/error_html_test.exs | 14 - test/chat_web/controllers/error_json_test.exs | 12 - .../controllers/page_controller_test.exs | 8 - test/support/channel_case.ex | 35 - test/support/conn_case.ex | 38 -- test/support/data_case.ex | 58 -- test/test_helper.exs | 2 - 50 files changed, 2447 deletions(-) delete mode 100644 assets/css/app.css delete mode 100644 assets/js/app.js delete mode 100644 assets/js/user_socket.js delete mode 100644 assets/tailwind.config.js delete mode 100644 assets/vendor/topbar.js delete mode 100644 config/config.exs delete mode 100644 config/dev.exs delete mode 100644 config/prod.exs delete mode 100644 config/runtime.exs delete mode 100644 config/test.exs delete mode 100644 lib/chat.ex delete mode 100644 lib/chat/application.ex delete mode 100644 lib/chat/message.ex delete mode 100644 lib/chat/release.ex delete mode 100644 lib/chat/repo.ex delete mode 100644 lib/chat_web.ex delete mode 100644 lib/chat_web/channels/room_channel.ex delete mode 100644 lib/chat_web/channels/user_socket.ex delete mode 100644 lib/chat_web/components/core_components.ex delete mode 100644 lib/chat_web/components/layouts.ex delete mode 100644 lib/chat_web/components/layouts/app.html.heex delete mode 100644 lib/chat_web/components/layouts/root.html.heex delete mode 100644 lib/chat_web/controllers/auth_controller.ex delete mode 100644 lib/chat_web/controllers/error_html.ex delete mode 100644 lib/chat_web/controllers/error_json.ex delete mode 100644 lib/chat_web/controllers/page_controller.ex delete mode 100644 lib/chat_web/controllers/page_html.ex delete mode 100644 lib/chat_web/controllers/page_html/home.html.heex delete mode 100644 lib/chat_web/endpoint.ex delete mode 100644 lib/chat_web/presence.ex delete mode 100644 lib/chat_web/router.ex delete mode 100644 lib/chat_web/telemetry.ex delete mode 100644 mix.exs delete mode 100644 mix.lock delete mode 100644 priv/repo/migrations/.formatter.exs delete mode 100644 priv/repo/migrations/20221012115654_create_messages.exs delete mode 100644 priv/repo/seeds.exs delete mode 100755 rel/overlays/bin/migrate delete mode 100755 rel/overlays/bin/migrate.bat delete mode 100755 rel/overlays/bin/server delete mode 100755 rel/overlays/bin/server.bat delete mode 100644 test/chat_web/channels/room_channel_test.exs delete mode 100644 test/chat_web/controllers/auth_controller_test.exs delete mode 100644 test/chat_web/controllers/error_html_test.exs delete mode 100644 test/chat_web/controllers/error_json_test.exs delete mode 100644 test/chat_web/controllers/page_controller_test.exs delete mode 100644 test/support/channel_case.ex delete mode 100644 test/support/conn_case.ex delete mode 100644 test/support/data_case.ex delete mode 100644 test/test_helper.exs 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 aa6580c..0000000 --- a/assets/js/app.js +++ /dev/null @@ -1,190 +0,0 @@ -import socket from "./user_socket.js" - -// 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, {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.delayedShow(200)) -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 - - -/* INITIAL SETUP OF VARIABLES AND JOINING CHANNEL -------------- */ -const ul = document.getElementById('msg-list'); // list of messages. -const name = document.getElementById('name'); // name of message sender -const msg = document.getElementById('msg'); // message input field -const send = document.getElementById('send'); // send button -const peopleListMobile = document.getElementById('people_online-list-mobile'); // online people list mobile -const peopleListDesktop = document.getElementById('people_online-list-desktop'); // online people list desktop - -const channel = socket.channel('room:lobby', {}); // connect to chat "room" -channel.join(); // join the channel. - - - -/* ONLINE people / PRESENCE FUNCTIONS -------------- */ - - -// This function will be probably caught when the person first enters the page -channel.on('presence_state', function (payload) { - // Array of objects with id and username - const currentlyOnlinePeople = Object.entries(payload).map(elem => ({username: elem[0], id: elem[1].metas[0].phx_ref})) - - updateOnlinePeopleList(currentlyOnlinePeople) -}) - -// Listening to presence events whenever a person leaves or joins -channel.on('presence_diff', function (payload) { - if(payload.joins && payload.leaves) { - // Array of objects with id and username - const currentlyOnlinePeople = Object.entries(payload.joins).map(elem => ({username: elem[0], id: elem[1].metas[0].phx_ref})) - const peopleThatLeft = Object.entries(payload.leaves).map(elem => ({username: elem[0], id: elem[1].metas[0].phx_ref})) - - updateOnlinePeopleList(currentlyOnlinePeople) - removePeopleThatLeft(peopleThatLeft) - } -}); - -function updateOnlinePeopleList(currentlyOnlinePeople) { - // Add joined people - for (var i = currentlyOnlinePeople.length - 1; i >= 0; i--) { - const name = currentlyOnlinePeople[i].username - const id = name + "-" + currentlyOnlinePeople[i].id - - if (document.getElementById(name) == null) { - var liMobile = document.createElement("li"); // create new person list item DOM element for mobile - var liDesktop = document.createElement("li"); // create new person list item DOM element for desktop - - liMobile.id = id + '_mobile' - liDesktop.id = id + '_desktop' - liMobile.innerHTML = `${sanitizeString(name)}` - liDesktop.innerHTML = `${sanitizeString(name)}` - - peopleListMobile.appendChild(liMobile); // append to people list - peopleListDesktop.appendChild(liDesktop); // append to people list - } - } -} - -function removePeopleThatLeft(peopleThatLeft) { - // Remove people that left - for (var i = peopleThatLeft.length - 1; i >= 0; i--) { - const name = peopleThatLeft[i].name - const id = name + "-" + peopleThatLeft[i].id - - const personThatLeftMobile = document.getElementById(id + '_mobile') - const personThatLeftDesktop = document.getElementById(id + '_desktop') - - if (personThatLeftMobile != null && personThatLeftDesktop != null) { - peopleListMobile.removeChild(personThatLeftMobile); // remove the person from list mobile - peopleListDesktop.removeChild(personThatLeftDesktop); // remove the person from list desktop - } - } -} - -/* SENDING MESSAGES FUNCTIONS ------------- */ - -// Listening to 'shout' events -channel.on('shout', function (payload) { - render_message(payload) -}); - -// Send the message to the server on "shout" channel -function sendMessage() { - - channel.push('shout', { - name: name.value || "guest", // get value of "name" of person sending the message. Set guest as default - message: msg.value, // get message text (value) from msg input field. - inserted_at: new Date() // date + time of when the message was sent - }); - - msg.value = ''; // reset the message input field for next message. -} - -// The page does not automatically scroll to show the latest message -// So invoke this after rendering messages to ensure the last one is in view: -function scroll_latest_message_into_view() { - window.scrollTo(0, document.documentElement.scrollHeight) // desktop - ul.scrollTo(0, ul.scrollHeight) // mobile -} - -// Render the message with Tailwind styles -function render_message(payload) { - - const li = document.createElement("li"); // create new list item DOM element - - // Message HTML with Tailwind CSS Classes for layout/style: - li.innerHTML = ` -
-
- ${payload.name} -
- ${formatDate(payload.inserted_at)} - ${formatTime(payload.inserted_at)} -
-
-
- ${payload.message} -
-
- ` - // Append to list - ul.appendChild(li); - scroll_latest_message_into_view(); -} - -// Listen for the [Enter] keypress event to send a message: -msg.addEventListener('keypress', function (event) { - if (event.keyCode == 13 && msg.value.length > 0) { // don't sent empty msg. - sendMessage() - } -}); - -// On "Send" button press -send.addEventListener('click', function (event) { - if (msg.value.length > 0) { // don't sent empty msg. - sendMessage() - } -}); - - -/* UTILS ------------ */ - -// Date formatting -function formatDate(datetime) { - const m = new Date(datetime); - return m.getUTCFullYear() + "/" - + ("0" + (m.getUTCMonth()+1)).slice(-2) + "/" - + ("0" + m.getUTCDate()).slice(-2); -} - -// Time formatting -function formatTime(datetime) { - const m = new Date(datetime); - return ("0" + m.getUTCHours()).slice(-2) + ":" - + ("0" + m.getUTCMinutes()).slice(-2) + ":" - + ("0" + m.getUTCSeconds()).slice(-2); -} - -// Sanitize string input borrowed from: -// stackoverflow.com/questions/23187013/sanitize-javascript-string -function sanitizeString(str){ - str = str.replace(/[^a-z0-9áéíóúñü \.,_-]/gim,""); - return str.trim(); -} \ No newline at end of file diff --git a/assets/js/user_socket.js b/assets/js/user_socket.js deleted file mode 100644 index 5b40269..0000000 --- a/assets/js/user_socket.js +++ /dev/null @@ -1,13 +0,0 @@ -// NOTE: The contents of this file will only be executed if -// you uncomment its entry in "assets/js/app.js". - -// Bring in Phoenix channels client library: -import {Socket} from "phoenix" - -// And connect to the path in "lib/chat_web/endpoint.ex". We pass the -// token for authentication. Read below how it should be used. -let socket = new Socket("/socket", {params: {token: window.personToken}}) - -// Connect to the socket: -socket.connect() -export default socket diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js deleted file mode 100644 index e3bf241..0000000 --- a/assets/tailwind.config.js +++ /dev/null @@ -1,26 +0,0 @@ -// See the Tailwind configuration guide for advanced usage -// https://tailwindcss.com/docs/configuration - -const plugin = require("tailwindcss/plugin") - -module.exports = { - content: [ - "./js/**/*.js", - "../lib/*_web.ex", - "../lib/*_web/**/*.*ex" - ], - theme: { - extend: { - colors: { - brand: "#FD4F00", - } - }, - }, - plugins: [ - require("@tailwindcss/forms"), - plugin(({addVariant}) => addVariant("phx-no-feedback", [".phx-no-feedback&", ".phx-no-feedback &"])), - 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 &"])) - ] -} diff --git a/assets/vendor/topbar.js b/assets/vendor/topbar.js deleted file mode 100644 index 4176ede..0000000 --- a/assets/vendor/topbar.js +++ /dev/null @@ -1,167 +0,0 @@ -/** - * @license MIT - * topbar 1.0.0, 2021-01-06 - * Modifications: - * - add delayedShow(time) (2022-09-21) - * http://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]; - }, - delayedShow: function(time) { - if (showing) return; - if (delayTimerId) return; - delayTimerId = setTimeout(() => topbar.show(), time); - }, - show: function () { - if (showing) return; - 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 566b770..0000000 --- a/config/config.exs +++ /dev/null @@ -1,55 +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 :chat, - ecto_repos: [Chat.Repo] - -# Configures the endpoint -config :chat, ChatWeb.Endpoint, - url: [host: "localhost"], - render_errors: [ - formats: [html: ChatWeb.ErrorHTML, json: ChatWeb.ErrorJSON], - layout: false - ], - pubsub_server: Chat.PubSub, - live_view: [signing_salt: "lvvIz0Oa"] - -# Configure esbuild (the version is required) -config :esbuild, - version: "0.14.41", - default: [ - 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.2.4", - default: [ - 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 a97061f..0000000 --- a/config/dev.exs +++ /dev/null @@ -1,75 +0,0 @@ -import Config - -# Configure your database -config :chat, Chat.Repo, - username: "postgres", - password: "postgres", - hostname: "localhost", - database: "chat_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 use it -# with esbuild to bundle .js and .css sources. -config :chat, ChatWeb.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: "odMGQmHhvRQ8crBIH3IN31hahkw6hD0RJwvmr5i3+Up96Hs4//+tkgzNdg3HSxLI", - watchers: [ - esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}, - tailwind: {Tailwind, :install_and_run, [:default, ~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 :chat, ChatWeb.Endpoint, - live_reload: [ - patterns: [ - ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$", - ~r"lib/chat_web/(controllers|live|components)/.*(ex|heex)$" - ] - ] - -# Enable dev routes for dashboard and mailbox -config :chat, 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 diff --git a/config/prod.exs b/config/prod.exs deleted file mode 100644 index 044a1da..0000000 --- a/config/prod.exs +++ /dev/null @@ -1,18 +0,0 @@ -import Config - -# For production, don't forget to configure the url host -# to something meaningful, Phoenix uses this information -# when generating URLs. - -# Note we also include the path to a cache manifest -# containing the digested version of static files. This -# manifest is generated by the `mix phx.digest` task, -# which you should run after static files are built and -# before starting your production server. -config :chat, ChatWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json" - -# 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 3e18c1c..0000000 --- a/config/runtime.exs +++ /dev/null @@ -1,97 +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/chat 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 :chat, ChatWeb.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"), do: [:inet6], else: [] - - config :chat, Chat.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 :chat, ChatWeb.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/plug_cowboy/Plug.Cowboy.html - # 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 :chat, ChatWeb.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 endpoint, ensuring - # no data is ever sent via http, always redirecting to https: - # - # config :chat, ChatWeb.Endpoint, - # force_ssl: [hsts: true] - # - # Check `Plug.SSL` for all available options in `force_ssl`. -end diff --git a/config/test.exs b/config/test.exs deleted file mode 100644 index 74009ba..0000000 --- a/config/test.exs +++ /dev/null @@ -1,27 +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 :chat, Chat.Repo, - username: "postgres", - password: "postgres", - hostname: "localhost", - database: "chat_test#{System.get_env("MIX_TEST_PARTITION")}", - pool: Ecto.Adapters.SQL.Sandbox, - pool_size: 10 - -# We don't run a server during test. If one is required, -# you can enable the server option below. -config :chat, ChatWeb.Endpoint, - http: [ip: {127, 0, 0, 1}, port: 4002], - secret_key_base: "Q1WJjPpcI6Vs2ieJQMcs1DjL4JPZ0HafQ3afIzEUMx7fN/K0HO0+85e02OhUQS9n", - server: 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 diff --git a/lib/chat.ex b/lib/chat.ex deleted file mode 100644 index 6442a14..0000000 --- a/lib/chat.ex +++ /dev/null @@ -1,9 +0,0 @@ -defmodule Chat do - @moduledoc """ - Chat 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/chat/application.ex b/lib/chat/application.ex deleted file mode 100644 index 1923c94..0000000 --- a/lib/chat/application.ex +++ /dev/null @@ -1,37 +0,0 @@ -defmodule Chat.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 = [ - # Start the Telemetry supervisor - ChatWeb.Telemetry, - # Start the Ecto repository - Chat.Repo, - # Start the PubSub system - {Phoenix.PubSub, name: Chat.PubSub}, - ChatWeb.Presence, - # Start the Endpoint (http/https) - ChatWeb.Endpoint - # Start a worker by calling: Chat.Worker.start_link(arg) - # {Chat.Worker, arg} - ] - - # See https://hexdocs.pm/elixir/Supervisor.html - # for other strategies and supported options - opts = [strategy: :one_for_one, name: Chat.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 - ChatWeb.Endpoint.config_change(changed, removed) - :ok - end -end diff --git a/lib/chat/message.ex b/lib/chat/message.ex deleted file mode 100644 index 54321a7..0000000 --- a/lib/chat/message.ex +++ /dev/null @@ -1,26 +0,0 @@ -defmodule Chat.Message do - use Ecto.Schema - import Ecto.Changeset - import Ecto.Query - - schema "messages" do - field :message, :string - field :name, :string - - timestamps() - end - - @doc false - def changeset(message, attrs) do - message - |> cast(attrs, [:name, :message]) - |> validate_required([:name, :message]) - end - - def get_messages(limit \\ 20) do - Chat.Message - |> limit(^limit) - |> order_by(desc: :inserted_at) - |> Chat.Repo.all() - end -end diff --git a/lib/chat/release.ex b/lib/chat/release.ex deleted file mode 100644 index 04b7809..0000000 --- a/lib/chat/release.ex +++ /dev/null @@ -1,28 +0,0 @@ -defmodule Chat.Release do - @moduledoc """ - Used for executing DB release tasks when run in production without Mix - installed. - """ - @app :chat - - 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/chat/repo.ex b/lib/chat/repo.ex deleted file mode 100644 index 43b4153..0000000 --- a/lib/chat/repo.ex +++ /dev/null @@ -1,5 +0,0 @@ -defmodule Chat.Repo do - use Ecto.Repo, - otp_app: :chat, - adapter: Ecto.Adapters.Postgres -end diff --git a/lib/chat_web.ex b/lib/chat_web.ex deleted file mode 100644 index 5052cc5..0000000 --- a/lib/chat_web.ex +++ /dev/null @@ -1,111 +0,0 @@ -defmodule ChatWeb 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 ChatWeb, :controller - use ChatWeb, :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: ChatWeb.Layouts] - - import Plug.Conn - - unquote(verified_routes()) - end - end - - def live_view do - quote do - use Phoenix.LiveView, - layout: {ChatWeb.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 - # HTML escaping functionality - import Phoenix.HTML - # Core UI components and translation - import ChatWeb.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: ChatWeb.Endpoint, - router: ChatWeb.Router, - statics: ChatWeb.static_paths() - end - end - - @doc """ - When used, dispatch to the appropriate controller/view/etc. - """ - defmacro __using__(which) when is_atom(which) do - apply(__MODULE__, which, []) - end -end diff --git a/lib/chat_web/channels/room_channel.ex b/lib/chat_web/channels/room_channel.ex deleted file mode 100644 index 7caa72b..0000000 --- a/lib/chat_web/channels/room_channel.ex +++ /dev/null @@ -1,74 +0,0 @@ -defmodule ChatWeb.RoomChannel do - use ChatWeb, :channel - alias ChatWeb.Presence - - @impl true - def join("room:lobby", payload, socket) do - if authorized?(payload) do - send(self(), :after_join) - {:ok, socket} - else - {:error, %{reason: "unauthorized"}} - end - end - - # Channels can be used in a request/response fashion - # by sending replies to requests from the client - @impl true - def handle_in("ping", payload, socket) do - {:reply, {:ok, payload}, socket} - end - - # It is also common to receive messages from the client and - # broadcast to everyone in the current topic (room:lobby). - @impl true - def handle_in("shout", payload, socket) do - # Insert message in database - {:ok, msg} = Chat.Message.changeset(%Chat.Message{}, payload) |> Chat.Repo.insert() - - # Assigning name to socket assigns and tracking presence - socket - |> assign(:username, msg.name) - |> track_presence() - |> broadcast("shout", Map.put_new(payload, :id, msg.id)) - - {:noreply, socket} - end - - @impl true - def handle_info(:after_join, socket) do - # Get messages and list them - Chat.Message.get_messages() - # reverts the enum to display the latest message at the bottom of the page - |> Enum.reverse() - |> Enum.each(fn msg -> - push(socket, "shout", %{ - name: msg.name, - message: msg.message, - inserted_at: msg.inserted_at - }) - end) - - # Send currently online people in lobby - push(socket, "presence_state", Presence.list("room:lobby")) - - {:noreply, socket} - end - - # Add authorization logic here as required. - defp authorized?(_payload) do - true - end - - # This creates a Presence track when the person joins the channel. - # Normally this is done when joining the channel, - # but the socket doesn't know the name so we wait for a message to be sent - # with the name to begin tracking. - defp track_presence(%{assigns: %{username: username}} = socket) do - Presence.track(socket, username, %{ - online_at: inspect(System.system_time(:second)) - }) - - socket - end -end diff --git a/lib/chat_web/channels/user_socket.ex b/lib/chat_web/channels/user_socket.ex deleted file mode 100644 index 459a251..0000000 --- a/lib/chat_web/channels/user_socket.ex +++ /dev/null @@ -1,44 +0,0 @@ -defmodule ChatWeb.UserSocket do - use Phoenix.Socket - - # A Socket handler - # - # It's possible to control the websocket connection and - # assign values that can be accessed by your channel topics. - - ## Channels - - channel "room:lobby", ChatWeb.RoomChannel - - # Socket params are passed from the client and can - # be used to verify and authenticate a user. After - # verification, you can put default assigns into - # the socket that will be set for all channels, ie - # - # {:ok, assign(socket, :user_id, verified_user_id)} - # - # To deny connection, return `:error` or `{:error, term}`. To control the - # response the client receives in that case, [define an error handler in the - # websocket - # configuration](https://hexdocs.pm/phoenix/Phoenix.Endpoint.html#socket/3-websocket-configuration). - # - # See `Phoenix.Token` documentation for examples in - # performing token verification on connect. - @impl true - def connect(_params, socket, _connect_info) do - {:ok, socket} - end - - # Socket id's are topics that allow you to identify all sockets for a given user: - # - # def id(socket), do: "user_socket:#{socket.assigns.user_id}" - # - # Would allow you to broadcast a "disconnect" event and terminate - # all active sockets and channels for a given user: - # - # Elixir.ChatWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{}) - # - # Returning `nil` makes this socket anonymous. - @impl true - def id(_socket), do: nil -end diff --git a/lib/chat_web/components/core_components.ex b/lib/chat_web/components/core_components.ex deleted file mode 100644 index 1f0b584..0000000 --- a/lib/chat_web/components/core_components.ex +++ /dev/null @@ -1,617 +0,0 @@ -defmodule ChatWeb.CoreComponents do - @moduledoc """ - Provides core UI components. - - The components in this module use Tailwind CSS, a utility-first CSS framework. - See the [Tailwind CSS documentation](https://tailwindcss.com) to learn how to - customize the generated components in this module. - - Icons are provided by [heroicons](https://heroicons.com), using the - [heroicons_elixir](https://github.com/mveytsman/heroicons_elixir) project. - """ - use Phoenix.Component - - alias Phoenix.LiveView.JS - - @doc """ - Renders a modal. - - ## Examples - - <.modal id="confirm-modal"> - Are you sure? - <:confirm>OK - <:cancel>Cancel - - - JS commands may be passed to the `:on_cancel` and `on_confirm` attributes - for the caller to react to each button press, for example: - - <.modal id="confirm" on_confirm={JS.push("delete")} on_cancel={JS.navigate(~p"/posts")}> - Are you sure you? - <:confirm>OK - <:cancel>Cancel - - """ - attr :id, :string, required: true - attr :show, :boolean, default: false - attr :on_cancel, JS, default: %JS{} - attr :on_confirm, JS, default: %JS{} - - slot :inner_block, required: true - slot :title - slot :subtitle - slot :confirm - slot :cancel - - def modal(assigns) do - ~H""" -