feat: Upgrade framework

This commit is contained in:
Robert Prehn 2021-07-02 16:06:31 -05:00
commit 42984b8c29
49 changed files with 27425 additions and 11583 deletions

4
.gitignore vendored
View file

@ -34,8 +34,8 @@ node_modules
/priv/static/
# Mnesia DBs
/apps/*/priv/mnesia/
/priv/mnesia/
/apps/*/priv/mnesia*
/priv/mnesia*
# Lock file for Brew, since the versions aren't really stable & isolated anyway
Brewfile.lock.json

View file

@ -18,6 +18,7 @@ variables:
.test_template: &test_template
stage: test
cache:
key: $CI_JOB_NAME
paths:
- _build/
- deps/
@ -42,10 +43,6 @@ build_image_for_commit:
image: "docker:20.10"
only:
- master
cache:
paths:
- _build/
- deps/
services:
- name: docker:20.10-dind
before_script:
@ -58,13 +55,14 @@ build_image_for_commit:
deploy_to_tags:
stage: deploy_tags
needs: ['test', 'build_image_for_commit']
image: "node:15.0"
image: "node:16"
only:
- master
cache:
key:
files:
- package-lock.json
- package.json
paths:
- node_modules/
script:
@ -72,7 +70,10 @@ deploy_to_tags:
- export GIT_AUTHOR_EMAIL=$GITLAB_USER_EMAIL
- export GIT_COMMITTER_NAME=$GITLAB_USER_NAME
- export GIT_COMMITTER_EMAIL=$GITLAB_USER_EMAIL
- npm install
- export GIT_BRANCH=$CI_COMMIT_REF_NAME
- git config user.email $GITLAB_USER_EMAIL
- git config user.name $GITLAB_USER_NAME
- npm install --no-save
- npx semantic-release --repository-url=$CI_REPOSITORY_URL
- script/generate-build-version
artifacts:
@ -107,3 +108,83 @@ deploy_commit_image_to_tag:
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA$IMAGE_TYPE $CI_REGISTRY_IMAGE:latest$IMAGE_TYPE
- docker push $CI_REGISTRY_IMAGE:$BUILD_VERSION$IMAGE_TYPE
- docker push $CI_REGISTRY_IMAGE:latest$IMAGE_TYPE
.dependabot_gitlab: &dependabot_gitlab
image:
name: docker.io/andrcuns/dependabot-gitlab:0.4.3
entrypoint: [""]
variables:
GIT_STRATEGY: none
RAILS_ENV: production
SETTINGS__STANDALONE: "true"
SETTINGS__GITLAB_URL: $CI_SERVER_URL
SETTINGS__GITLAB_ACCESS_TOKEN: $GITLAB_TOKEN
before_script:
- cd /home/dependabot/app
script:
- bundle exec rake "dependabot:update[$CI_PROJECT_PATH,$PACKAGE_MANAGER,$DIRECTORY]"
only:
- schedules
npm-release-tools:
extends: .dependabot_gitlab
variables:
DIRECTORY: "/"
PACKAGE_MANAGER: npm
only:
variables:
- $PACKAGE_MANAGER_SET =~ /(\bnpm|yarn\b)/
npm-assets:
extends: .dependabot_gitlab
variables:
DIRECTORY: "/apps/app/assets"
PACKAGE_MANAGER: npm
only:
variables:
- $PACKAGE_MANAGER_SET =~ /(\bnpm|yarn\b)/
mix-admin:
extends: .dependabot_gitlab
variables:
DIRECTORY: "/apps/admin"
PACKAGE_MANAGER: mix
only:
variables:
- $PACKAGE_MANAGER_SET =~ /\bmix\b/
mix-app:
extends: .dependabot_gitlab
variables:
DIRECTORY: "/apps/app"
PACKAGE_MANAGER: mix
only:
variables:
- $PACKAGE_MANAGER_SET =~ /\bmix\b/
mix-core:
extends: .dependabot_gitlab
variables:
DIRECTORY: "/apps/core"
PACKAGE_MANAGER: mix
only:
variables:
- $PACKAGE_MANAGER_SET =~ /\bmix\b/
mix-content:
extends: .dependabot_gitlab
variables:
DIRECTORY: "/apps/content"
PACKAGE_MANAGER: mix
only:
variables:
- $PACKAGE_MANAGER_SET =~ /\bmix\b/
docker:
extends: .dependabot_gitlab
variables:
DIRECTORY: "/"
PACKAGE_MANAGER: docker
only:
variables:
- $PACKAGE_MANAGER_SET =~ /\bdocker\b/

30
.gitlab/dependabot.yml Normal file
View file

@ -0,0 +1,30 @@
version: 2
updates:
- package-ecosystem: docker
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: mix
directory: "/apps/admin"
schedule:
interval: "daily"
- package-ecosystem: mix
directory: "/apps/app"
schedule:
interval: "daily"
- package-ecosystem: mix
directory: "/apps/content"
schedule:
interval: "daily"
- package-ecosystem: mix
directory: "/apps/core"
schedule:
interval: "daily"
- package-ecosystem: npm
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: npm
directory: "/apps/app/assets"
schedule:
interval: "daily"

View file

@ -1,3 +1,3 @@
erlang 23.0.2
elixir 1.10.3-otp-23
elixir 1.12.1
nodejs 14.5.0

View file

@ -1,4 +1,4 @@
FROM elixir:1.10.4-alpine AS elixir-builder
FROM elixir:1.12.1-alpine AS elixir-builder
RUN mix local.hex --force \
&& mix local.rebar --force
@ -27,7 +27,7 @@ RUN mix deps.get
# Leave off here so that we can built assets and compile the elixir app in parallel
FROM node:15.0 AS asset-builder
FROM node:16.3.0 AS asset-builder
# Build assets in a node container
ADD ./apps/app/assets/ /root/app/apps/app/assets/

View file

@ -1,7 +1,7 @@
defmodule Legendary.Admin.MixProject do
use Mix.Project
@version "2.10.0"
@version "2.11.2"
def project do
[
@ -50,7 +50,7 @@ defmodule Legendary.Admin.MixProject do
{:phoenix_ecto, "~> 4.0"},
{:phoenix_html, "~> 2.11"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_dashboard, "~> 0.2.0"},
{:phoenix_live_dashboard, "~> 0.4.0"},
{:postgrex, ">= 0.0.0"},
{:telemetry_metrics, "~> 0.4"},
{:telemetry_poller, "~> 0.4"},

View file

@ -14,6 +14,7 @@ import "../css/app.css"
//
import "phoenix_html"
import "alpinejs"
import "./live"
import { ready } from "./utils"
function togglePasswordFieldVisibility()
@ -38,7 +39,7 @@ const toggleSidebar = (event) => {
}
ready(() => {
document.getElementById('nav-toggle').onclick = function(){
(document.getElementById('nav-toggle') ||{}).onclick = function(){
document.getElementById("nav-content").classList.toggle("hidden");
}

View file

@ -0,0 +1,23 @@
import {Socket} from "phoenix"
import LiveSocket from "phoenix_live_view"
import topbar from "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: "#3B82F6"}, 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()
// Expose liveSocket on window for web console debug logs and latency simulation:
// >> liveSocket.enableDebug()
// >> liveSocket.enableLatencySim(1000)
// The latency simulator is enabled for the duration of the browser session.
// Call disableLatencySim() to disable:
// >> liveSocket.disableLatencySim()
window.liveSocket = liveSocket

File diff suppressed because it is too large Load diff

View file

@ -13,38 +13,38 @@
"autoprefixer": "^9.8.6",
"csswring": "^7.0.0",
"glob": "^7.1.6",
"gulp": "^4.0.2",
"phoenix": "file:/../../../deps/phoenix",
"phoenix_html": "file:/../../../deps/phoenix_html",
"phoenix_live_view": "file:../../../deps/phoenix_live_view",
"postcss-color-function": "^4.1.0",
"simplemde": "^1.11.2",
"stylelint": "^13.6.1",
"tailwindcss": "^1.7.3"
"tailwindcss": "^1.7.3",
"topbar": "^1.0.1"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"babel-loader": "^8.0.0",
"copy-webpack-plugin": "^5.1.1",
"copy-webpack-plugin": "^9.0.1",
"css-loader": "^3.4.2",
"extract-text-webpack-plugin": "^3.0.2",
"css-minimizer-webpack-plugin": "^3.0.2",
"file-loader": "^6.0.0",
"image-webpack-loader": "^6.0.0",
"less": "^3.11.3",
"less-loader": "^6.2.0",
"mini-css-extract-plugin": "^0.9.0",
"node-sass": "^4.13.1",
"optimize-css-assets-webpack-plugin": "^5.0.1",
"mini-css-extract-plugin": "^1.6.2",
"postcss-css-variables": "^0.17.0",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
"postcss-loader": "^6.1.0",
"sass": "^1.35.1",
"sass-loader": "^8.0.2",
"style-loader": "^1.2.1",
"stylelint-config-standard": "^20.0.0",
"stylelint": "^13.13.1",
"stylelint-config-standard": "^22.0.0",
"stylelint-order": "^4.1.0",
"terser-webpack-plugin": "^2.3.2",
"webpack": "4.41.5",
"webpack-cli": "^3.3.2"
"webpack": "^5.1.0",
"webpack-cli": "^4.7.2"
},
"resolutions": {
"graceful-fs": "4.2.3"

View file

@ -1,8 +1,19 @@
module.exports = {
future: {
removeDeprecatedGapUtilities: true,
purgeLayersByDefault: true,
},
purge: {
enabled: true,
layers: ['base', 'components', 'utilities'],
content: [
'../../../**/views/*.ex',
'../../../**/*.html.eex',
'../../../**/*.html.leex',
'../../../**/*.html.heex',
'./js/**/*.js'
]
},
purge: [],
theme: {
extend: {},
},

View file

@ -2,7 +2,7 @@ const path = require('path');
const glob = require('glob');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const nodeModulesPath = path.resolve(__dirname, 'node_modules')
@ -14,7 +14,7 @@ module.exports = (env, options) => {
optimization: {
minimizer: [
new TerserPlugin({ cache: true, parallel: true, sourceMap: devMode }),
new OptimizeCSSAssetsPlugin({})
new CssMinimizerPlugin(),
]
},
mode: options.mode,
@ -63,7 +63,7 @@ module.exports = (env, options) => {
{
test: /\.css$/,
use: [
{loader: MiniCssExtractPlugin.loader, options: {sourceMap: true}},
{loader: MiniCssExtractPlugin.loader},
{loader: 'css-loader', options: {sourceMap: true}},
{loader: 'postcss-loader', options: {sourceMap: true}},
],
@ -75,12 +75,12 @@ module.exports = (env, options) => {
filename: 'css/[name].css',
chunkFilename: '[id].css',
}),
new CopyWebpackPlugin([
new CopyWebpackPlugin({patterns: [
{
from: path.resolve(__dirname, 'static'),
to: path.resolve(__dirname, '../priv/static'),
},
]),
]}),
],
resolve: {
alias: {

View file

@ -27,6 +27,27 @@ defmodule AppWeb do
end
end
def live_view do
quote do
use Phoenix.LiveView,
layout: {AppWeb.LayoutView, "live.html"}
import AppWeb.LiveHelpers
unquote(view_helpers())
end
end
def live_component do
quote do
use Phoenix.LiveComponent
import AppWeb.LiveHelpers
unquote(view_helpers())
end
end
def view do
quote do
use Phoenix.View,
@ -48,6 +69,7 @@ defmodule AppWeb do
import Plug.Conn
import Phoenix.Controller
import Phoenix.LiveView.Router
end
end
@ -66,9 +88,10 @@ defmodule AppWeb do
# Import basic rendering functionality (render, render_layout, etc)
import Phoenix.View
import Legendary.CoreWeb.Helpers
import AppWeb.ErrorHelpers
import AppWeb.Gettext
import Legendary.CoreWeb.Helpers
import Phoenix.LiveView.Helpers
alias AppWeb.Router.Helpers, as: Routes
end
end

View file

View file

@ -0,0 +1,41 @@
defmodule AppWeb.LiveHelpers do
@moduledoc """
Commonly functions for LiveViews.
"""
import Phoenix.LiveView
alias Legendary.Auth.User
alias Pow.Store.CredentialsCache
alias AppWeb.Pow.Routes
def assign_defaults(socket, session) do
assign_new(socket, :current_user, fn -> get_user(socket, session) end)
end
def require_auth(socket) do
if socket.assigns.current_user do
socket
else
redirect(socket, to: Routes.after_sign_out_path(%Plug.Conn{}))
end
end
defp get_user(socket, session, config \\ [otp_app: :core])
defp get_user(socket, %{"core_auth" => signed_token}, config) do
{otp_app, _config} = Keyword.pop(config, :otp_app, :core)
{store, store_config} = Pow.Plug.Base.store(Application.get_env(otp_app, :pow))
conn = struct!(Plug.Conn, secret_key_base: socket.endpoint.config(:secret_key_base))
salt = Atom.to_string(Pow.Plug.Session)
with {:ok, token} <- Pow.Plug.verify_token(conn, salt, signed_token, config),
{user, _metadata} <- store.get(store_config, token) do
user
else
_any -> nil
end
end
defp get_user(_, _, _), do: nil
end

View file

@ -9,10 +9,11 @@ defmodule AppWeb.Router do
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :fetch_live_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :put_layout, {AppWeb.LayoutView, :app}
plug :put_root_layout, {AppWeb.LayoutView, :root}
end
pipeline :api do
@ -57,6 +58,7 @@ defmodule AppWeb.Router do
pow_extension_routes()
end
use Legendary.Core.Routes
use Legendary.Admin.Routes
use Legendary.Content.Routes
end

View file

@ -0,0 +1,22 @@
<div class="fixed w-full px-4 z-50 mt-20">
<%= [info: "green", error: "red"] |> Enum.map(fn {level, color} -> %>
<%= if live_flash(@flash, level) do %>
<div
class="relative bg-<%= color %>-100 lg:w-1/2 w-full p-5 object-right rounded shadow-xl m-auto mb-5 js-flash"
phx-click="lv:clear-flash"
phx-value-key="<%= level %>"
>
<div class="flex justify-between text-<%= color %>-700">
<div class="flex space-x-3">
<div class="flex-1 leading-tight text-sm font-medium">
<%= live_flash(@flash, level) %>
</div>
</div>
<div class="flex-none">
&times;
</div>
</div>
</div>
<% end %>
<% end) %>
</div>

View file

@ -1,3 +1,5 @@
<% conn_or_socket = if assigns[:conn], do: assigns[:conn], else: @socket %>
<nav class="flex items-center justify-between flex-wrap bg-grey-dark p-6 w-full z-10 bg-gray-800">
<div class="flex items-center flex-no-shrink text-white mr-6">
<a class="text-white no-underline hover:text-white hover:no-underline" href="/">
@ -35,14 +37,14 @@
class: "inline-block text-white no-underline hover:text-white hover:text-underline py-2 px-4"
%>
</li>
<%= if has_role?(@conn, :admin) do %>
<%= if has_role?(conn_or_socket, :admin) do %>
<li class="mr-3">
<a class="inline-block py-2 px-4 text-white no-underline" href="/admin">Admin</a>
</li>
<% end %>
<%= if Pow.Plug.current_user(@conn) do %>
<%= if current_user(conn_or_socket) do %>
<li class="mr-3">
<%= link "Sign Out", to: Routes.pow_session_path(@conn, :delete), method: :delete, class: "inline-block text-white no-underline hover:text-white hover:text-underline py-2 px-4" %>
<%= link "Sign Out", to: Routes.pow_session_path(conn_or_socket, :delete), method: :delete, class: "inline-block text-white no-underline hover:text-white hover:text-underline py-2 px-4" %>
</li>
<% else %>
<% end %>

View file

@ -1,24 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title><%= title(@view_module, @view_template, assigns) %></title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<%= feed_tag(@conn, @view_module, @view_template, assigns) %>
<script defer type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</head>
<body class="text-gray-800 antialiased">
<main role="main">
<!-- Page Contents -->
<div class="bg-gray-100 min-h-screen">
<%= render "_menu.html", assigns %>
<%= render "_menu.html", assigns %>
<%= flash_block(@conn) %>
<%= flash_block(@conn) %>
<%= @inner_content %>
</div>
</main>
</body>
</html>
<%= @inner_content %>

View file

@ -0,0 +1,6 @@
<%= render "_menu.html", assigns %>
<%= render "_live_flash_block.html", flash: @flash %>
<%= @inner_content %>

View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<%= csrf_meta_tag() %>
<%= live_title_tag title(@view_module, @view_template, assigns) %>
<link phx-track-static rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<script defer phx-track-static type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</head>
<body class="text-gray-800 antialiased">
<main role="main">
<!-- Page Contents -->
<div class="bg-gray-100 min-h-screen">
<%= @inner_content %>
</div>
</main>
</body>
</html>

View file

@ -44,12 +44,14 @@ defmodule App.MixProject do
{:core, in_umbrella: true},
{:ecto_sql, "~> 3.4"},
{:excoveralls, "~> 0.10", only: [:dev, :test]},
{:floki, ">= 0.30.0"},
{:oban, "~> 2.1"},
{:phoenix, "~> 1.5.8"},
{:phoenix_ecto, "~> 4.0"},
{:phoenix_html, "~> 2.11"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_dashboard, "~> 0.2.0"},
{:phoenix_live_dashboard, "~> 0.4.0"},
{:phoenix_live_view, "~> 0.15.7", override: true},
{:postgrex, ">= 0.0.0"},
{:telemetry_metrics, "~> 0.4"},
{:telemetry_poller, "~> 0.4"},

View file

@ -42,7 +42,7 @@ defmodule Legendary.Content do
def process_content(text) do
text
|> Earmark.as_html!(encode: false)
|> Earmark.as_html!()
end
# Include shared imports and aliases for views

View file

@ -3,8 +3,6 @@ defmodule Legendary.Content.FeedsController do
alias Legendary.Content.{Posts}
plug :put_layout, false when action in [:preview]
def index(conn, params) do
category = params |> Map.get("category")
posts = Posts.list_posts(params)

View file

@ -5,9 +5,9 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title><%= title(@view_module, @view_template, assigns) %></title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<link phx-track-static rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<%= feed_tag(@conn, @view_module, @view_template, assigns) %>
<script defer type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
<script phx-track-static defer type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</head>
<body class="text-gray-800 antialiased">
<main role="main">

View file

@ -1,7 +1,7 @@
defmodule Legendary.Content.MixProject do
use Mix.Project
@version "2.10.0"
@version "2.11.2"
def project do
[
@ -42,9 +42,9 @@ defmodule Legendary.Content.MixProject do
defp deps do
[
{:core, in_umbrella: true},
{:earmark, "1.4.3"},
{:earmark, "1.4.15"},
{:excoveralls, "~> 0.10", only: [:dev, :test]},
{:floki, "~> 0.25.0"},
{:floki, ">= 0.30.0"},
{:gettext, "~> 0.11"},
{:jason, "~> 1.0"},
{:mock, "~> 0.3.0", only: :test},
@ -54,10 +54,10 @@ defmodule Legendary.Content.MixProject do
{:phoenix, "~> 1.5.8"},
{:phoenix_ecto, "~> 4.0"},
{:phoenix_html, "~> 2.11"},
{:phoenix_html_sanitizer, "~> 1.0.0"},
{:phoenix_html_sanitizer, "~> 1.1.0"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_dashboard, "~> 0.2.0"},
{:php_serializer, "~> 0.9.0"},
{:phoenix_live_dashboard, "~> 0.4.0"},
{:php_serializer, "~> 2.0.0"},
{:plug_cowboy, "~> 2.0"},
{:sitemap, "~> 1.1"},
{:slugger, "~> 0.3"},

View file

@ -0,0 +1,32 @@
# Feature Flags
Legendary comes with [Fun with Flags](https://github.com/tompave/fun_with_flags)
preconfigured for managing [feature flags](https://en.wikipedia.org/wiki/Feature_toggle).
This allows you to have more granular control over which users see which features
and when. For example, you can hide a feature which is not complete, or show it
to only a select group of testers.
Fun With Flags supports a variety of different feature gate types. From
the Fun With Flags docs:
* **Boolean**: globally on and off.
* **Actors**: on or off for specific structs or data. The `FunWithFlags.Actor` protocol can be implemented for types and structs that should have specific rules. For example, in web applications it's common to use a `%User{}` struct or equivalent as an actor, or perhaps the current country of the request.
* **Groups**: on or off for structs or data that belong to a category or satisfy a condition. The `FunWithFlags.Group` protocol can be implemented for types and structs that belong to groups for which a feature flag can be enabled or disabled. For example, one could implement the protocol for a `%User{}` struct to identify administrators.
* **%-of-Time**: globally on for a percentage of the time. It ignores actors and groups. Mutually exclusive with the %-of-actors gate.
* **%-of-Actors**: globally on for a percentage of the actors. It only applies when the flag is checked with a specific actor and is ignored when the flag is checked without actor arguments. Mutually exclusive with the %-of-time gate.
Since feature flags may be checked often (sometimes multiple times per request),
Fun With Flags uses a two-layer approach. Flags are cached in [ETS](https://erlang.org/doc/man/ets.html)
and also persisted to longer-term storage so that they are not lost when the app
restarts.
By default, Legendary caches the flags for five minutes. We use Ecto for
persistence. We also use Phoenix PubSub to inform application nodes when a flag
has been updated. This configuration is a sensible default that we would not
expect you to need to change in most cases.
## UI
We integrate the Fun With Flags UI for managing flags. You can reach it through
a link in the admin.

View file

@ -3,6 +3,12 @@ defmodule Legendary.Auth.UserAdmin do
alias Legendary.Auth.User
alias Legendary.Core.Repo
def custom_links(_schema) do
[
%{name: "Feature Flags", url: "/admin/feature-flags", order: 2, location: :top, icon: "flag"},
]
end
def create_changeset(schema, attrs) do
Legendary.Auth.User.admin_changeset(schema, attrs)
end

View file

@ -0,0 +1,45 @@
defmodule AuthWeb.Pow.ControllerCallbacks do
@moduledoc """
Hook into Pow Controllers to provide additional framework feature. In particular,
we disconnect any active live views when a user logs out. This will cause the
live view to re-connect with the new session environment.
"""
alias Pow.Extension.Phoenix.ControllerCallbacks
alias Plug.Conn
def before_respond(Pow.Phoenix.SessionController, :create, {:ok, conn}, config) do
user = conn.assigns.current_user
conn =
conn
|> Conn.put_session(:current_user_id, user.id)
|> Conn.put_session(:live_socket_id, "users_sockets:#{user.id}")
ControllerCallbacks.before_respond(
Pow.Phoenix.SessionController,
:create,
{:ok, conn},
config
)
end
def before_respond(Pow.Phoenix.SessionController, :delete, {:ok, conn}, config) do
live_socket_id = Conn.get_session(conn, :live_socket_id)
AppWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{})
conn =
conn
|> Conn.delete_session(:live_socket_id)
ControllerCallbacks.before_respond(
Pow.Phoenix.SessionController,
:delete,
{:ok, conn},
config
)
end
defdelegate before_respond(controller, action, results, config), to: ControllerCallbacks
defdelegate before_process(controller, action, results, config), to: ControllerCallbacks
end

View file

@ -1,7 +1,12 @@
defmodule Legendary.AuthWeb.Helpers do
def has_role?(conn = %Plug.Conn{}, role) do
conn
|> Pow.Plug.current_user()
def current_user(socket = %Phoenix.LiveView.Socket{assigns: %{current_user: user}}), do: user
def current_user(socket = %Phoenix.LiveView.Socket{assigns: %{__assigns__: %{current_user: user}}}), do: user
def current_user(%Phoenix.LiveView.Socket{}), do: nil
def current_user(conn), do: Pow.Plug.current_user(conn)
def has_role?(conn_or_socket, role) do
conn_or_socket
|> current_user()
|> Legendary.Auth.Roles.has_role?(role)
end
end

View file

@ -0,0 +1,11 @@
defmodule Legendary.Core.Routes do
defmacro __using__(_opts \\ []) do
quote do
scope path: "/admin/feature-flags" do
pipe_through :require_admin
forward "/", FunWithFlags.UI.Router, namespace: "admin/feature-flags"
end
end
end
end

View file

@ -7,11 +7,8 @@ defmodule Legendary.CoreWeb.Helpers do
import Phoenix.Controller, only: [get_flash: 2]
import Legendary.CoreWeb.ErrorHelpers
def has_role?(conn = %Plug.Conn{}, role) do
conn
|> Pow.Plug.current_user()
|> Legendary.Auth.Roles.has_role?(role)
end
defdelegate current_user(a), to: Legendary.AuthWeb.Helpers
defdelegate has_role?(a, b), to: Legendary.AuthWeb.Helpers
def changeset_error_block(changeset) do
~E"""

View file

@ -1,7 +1,7 @@
defmodule Legendary.Core.MixProject do
use Mix.Project
@version "2.10.0"
@version "2.11.2"
def project do
[
@ -58,6 +58,7 @@ defmodule Legendary.Core.MixProject do
"guides/features/content-management.md",
"guides/features/devops-templates.md",
"guides/features/email.md",
"guides/features/feature-flags.md",
"guides/features/i18n.md",
"guides/features/tasks-and-scripts.md",
]
@ -139,15 +140,17 @@ defmodule Legendary.Core.MixProject do
{:ex_cldr, "~> 2.13.0"},
{:ex_doc, "~> 0.24", only: :dev, runtime: false},
{:excoveralls, "~> 0.10", only: [:dev, :test]},
{:fun_with_flags, "~> 1.6.0"},
{:fun_with_flags_ui, "~> 0.7.2"},
{:phoenix, "~> 1.5.8"},
{:phoenix_ecto, "~> 4.1"},
{:ecto_sql, "~> 3.4"},
{:ex_prompt, "~> 0.1.5"},
{:ex_prompt, "~> 0.2.0"},
{:linguist, "0.3.1"},
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 2.11"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_dashboard, "~> 0.2.0"},
{:phoenix_live_dashboard, "~> 0.4.0"},
{:phoenix_pubsub, "~> 2.0"},
{:pow, "~> 1.0.20"},
{:telemetry_metrics, "~> 0.4"},

View file

@ -0,0 +1,23 @@
defmodule Legendary.Core.Repo.Migrations.AddFeatureFlagTable do
use Ecto.Migration
def up do
create table(:fun_with_flags_toggles, primary_key: false) do
add :id, :bigserial, primary_key: true
add :flag_name, :string, null: false
add :gate_type, :string, null: false
add :target, :string, null: false
add :enabled, :boolean, null: false
end
create index(
:fun_with_flags_toggles,
[:flag_name, :gate_type, :target],
[unique: true, name: "fwf_flag_name_gate_target_idx"]
)
end
def down do
drop table(:fun_with_flags_toggles)
end
end

View file

@ -40,7 +40,7 @@ config :core, :pow,
user: Legendary.Auth.User,
repo: Legendary.Core.Repo,
extensions: [PowEmailConfirmation, PowPersistentSession, PowResetPassword],
controller_callbacks: Pow.Extension.Phoenix.ControllerCallbacks,
controller_callbacks: AuthWeb.Pow.ControllerCallbacks,
mailer_backend: Legendary.AuthWeb.Pow.Mailer,
web_mailer_module: Legendary.AuthWeb,
web_module: Legendary.AuthWeb,
@ -74,7 +74,25 @@ config :app,
crontab: [
]
config :mnesia, dir: to_charlist(Path.expand("./priv/mnesia"))
config :mnesia, dir: to_charlist(Path.expand("./priv/mnesia@#{Kernel.node}"))
# Feature flags
config :fun_with_flags, :cache,
enabled: true,
ttl: 300 # seconds
config :fun_with_flags, :persistence,
adapter: FunWithFlags.Store.Persistent.Ecto,
repo: Legendary.Core.Repo
config :fun_with_flags, :cache_bust_notifications,
enabled: true,
adapter: FunWithFlags.Notifications.PhoenixPubSub,
client: App.PubSub
# Notifications can also be disabled, which will also remove the Redis/Redix dependency
config :fun_with_flags, :cache_bust_notifications, [enabled: false]
import_config "email_styles.exs"
import_config "admin.exs"

View file

@ -15,7 +15,7 @@ use Mix.Config
]
|> Enum.map(fn {otp_app, module} ->
config otp_app, Module.concat(module, "Endpoint"),
http: [port: 4000],
http: [port: String.to_integer(System.get_env("PORT") || "4000")],
debug_errors: true,
code_reloader: true,
check_origin: false,
@ -24,18 +24,19 @@ use Mix.Config
"node_modules/webpack/bin/webpack.js",
"--mode",
"development",
"--watch-stdin",
"--watch",
"--watch-options-stdin",
cd: Path.expand("../apps/#{otp_app}/assets", __DIR__)
]
]
config otp_app, Module.concat(module, "Endpoint"),
config otp_app, AppWeb.Endpoint,
live_reload: [
patterns: [
~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",
~r"priv/gettext/.*(po)$",
~r"lib/app/(live|views)/.*(ex)$",
~r"lib/app/templates/.*(eex)$"
~r"(live|views)/.*(ex)$",
~r"templates/.*(eex)$"
]
]
end)
@ -61,7 +62,7 @@ config :core, Legendary.CoreMailer, adapter: Bamboo.LocalAdapter
config :libcluster,
topologies: [
erlang_hosts: [
strategy: Elixir.Cluster.Strategy.ErlangHosts,
strategy: Elixir.Cluster.Strategy.Gossip,
]
]

View file

@ -73,7 +73,7 @@ config :core, Legendary.CoreMailer,
username: {:system, "SMTP_USERNAME"},
password: {:system, "SMTP_PASSWORD"},
tls: :if_available,
allowed_tls_versions: [:"tlsv1", :"tlsv1.1", :"tlsv1.2"],
allowed_tls_versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"],
ssl: false,
retries: 1,
no_mx_lookups: false,

View file

@ -1,7 +1,7 @@
defmodule Legendary.Mixfile do
use Mix.Project
@version "2.10.0"
@version "2.11.2"
def project do
[

View file

@ -16,25 +16,25 @@
"db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"},
"decimal": {:hex, :decimal, "1.9.0", "83e8daf59631d632b171faabafb4a9f4242c514b0a06ba3df493951c08f64d07", [:mix], [], "hexpm", "b1f2343568eed6928f3e751cf2dffde95bfaa19dd95d09e8a9ea92ccfd6f7d85"},
"dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"},
"earmark_parser": {:hex, :earmark_parser, "1.4.12", "b245e875ec0a311a342320da0551da407d9d2b65d98f7a9597ae078615af3449", [:mix], [], "hexpm", "711e2cc4d64abb7d566d43f54b78f7dc129308a63bc103fbd88550d2174b3160"},
"earmark": {:hex, :earmark, "1.4.15", "2c7f924bf495ec1f65bd144b355d0949a05a254d0ec561740308a54946a67888", [:mix], [{:earmark_parser, ">= 1.4.13", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "3b1209b85bc9f3586f370f7c363f6533788fb4e51db23aa79565875e7f9999ee"},
"earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"},
"ecto": {:hex, :ecto, "3.4.6", "08f7afad3257d6eb8613309af31037e16c36808dfda5a3cd0cb4e9738db030e4", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6f13a9e2a62e75c2dcfc7207bfc65645ab387af8360db4c89fee8b5a4bf3f70b"},
"ecto_sql": {:hex, :ecto_sql, "3.4.4", "d28bac2d420f708993baed522054870086fd45016a9d09bb2cd521b9c48d32ea", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "edb49af715dd72f213b66adfd0f668a43c17ed510b5d9ac7528569b23af57fe8"},
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"ex_cldr": {:hex, :ex_cldr, "2.13.0", "742f14a4afcfea61a190d603d8e555d2c91d71e4e8fc2520d5dc35616969e225", [:mix], [{:cldr_utils, "~> 2.3", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "5e4cf3e945ee60156a3342e2a762f69036ffbe1f80520cc88592d68f12c5db55"},
"ex_doc": {:hex, :ex_doc, "0.24.0", "2df14354835afaabdf87cb2971ea9485d8a36ff590e4b6c250b4f60c8fdf9143", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "a0f4bcff21ceebea48414e49885d2a3e542200f76a2facf3f8faa54935eeb721"},
"ex_prompt": {:hex, :ex_prompt, "0.1.5", "b136642d0962f8ea37b3c9fa185ad1f42c71c3b9c6c3950f0358d7f3d2db2970", [:mix], [], "hexpm", "ad19a404708c9c7b05d36090b2d074ceafbed248a8de1a22d45a05ebe6994b83"},
"ex_prompt": {:hex, :ex_prompt, "0.2.0", "4030424e9a7710e1939d81eea4a82af2e0a1826065adb28d59bc01e919af4a60", [:mix], [], "hexpm", "220ac023d87d529457b87c9db4b40ce542bff93ae2de16c582808c6822dfe3e8"},
"excoveralls": {:hex, :excoveralls, "0.13.0", "4e1b7cc4e0351d8d16e9be21b0345a7e165798ee5319c7800b9138ce17e0b38e", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "fe2a56c8909564e2e6764765878d7d5e141f2af3bc8ff3b018a68ee2a218fced"},
"file_system": {:hex, :file_system, "0.2.8", "f632bd287927a1eed2b718f22af727c5aeaccc9a98d8c2bd7bff709e851dc986", [:mix], [], "hexpm", "97a3b6f8d63ef53bd0113070102db2ce05352ecf0d25390eb8d747c2bde98bca"},
"floki": {:hex, :floki, "0.25.0", "b1c9ddf5f32a3a90b43b76f3386ca054325dc2478af020e87b5111c19f2284ac", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "631f4e627c46d5ecd347df5a2accdaf0621c77c3693c5b75a8ad58e84c61f242"},
"floki": {:hex, :floki, "0.31.0", "f05ee8a8e6a3ced4e62beeb2c79a63bc8e12ab98fbaaf6e6a3d9b76b1278e23f", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "b05afa372f5c345a5bf240ac25ea1f0f3d5fcfd7490ac0beeb4a203f9444891e"},
"gen_smtp": {:hex, :gen_smtp, "1.1.1", "bf9303c31735100631b1d708d629e4c65944319d1143b5c9952054f4a1311d85", [:rebar3], [{:hut, "1.3.0", [hex: :hut, repo: "hexpm", optional: false]}, {:ranch, ">= 1.7.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "51bc50cc017efd4a4248cbc39ea30fb60efa7d4a49688986fafad84434ff9ab7"},
"gen_stage": {:hex, :gen_stage, "1.0.0", "51c8ae56ff54f9a2a604ca583798c210ad245f415115453b773b621c49776df5", [:mix], [], "hexpm", "1d9fc978db5305ac54e6f5fec7adf80cd893b1000cf78271564c516aa2af7706"},
"gen_state_machine": {:hex, :gen_state_machine, "2.1.0", "a38b0e53fad812d29ec149f0d354da5d1bc0d7222c3711f3a0bd5aa608b42992", [:mix], [], "hexpm", "ae367038808db25cee2f2c4b8d0531522ea587c4995eb6f96ee73410a60fa06b"},
"gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"},
"hackney": {:hex, :hackney, "1.17.4", "99da4674592504d3fb0cfef0db84c3ba02b4508bae2dff8c0108baa0d6e0977c", [:rebar3], [{:certifi, "~>2.6.1", [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.3.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", "de16ff4996556c8548d512f4dbe22dd58a587bf3332e7fd362430a7ef3986b16"},
"html_entities": {:hex, :html_entities, "0.5.1", "1c9715058b42c35a2ab65edc5b36d0ea66dd083767bef6e3edb57870ef556549", [:mix], [], "hexpm", "30efab070904eb897ff05cd52fa61c1025d7f8ef3a9ca250bc4e6513d16c32de"},
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.0.1", "2572e7122c78ab7e57b613e7c7f5e42bf9b3c25e430e32f23f1413d86db8a0af", [:mix], [{:mochiweb, "~> 2.12.2", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm", "c334e2835e094fb9c04658bd4cfc7533fa51a8f56f11343c57ab9cb2a01d8613"},
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.4.1", "e8a67da405fe9f0d1be121a40a60f70811192033a5b8d00a95dddd807f5e053e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm", "68d92656f47cd73598c45ad2394561f025c8c65d146001b955fd7b517858962a"},
"hut": {:hex, :hut, "1.3.0", "71f2f054e657c03f959cf1acc43f436ea87580696528ca2a55c8afb1b06c85e7", [:"erlang.mk", :rebar, :rebar3], [], "hexpm", "7e15d28555d8a1f2b5a3a931ec120af0753e4853a4c66053db354f35bf9ab563"},
"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.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
@ -49,7 +49,7 @@
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mochiweb": {:hex, :mochiweb, "2.12.2", "80804ad342afa3d7f3524040d4eed66ce74b17a555de454ac85b07c479928e46", [:make, :rebar], [], "hexpm", "d3e681d4054b74a96cf2efcd09e94157ab83a5f55ddc4ce69f90b8144673bd7a"},
"mochiweb": {:hex, :mochiweb, "2.20.1", "e4dbd0ed716f076366ecf62ada5755a844e1d95c781e8c77df1d4114be868cdf", [:rebar3], [], "hexpm", "d1aeee7870470d2fa9eae0b3d5ab6c33801aa2d82b10e9dade885c5c921b36aa"},
"mock": {:hex, :mock, "0.3.5", "feb81f52b8dcf0a0d65001d2fec459f6b6a8c22562d94a965862f6cc066b5431", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "6fae404799408300f863550392635d8f7e3da6b71abdd5c393faf41b131c8728"},
"neotomex": {:hex, :neotomex, "0.1.7", "64f76513653aa87ea7abdde0fd600e56955d838020a13d88f2bf334c88ac3e7a", [:mix], [], "hexpm", "4b87b8f614d1cd89dc8ba80ba0e559bedb3ebf6f6d74cd774fcfdd215e861445"},
"nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
@ -58,10 +58,10 @@
"phoenix": {:hex, :phoenix, "1.5.9", "a6368d36cfd59d917b37c44386e01315bc89f7609a10a45a22f47c007edf2597", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7e4bce20a67c012f1fbb0af90e5da49fa7bf0d34e3a067795703b74aef75427d"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.1.0", "a044d0756d0464c5a541b4a0bf4bcaf89bffcaf92468862408290682c73ae50d", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "c5e666a341ff104d0399d8f0e4ff094559b2fde13a5985d4cb5023b2c2ac558b"},
"phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"},
"phoenix_html_sanitizer": {:hex, :phoenix_html_sanitizer, "1.0.2", "e2c8cfbc83660e362753de127cc957bec3442a8aecdf271fb65a684a906fccf5", [:mix], [{:html_sanitize_ex, "~> 1.0.0", [hex: :html_sanitize_ex, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "47aebb08fa954b7ad95f295fb701df9800ee3a489212119c9c6074a65e1e5a10"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.2.6", "1b4e1b7d797386b7f9d70d2af931dc9843a5f2f2423609d22cef1eec4e4dba7d", [:mix], [{:phoenix_html, "~> 2.14.1 or ~> 2.15", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.13.1", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.4.0 or ~> 0.5.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "b20dcad98c4ca63d38a7f5e7a40936e1e8e9da983d3d722b88ae33afb866c9ca"},
"phoenix_html_sanitizer": {:hex, :phoenix_html_sanitizer, "1.1.0", "ea9e1162217621208ba6b2951a24abe2c06b39347f65c22c31312f9f5ac0fa75", [:mix], [{:html_sanitize_ex, "~> 1.1", [hex: :html_sanitize_ex, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "089f28f0592d58f7cf1f032b89c13e873dc73c77a2ccf3386aee976c6ff077c9"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.4.0", "87990e68b60213d7487e65814046f9a2bed4a67886c943270125913499b3e5c3", [:mix], [{:ecto_psql_extras, "~> 0.4.1 or ~> 0.5", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.14.1 or ~> 2.15", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.15.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.4.0 or ~> 0.5.0 or ~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "8d52149e58188e9e4497cc0d8900ab94d9b66f96998ec38c47c7a4f8f4f50e57"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.4", "940c0344b1d66a2e46eef02af3a70e0c5bb45a4db0bf47917add271b76cd3914", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "38f9308357dea4cc77f247e216da99fcb0224e05ada1469167520bed4cb8cccd"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.13.3", "2186c55cc7c54ca45b97c6f28cfd267d1c61b5f205f3c83533704cd991bdfdec", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.4.17 or ~> 1.5.2", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "c6309a7da2e779cb9cdf2fb603d75f38f49ef324bedc7a81825998bd1744ff8a"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.15.7", "09720b8e5151b3ca8ef739cd7626d4feb987c69ba0b509c9bbdb861d5a365881", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.5.7", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 0.5", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a756cf662420272d0f1b3b908cce5222163b5a95aa9bab404f9d29aff53276e"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
"php_serializer": {:hex, :php_serializer, "0.9.2", "59c5fd6bd3096671fd89358fb8229341ac7423b50ad8d45a15213b02ea2edab2", [:mix], [], "hexpm", "34eb835a460944f7fc216773b363c02e7dcf8ac0390c9e9ccdbd92b31a7ca59a"},
"plug": {:hex, :plug, "1.11.1", "f2992bac66fdae679453c9e86134a4201f6f43a687d8ff1cd1b2862d53c80259", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "23524e4fefbb587c11f0833b3910bfb414bf2e2534d61928e920f54e3a1b881f"},
@ -76,7 +76,7 @@
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm", "94884f84783fc1ba027aba8fe8a7dae4aad78c98e9f9c76667ec3471585c08c6"},
"telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.5.0", "1b796e74add83abf844e808564275dfb342bcc930b04c7577ab780e262b0d998", [:mix], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "31225e6ce7a37a421a0a96ec55244386aec1c190b22578bd245188a4a33298fd"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.0", "da9d49ee7e6bb1c259d36ce6539cd45ae14d81247a2b0c90edf55e2b50507f7b", [:mix], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5cfe67ad464b243835512aa44321cee91faed6ea868d7fb761d7016e02915c3d"},
"telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"},
"timex": {:hex, :timex, "3.6.2", "845cdeb6119e2fef10751c0b247b6c59d86d78554c83f78db612e3290f819bc2", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "26030b46199d02a590be61c2394b37ea25a3664c02fafbeca0b24c972025d47a"},
"tzdata": {:hex, :tzdata, "1.0.3", "73470ad29dde46e350c60a66e6b360d3b99d2d18b74c4c349dbebbc27a09a3eb", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a6e1ee7003c4d04ecbd21dd3ec690d4c6662db5d3bbdd7262d53cdf5e7c746c1"},

14340
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "@mythic-insight/legendary",
"version": "2.10.0",
"version": "2.11.2",
"private": true,
"description": "The Legendary Phoenix Boilerplate.",
"main": "index.js",
@ -19,14 +19,16 @@
"homepage": "https://gitlab.com/mythic-insight/legendary#readme",
"devDependencies": {
"@google/semantic-release-replace-plugin": "^1.0.2",
"@semantic-release/commit-analyzer": "^6.1.0",
"@semantic-release/commit-analyzer": "^8.0.1",
"@semantic-release/exec": "^5.0.0",
"@semantic-release/git": "^7.0.8",
"@semantic-release/npm": "^7.0.9",
"@semantic-release/git": "^9.0.0",
"@semantic-release/npm": "^7.1.3",
"dot": "^1.1.3",
"semantic-release": "^15.14.0"
"http-proxy": "^1.18.1",
"semantic-release": "^17.4.4"
},
"release": {
"branch": "master",
"plugins": [
"@semantic-release/commit-analyzer"
],

View file

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -x
set -e
@ -6,10 +6,10 @@ set -e
if ! brew -v &> /dev/null
then
echo "WARNING: Cannot find brew. Skipping brewfile installation."
export KERL_CONFIGURE_OPTIONS="--disable-hipe"
export KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS --disable-hipe"
else
brew bundle
export KERL_CONFIGURE_OPTIONS="--disable-hipe --with-ssl=$(brew --prefix openssl)"
export KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS --disable-hipe --with-ssl=$(brew --prefix openssl)"
fi
if ! which asdf &> /dev/null

View file

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -x
set -e

5
script/env-ci Executable file
View file

@ -0,0 +1,5 @@
#!/usr/bin/env node
const envCi = require('env-ci');
console.log(envCi());

34
script/proxy Executable file
View file

@ -0,0 +1,34 @@
#!/usr/bin/env node
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create a proxy server with custom application logic
//
var proxy = new httpProxy.createProxyServer({});
var proxyServer = http.createServer(function (req, res) {
proxy.web(req, res, {
target: {
host: 'localhost',
port: 4001
}
});
});
//
// Listen to the `upgrade` event and proxy the
// WebSocket requests as well.
//
proxyServer.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head, {
target: {
host: 'localhost',
port: 4001
}
});
});
console.log("listening on port 4000")
proxyServer.listen(4000);

View file

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -x
set -e

33
script/server-clustered Executable file
View file

@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -x
set -e
DIR_PATH=$(dirname $0)
$DIR_PATH/update
trap_with_arg() { # from https://stackoverflow.com/a/2183063/804678
local func="$1"; shift
for sig in "$@"; do
trap "$func $sig" "$sig"
done
}
stop() {
trap - SIGINT EXIT
printf '\n%s\n' "received $1, killing child processes"
kill -s SIGINT 0
}
trap_with_arg 'stop' EXIT SIGINT SIGTERM SIGHUP
CLUSTER_COOKIE=`openssl rand -hex 8`
PORT=4002 elixir --sname two --cookie $CLUSTER_COOKIE -S mix phx.server 2>/dev/null &
PORT=4003 elixir --sname three --cookie $CLUSTER_COOKIE -S mix phx.server 2>/dev/null &
PORT=4004 elixir --sname four --cookie $CLUSTER_COOKIE -S mix phx.server 2>/dev/null &
$DIR_PATH/proxy &
PORT=4001 iex --sname one --cookie $CLUSTER_COOKIE -S mix phx.server

View file

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -x
set -e

View file

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -x
set -e