1
0
mirror of https://github.com/danbee/chess synced 2025-03-04 08:39:06 +00:00

Compare commits

..

45 Commits

Author SHA1 Message Date
205d5a5a24 Add back @session_options 2023-10-04 15:33:52 -05:00
87504064e7 WIP: Game info 2023-10-04 12:09:06 -05:00
3543ccdcae Fix layout issue caused by live component container 2023-10-04 12:09:06 -05:00
1ea842d0ab Bunch of fixes 2023-10-04 12:09:04 -05:00
f5c35de8d8 Clients subscribe to the game to get updates 2023-10-04 12:08:46 -05:00
bbc1838d7e Tidy 2023-10-04 12:08:46 -05:00
04e00e530b Now we're correctly handling moves 2023-10-04 12:08:44 -05:00
7e2c841b59 Correctly choose pieces 2023-10-04 12:07:11 -05:00
b01403cbe4 These variables aren't used 2023-10-04 12:07:11 -05:00
dea6198e30 WIP 2023-10-04 12:07:07 -05:00
d2074ade11 Install LiveView 2023-10-04 12:06:12 -05:00
2f561c28fe Few rendering fix ups 2023-10-04 12:04:19 -05:00
34551788c7 Render the initial board in Phoenix 2023-10-04 12:04:19 -05:00
a26f044822 Correct build command 2023-02-05 12:46:37 -06:00
a750756187 Working dart_sass version 2023-02-05 12:44:18 -06:00
662efda6b1 Install Yarn properly 2023-02-05 12:18:20 -06:00
6f7b087b82 Install NodeJS and Yarn 2023-02-05 11:59:58 -06:00
b1451535ca Add assets step 2023-02-04 23:35:05 -06:00
e4fc3a1b6f Install ChromeDriver 2023-02-04 23:18:22 -06:00
6cecc3005c Force install of Chrome 2023-02-04 23:02:35 -06:00
c19f586d13 Update Apt 2023-02-04 23:01:22 -06:00
f5641150a0 Rename pg-db to db 2023-02-04 22:59:58 -06:00
f0ed129028 Add files for Codeship Pro 2023-02-04 22:58:09 -06:00
1a9358d5e0 Install Chromedriver for Codeship 2023-02-04 21:40:21 -06:00
8f683dd73f Mix format 2023-02-04 21:35:56 -06:00
69f05a1c5d Fix tests 2023-02-04 21:33:48 -06:00
01471967c8 Update deps and format code 2023-02-02 19:32:42 -06:00
5cd457bc62 Switch default domain 2023-01-30 12:19:36 -06:00
27f5fc6730 Switch to Config module 2023-01-30 12:19:22 -06:00
d6ca73e4bd Will this work? 2023-01-30 11:52:33 -06:00
9909abd17f NodeJS version 14.20.1 2023-01-30 11:52:33 -06:00
6eb2a53695 Is this the right format? 2022-10-12 20:41:50 -05:00
9b0c75c2ce Update NodeJS version 2022-10-12 20:40:23 -05:00
7bf2312106 Update Elixir 2022-10-12 20:40:11 -05:00
1de19ae6c9 Mix buildpacks 2022-02-15 21:28:49 -06:00
fc83a1e16d 23.3.2 2022-02-15 21:07:16 -06:00
909d04f2a1 Add Gigalixir asset deploy script 2022-02-15 21:05:07 -06:00
6c51aa113f OTP? 2022-02-15 21:04:29 -06:00
a893dd3e85 Upgrade to latest Elixir/Erlang 2022-02-15 21:00:29 -06:00
c3e1206b58 Add :ssl to extra applications 2022-02-15 18:42:58 -06:00
14952a5d6c Add Runtime config 2022-02-15 18:37:53 -06:00
a83ee57e7b Switch to ESBuild and Dart-Sass 2022-02-15 18:37:33 -06:00
cfa472e13a Compatible Node version 2022-02-15 18:36:27 -06:00
1d7fb6c87b Migrate SASS to use new math.div function 2022-02-15 18:36:10 -06:00
d56502a001 Upgrade Phoenix 2022-02-15 12:46:08 -06:00
86 changed files with 1972 additions and 4788 deletions

View File

@ -1,4 +1,3 @@
https://github.com/gigalixir/gigalixir-buildpack-clean-cache.git
https://github.com/HashNuke/heroku-buildpack-elixir https://github.com/HashNuke/heroku-buildpack-elixir
https://github.com/gjaldon/heroku-buildpack-phoenix-static https://github.com/gjaldon/heroku-buildpack-phoenix-static
https://github.com/gigalixir/gigalixir-buildpack-distillery.git https://github.com/gigalixir/gigalixir-buildpack-mix.git

3
.formatter.exs Normal file
View File

@ -0,0 +1,3 @@
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

View File

@ -1,4 +1,4 @@
elixir 1.11.3 elixir 1.14.1
python 2.7.14 python 3.9.1
nodejs 10.16.0 nodejs 16.14.0
erlang 23.2.3 erlang 24.2.1

42
Dockerfile Normal file
View File

@ -0,0 +1,42 @@
FROM --platform=linux/amd64 elixir:1.14.1
# Create a directory for your application code and set it as the WORKDIR. All following commands will be run in this directory.
RUN mkdir /app
WORKDIR /app
# Update package repo
RUN apt-get update
# Install Chrome
RUN wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb && \
apt-get -y install ./google-chrome-stable_current_amd64.deb
# Install ChromeDriver
RUN CHROMEDRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` && \
mkdir -p /opt/chromedriver-$CHROMEDRIVER_VERSION && \
curl -sS -o /tmp/chromedriver_linux64.zip http://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip && \
unzip -qq /tmp/chromedriver_linux64.zip -d /opt/chromedriver-$CHROMEDRIVER_VERSION && \
rm /tmp/chromedriver_linux64.zip && \
chmod +x /opt/chromedriver-$CHROMEDRIVER_VERSION/chromedriver && \
ln -fs /opt/chromedriver-$CHROMEDRIVER_VERSION/chromedriver /usr/local/bin/chromedriver
# Install NodeJS
RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash - && \
apt-get install nodejs
# Install Yarn
RUN npm install --global yarn
# Install Rebar and Hex
RUN mix local.rebar --force && mix local.hex --force
# Install the Phoenix Mix archive
RUN mix archive.install --sha512 2a2f5167f5ea30f314500da449dbd8cfb4b6986cc27197c82fa4cc328798814f89a4dbe0183a5f213faed3587e8133ce99c1fab74cf1597978a270bdcc7bf789 --force https://github.com/phoenixframework/archives/raw/master/phx_new.ez
# COPY mix.exs and mix.lock and install dependencies before adding the full code so the cache only
# gets invalidated when dependencies are changed
COPY mix.exs mix.lock ./
RUN mix deps.get
# Copy the app source code into the image
COPY ./ /app

View File

@ -1,3 +1,5 @@
@use "sass:math";
.opponent-finder__result { .opponent-finder__result {
border-bottom: 1px dotted $black; border-bottom: 1px dotted $black;
border-bottom-left-radius: $base-border-radius; border-bottom-left-radius: $base-border-radius;
@ -5,14 +7,14 @@
border-left: 1px dotted $black; border-left: 1px dotted $black;
border-right: 1px dotted $black; border-right: 1px dotted $black;
margin-top: -$small-spacing; margin-top: -$small-spacing;
padding: $small-spacing / 3; padding: math.div($small-spacing, 3);
} }
.opponent-finder__result-item { .opponent-finder__result-item {
border-radius: $base-border-radius / 2; border-radius: $base-border-radius * 0.5;
cursor: pointer; cursor: pointer;
display: block; display: block;
padding: $small-spacing / 3 $base-spacing / 2; padding: math.div($small-spacing, 3) $base-spacing * 0.5;
text-decoration: none; text-decoration: none;
&:hover, &:hover,

View File

@ -1,3 +1,5 @@
@use "sass:math";
$_form-background-color: $background-color; $_form-background-color: $background-color;
fieldset { fieldset {
@ -9,14 +11,14 @@ fieldset {
legend { legend {
font-weight: $heavy-font-weight; font-weight: $heavy-font-weight;
margin-bottom: $small-spacing / 2; margin-bottom: $small-spacing * 0.5;
padding: 0; padding: 0;
} }
label { label {
display: block; display: block;
font-weight: $heavy-font-weight; font-weight: $heavy-font-weight;
margin-bottom: $small-spacing / 2; margin-bottom: $small-spacing * 0.5;
} }
input, input,
@ -35,7 +37,7 @@ textarea {
box-sizing: border-box; box-sizing: border-box;
color: $foreground-color; color: $foreground-color;
margin-bottom: $small-spacing; margin-bottom: $small-spacing;
padding: $base-spacing / 3; padding: math.div($base-spacing, 3);
transition: border-color $base-duration $base-timing; transition: border-color $base-duration $base-timing;
width: 100%; width: 100%;

View File

@ -1,7 +1,7 @@
$base-border-radius: 0.5rem; $base-border-radius: 0.5rem;
$base-spacing: 2rem; $base-spacing: 2rem;
$small-spacing: $base-spacing / 2; $small-spacing: $base-spacing * 0.5;
$x-small-spacing: $small-spacing / 2; $x-small-spacing: $small-spacing * 0.5;
$base-z-index: 0; $base-z-index: 0;
$container-width: 90%; $container-width: 90%;

View File

@ -130,7 +130,7 @@
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive] /// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @param {number} $num - id of the child /// @param {number} $num - id of the child
@mixin middle($num) { @mixin middle($num) {
&:nth-child(#{round($num / 2)}) { &:nth-child(#{round($num * 0.5)}) {
@content; @content;
} }
} }

View File

@ -67,6 +67,8 @@
/// ///
/// @require {function} _fetch-bourbon-setting /// @require {function} _fetch-bourbon-setting
@use "sass:math";
@function modular-scale( @function modular-scale(
$increment, $increment,
$value: _fetch-bourbon-setting("modular-scale-base"), $value: _fetch-bourbon-setting("modular-scale-base"),
@ -78,7 +80,7 @@
// scale $v2 to just above $v1 // scale $v2 to just above $v1
@while $v2 > $v1 { @while $v2 > $v1 {
$v2: ($v2 / $ratio); // will be off-by-1 $v2: math.div($v2, $ratio); // will be off-by-1
} }
@while $v2 < $v1 { @while $v2 < $v1 {
$v2: ($v2 * $ratio); // will fix off-by-1 $v2: ($v2 * $ratio); // will fix off-by-1
@ -102,15 +104,15 @@
@if $increment < 0 { @if $increment < 0 {
// adjust $v2 to just below $v1 // adjust $v2 to just below $v1
@if $double-stranded { @if $double-stranded {
$v2: ($v2 / $ratio); $v2: math.div($v2, $ratio);
} }
@for $i from $increment through -1 { @for $i from $increment through -1 {
@if $double-stranded and ($v1 / $ratio) < $v2 { @if $double-stranded and math.div($v1, $ratio) < $v2 {
$value: $v2; $value: $v2;
$v2: ($v2 / $ratio); $v2: math.div($v2, $ratio);
} @else { } @else {
$v1: ($v1 / $ratio); $v1: math.div($v1, $ratio);
$value: $v1; $value: $v1;
} }
} }

View File

@ -12,6 +12,8 @@
/// // Output /// // Output
/// $dimension: 10; /// $dimension: 10;
@use "sass:math";
@function strip-unit($value) { @function strip-unit($value) {
@return ($value / ($value * 0 + 1)); @return math.div($value, $value * 0 + 1);
} }

View File

@ -55,25 +55,25 @@
@if $direction == "up" { @if $direction == "up" {
border-color: transparent transparent $color; border-color: transparent transparent $color;
border-width: 0 ($width / 2) $height; border-width: 0 ($width * 0.5) $height;
} @else if $direction == "up-right" { } @else if $direction == "up-right" {
border-color: transparent $color transparent transparent; border-color: transparent $color transparent transparent;
border-width: 0 $width $width 0; border-width: 0 $width $width 0;
} @else if $direction == "right" { } @else if $direction == "right" {
border-color: transparent transparent transparent $color; border-color: transparent transparent transparent $color;
border-width: ($height / 2) 0 ($height / 2) $width; border-width: ($height * 0.5) 0 ($height * 0.5) $width;
} @else if $direction == "down-right" { } @else if $direction == "down-right" {
border-color: transparent transparent $color; border-color: transparent transparent $color;
border-width: 0 0 $width $width; border-width: 0 0 $width $width;
} @else if $direction == "down" { } @else if $direction == "down" {
border-color: $color transparent transparent; border-color: $color transparent transparent;
border-width: $height ($width / 2) 0; border-width: $height ($width * 0.5) 0;
} @else if $direction == "down-left" { } @else if $direction == "down-left" {
border-color: transparent transparent transparent $color; border-color: transparent transparent transparent $color;
border-width: $width 0 0 $width; border-width: $width 0 0 $width;
} @else if $direction == "left" { } @else if $direction == "left" {
border-color: transparent $color transparent transparent; border-color: transparent $color transparent transparent;
border-width: ($height / 2) $width ($height / 2) 0; border-width: ($height * 0.5) $width ($height * 0.5) 0;
} @else if $direction == "up-left" { } @else if $direction == "up-left" {
border-color: $color transparent transparent; border-color: $color transparent transparent;
border-width: $width $width 0 0; border-width: $width $width 0 0;

View File

@ -19,13 +19,15 @@
/// ///
/// @access private /// @access private
@use "sass:math";
@function _contrast-ratio($color-1, $color-2) { @function _contrast-ratio($color-1, $color-2) {
$-local-lightness-1: _lightness($color-1) + 0.05; $-local-lightness-1: _lightness($color-1) + 0.05;
$-local-lightness-2: _lightness($color-2) + 0.05; $-local-lightness-2: _lightness($color-2) + 0.05;
@if $-local-lightness-1 > $-local-lightness-2 { @if $-local-lightness-1 > $-local-lightness-2 {
@return $-local-lightness-1 / $-local-lightness-2; @return math.div($-local-lightness-1, $-local-lightness-2);
} @else { } @else {
@return $-local-lightness-2 / $-local-lightness-1; @return math.div($-local-lightness-2, $-local-lightness-1);
} }
} }

View File

@ -11,11 +11,13 @@
/// ///
/// @access private /// @access private
@use "sass:math";
@function _gamma($channel) { @function _gamma($channel) {
@if $channel < 0.03928 { @if $channel < 0.03928 {
@return $channel / 12.92; @return math.div($channel, 12.92);
} @else { } @else {
$c: ($channel + 0.055) / 1.055; $c: math.div($channel + 0.055, 1.055);
@return (133 * $c * $c * $c + 155 * $c * $c) / 288; @return math.div(133 * $c * $c * $c + 155 * $c * $c, 288);
} }
} }

View File

@ -11,14 +11,16 @@
/// ///
/// @access private /// @access private
@use "sass:math";
@function _lightness($hex-color) { @function _lightness($hex-color) {
$-local-red-raw: red(rgba($hex-color, 1)); $-local-red-raw: red(rgba($hex-color, 1));
$-local-green-raw: green(rgba($hex-color, 1)); $-local-green-raw: green(rgba($hex-color, 1));
$-local-blue-raw: blue(rgba($hex-color, 1)); $-local-blue-raw: blue(rgba($hex-color, 1));
$-local-red: _gamma($-local-red-raw / 255); $-local-red: _gamma(math.div($-local-red-raw, 255));
$-local-green: _gamma($-local-green-raw / 255); $-local-green: _gamma(math.div($-local-green-raw, 255));
$-local-blue: _gamma($-local-blue-raw / 255); $-local-blue: _gamma(math.div($-local-blue-raw, 255));
@return $-local-red * 0.2126 + $-local-green * 0.7152 + $-local-blue * 0.0722; @return $-local-red * 0.2126 + $-local-green * 0.7152 + $-local-blue * 0.0722;
} }

View File

@ -22,8 +22,6 @@ import React from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import { createStore } from "redux"; import { createStore } from "redux";
import css from "../css/app.scss";
import Game from "./components/game"; import Game from "./components/game";
import OpponentFinder from "./components/opponent-finder"; import OpponentFinder from "./components/opponent-finder";
import chessBoardReducer from "./reducers/chess-board"; import chessBoardReducer from "./reducers/chess-board";

View File

@ -3,19 +3,19 @@
"description": " ", "description": " ",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"deploy": "webpack --mode production", "deploy": "cd .. && mix assets.deploy && rm -f _build/esbuild"
"watch": "webpack --mode development --watch-stdin"
}, },
"dependencies": { "dependencies": {
"@babel/polyfill": "^7.12.1", "@babel/polyfill": "^7.12.1",
"axios": "^0.21.0", "axios": "^0.21.0",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"esbuild": "^0.14.21",
"gettext.js": "^1.0.0", "gettext.js": "^1.0.0",
"immutable": "^3.8.2", "immutable": "^3.8.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"phoenix": "file:../deps/phoenix", "phoenix": "^1.7.0-rc.2",
"phoenix_html": "file:../deps/phoenix_html", "phoenix_html": "^3.2.0",
"phoenix_live_view": "file:../deps/phoenix_live_view", "phoenix_live_view": "^0.18.11",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-redux": "^7.2.4", "react-redux": "^7.2.4",
@ -24,18 +24,7 @@
"url-loader": "^4.1.1" "url-loader": "^4.1.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.14.6",
"@babel/preset-env": "^7.14.7",
"@babel/preset-react": "^7.14.5",
"babel-loader": "^8.2.2",
"copy-webpack-plugin": "^9.0.0",
"css-loader": "^5.2.6", "css-loader": "^5.2.6",
"mini-css-extract-plugin": "^1.6.0", "mini-css-extract-plugin": "^1.6.0"
"node-sass": "^6.0.0",
"optimize-css-assets-webpack-plugin": "^6.0.1",
"sass-loader": "^12.1.0",
"terser-webpack-plugin": "^5.1.3",
"webpack": "^5.40.0",
"webpack-cli": "^4.7.2"
} }
} }

View File

@ -1,56 +0,0 @@
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 CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports = (env, options) => {
const devMode = options.mode !== "production";
return {
optimization: {
minimizer: [new TerserPlugin(), new OptimizeCSSAssetsPlugin({})],
},
entry: {
app: glob.sync("./vendor/**/*.js").concat(["./js/app.js"]),
},
output: {
filename: "[name].js",
path: path.resolve(__dirname, "../priv/static/js"),
publicPath: "/js/",
},
devtool: devMode ? "eval-cheap-module-source-map" : undefined,
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
{
test: /\.s?css$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
{
test: /\.(png|jpg|gif|svg)$/i,
use: [
{
loader: "url-loader",
options: {
limit: 8192,
name: "[name].[hash:7].[ext]",
},
},
],
},
],
},
plugins: [
new MiniCssExtractPlugin({ filename: "../css/app.css" }),
new CopyWebpackPlugin({ patterns: [{ from: "static/", to: "../" }] }),
],
};
};

734
assets/yarn-error.log Normal file
View File

@ -0,0 +1,734 @@
Arguments:
/Users/danbarber/.asdf/installs/nodejs/16.14.0/bin/node /Users/danbarber/.asdf/installs/yarn/1.22.10/bin/yarn.js add phoenix phoenix_html phoenix_live_view
PATH:
/Users/danbarber/.asdf/plugins/nodejs/shims:/Users/danbarber/.asdf/installs/nodejs/16.14.0/bin:/Users/danbarber/.asdf/installs/yarn/1.22.10/bin:/Users/danbarber/.bin:/usr/local/share/npm/bin:.git/safe/../../bin:/Users/danbarber/.asdf/shims:/opt/homebrew/bin/../opt/asdf/libexec/bin:/usr/local/sbin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/VMware Fusion.app/Contents/Public:/usr/local/zfs/bin:/opt/X11/bin:/Library/Apple/usr/bin:/Applications/Wireshark.app/Contents/MacOS:/Applications/kitty.app/Contents/MacOS:/Users/danbarber/.fzf/bin
Yarn version:
1.22.10
Node version:
16.14.0
Platform:
darwin arm64
Trace:
Error: ENOENT: no such file or directory, open '/Users/danbarber/Library/Caches/Yarn/v6/npm-esbuild-linux-arm64-0.14.21-e05599ea6253b58394157da162d856f3ead62f9e-integrity/node_modules/esbuild-linux-arm64/.yarn-metadata.json'
npm manifest:
{
"repository": {},
"description": " ",
"license": "MIT",
"scripts": {
"deploy": "cd .. && mix assets.deploy && rm -f _build/esbuild"
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"axios": "^0.21.0",
"classnames": "^2.3.1",
"esbuild": "^0.14.21",
"gettext.js": "^1.0.0",
"immutable": "^3.8.2",
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.4",
"redux": "^4.1.0",
"redux-watch": "^1.2.0",
"url-loader": "^4.1.1"
},
"devDependencies": {
"css-loader": "^5.2.6",
"mini-css-extract-plugin": "^1.6.0"
}
}
yarn manifest:
No manifest
Lockfile:
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/polyfill@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.12.1.tgz#1f2d6371d1261bbd961f3c5d5909150e12d0bd96"
integrity sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==
dependencies:
core-js "^2.6.5"
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.12.1", "@babel/runtime@^7.9.2":
version "7.14.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.6.tgz#535203bc0892efc7dec60bdc27b2ecf6e409062d"
integrity sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==
dependencies:
regenerator-runtime "^0.13.4"
"@types/hoist-non-react-statics@^3.3.0":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
dependencies:
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
"@types/json-schema@^7.0.6":
version "7.0.7"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
"@types/prop-types@*":
version "15.7.3"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/react-redux@^7.1.16":
version "7.1.16"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.16.tgz#0fbd04c2500c12105494c83d4a3e45c084e3cb21"
integrity sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==
dependencies:
"@types/hoist-non-react-statics" "^3.3.0"
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
redux "^4.0.0"
"@types/react@*":
version "17.0.11"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.11.tgz#67fcd0ddbf5a0b083a0f94e926c7d63f3b836451"
integrity sha512-yFRQbD+whVonItSk7ZzP/L+gPTJVBkL/7shLEF+i9GC/1cV3JmUxEQz6+9ylhUpWSDuqo1N9qEvqS6vTj4USUA==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/scheduler@*":
version "0.16.1"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275"
integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==
ajv-keywords@^3.5.2:
version "3.5.2"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
ajv@^6.12.5:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ansi-styles@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178"
integrity sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=
axios@^0.21.0:
version "0.21.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
dependencies:
follow-redirects "^1.10.0"
big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
chalk@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f"
integrity sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=
dependencies:
ansi-styles "~1.0.0"
has-color "~0.1.0"
strip-ansi "~0.1.0"
classnames@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
colorette@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
core-js@^2.6.5:
version "2.6.12"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
css-loader@^5.2.6:
version "5.2.6"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.2.6.tgz#c3c82ab77fea1f360e587d871a6811f4450cc8d1"
integrity sha512-0wyN5vXMQZu6BvjbrPdUJvkCzGEO24HC7IS7nW4llc6BBFC+zwR9CKtYGv63Puzsg10L/o12inMY5/2ByzfD6w==
dependencies:
icss-utils "^5.1.0"
loader-utils "^2.0.0"
postcss "^8.2.15"
postcss-modules-extract-imports "^3.0.0"
postcss-modules-local-by-default "^4.0.0"
postcss-modules-scope "^3.0.0"
postcss-modules-values "^4.0.0"
postcss-value-parser "^4.1.0"
schema-utils "^3.0.0"
semver "^7.3.5"
cssesc@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
csstype@^3.0.2:
version "3.0.8"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340"
integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==
emojis-list@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
encoding@^0.1.11:
version "0.1.13"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
dependencies:
iconv-lite "^0.6.2"
esbuild-android-arm64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.21.tgz#8842d0c3b7c81fbe2dc46ddb416ffd6eb822184b"
integrity sha512-Bqgld1TY0wZv8TqiQmVxQFgYzz8ZmyzT7clXBDZFkOOdRybzsnj8AZuK1pwcLVA7Ya6XncHgJqIao7NFd3s0RQ==
esbuild-darwin-64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.21.tgz#ec7df02ad88ecf7f8fc23a3ed7917e07dea0c9c9"
integrity sha512-j+Eg+e13djzyYINVvAbOo2/zvZ2DivuJJTaBrJnJHSD7kUNuGHRkHoSfFjbI80KHkn091w350wdmXDNSgRjfYQ==
esbuild-darwin-arm64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.21.tgz#0c2a977edec1ef54097ee56a911518c820d4e5e4"
integrity sha512-nDNTKWDPI0RuoPj5BhcSB2z5EmZJJAyRtZLIjyXSqSpAyoB8eyAKXl4lB8U2P78Fnh4Lh1le/fmpewXE04JhBQ==
esbuild-freebsd-64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.21.tgz#f5b5fc1d031286c3a0949d1bda7db774b7d0404e"
integrity sha512-zIurkCHXhxELiDZtLGiexi8t8onQc2LtuE+S7457H/pP0g0MLRKMrsn/IN4LDkNe6lvBjuoZZi2OfelOHn831g==
esbuild-freebsd-arm64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.21.tgz#a05cab908013e4992b31a675850b8c44eb468c0c"
integrity sha512-wdxMmkJfbwcN+q85MpeUEamVZ40FNsBa9mPq8tAszDn8TRT2HoJvVRADPIIBa9SWWwlDChIMjkDKAnS3KS/sPA==
esbuild-linux-32@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.21.tgz#638d244cc58b951f447addb4bade628d126ef84b"
integrity sha512-fmxvyzOPPh2xiEHojpCeIQP6pXcoKsWbz3ryDDIKLOsk4xp3GbpHIEAWP0xTeuhEbendmvBDVKbAVv3PnODXLg==
esbuild-linux-64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.21.tgz#8eb634abee928be7e35b985fafbfef2f2e31397f"
integrity sha512-edZyNOv1ql+kpmlzdqzzDjRQYls+tSyi4QFi+PdBhATJFUqHsnNELWA9vMSzAaInPOEaVUTA5Ml28XFChcy4DA==
esbuild-linux-arm64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.21.tgz#e05599ea6253b58394157da162d856f3ead62f9e"
integrity sha512-t5qxRkq4zdQC0zXpzSB2bTtfLgOvR0C6BXYaRE/6/k8/4SrkZcTZBeNu+xGvwCU4b5dU9ST9pwIWkK6T1grS8g==
esbuild-linux-arm@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.21.tgz#1ae1078231cf689d3ba894a32d3723c0be9b91fd"
integrity sha512-aSU5pUueK6afqmLQsbU+QcFBT62L+4G9hHMJDHWfxgid6hzhSmfRH9U/f+ymvxsSTr/HFRU4y7ox8ZyhlVl98w==
esbuild-linux-mips64le@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.21.tgz#f05be62d126764e99b37edcac5bb49b78c7a8890"
integrity sha512-jLZLQGCNlUsmIHtGqNvBs3zN+7a4D9ckf0JZ+jQTwHdZJ1SgV9mAjbB980OFo66LoY+WeM7t3WEnq3FjI1zw4A==
esbuild-linux-ppc64le@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.21.tgz#592c98d82dad7982268ef8deed858c4566f07ab1"
integrity sha512-4TWxpK391en2UBUw6GSrukToTDu6lL9vkm3Ll40HrI08WG3qcnJu7bl8e1+GzelDsiw1QmfAY/nNvJ6iaHRpCQ==
esbuild-linux-riscv64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.21.tgz#0db7bd6f10d8f9afea973a7d6bf87b449b864b7b"
integrity sha512-fElngqOaOfTsF+u+oetDLHsPG74vB2ZaGZUqmGefAJn3a5z9Z2pNa4WpVbbKgHpaAAy5tWM1m1sbGohj6Ki6+Q==
esbuild-linux-s390x@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.21.tgz#254a9354d34c9d1b41a3e21d2ec9269cbbb2c5df"
integrity sha512-brleZ6R5fYv0qQ7ZBwenQmP6i9TdvJCB092c/3D3pTLQHBGHJb5zWgKxOeS7bdHzmLy6a6W7GbFk6QKpjyD6QA==
esbuild-netbsd-64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.21.tgz#4cb783d060b02bf3b897a9a12cce2b3b547726f8"
integrity sha512-nCEgsLCQ8RoFWVV8pVI+kX66ICwbPP/M9vEa0NJGIEB/Vs5sVGMqkf67oln90XNSkbc0bPBDuo4G6FxlF7PN8g==
esbuild-openbsd-64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.21.tgz#f886b93feefddbe573528fa4b421c9c6e2bc969b"
integrity sha512-h9zLMyVD0T73MDTVYIb/qUTokwI6EJH9O6wESuTNq6+XpMSr6C5aYZ4fvFKdNELW+Xsod+yDS2hV2JTUAbFrLA==
esbuild-sunos-64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.21.tgz#3829e4d57d4cb6950837fe90b0b67cdfb37cf13a"
integrity sha512-Kl+7Cot32qd9oqpLdB1tEGXEkjBlijrIxMJ0+vlDFaqsODutif25on0IZlFxEBtL2Gosd4p5WCV1U7UskNQfXA==
esbuild-windows-32@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.21.tgz#b858a22d1a82e53cdc59310cd56294133f7a95e7"
integrity sha512-V7vnTq67xPBUCk/9UtlolmQ798Ecjdr1ZoI1vcSgw7M82aSSt0eZdP6bh5KAFZU8pxDcx3qoHyWQfHYr11f22A==
esbuild-windows-64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.21.tgz#7bb5a027d5720cf9caf18a4bedd11327208f1f12"
integrity sha512-kDgHjKOHwjfJDCyRGELzVxiP/RBJBTA+wyspf78MTTJQkyPuxH2vChReNdWc+dU2S4gIZFHMdP1Qrl/k22ZmaA==
esbuild-windows-arm64@0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.21.tgz#25df54521ad602c826b262ea2e7cc1fe80f5c2f5"
integrity sha512-8Sbo0zpzgwWrwjQYLmHF78f7E2xg5Ve63bjB2ng3V2aManilnnTGaliq2snYg+NOX60+hEvJHRdVnuIAHW0lVw==
esbuild@^0.14.21:
version "0.14.21"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.21.tgz#b3e05f900f1c4394f596d60d63d9816468f0f671"
integrity sha512-7WEoNMBJdLN993dr9h0CpFHPRc3yFZD+EAVY9lg6syJJ12gc5fHq8d75QRExuhnMkT2DaRiIKFThRvDWP+fO+A==
optionalDependencies:
esbuild-android-arm64 "0.14.21"
esbuild-darwin-64 "0.14.21"
esbuild-darwin-arm64 "0.14.21"
esbuild-freebsd-64 "0.14.21"
esbuild-freebsd-arm64 "0.14.21"
esbuild-linux-32 "0.14.21"
esbuild-linux-64 "0.14.21"
esbuild-linux-arm "0.14.21"
esbuild-linux-arm64 "0.14.21"
esbuild-linux-mips64le "0.14.21"
esbuild-linux-ppc64le "0.14.21"
esbuild-linux-riscv64 "0.14.21"
esbuild-linux-s390x "0.14.21"
esbuild-netbsd-64 "0.14.21"
esbuild-openbsd-64 "0.14.21"
esbuild-sunos-64 "0.14.21"
esbuild-windows-32 "0.14.21"
esbuild-windows-64 "0.14.21"
esbuild-windows-arm64 "0.14.21"
fast-deep-equal@^3.1.1:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
follow-redirects@^1.10.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43"
integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==
gettext-parser@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/gettext-parser/-/gettext-parser-1.1.0.tgz#2c5a6638d893934b9b55037d0ad82cb7004b2679"
integrity sha1-LFpmONiTk0ubVQN9CtgstwBLJnk=
dependencies:
encoding "^0.1.11"
gettext.js@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/gettext.js/-/gettext.js-1.0.0.tgz#7fefb01512c134759c51166ab4d3db26a585ae1a"
integrity sha512-cpnxNL5C9SlD7ms/NSCuGsQdaVQmwCYn9MILWpYjSPMAkX4aD/5/qC+QgH4GCRY0OMEcSiVBsqgWMEoTcETggQ==
dependencies:
po2json "^0.4.0"
has-color@~0.1.0:
version "0.1.7"
resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f"
integrity sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
dependencies:
react-is "^16.7.0"
iconv-lite@^0.6.2:
version "0.6.3"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
icss-utils@^5.0.0, icss-utils@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
immutable@^3.8.2:
version "3.8.2"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
integrity sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json5@^2.1.2:
version "2.2.0"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
dependencies:
minimist "^1.2.5"
loader-utils@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0"
integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==
dependencies:
big.js "^5.2.2"
emojis-list "^3.0.0"
json5 "^2.1.2"
lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
mime-db@1.48.0:
version "1.48.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d"
integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==
mime-types@^2.1.27:
version "2.1.31"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b"
integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==
dependencies:
mime-db "1.48.0"
mini-css-extract-plugin@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.0.tgz#b4db2525af2624899ed64a23b0016e0036411893"
integrity sha512-nPFKI7NSy6uONUo9yn2hIfb9vyYvkFu95qki0e21DQ9uaqNKDP15DGpK0KnV6wDroWxPHtExrdEwx/yDQ8nVRw==
dependencies:
loader-utils "^2.0.0"
schema-utils "^3.0.0"
webpack-sources "^1.1.0"
minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
nanoid@^3.1.23:
version "3.1.23"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81"
integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==
nomnom@1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7"
integrity sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=
dependencies:
chalk "~0.4.0"
underscore "~1.6.0"
object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
object-path@^0.11.5:
version "0.11.5"
resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.11.5.tgz#d4e3cf19601a5140a55a16ad712019a9c50b577a"
integrity sha512-jgSbThcoR/s+XumvGMTMf81QVBmah+/Q7K7YduKeKVWL7N111unR2d6pZZarSk6kY/caeNxUDyxOvMWyzoU2eg==
"phoenix@file:../deps/phoenix":
version "1.6.6"
"phoenix_html@file:../deps/phoenix_html":
<<<<<<< HEAD
version "3.2.0"
=======
version "2.14.3"
"phoenix_live_view@file:../deps/phoenix_live_view":
version "0.15.3"
picomatch@^2.2.1, picomatch@^2.2.3:
version "2.3.0"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
"phoenix_live_view@file:../deps/phoenix_live_view":
version "0.15.3"
pify@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
pinkie-promise@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
dependencies:
pinkie "^2.0.0"
pinkie@^2.0.0:
version "2.0.4"
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
pkg-dir@^4.1.0, pkg-dir@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
dependencies:
find-up "^4.0.0"
>>>>>>> 7af5f8c (Install LiveView)
po2json@^0.4.0:
version "0.4.5"
resolved "https://registry.yarnpkg.com/po2json/-/po2json-0.4.5.tgz#47bb2952da32d58a1be2f256a598eebc0b745118"
integrity sha1-R7spUtoy1Yob4vJWpZjuvAt0URg=
dependencies:
gettext-parser "1.1.0"
nomnom "1.8.1"
postcss-modules-extract-imports@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d"
integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==
postcss-modules-local-by-default@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c"
integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==
dependencies:
icss-utils "^5.0.0"
postcss-selector-parser "^6.0.2"
postcss-value-parser "^4.1.0"
postcss-modules-scope@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06"
integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==
dependencies:
postcss-selector-parser "^6.0.4"
postcss-modules-values@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c"
integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==
dependencies:
icss-utils "^5.0.0"
postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
version "6.0.6"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea"
integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==
dependencies:
cssesc "^3.0.0"
util-deprecate "^1.0.2"
postcss-value-parser@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
postcss@^8.2.15:
version "8.3.5"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.5.tgz#982216b113412bc20a86289e91eb994952a5b709"
integrity sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==
dependencies:
colorette "^1.2.2"
nanoid "^3.1.23"
source-map-js "^0.6.2"
prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.8.1"
punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
react-dom@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler "^0.20.2"
react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-redux@^7.2.4:
version "7.2.4"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.4.tgz#1ebb474032b72d806de2e0519cd07761e222e225"
integrity sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==
dependencies:
"@babel/runtime" "^7.12.1"
"@types/react-redux" "^7.1.16"
hoist-non-react-statics "^3.3.2"
loose-envify "^1.4.0"
prop-types "^15.7.2"
react-is "^16.13.1"
react@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
redux-watch@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/redux-watch/-/redux-watch-1.2.0.tgz#b3a745e15855ef72db0e06a60a4b2fe3676d79a7"
integrity sha512-Ws4Q+e5zFGMyy1H709c1Ws8apSd6MqoJRIzBDHbI4nikome/IZWVTYXdQNz+VJxPjyX/h2E+lYEo41fXgjCF8g==
dependencies:
object-path "^0.11.5"
redux@^4.0.0, redux@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.0.tgz#eb049679f2f523c379f1aff345c8612f294c88d4"
integrity sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==
dependencies:
"@babel/runtime" "^7.9.2"
regenerator-runtime@^0.13.4:
version "0.13.7"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
"safer-buffer@>= 2.1.2 < 3.0.0":
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
scheduler@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
schema-utils@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.0.0.tgz#67502f6aa2b66a2d4032b4279a2944978a0913ef"
integrity sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==
dependencies:
"@types/json-schema" "^7.0.6"
ajv "^6.12.5"
ajv-keywords "^3.5.2"
semver@^7.3.5:
version "7.3.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
dependencies:
lru-cache "^6.0.0"
source-list-map@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
source-map-js@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
strip-ansi@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991"
integrity sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=
underscore@~1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8"
integrity sha1-izixDKze9jM3uLJOT/htRa6lKag=
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
url-loader@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2"
integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==
dependencies:
loader-utils "^2.0.0"
mime-types "^2.1.27"
schema-utils "^3.0.0"
util-deprecate@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
webpack-sources@^1.1.0:
version "1.4.3"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
dependencies:
source-list-map "^2.0.0"
source-map "~0.6.1"
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==

File diff suppressed because it is too large Load Diff

View File

@ -3,5 +3,5 @@
echo "Building assets" echo "Building assets"
cd assets cd assets
yarn install yarn install
yarn run build yarn run deploy
cd .. cd ..

View File

@ -6,8 +6,8 @@ source /dev/stdin <<< "$(curl -sSL https://raw.githubusercontent.com/codeship/sc
echo "Installing Elixir" echo "Installing Elixir"
source /dev/stdin <<< "$(curl -sSL https://raw.githubusercontent.com/codeship/scripts/master/languages/elixir.sh)" source /dev/stdin <<< "$(curl -sSL https://raw.githubusercontent.com/codeship/scripts/master/languages/elixir.sh)"
echo "Installing PhantomJS" echo "Installing ChromeDriver"
curl -sSL https://raw.githubusercontent.com/codeship/scripts/master/packages/phantomjs.sh | bash -s curl -sSL https://raw.githubusercontent.com/codeship/scripts/master/packages/chromedriver.sh | bash -s
echo "Installing NodeJS" echo "Installing NodeJS"
nvm install $NODE_VERSION nvm install $NODE_VERSION

18
codeship-services.yml Normal file
View File

@ -0,0 +1,18 @@
# Docker Compose-like syntax, see here for details:
# https://documentation.codeship.com/pro/builds-and-configuration/services/
app:
build:
image: danbee/chess
dockerfile: Dockerfile
environment:
MIX_ENV: test
PGHOST: db
PGUSER: postgres
PGPASSWORD: password
depends_on:
- db
db:
image: healthcheck/postgres:alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password

9
codeship-steps.yml Normal file
View File

@ -0,0 +1,9 @@
# This is where we define the test steps that would be run in a Codeship Pro build.
# The build passes as long as every test step returns with a non-zero exit code.
# See here for more: https://documentation.codeship.com/pro/builds-and-configuration/steps/
- name: build_assets
command: bin/codeship_assets
service: app
- name: run_mix_test
command: /bin/bash -c 'mix ecto.create && mix test'
service: app

View File

@ -3,7 +3,7 @@
# #
# This configuration file is loaded before any dependency and # This configuration file is loaded before any dependency and
# is restricted to this project. # is restricted to this project.
use Mix.Config import Config
config :phoenix, :json_library, Jason config :phoenix, :json_library, Jason
@ -31,8 +31,27 @@ config :chess, Chess.Auth.Guardian,
secret_key: "vd2vXkrYTTFKSKmNMoS2/Hk4Fxn8BkyzsVArRkxJazdQ3mr6bI4YgAC6f8ODiWlM" secret_key: "vd2vXkrYTTFKSKmNMoS2/Hk4Fxn8BkyzsVArRkxJazdQ3mr6bI4YgAC6f8ODiWlM"
config :formulator, config :formulator,
translate_error_module: ChessWeb.ErrorHelpers validate: false,
translate_error_module: ChessWeb.ErrorHelpers
# Configure esbuild (the version is required)
config :esbuild,
version: "0.17.5",
default: [
args:
~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/* --loader:.js=jsx),
cd: Path.expand("../assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]
# Configure dart_sass
config :dart_sass,
version: "1.58.0",
default: [
args: ~w(css/app.scss ../priv/static/assets/app.css),
cd: Path.expand("../assets", __DIR__)
]
# Import environment specific config. This must remain at the bottom # Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above. # of this file so it overrides the configuration defined above.
import_config "#{Mix.env}.exs" import_config "#{config_env()}.exs"

View File

@ -1,4 +1,4 @@
use Mix.Config import Config
# For development, we disable any cache and enable # For development, we disable any cache and enable
# debugging and code reloading. # debugging and code reloading.
@ -10,16 +10,7 @@ config :chess, ChessWeb.Endpoint,
http: [port: 4000], http: [port: 4000],
debug_errors: true, debug_errors: true,
code_reloader: true, code_reloader: true,
check_origin: false, check_origin: false
watchers: [
node: [
"node_modules/webpack/bin/webpack.js",
"--mode",
"development",
"--watch",
cd: Path.expand("../assets", __DIR__)
]
]
# Watch static and templates for browser reloading. # Watch static and templates for browser reloading.
config :chess, ChessWeb.Endpoint, config :chess, ChessWeb.Endpoint,

View File

@ -1,8 +1,8 @@
use Mix.Config import Config
config :chess, ChessWeb.Endpoint, config :chess, ChessWeb.Endpoint,
cache_static_manifest: "priv/static/cache_manifest.json", cache_static_manifest: "priv/static/cache_manifest.json",
check_origin: ["https://chess.danbarber.me", "https://64squares.club"], check_origin: ["https://chess.danbee.in", "https://64squares.club"],
http: [port: {:system, "PORT"}], http: [port: {:system, "PORT"}],
root: "./assets", root: "./assets",
secret_key_base: System.get_env("SECRET_KEY_BASE"), secret_key_base: System.get_env("SECRET_KEY_BASE"),

70
config/runtime.exs Normal file
View File

@ -0,0 +1,70 @@
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.
# Start the phoenix server if environment is set and running in a release
if System.get_env("PHX_SERVER") && System.get_env("RELEASE_NAME") do
config :chess, ChessWeb.Endpoint, server: true
end
if config_env() == :prod do
# 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 :chess, ChessWeb.Endpoint,
url: [host: host, port: 443],
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
# ## Using releases
#
# If you are doing OTP releases, you need to instruct Phoenix
# to start each relevant endpoint:
#
# config :<%= @web_app_name %>, <%= @endpoint_module %>, server: true
#
# Then you can assemble a release by calling `mix release`.
# See `mix help release` for more information.<%= if @mailer do %>
# ## 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 :<%= @app_name %>, <%= @app_module %>.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 %>
end

View File

@ -1,4 +1,4 @@
use Mix.Config import Config
# We don't run a server during test. If one is required, # We don't run a server during test. If one is required,
# you can enable the server option below. # you can enable the server option below.
@ -18,7 +18,7 @@ config :chess, Chess.Mailer, adapter: Bamboo.TestAdapter
config :chess, Chess.Repo, config :chess, Chess.Repo,
adapter: Ecto.Adapters.Postgres, adapter: Ecto.Adapters.Postgres,
database: "chess_test", database: "chess_test",
hostname: "localhost", hostname: System.get_env("PGHOST") || "localhost",
port: System.get_env("POSTGRES_PORT") || "5432", port: System.get_env("POSTGRES_PORT") || "5432",
pool: Ecto.Adapters.SQL.Sandbox pool: Ecto.Adapters.SQL.Sandbox

19
docker-compose.yml Normal file
View File

@ -0,0 +1,19 @@
version: '3'
services:
app:
build: .
command: /bin/bash -c 'mix ecto.create && mix phx.server'
ports:
- "4000:4000"
environment:
MIX_ENV: dev
PGHOST: db
PGUSER: postgres
PGPASSWORD: password
links:
- db
db:
image: healthcheck/postgres:alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password

View File

@ -1,5 +1,5 @@
# Erlang version # Erlang version
erlang_version=23.2.3 erlang_version=OTP-24.2.1
# Elixir version # Elixir version
elixir_version=1.11.3 elixir_version=1.14.1

View File

@ -11,7 +11,7 @@ defmodule Chess do
{Phoenix.PubSub, [name: Chess.PubSub, adapter: Phoenix.PubSub.PG2]}, {Phoenix.PubSub, [name: Chess.PubSub, adapter: Phoenix.PubSub.PG2]},
{Chess.Repo, []}, {Chess.Repo, []},
{ChessWeb.Endpoint, []}, {ChessWeb.Endpoint, []},
{ChessWeb.Presence, []}, {ChessWeb.Presence, []}
] ]
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html

View File

@ -4,7 +4,6 @@ defmodule Chess.Auth do
""" """
import Ecto.Query, warn: false import Ecto.Query, warn: false
alias Comeonin.Argon2
alias Chess.Repo alias Chess.Repo
alias Chess.Store.User alias Chess.Store.User
@ -41,11 +40,13 @@ defmodule Chess.Auth do
@doc false @doc false
def authenticate_user(email, password) do def authenticate_user(email, password) do
query = from u in User, query =
where: u.email == ^email from(u in User,
where: u.email == ^email
)
query query
|> Repo.one |> Repo.one()
|> Argon2.check_pass(password) |> Argon2.check_pass(password)
end end
end end

View File

@ -12,6 +12,7 @@ defmodule Chess.Auth.ErrorHandler do
|> put_flash(:info, "You must be logged in") |> put_flash(:info, "You must be logged in")
|> redirect(to: "/") |> redirect(to: "/")
|> halt() |> halt()
"json" -> "json" ->
conn conn
|> put_status(403) |> put_status(403)

View File

@ -10,8 +10,9 @@ defmodule Chess.Auth.Guardian do
end end
def resource_from_claims(claims) do def resource_from_claims(claims) do
user = claims["sub"] user =
|> Auth.get_user! claims["sub"]
|> Auth.get_user!()
{:ok, user} {:ok, user}
end end

View File

@ -7,11 +7,11 @@ defmodule Chess.Auth.Pipeline do
module: Chess.Auth.Guardian module: Chess.Auth.Guardian
# If there is a session token, validate it # If there is a session token, validate it
plug Guardian.Plug.VerifySession, claims: %{"typ" => "access"} plug(Guardian.Plug.VerifySession, claims: %{"typ" => "access"})
# If there is an authorization header, validate it # If there is an authorization header, validate it
plug Guardian.Plug.VerifyHeader, claims: %{"typ" => "access"} plug(Guardian.Plug.VerifyHeader, claims: %{"typ" => "access"})
# Load the user if either of the verifications worked # Load the user if either of the verifications worked
plug Guardian.Plug.LoadResource, allow_blank: true plug(Guardian.Plug.LoadResource, allow_blank: true)
end end

View File

@ -3,12 +3,10 @@ defmodule Chess.Board do
def transform(board) do def transform(board) do
Enum.map(0..7, fn rank -> Enum.map(0..7, fn rank ->
{rank, Enum.map(0..7, fn file ->
Enum.map(0..7, fn file -> board
{file, |> piece({file, rank})
board end)
|> piece({file, rank})}
end)}
end) end)
end end
@ -33,8 +31,8 @@ defmodule Chess.Board do
end end
def move_piece(board, %{ def move_piece(board, %{
from: {from_file, from_rank}, "from" => [from_file, from_rank],
to: {to_file, to_rank} "to" => [to_file, to_rank]
}) do }) do
{piece, board} = Map.pop(board, to_index({from_file, from_rank})) {piece, board} = Map.pop(board, to_index({from_file, from_rank}))
{piece_captured, board} = Map.pop(board, to_index({to_file, to_rank})) {piece_captured, board} = Map.pop(board, to_index({to_file, to_rank}))
@ -69,15 +67,15 @@ defmodule Chess.Board do
def castling_move(board, %{from: {4, rank}, to: {2, _rank}}) do def castling_move(board, %{from: {4, rank}, to: {2, _rank}}) do
move_piece(board, %{ move_piece(board, %{
from: {0, rank}, "from" => [0, rank],
to: {3, rank} "to" => [3, rank]
}) })
end end
def castling_move(board, %{from: {4, rank}, to: {6, _rank}}) do def castling_move(board, %{"from" => [4, rank], "to" => [6, _rank]}) do
move_piece(board, %{ move_piece(board, %{
from: {7, rank}, "from" => [7, rank],
to: {5, rank} "to" => [5, rank]
}) })
end end

View File

@ -12,9 +12,7 @@ defmodule Chess.Emails do
new_email() new_email()
|> to(game.opponent) |> to(game.opponent)
|> from({"64squares", "games@64squares.club"}) |> from({"64squares", "games@64squares.club"})
|> subject( |> subject("[64squares] #{game.user.name} has invited you to play a game of chess.")
"[64squares] #{game.user.name} has invited you to play a game of chess."
)
|> text_body(""" |> text_body("""
Game link: #{Helpers.game_url(conn, :show, game)} Game link: #{Helpers.game_url(conn, :show, game)}
""") """)
@ -27,9 +25,7 @@ defmodule Chess.Emails do
new_email() new_email()
|> to(opponent) |> to(opponent)
|> from({"64squares", "games@64squares.club"}) |> from({"64squares", "games@64squares.club"})
|> subject( |> subject("[64squares] #{user.name} has moved.")
"[64squares] #{user.name} has moved."
)
|> text_body(""" |> text_body("""
Game link: #{Helpers.game_url(socket, :show, game)} Game link: #{Helpers.game_url(socket, :show, game)}
""") """)

View File

@ -5,7 +5,7 @@ defmodule Chess.MoveList do
def transform(moves) do def transform(moves) do
moves moves
|> Enum.map(&(Move.transform(&1))) |> Enum.map(&Move.transform(&1))
|> Enum.chunk_every(2) |> Enum.chunk_every(2)
end end
end end

View File

@ -22,13 +22,17 @@ defmodule Chess.Moves.Generator do
defp _moves(_colour, _board, {_file, 0}, {_, -1}), do: [] defp _moves(_colour, _board, {_file, 0}, {_, -1}), do: []
defp _moves(_colour, _board, {7, _rank}, {1, _}), do: [] defp _moves(_colour, _board, {7, _rank}, {1, _}), do: []
defp _moves(_colour, _board, {_file, 7}, {_, 1}), do: [] defp _moves(_colour, _board, {_file, 7}, {_, 1}), do: []
defp _moves(colour, board, {file, rank}, {fv, rv}) do defp _moves(colour, board, {file, rank}, {fv, rv}) do
next_square = {file + fv, rank + rv} next_square = {file + fv, rank + rv}
cond do cond do
can_capture_piece?(colour, board, next_square) -> can_capture_piece?(colour, board, next_square) ->
[next_square] [next_square]
obstruction?(colour, board, next_square) -> obstruction?(colour, board, next_square) ->
[] []
true -> true ->
[next_square | _moves(colour, board, next_square, {fv, rv})] [next_square | _moves(colour, board, next_square, {fv, rv})]
end end
@ -36,14 +40,18 @@ defmodule Chess.Moves.Generator do
# Move generation for pieces that follow a pattern # Move generation for pieces that follow a pattern
defp _moves(_colour, _board, {_file, _rank}, []), do: [] defp _moves(_colour, _board, {_file, _rank}, []), do: []
defp _moves(colour, board, {file, rank}, [{fv, rv} | moves]) do defp _moves(colour, board, {file, rank}, [{fv, rv} | moves]) do
move_square = {file + fv, rank + rv} move_square = {file + fv, rank + rv}
cond do cond do
outside_board?(move_square) || outside_board?(move_square) ||
obstruction?(colour, board, move_square) -> obstruction?(colour, board, move_square) ->
_moves(colour, board, {file, rank}, moves) _moves(colour, board, {file, rank}, moves)
can_capture_piece?(colour, board, move_square) -> can_capture_piece?(colour, board, move_square) ->
[move_square | _moves(colour, board, {file, rank}, moves)] [move_square | _moves(colour, board, {file, rank}, moves)]
true -> true ->
[move_square | _moves(colour, board, {file, rank}, moves)] [move_square | _moves(colour, board, {file, rank}, moves)]
end end
@ -66,6 +74,7 @@ defmodule Chess.Moves.Generator do
piece = piece =
board board
|> Board.piece({file, rank}) |> Board.piece({file, rank})
piece && piece["colour"] == colour piece && piece["colour"] == colour
end end
end end

View File

@ -28,7 +28,7 @@ defmodule Chess.Moves.Piece do
end end
defp attacked_by_knight?(board, {file, rank}) do defp attacked_by_knight?(board, {file, rank}) do
_attacked?(board, {file, rank}, Knight.pattern, "knight") _attacked?(board, {file, rank}, Knight.pattern(), "knight")
end end
defp attacked_by_pawn?(board, {file, rank}) do defp attacked_by_pawn?(board, {file, rank}) do
@ -46,22 +46,24 @@ defmodule Chess.Moves.Piece do
board board
|> Generator.moves({file, rank}, pattern) |> Generator.moves({file, rank}, pattern)
Enum.any?(moves, &(match_piece(board, &1, "pawn"))) Enum.any?(moves, &match_piece(board, &1, "pawn"))
end end
defp _attacked?(_board, {0, _rank}, {-1, _}, _), do: false defp _attacked?(_board, {0, _rank}, {-1, _}, _), do: false
defp _attacked?(_board, {_file, 0}, {_, -1}, _), do: false defp _attacked?(_board, {_file, 0}, {_, -1}, _), do: false
defp _attacked?(_board, {7, _rank}, {1, _}, _), do: false defp _attacked?(_board, {7, _rank}, {1, _}, _), do: false
defp _attacked?(_board, {_file, 7}, {_, 1}, _), do: false defp _attacked?(_board, {_file, 7}, {_, 1}, _), do: false
defp _attacked?(board, {file, rank}, {fv, rv}, pieces) do defp _attacked?(board, {file, rank}, {fv, rv}, pieces) do
board board
|> Generator.moves({file, rank}, {fv, rv}) |> Generator.moves({file, rank}, {fv, rv})
|> List.last |> List.last()
|> case do |> case do
{file, rank} -> {file, rank} ->
piece = board["#{file},#{rank}"] piece = board["#{file},#{rank}"]
Enum.any?(pieces, &(match?(%{"type" => ^&1}, piece))) Enum.any?(pieces, &match?(%{"type" => ^&1}, piece))
nil -> nil ->
false false
end end
@ -72,7 +74,7 @@ defmodule Chess.Moves.Piece do
board board
|> Generator.moves({file, rank}, pattern) |> Generator.moves({file, rank}, pattern)
Enum.any?(moves, &(match_piece(board, &1, piece_type))) Enum.any?(moves, &match_piece(board, &1, piece_type))
end end
defp match_piece(board, {file, rank}, piece_type) do defp match_piece(board, {file, rank}, piece_type) do

View File

@ -37,8 +37,10 @@ defmodule Chess.Moves.Pieces.Pawn do
cond do cond do
obstruction?(board, {file, rank + 1}) -> obstruction?(board, {file, rank + 1}) ->
[] []
rank == 1 -> rank == 1 ->
[{file, rank + 1} | _moves("white", board, {file, rank + 1})] [{file, rank + 1} | _moves("white", board, {file, rank + 1})]
true -> true ->
[{file, rank + 1}] [{file, rank + 1}]
end end
@ -48,16 +50,20 @@ defmodule Chess.Moves.Pieces.Pawn do
cond do cond do
obstruction?(board, {file, rank - 1}) -> obstruction?(board, {file, rank - 1}) ->
[] []
rank == 6 -> rank == 6 ->
[{file, rank - 1} | _moves("black", board, {file, rank - 1})] [{file, rank - 1} | _moves("black", board, {file, rank - 1})]
true -> true ->
[{file, rank - 1}] [{file, rank - 1}]
end end
end end
def _capture_moves(_colour, _board, {_file, _rank}, []), do: [] def _capture_moves(_colour, _board, {_file, _rank}, []), do: []
def _capture_moves(colour, board, {file, rank}, [{fv, rv} | moves]) do def _capture_moves(colour, board, {file, rank}, [{fv, rv} | moves]) do
move_square = {file + fv, rank + rv} move_square = {file + fv, rank + rv}
if can_capture_piece?(colour, board, move_square) do if can_capture_piece?(colour, board, move_square) do
[move_square | _capture_moves(colour, board, {file, rank}, moves)] [move_square | _capture_moves(colour, board, {file, rank}, moves)]
else else

28
lib/chess/release.ex Normal file
View File

@ -0,0 +1,28 @@
defmodule Chess.Release do
@moduledoc """
Used for executing DB release tasks when run in production without Mix
installed.
"""
@app :chess
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

View File

@ -23,7 +23,7 @@ defmodule Chess.Repo.Queries do
def opponents(user, query_string) do def opponents(user, query_string) do
user user
|> User.opponents |> User.opponents()
|> User.matches(query_string) |> User.matches(query_string)
end end
end end

View File

@ -8,13 +8,13 @@ defmodule Chess.Store.Move do
alias Chess.Store.Game alias Chess.Store.Game
schema "moves" do schema "moves" do
field :from, :map field(:from, :map)
field :to, :map field(:to, :map)
field :piece, :map field(:piece, :map)
field :piece_captured, :map field(:piece_captured, :map)
belongs_to :game, Game belongs_to(:game, Game)
timestamps() timestamps()
end end
@ -31,7 +31,7 @@ defmodule Chess.Store.Move do
piece: move.piece, piece: move.piece,
piece_captured: move.piece_captured, piece_captured: move.piece_captured,
from: <<97 + move.from["file"], 49 + move.from["rank"]>>, from: <<97 + move.from["file"], 49 + move.from["rank"]>>,
to: <<97 + move.to["file"], 49 + move.to["rank"]>>, to: <<97 + move.to["file"], 49 + move.to["rank"]>>
} }
end end

View File

@ -6,16 +6,14 @@ defmodule Chess.Store.User do
import Ecto.Changeset import Ecto.Changeset
import Ecto.Query import Ecto.Query
alias Comeonin.Argon2
schema "users" do schema "users" do
field :name, :string field(:name, :string)
field :email, :string field(:email, :string)
field :password, :string, virtual: true field(:password, :string, virtual: true)
field :password_hash, :string field(:password_hash, :string)
has_many :games, Chess.Store.Game has_many(:games, Chess.Store.Game)
has_many :games_as_opponent, Chess.Store.Game, foreign_key: :opponent_id has_many(:games_as_opponent, Chess.Store.Game, foreign_key: :opponent_id)
timestamps() timestamps()
end end
@ -53,26 +51,32 @@ defmodule Chess.Store.User do
end end
def find_by_name(name) do def find_by_name(name) do
from user in __MODULE__, from(user in __MODULE__,
where: user.name == ^name where: user.name == ^name
)
end end
def opponents(user) do def opponents(user) do
from user in __MODULE__, from(user in __MODULE__,
where: user.id != ^user.id where: user.id != ^user.id
)
end end
def matches(query, query_string) do def matches(query, query_string) do
from user in query, from(user in query,
where: ilike(user.name, ^"%#{query_string}%") where:
or user.email == ^query_string ilike(user.name, ^"%#{query_string}%") or
user.email == ^query_string
)
end end
defp hash_password(changeset) do defp hash_password(changeset) do
password = get_change(changeset, :password) password = get_change(changeset, :password)
if password do if password do
changeset changeset
|> change(Argon2.add_hash(password)) |> change(Argon2.add_hash(password))
|> change(password: nil)
else else
changeset changeset
end end

View File

@ -32,8 +32,9 @@ defmodule ChessWeb do
def view do def view do
quote do quote do
use Phoenix.View, root: "lib/chess_web/templates", use Phoenix.View,
namespace: ChessWeb root: "lib/chess_web/templates",
namespace: ChessWeb
# Import convenience functions from controllers # Import convenience functions from controllers
import Phoenix.Controller, import Phoenix.Controller,

View File

@ -68,6 +68,7 @@ defmodule ChessWeb.Presence do
information, while maintaining the required `:metas` field from the information, while maintaining the required `:metas` field from the
original presence data. original presence data.
""" """
use Phoenix.Presence, otp_app: :chess, use Phoenix.Presence,
pubsub_server: Chess.PubSub otp_app: :chess,
pubsub_server: Chess.PubSub
end end

View File

@ -4,7 +4,7 @@ defmodule ChessWeb.UserSocket do
alias Phoenix.Token alias Phoenix.Token
## Channels ## Channels
channel "game:*", ChessWeb.GameChannel channel("game:*", ChessWeb.GameChannel)
# Socket params are passed from the client and can # Socket params are passed from the client and can
# be used to verify and authenticate a user. After # be used to verify and authenticate a user. After
@ -21,10 +21,12 @@ defmodule ChessWeb.UserSocket do
case Token.verify(socket, "game socket", token, max_age: 1_209_600) do case Token.verify(socket, "game socket", token, max_age: 1_209_600) do
{:ok, user_id} -> {:ok, user_id} ->
{:ok, assign(socket, :user_id, user_id)} {:ok, assign(socket, :user_id, user_id)}
{:error, _reason} -> {:error, _reason} ->
:error :error
end end
end end
def connect(%{}, _socket), do: :error def connect(%{}, _socket), do: :error
# Socket id's are topics that allow you to identify all sockets for a given user: # Socket id's are topics that allow you to identify all sockets for a given user:

View File

@ -10,8 +10,8 @@ defmodule ChessWeb.Api.OpponentsController do
conn conn
|> current_user() |> current_user()
|> Queries.opponents(query_string) |> Queries.opponents(query_string)
|> Repo.all |> Repo.all()
render conn, "index.json", %{opponents: opponents} render(conn, "index.json", %{opponents: opponents})
end end
end end

View File

@ -22,6 +22,7 @@ defmodule ChessWeb.PasswordController do
conn conn
|> put_flash(:info, gettext("Password updated successfully.")) |> put_flash(:info, gettext("Password updated successfully."))
|> redirect(to: page_path(conn, :index)) |> redirect(to: page_path(conn, :index))
{:error, changeset} -> {:error, changeset} ->
render(conn, "edit.html", changeset: changeset) render(conn, "edit.html", changeset: changeset)
end end

View File

@ -22,6 +22,7 @@ defmodule ChessWeb.ProfileController do
conn conn
|> put_flash(:info, gettext("Profile updated successfully.")) |> put_flash(:info, gettext("Profile updated successfully."))
|> redirect(to: page_path(conn, :index)) |> redirect(to: page_path(conn, :index))
{:error, changeset} -> {:error, changeset} ->
render(conn, "edit.html", changeset: changeset) render(conn, "edit.html", changeset: changeset)
end end

View File

@ -18,6 +18,7 @@ defmodule ChessWeb.RegistrationController do
|> Guardian.Plug.sign_in(user) |> Guardian.Plug.sign_in(user)
|> put_flash(:info, "Registered successfully.") |> put_flash(:info, "Registered successfully.")
|> redirect(to: page_path(conn, :index)) |> redirect(to: page_path(conn, :index))
{:error, changeset} -> {:error, changeset} ->
render(conn, "new.html", changeset: changeset) render(conn, "new.html", changeset: changeset)
end end

View File

@ -11,17 +11,19 @@ defmodule ChessWeb.SessionController do
end end
def create( def create(
conn, conn,
%{"user" => %{"email" => email, "password" => password}} %{"user" => %{"email" => email, "password" => password}}
) do ) do
case Auth.authenticate_user(email, password) do case Auth.authenticate_user(email, password) do
{:ok, user} -> {:ok, user} ->
conn conn
|> Guardian.Plug.sign_in(user) |> Guardian.Plug.sign_in(user)
|> put_flash(:info, "You are logged in") |> put_flash(:info, "You are logged in")
|> redirect(to: game_path(conn, :index)) |> redirect(to: game_path(conn, :index))
{:error, _error} -> {:error, _error} ->
changeset = User.changeset(%User{}) changeset = User.changeset(%User{})
conn conn
|> put_flash(:error, "Bad email or password") |> put_flash(:error, "Bad email or password")
|> render("new.html", changeset: changeset) |> render("new.html", changeset: changeset)

View File

@ -7,8 +7,8 @@ defmodule ChessWeb.Endpoint do
signing_salt: "9LqUhZTU" signing_salt: "9LqUhZTU"
] ]
if Application.get_env(:chess, :sql_sandbox) do if sandbox = Application.compile_env(:chess, :sandbox) do
plug(Phoenix.Ecto.SQL.Sandbox) plug(Phoenix.Ecto.SQL.Sandbox, sandbox: sandbox)
end end
socket("/socket", ChessWeb.UserSocket) socket("/socket", ChessWeb.UserSocket)

View File

@ -4,57 +4,53 @@ defmodule ChessWeb.Router do
alias Phoenix.Token alias Phoenix.Token
pipeline :browser do pipeline :browser do
plug :accepts, ["html"] plug(:accepts, ["html"])
plug :fetch_session plug(:fetch_session)
plug :fetch_live_flash plug(:fetch_live_flash)
plug :protect_from_forgery plug(:protect_from_forgery)
plug :put_secure_browser_headers plug(:put_secure_browser_headers)
end end
pipeline :auth do pipeline :auth do
plug Chess.Auth.Pipeline plug(Chess.Auth.Pipeline)
end end
pipeline :ensure_auth do pipeline :ensure_auth do
plug Guardian.Plug.EnsureAuthenticated plug(Guardian.Plug.EnsureAuthenticated)
plug :put_user_token plug(:put_user_token)
end end
pipeline :api do pipeline :api do
plug :fetch_session plug(:fetch_session)
plug :accepts, ["json"] plug(:accepts, ["json"])
end end
scope "/", ChessWeb do scope "/", ChessWeb do
pipe_through [:browser, :auth] # Use the default browser stack # Use the default browser stack
pipe_through([:browser, :auth])
get "/", PageController, :index get("/", PageController, :index)
resources "/session", SessionController, resources("/session", SessionController, only: [:new, :create, :delete], singleton: true)
only: [:new, :create, :delete], singleton: true resources("/registration", RegistrationController, only: [:new, :create], singleton: true)
resources "/registration", RegistrationController,
only: [:new, :create], singleton: true
end end
scope "/", ChessWeb do scope "/", ChessWeb do
pipe_through [:browser, :auth, :ensure_auth] pipe_through([:browser, :auth, :ensure_auth])
resources "/games", GameController, resources("/games", GameController, only: [:index, :new, :create, :show, :delete])
only: [:index, :new, :create, :show, :delete] resources("/profile", ProfileController, only: [:edit, :update], singleton: true)
resources "/profile", ProfileController, resources("/password", PasswordController, only: [:edit, :update], singleton: true)
only: [:edit, :update], singleton: true
resources "/password", PasswordController,
only: [:edit, :update], singleton: true
end end
# Other scopes may use custom stacks. # Other scopes may use custom stacks.
scope "/api", as: :api do scope "/api", as: :api do
pipe_through [:api, :auth, :ensure_auth] pipe_through([:api, :auth, :ensure_auth])
resources "/opponents", ChessWeb.Api.OpponentsController, only: [:index] resources("/opponents", ChessWeb.Api.OpponentsController, only: [:index])
end end
if Mix.env == :dev do if Mix.env() == :dev do
forward "/sent_emails", Bamboo.SentEmailViewerPlug forward("/sent_emails", Bamboo.SentEmailViewerPlug)
end end
defp put_user_token(conn, _) do defp put_user_token(conn, _) do

View File

@ -3,16 +3,17 @@ defmodule ChessWeb.Api.OpponentsView do
def render("index.json", %{opponents: opponents}) do def render("index.json", %{opponents: opponents}) do
%{ %{
opponents: Enum.map(opponents, fn opponent -> opponents:
opponent_attrs(opponent) Enum.map(opponents, fn opponent ->
end) opponent_attrs(opponent)
end)
} }
end end
def opponent_attrs(opponent) do def opponent_attrs(opponent) do
%{ %{
id: opponent.id, id: opponent.id,
name: opponent.name, name: opponent.name
} }
end end
end end

View File

@ -10,7 +10,7 @@ defmodule ChessWeb.ErrorHelpers do
""" """
def error_tag(form, field) do def error_tag(form, field) do
if error = form.errors[field] do if error = form.errors[field] do
content_tag :span, translate_error(error), class: "help-block" content_tag(:span, translate_error(error), class: "help-block")
end end
end end

View File

@ -2,16 +2,16 @@ defmodule ChessWeb.ErrorView do
use ChessWeb, :view use ChessWeb, :view
def render("404.html", _assigns) do def render("404.html", _assigns) do
gettext "Page not found" gettext("Page not found")
end end
def render("500.html", _assigns) do def render("500.html", _assigns) do
gettext "Internal server error" gettext("Internal server error")
end end
# In case no render clause matches or no # In case no render clause matches or no
# template is found, let's render it as 500 # template is found, let's render it as 500
def template_not_found(_template, assigns) do def template_not_found(_template, assigns) do
render "500.html", assigns render("500.html", assigns)
end end
end end

View File

@ -42,8 +42,8 @@ defmodule ChessWeb.GameView do
|> player_colour(game) == game.turn |> player_colour(game) == game.turn
end end
def player_colour(user, game) do def player_colour(conn, game) do
(user.id == game.user_id && "white") || "black" (current_user(conn).id == game.user_id && "white") || "black"
end end
def files(conn, game) do def files(conn, game) do

43
mix.exs
View File

@ -5,9 +5,9 @@ defmodule Chess.Mixfile do
[ [
app: :chess, app: :chess,
version: "0.2.0", version: "0.2.0",
elixir: "~> 1.11.3", elixir: "~> 1.14.1",
elixirc_paths: elixirc_paths(Mix.env()), elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(), compilers: [:phoenix] ++ Mix.compilers(),
build_embedded: Mix.env() == :prod, build_embedded: Mix.env() == :prod,
start_permanent: Mix.env() == :prod, start_permanent: Mix.env() == :prod,
aliases: aliases(), aliases: aliases(),
@ -21,7 +21,7 @@ defmodule Chess.Mixfile do
def application do def application do
[ [
mod: {Chess, []}, mod: {Chess, []},
extra_applications: [:logger] extra_applications: [:logger, :ssl]
] ]
end end
@ -34,27 +34,29 @@ defmodule Chess.Mixfile do
# Type `mix help deps` for examples and options. # Type `mix help deps` for examples and options.
defp deps do defp deps do
[ [
{:argon2_elixir, "~> 1.3"}, {:argon2_elixir, "~> 3.0"},
{:bamboo, "~> 1.0"}, {:bamboo, "~> 2.0"},
{:comeonin, "~> 4.0"}, {:comeonin, "~> 5.0"},
{:cowboy, "~> 2.1"}, {:cowboy, "~> 2.0"},
{:plug_cowboy, "~> 2.1"},
{:credo, "~> 1.0", only: [:dev, :test]}, {:credo, "~> 1.0", only: [:dev, :test]},
{:dart_sass, "~> 0.5", runtime: Mix.env() == :dev},
{:ecto_sql, "~> 3.0"}, {:ecto_sql, "~> 3.0"},
{:floki, ">= 0.27.0", only: :test}, {:floki, "~> 0.34", only: :test},
{:formulator, "~> 0.1.6"}, {:esbuild, "~> 0.6", runtime: Mix.env() == :dev},
{:gettext, "~> 0.16.0"}, {:formulator, "~> 0.4.0"},
{:guardian, "~> 1.0"}, {:gettext, "~> 0.22.0"},
{:guardian, "~> 2.0"},
{:jason, "~> 1.0"}, {:jason, "~> 1.0"},
{:phoenix, "~> 1.5.7"}, {:phoenix, "~> 1.6.0"},
{:phoenix_ecto, "~> 4.0"}, {:phoenix_ecto, "~> 4.0"},
{:phoenix_html, "~> 2.0"}, {:phoenix_html, "~> 3.2.0"},
{:phoenix_live_reload, "~> 1.0", only: :dev}, {:phoenix_live_reload, "~> 1.0", only: :dev},
{:phoenix_live_view, "~> 0.15.3"}, {:phoenix_live_view, "~> 0.18"},
{:phoenix_pubsub, "~> 2.0"}, {:phoenix_pubsub, "~> 2.0"},
{:postgrex, ">= 0.15.0"}, {:plug_cowboy, "~> 2.0"},
{:postgrex, "~> 0.16.0"},
{:secure_random, "~> 0.5"}, {:secure_random, "~> 0.5"},
{:wallaby, "~> 0.28.0", [runtime: false, only: :test]} {:wallaby, "~> 0.30.0", [runtime: false, only: :test]}
] ]
end end
@ -68,7 +70,12 @@ defmodule Chess.Mixfile do
[ [
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"], "ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate", "test"] test: ["ecto.create --quiet", "ecto.migrate", "test"],
"assets.deploy": [
"esbuild default --minify",
"sass default --no-source-map --style=compressed",
"phx.digest"
]
] ]
end end
end end

381
mix.lock
View File

@ -1,324 +1,61 @@
%{ %{
argon2_elixir: "argon2_elixir": {:hex, :argon2_elixir, "3.0.0", "fd4405f593e77b525a5c667282172dd32772d7c4fa58cdecdaae79d2713b6c5f", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "8b753b270af557d51ba13fcdebc0f0ab27a2a6792df72fd5a6cf9cfaffcedc57"},
{:hex, :argon2_elixir, "1.3.3", "bamboo": {:hex, :bamboo, "2.3.0", "d2392a2cabe91edf488553d3c70638b532e8db7b76b84b0a39e3dfe492ffd6fc", [:mix], [{:hackney, ">= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.4 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "dd0037e68e108fd04d0e8773921512c940e35d981e097b5793543e3b2f9cd3f6"},
"487ffa071ef78c51d9b16e50ff3cf30cf8204e0aa4bdc8afd3765fdd8195e213", [:make, :mix], "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"},
[{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "castore": {:hex, :castore, "0.1.22", "4127549e411bedd012ca3a308dede574f43819fe9394254ca55ab4895abfa1a2", [:mix], [], "hexpm", "c17576df47eb5aa1ee40cc4134316a99f5cad3e215d5c77b8dd3cfef12a22cac"},
"0ca19822ba4b85fe6dab75d1ed36bd9257a88cc4385bc32be177d861a1f3ec31"}, "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"},
bamboo: "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
{:hex, :bamboo, "1.6.0", "adfb583bef028923aae6f22deaea6667290561da1246058556ecaeb0fec5a175", "comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"},
[:mix], "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
[ "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
{:hackney, ">= 1.13.0", [hex: :hackney, repo: "hexpm", optional: false]}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]} "credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"},
], "hexpm", "454e67feacbc9b6e00553ce1d2fba003c861e0035600d59b09d6159985b17f9b"}, "dart_sass": {:hex, :dart_sass, "0.5.1", "d45f20a8e324313689fb83287d4702352793ce8c9644bc254155d12656ade8b6", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "24f8a1c67e8b5267c51a33cbe6c0b5ebf12c2c83ace88b5ac04947d676b4ec81"},
bunt: "db_connection": {:hex, :db_connection, "2.4.3", "3b9aac9f27347ec65b271847e6baeb4443d8474289bd18c1d6f4de655b70c94d", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c127c15b0fa6cfb32eed07465e05da6c815b032508d4ed7c116122871df73c12"},
{:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
[:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, "ecto": {:hex, :ecto, "3.9.4", "3ee68e25dbe0c36f980f1ba5dd41ee0d3eb0873bccae8aeaf1a2647242bffa35", [: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 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "de5f988c142a3aa4ec18b85a4ec34a2390b65b24f02385c1144252ff6ff8ee75"},
certifi: "ecto_sql": {:hex, :ecto_sql, "3.9.2", "34227501abe92dba10d9c3495ab6770e75e79b836d114c41108a4bf2ce200ad5", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1eb5eeb4358fdbcd42eac11c1fbd87e3affd7904e639d77903c1358b2abd3f70"},
{:hex, :certifi, "2.6.1", "dbab8e5e155a0763eea978c913ca280a6b544bfa115633fa20249c3d396d9493", "elixir_make": {:hex, :elixir_make, "0.7.3", "c37fdae1b52d2cc51069713a58c2314877c1ad40800a57efb213f77b078a460d", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "24ada3e3996adbed1fa024ca14995ef2ba3d0d17b678b0f3f2b1f66e6ce2b274"},
[:rebar3], [], "hexpm", "524c97b4991b3849dd5c17a631223896272c6b0af446778ba4675a1dff53bb7e"}, "esbuild": {:hex, :esbuild, "0.6.0", "9ba6ead054abd43cb3d7b14946a0cdd1493698ccd8e054e0e5d6286d7f0f509c", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "30f9a05d4a5bab0d3e37398f312f80864e1ee1a081ca09149d06d474318fd040"},
combine: "expo": {:hex, :expo, "0.3.0", "13127c1d5f653b2927f2616a4c9ace5ae372efd67c7c2693b87fd0fdc30c6feb", [:mix], [], "hexpm", "fb3cd4bf012a77bc1608915497dae2ff684a06f0fa633c7afa90c4d72b881823"},
{:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
[:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "floki": {:hex, :floki, "0.34.0", "002d0cc194b48794d74711731db004fafeb328fe676976f160685262d43706a8", [:mix], [], "hexpm", "9c3a9f43f40dde00332a589bd9d389b90c1f518aef500364d00636acc5ebc99c"},
comeonin: "formulator": {:hex, :formulator, "0.4.0", "43094c3a63e1ee077a01e79425f823d46e031cf7bc9f74045edcda695601efed", [:mix], [{:gettext, ">= 0.11.0", [hex: :gettext, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.4 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "15c34113d6a797bb03d089a0b976b0cf918d64e24d2096986b61735fffaf1980"},
{:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", "gettext": {:hex, :gettext, "0.22.0", "a25d71ec21b1848957d9207b81fd61cb25161688d282d58bdafef74c2270bdc4", [:mix], [{:expo, "~> 0.3.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "cb0675141576f73720c8e49b4f0fd3f2c69f0cd8c218202724d4aebab8c70ace"},
[:mix], "guardian": {:hex, :guardian, "2.3.1", "2b2d78dc399a7df182d739ddc0e566d88723299bfac20be36255e2d052fd215d", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bbe241f9ca1b09fad916ad42d6049d2600bbc688aba5b3c4a6c82592a54274c3"},
[ "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.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", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, "httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"},
{:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
[hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"},
{:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]} "jose": {:hex, :jose, "1.11.5", "3bc2d75ffa5e2c941ca93e5696b54978323191988eb8d225c2e663ddfefd515e", [:mix, :rebar3], [], "hexpm", "dcd3b215bafe02ea7c5b23dafd3eb8062a5cd8f2d904fd9caa323d37034ab384"},
], "hexpm", "d8700a0ca4dbb616c22c9b3f6dd539d88deaafec3efe66869d6370c9a559b3e9"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
connection: "mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"},
{:hex, :connection, "1.1.0", "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, "phoenix": {:hex, :phoenix, "1.6.15", "0a1d96bbc10747fd83525370d691953cdb6f3ccbac61aa01b4acb012474b047d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d70ab9fbf6b394755ea88b644d34d79d8b146e490973151f248cacd122d20672"},
cowboy: "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
{:hex, :cowboy, "2.8.0", "f3dc62e35797ecd9ac1b50db74611193c29815401e53bac9a5c0577bd7bc667d", "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"},
[:rebar3], "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [: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", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"},
[ "phoenix_live_view": {:hex, :phoenix_live_view, "0.18.11", "c50eac83dae6b5488859180422dfb27b2c609de87f4aa5b9c926ecd0501cd44f", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76c99a0ffb47cd95bf06a917e74f282a603f3e77b00375f3c2dd95110971b102"},
{:cowlib, "~> 2.9.1", [hex: :cowlib, repo: "hexpm", optional: false]}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
{:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]} "phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"},
], "hexpm", "4643e4fba74ac96d4d152c75803de6fad0b3fa5df354c71afdd6cbeeb15fac8a"}, "phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"},
cowboy_telemetry: "plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.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.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"},
{:hex, :cowboy_telemetry, "0.3.1", "plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"},
"ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], "plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"},
[ "poison": {:hex, :poison, "4.0.1", "bcb755a16fac91cad79bfe9fc3585bb07b9331e50cfe3420a24bcc2d735709ae", [:mix], [], "hexpm", "ba8836feea4b394bb718a161fc59a288fe0109b5006d6bdf97b6badfcf6f0f25"},
{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]} "postgrex": {:hex, :postgrex, "0.16.5", "fcc4035cc90e23933c5d69a9cd686e329469446ef7abba2cf70f08e2c4b69810", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "edead639dc6e882618c01d8fc891214c481ab9a3788dfe38dd5e37fd1d5fb2e8"},
], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
cowlib: "secure_random": {:hex, :secure_random, "0.5.1", "c5532b37c89d175c328f5196a0c2a5680b15ebce3e654da37129a9fe40ebf51b", [:mix], [], "hexpm", "1b9754f15e3940a143baafd19da12293f100044df69ea12db5d72878312ae6ab"},
{:hex, :cowlib, "2.9.1", "61a6c7c50cf07fdd24b2f45b89500bb93b6686579b069a89f88cb211e1125c78", "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
[:rebar3], [], "hexpm", "e4175dc240a70d996156160891e1c62238ede1729e45740bdd38064dad476170"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
credo: "tesla": {:hex, :tesla, "1.5.0", "7ee3616be87024a2b7231ae14474310c9b999c3abb1f4f8dbc70f86bd9678eef", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "1d0385e41fbd76af3961809088aef15dec4c2fdaab97b1c93c6484cb3695a122"},
{:hex, :credo, "1.5.4", "9914180105b438e378e94a844ec3a5088ae5875626fc945b7c1462b41afc3198", "timex": {:hex, :timex, "3.6.3", "58ce6c9eda8ed47fc80c24dde09d481465838d3bcfc230949287fc1b0b0041c1", [: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", "6d69f4f95fcf5684102a9cb3cf92c5ba6545bd60ed8d8a6a93cd2a4a4fb0d9ec"},
[:mix], "timex_ecto": {:hex, :timex_ecto, "3.4.0", "7871043345626a591bfa3e313aa271df4a4eda79f51eb69e83f326f0b8f3181c", [:mix], [{:ecto, "~> 2.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:timex, "~> 3.6", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "4237fa971c8fb9baeeb901b3ae4efee663e0da335e291228f215d99cf8a64799"},
[ "tzdata": {:hex, :tzdata, "1.0.5", "69f1ee029a49afa04ad77801febaf69385f3d3e3d1e4b56b9469025677b89a28", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "55519aa2a99e5d2095c1e61cc74c9be69688f8ab75c27da724eb8279ff402a5a"},
{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
{:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, "wallaby": {:hex, :wallaby, "0.30.1", "81342a34080867ab359aca23de4d1d8c6bbdeb35d8ce2a8c42e42b758d539963", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:httpoison, "~> 0.12 or ~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_ecto, ">= 3.0.0", [hex: :phoenix_ecto, repo: "hexpm", optional: true]}, {:web_driver_client, "~> 0.2.0", [hex: :web_driver_client, repo: "hexpm", optional: false]}], "hexpm", "457251df6a94ff80816524136edbce6400cb1ee979586c90224ff634e9543d78"},
{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]} "web_driver_client": {:hex, :web_driver_client, "0.2.0", "63b76cd9eb3b0716ec5467a0f8bead73d3d9612e63f7560d21357f03ad86e31a", [:mix], [{:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:tesla, "~> 1.3", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "83cc6092bc3e74926d1c8455f0ce927d5d1d36707b74d9a65e38c084aab0350f"},
], "hexpm", "cf51af45eadc0a3f39ba13b56fdac415c91b34f7b7533a13dc13550277141bc4"},
db_connection:
{:hex, :db_connection, "2.3.1",
"4c9f3ed1ef37471cbdd2762d6655be11e38193904d9c5c1c9389f1b891a3088e", [:mix],
[{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm",
"abaab61780dde30301d840417890bd9f74131041afd02174cf4e10635b3a63f5"},
decimal:
{:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697",
[:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
ecto:
{:hex, :ecto, "3.5.5", "48219a991bb86daba6e38a1e64f8cea540cded58950ff38fbc8163e062281a07",
[: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", "98dd0e5e1de7f45beca6130d13116eae675db59adfa055fb79612406acf6f6f1"},
ecto_sql:
{:hex, :ecto_sql, "3.5.3", "1964df0305538364b97cc4661a2bd2b6c89d803e66e5655e4e55ff1571943efd",
[:mix],
[
{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]},
{:ecto, "~> 3.5.0", [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.1", [hex: :tds, repo: "hexpm", optional: true]},
{:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}
], "hexpm", "d2f53592432ce17d3978feb8f43e8dc0705e288b0890caf06d449785f018061c"},
elixir_make:
{:hex, :elixir_make, "0.6.2",
"7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm",
"03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"},
file_system:
{:hex, :file_system, "0.2.10",
"fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm",
"41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
floki:
{:hex, :floki, "0.29.0", "b1710d8c93a2f860dc2d7adc390dd808dc2fb8f78ee562304457b75f4c640881",
[:mix],
[{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}],
"hexpm", "008585ce64b9f74c07d32958ec9866f4b8a124bf4da1e2941b28e41384edaaad"},
formulator:
{:hex, :formulator, "0.1.8",
"eb43e1646828edb6614c2cf9c269d55b3d970414684f1e0290734d22c4936af4", [:mix],
[
{:gettext, ">= 0.11.0", [hex: :gettext, repo: "hexpm", optional: false]},
{:phoenix_html, "~> 2.4", [hex: :phoenix_html, repo: "hexpm", optional: false]}
], "hexpm", "dae3ff05743db0e31ef722e6e6ef7ed32836a65c422979e4c09b7c2f0494cf2c"},
gettext:
{:hex, :gettext, "0.16.1", "e2130b25eebcbe02bb343b119a07ae2c7e28bd4b146c4a154da2ffb2b3507af2",
[:mix], [], "hexpm", "dd3a7ea5e3e87ee9df29452dd9560709b4c7cc8141537d0b070155038d92bdf1"},
guardian:
{:hex, :guardian, "1.2.1", "bdc8dd3dbf0fb7216cb6f91c11831faa1a64d39cdaed9a611e37f2413e584983",
[:mix],
[
{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]},
{:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: true]},
{:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}
], "hexpm", "723fc404edfb7bd5cba4cd83329b352037f102aa97468f44e58ac7f47c136a98"},
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"},
httpoison:
{:hex, :httpoison, "1.8.0",
"6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix],
[{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm",
"28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"},
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"},
jose:
{:hex, :jose, "1.11.1", "59da64010c69aad6cde2f5b9248b896b84472e99bd18f246085b7b9fe435dcdb",
[:mix, :rebar3], [], "hexpm",
"078f6c9fb3cd2f4cfafc972c814261a7d1e8d2b3685c0a76eb87e158efff1ac5"},
metrics:
{:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486",
[:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
mime:
{:hex, :mime, "1.5.0", "203ef35ef3389aae6d361918bf3f952fa17a09e8e43b5aa592b93eba05d0fb8d",
[:mix], [], "hexpm", "55a94c0f552249fc1a3dd9cd2d3ab9de9d3c89b559c2bd01121f824834f24746"},
mimerl:
{:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3",
[:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
parse_trans:
{:hex, :parse_trans, "3.3.1",
"16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm",
"07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
phoenix:
{:hex, :phoenix, "1.5.7", "2923bb3af924f184459fe4fa4b100bd25fa6468e69b2803dfae82698269aa5e0",
[:mix],
[
{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]},
{:phoenix_html, "~> 2.13", [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", "774cd64417c5a3788414fdbb2be2eb9bcd0c048d9e6ad11a0c1fd67b7c0d0978"},
phoenix_ecto:
{:hex, :phoenix_ecto, "4.2.1",
"13f124cf0a3ce0f1948cf24654c7b9f2347169ff75c1123f44674afee6af3b03", [:mix],
[
{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]},
{:phoenix_html, "~> 2.14.2 or ~> 2.15",
[hex: :phoenix_html, repo: "hexpm", optional: true]},
{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}
], "hexpm", "478a1bae899cac0a6e02be1deec7e2944b7754c04e7d4107fc5a517f877743c0"},
phoenix_html:
{:hex, :phoenix_html, "2.14.3",
"51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix],
[{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm",
"efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"},
phoenix_live_reload:
{:hex, :phoenix_live_reload, "1.3.0",
"f35f61c3f959c9a01b36defaa1f0624edd55b87e236b606664a556d6f72fd2e7", [: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", "02c1007ae393f2b76ec61c1a869b1e617179877984678babde131d716f95b582"},
phoenix_live_view:
{:hex, :phoenix_live_view, "0.15.3",
"70c7917e5c421e32d1a1c8ddf8123378bb741748cd8091eb9d557fb4be92a94f", [: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", "cabcfb6738419a08600009219a5f0d861de97507fc1232121e1d5221aba849bd"},
phoenix_pubsub:
{:hex, :phoenix_pubsub, "2.0.0",
"a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm",
"c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
plug:
{:hex, :plug, "1.11.0", "f17217525597628298998bc3baed9f8ea1fa3f1160aa9871aee6df47a6e4d38e",
[: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", "2d9c633f0499f9dc5c2fd069161af4e2e7756890b81adcbb2ceaa074e8308876"},
plug_cowboy:
{:hex, :plug_cowboy, "2.4.1",
"779ba386c0915027f22e14a48919a9545714f849505fa15af2631a0d298abf0f", [:mix],
[
{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]},
{:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]},
{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]},
{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}
], "hexpm", "d72113b6dff7b37a7d9b2a5b68892808e3a9a752f2bf7e503240945385b70507"},
plug_crypto:
{:hex, :plug_crypto, "1.2.0",
"1cb20793aa63a6c619dd18bb33d7a3aa94818e5fd39ad357051a67f26dfa2df6", [:mix], [], "hexpm",
"a48b538ae8bf381ffac344520755f3007cc10bd8e90b240af98ea29b69683fc2"},
poison:
{:hex, :poison, "4.0.1", "bcb755a16fac91cad79bfe9fc3585bb07b9331e50cfe3420a24bcc2d735709ae",
[:mix], [], "hexpm", "ba8836feea4b394bb718a161fc59a288fe0109b5006d6bdf97b6badfcf6f0f25"},
poolboy:
{:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b",
[:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
postgrex:
{:hex, :postgrex, "0.15.7",
"724410acd48abac529d0faa6c2a379fb8ae2088e31247687b16cacc0e0883372", [:mix],
[
{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]},
{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]},
{:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]},
{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}
], "hexpm", "88310c010ff047cecd73d5ceca1d99205e4b1ab1b9abfdab7e00f5c9d20ef8f9"},
ranch:
{:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881",
[:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},
secure_random:
{:hex, :secure_random, "0.5.1",
"c5532b37c89d175c328f5196a0c2a5680b15ebce3e654da37129a9fe40ebf51b", [:mix], [], "hexpm",
"1b9754f15e3940a143baafd19da12293f100044df69ea12db5d72878312ae6ab"},
ssl_verify_fun:
{:hex, :ssl_verify_fun, "1.1.6",
"cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3],
[], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
telemetry:
{:hex, :telemetry, "0.4.2",
"2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm",
"2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"},
tesla:
{:hex, :tesla, "1.3.3", "26ae98627af5c406584aa6755ab5fc96315d70d69a24dd7f8369cfcb75094a45",
[:mix],
[
{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]},
{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]},
{:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]},
{:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]},
{:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]},
{:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]},
{:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]},
{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]},
{:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]},
{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]},
{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}
], "hexpm", "2648f1c276102f9250299e0b7b57f3071c67827349d9173f34c281756a1b124c"},
timex:
{:hex, :timex, "3.6.3", "58ce6c9eda8ed47fc80c24dde09d481465838d3bcfc230949287fc1b0b0041c1",
[: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", "6d69f4f95fcf5684102a9cb3cf92c5ba6545bd60ed8d8a6a93cd2a4a4fb0d9ec"},
timex_ecto:
{:hex, :timex_ecto, "3.4.0",
"7871043345626a591bfa3e313aa271df4a4eda79f51eb69e83f326f0b8f3181c", [:mix],
[
{:ecto, "~> 2.2", [hex: :ecto, repo: "hexpm", optional: false]},
{:timex, "~> 3.6", [hex: :timex, repo: "hexpm", optional: false]}
], "hexpm", "4237fa971c8fb9baeeb901b3ae4efee663e0da335e291228f215d99cf8a64799"},
tzdata:
{:hex, :tzdata, "1.0.5", "69f1ee029a49afa04ad77801febaf69385f3d3e3d1e4b56b9469025677b89a28",
[:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm",
"55519aa2a99e5d2095c1e61cc74c9be69688f8ab75c27da724eb8279ff402a5a"},
unicode_util_compat:
{:hex, :unicode_util_compat, "0.7.0",
"bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm",
"25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
wallaby:
{:hex, :wallaby, "0.28.0", "2ff217c0f245cadb3e5d91748ebcf0102873ceb9ef8a3507717c8bdd73915668",
[:mix],
[
{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: true]},
{:httpoison, "~> 0.12 or ~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]},
{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]},
{:phoenix_ecto, ">= 3.0.0", [hex: :phoenix_ecto, repo: "hexpm", optional: true]},
{:web_driver_client, "~> 0.1.0", [hex: :web_driver_client, repo: "hexpm", optional: false]}
], "hexpm", "e58112650d0b51e81714a626eab7d486d7a77342c9bbc2ba262b6653f9b22558"},
web_driver_client:
{:hex, :web_driver_client, "0.1.0",
"19466a989c76b7ec803c796cec0fec4611a64f445fd5120ce50c9e3817e09c2c", [:mix],
[
{:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: false]},
{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]},
{:tesla, "~> 1.3.0", [hex: :tesla, repo: "hexpm", optional: false]}
], "hexpm", "c9c031ca915e8fc75b5e24ac93503244f3cc406dd7f53047087a45aa62d60e9e"}
} }

View File

@ -1 +1,3 @@
node_version=10.16.0 node_version=14.15.4
yarn_version=1.22.10

View File

@ -76,15 +76,13 @@ defmodule Chess.AuthTest do
test "authenticate_user/1 returns false on incorrect password " do test "authenticate_user/1 returns false on incorrect password " do
user_fixture(email: "link@hyrule.com", password: "eyeofsheikah") user_fixture(email: "link@hyrule.com", password: "eyeofsheikah")
assert {:error, message} = assert {:error, message} = Auth.authenticate_user("link@hyrule.com", "shadowtemple")
Auth.authenticate_user("link@hyrule.com", "shadowtemple")
assert message == "invalid password" assert message == "invalid password"
end end
test "authenticate_user/1 returns true on correct password " do test "authenticate_user/1 returns true on correct password " do
user = user_fixture(email: "link@hyrule.com", password: "eyeofsheikah") user = user_fixture(email: "link@hyrule.com", password: "eyeofsheikah")
assert {:ok, ^user} = assert {:ok, ^user} = Auth.authenticate_user("link@hyrule.com", "eyeofsheikah")
Auth.authenticate_user("link@hyrule.com", "eyeofsheikah")
end end
end end
end end

View File

@ -72,7 +72,7 @@ defmodule Chess.BoardTest do
"3,0" => %{"type" => "queen", "colour" => "white"} "3,0" => %{"type" => "queen", "colour" => "white"}
} }
%{board: new_board} = Board.move_piece(board, %{from: {3, 0}, to: {5, 2}}) %{board: new_board} = Board.move_piece(board, %{"from" => [3, 0], "to" => [5, 2]})
assert new_board == %{ assert new_board == %{
"5,2" => %{"type" => "queen", "colour" => "white"} "5,2" => %{"type" => "queen", "colour" => "white"}
@ -85,7 +85,7 @@ defmodule Chess.BoardTest do
"7,0" => %{"type" => "rook", "colour" => "white"} "7,0" => %{"type" => "rook", "colour" => "white"}
} }
%{board: new_board} = Board.move_piece(board, %{from: {4, 0}, to: {6, 0}}) %{board: new_board} = Board.move_piece(board, %{"from" => [4, 0], "to" => [6, 0]})
assert new_board == %{ assert new_board == %{
"6,0" => %{"type" => "king", "colour" => "white"}, "6,0" => %{"type" => "king", "colour" => "white"},
@ -99,7 +99,7 @@ defmodule Chess.BoardTest do
"0,0" => %{"type" => "rook", "colour" => "white"} "0,0" => %{"type" => "rook", "colour" => "white"}
} }
%{board: new_board} = Board.move_piece(board, %{from: {4, 0}, to: {2, 0}}) %{board: new_board} = Board.move_piece(board, %{"from" => [4, 0], "to" => [2, 0]})
assert new_board == %{ assert new_board == %{
"2,0" => %{"type" => "king", "colour" => "white"}, "2,0" => %{"type" => "king", "colour" => "white"},

View File

@ -8,7 +8,7 @@ defmodule Chess.GameStateTest do
test "king is in check" do test "king is in check" do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"4,7" => %{"type" => "queen", "colour" => "black"}, "4,7" => %{"type" => "queen", "colour" => "black"}
} }
assert GameState.king_in_check?(board, "white") assert GameState.king_in_check?(board, "white")
@ -17,7 +17,7 @@ defmodule Chess.GameStateTest do
test "king is not in check" do test "king is not in check" do
board = %{ board = %{
"5,0" => %{"type" => "king", "colour" => "white"}, "5,0" => %{"type" => "king", "colour" => "white"},
"4,7" => %{"type" => "queen", "colour" => "black"}, "4,7" => %{"type" => "queen", "colour" => "black"}
} }
refute GameState.king_in_check?(board, "white") refute GameState.king_in_check?(board, "white")
@ -26,7 +26,7 @@ defmodule Chess.GameStateTest do
test "king is in check by a knight" do test "king is in check by a knight" do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"3,2" => %{"type" => "knight", "colour" => "black"}, "3,2" => %{"type" => "knight", "colour" => "black"}
} }
assert GameState.king_in_check?(board, "white") assert GameState.king_in_check?(board, "white")
@ -35,7 +35,7 @@ defmodule Chess.GameStateTest do
test "king is in check by a pawn" do test "king is in check by a pawn" do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"3,1" => %{"type" => "pawn", "colour" => "black"}, "3,1" => %{"type" => "pawn", "colour" => "black"}
} }
assert GameState.king_in_check?(board, "white") assert GameState.king_in_check?(board, "white")
@ -45,7 +45,7 @@ defmodule Chess.GameStateTest do
board = %{ board = %{
"0,0" => %{"type" => "king", "colour" => "white"}, "0,0" => %{"type" => "king", "colour" => "white"},
"0,4" => %{"type" => "queen", "colour" => "black"}, "0,4" => %{"type" => "queen", "colour" => "black"},
"1,4" => %{"type" => "rook", "colour" => "black"}, "1,4" => %{"type" => "rook", "colour" => "black"}
} }
assert GameState.player_checkmated?(board, "white") assert GameState.player_checkmated?(board, "white")
@ -54,7 +54,7 @@ defmodule Chess.GameStateTest do
test "king is not in checkmate by a queen" do test "king is not in checkmate by a queen" do
board = %{ board = %{
"0,0" => %{"type" => "king", "colour" => "white"}, "0,0" => %{"type" => "king", "colour" => "white"},
"0,4" => %{"type" => "queen", "colour" => "black"}, "0,4" => %{"type" => "queen", "colour" => "black"}
} }
refute GameState.player_checkmated?(board, "white") refute GameState.player_checkmated?(board, "white")
@ -64,7 +64,7 @@ defmodule Chess.GameStateTest do
board = %{ board = %{
"0,0" => %{"type" => "king", "colour" => "white"}, "0,0" => %{"type" => "king", "colour" => "white"},
"1,1" => %{"type" => "queen", "colour" => "black"}, "1,1" => %{"type" => "queen", "colour" => "black"},
"2,3" => %{"type" => "knight", "colour" => "black"}, "2,3" => %{"type" => "knight", "colour" => "black"}
} }
assert GameState.player_checkmated?(board, "white") assert GameState.player_checkmated?(board, "white")
@ -75,7 +75,7 @@ defmodule Chess.GameStateTest do
"0,0" => %{"type" => "king", "colour" => "white"}, "0,0" => %{"type" => "king", "colour" => "white"},
"2,0" => %{"type" => "knight", "colour" => "white"}, "2,0" => %{"type" => "knight", "colour" => "white"},
"0,5" => %{"type" => "queen", "colour" => "black"}, "0,5" => %{"type" => "queen", "colour" => "black"},
"1,5" => %{"type" => "rook", "colour" => "black"}, "1,5" => %{"type" => "rook", "colour" => "black"}
} }
refute GameState.player_checkmated?(board, "white") refute GameState.player_checkmated?(board, "white")
@ -86,7 +86,7 @@ defmodule Chess.GameStateTest do
"0,0" => %{"type" => "king", "colour" => "white"}, "0,0" => %{"type" => "king", "colour" => "white"},
"2,3" => %{"type" => "bishop", "colour" => "white"}, "2,3" => %{"type" => "bishop", "colour" => "white"},
"0,5" => %{"type" => "queen", "colour" => "black"}, "0,5" => %{"type" => "queen", "colour" => "black"},
"1,5" => %{"type" => "rook", "colour" => "black"}, "1,5" => %{"type" => "rook", "colour" => "black"}
} }
refute GameState.player_checkmated?(board, "white") refute GameState.player_checkmated?(board, "white")
@ -96,7 +96,7 @@ defmodule Chess.GameStateTest do
board = %{ board = %{
"0,0" => %{"type" => "king", "colour" => "white"}, "0,0" => %{"type" => "king", "colour" => "white"},
"1,2" => %{"type" => "rook", "colour" => "black"}, "1,2" => %{"type" => "rook", "colour" => "black"},
"2,1" => %{"type" => "rook", "colour" => "black"}, "2,1" => %{"type" => "rook", "colour" => "black"}
} }
assert GameState.player_stalemated?(board, "white") assert GameState.player_stalemated?(board, "white")

View File

@ -12,18 +12,18 @@ defmodule Chess.MoveListTest do
%Move{ %Move{
piece: %{"type" => "pawn", "colour" => "white"}, piece: %{"type" => "pawn", "colour" => "white"},
from: %{"file" => 4, "rank" => 1}, from: %{"file" => 4, "rank" => 1},
to: %{"file" => 4, "rank" => 3}, to: %{"file" => 4, "rank" => 3}
}, },
%Move{ %Move{
piece: %{"type" => "pawn", "colour" => "black"}, piece: %{"type" => "pawn", "colour" => "black"},
from: %{"file" => 4, "rank" => 6}, from: %{"file" => 4, "rank" => 6},
to: %{"file" => 4, "rank" => 4}, to: %{"file" => 4, "rank" => 4}
}, },
%Move{ %Move{
piece: %{"type" => "knight", "colour" => "white"}, piece: %{"type" => "knight", "colour" => "white"},
from: %{"file" => 1, "rank" => 0}, from: %{"file" => 1, "rank" => 0},
to: %{"file" => 2, "rank" => 2}, to: %{"file" => 2, "rank" => 2}
}, }
] ]
expected_result = [ expected_result = [
@ -51,7 +51,7 @@ defmodule Chess.MoveListTest do
from: "b1", from: "b1",
to: "c3" to: "c3"
} }
], ]
] ]
assert MoveList.transform(moves) == expected_result assert MoveList.transform(moves) == expected_result

View File

@ -6,7 +6,7 @@ defmodule Chess.Moves.PieceTest do
test "piece is not being attacked" do test "piece is not being attacked" do
board = %{ board = %{
"4,5" => %{"type" => "king", "colour" => "white"}, "4,5" => %{"type" => "king", "colour" => "white"},
"2,1" => %{"type" => "rook", "colour" => "black"}, "2,1" => %{"type" => "rook", "colour" => "black"}
} }
refute Piece.attacked?(board, {4, 5}) refute Piece.attacked?(board, {4, 5})
@ -15,7 +15,7 @@ defmodule Chess.Moves.PieceTest do
test "piece on the edge of the board is not being attacked" do test "piece on the edge of the board is not being attacked" do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"2,7" => %{"type" => "rook", "colour" => "black"}, "2,7" => %{"type" => "rook", "colour" => "black"}
} }
refute Piece.attacked?(board, {4, 0}) refute Piece.attacked?(board, {4, 0})
@ -25,7 +25,7 @@ defmodule Chess.Moves.PieceTest do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"4,1" => %{"type" => "pawn", "colour" => "white"}, "4,1" => %{"type" => "pawn", "colour" => "white"},
"7,3" => %{"type" => "bishop", "colour" => "black"}, "7,3" => %{"type" => "bishop", "colour" => "black"}
} }
assert Piece.attacked?(board, {4, 0}) assert Piece.attacked?(board, {4, 0})
@ -34,7 +34,7 @@ defmodule Chess.Moves.PieceTest do
test "piece is not being attacked by piece of its own colour" do test "piece is not being attacked by piece of its own colour" do
board = %{ board = %{
"4,5" => %{"type" => "king", "colour" => "white"}, "4,5" => %{"type" => "king", "colour" => "white"},
"2,5" => %{"type" => "rook", "colour" => "white"}, "2,5" => %{"type" => "rook", "colour" => "white"}
} }
refute Piece.attacked?(board, {4, 5}) refute Piece.attacked?(board, {4, 5})
@ -43,7 +43,7 @@ defmodule Chess.Moves.PieceTest do
test "piece can be attacked by a rook" do test "piece can be attacked by a rook" do
board = %{ board = %{
"4,5" => %{"type" => "king", "colour" => "white"}, "4,5" => %{"type" => "king", "colour" => "white"},
"2,5" => %{"type" => "rook", "colour" => "black"}, "2,5" => %{"type" => "rook", "colour" => "black"}
} }
assert Piece.attacked?(board, {4, 5}) assert Piece.attacked?(board, {4, 5})
@ -52,7 +52,7 @@ defmodule Chess.Moves.PieceTest do
test "piece can be attacked by a bishop" do test "piece can be attacked by a bishop" do
board = %{ board = %{
"4,5" => %{"type" => "king", "colour" => "white"}, "4,5" => %{"type" => "king", "colour" => "white"},
"6,7" => %{"type" => "bishop", "colour" => "black"}, "6,7" => %{"type" => "bishop", "colour" => "black"}
} }
assert Piece.attacked?(board, {4, 5}) assert Piece.attacked?(board, {4, 5})
@ -61,7 +61,7 @@ defmodule Chess.Moves.PieceTest do
test "piece can be attacked by a queen" do test "piece can be attacked by a queen" do
board = %{ board = %{
"4,5" => %{"type" => "king", "colour" => "white"}, "4,5" => %{"type" => "king", "colour" => "white"},
"6,7" => %{"type" => "queen", "colour" => "black"}, "6,7" => %{"type" => "queen", "colour" => "black"}
} }
assert Piece.attacked?(board, {4, 5}) assert Piece.attacked?(board, {4, 5})
@ -70,7 +70,7 @@ defmodule Chess.Moves.PieceTest do
test "piece is not attacked by a knight" do test "piece is not attacked by a knight" do
board = %{ board = %{
"4,5" => %{"type" => "king", "colour" => "white"}, "4,5" => %{"type" => "king", "colour" => "white"},
"7,7" => %{"type" => "knight", "colour" => "black"}, "7,7" => %{"type" => "knight", "colour" => "black"}
} }
refute Piece.attacked?(board, {4, 5}) refute Piece.attacked?(board, {4, 5})
@ -79,7 +79,7 @@ defmodule Chess.Moves.PieceTest do
test "piece can be attacked by a knight" do test "piece can be attacked by a knight" do
board = %{ board = %{
"4,5" => %{"type" => "king", "colour" => "white"}, "4,5" => %{"type" => "king", "colour" => "white"},
"5,7" => %{"type" => "knight", "colour" => "black"}, "5,7" => %{"type" => "knight", "colour" => "black"}
} }
assert Piece.attacked?(board, {4, 5}) assert Piece.attacked?(board, {4, 5})
@ -88,7 +88,7 @@ defmodule Chess.Moves.PieceTest do
test "piece can be attacked by a pawn" do test "piece can be attacked by a pawn" do
board = %{ board = %{
"4,5" => %{"type" => "king", "colour" => "white"}, "4,5" => %{"type" => "king", "colour" => "white"},
"5,6" => %{"type" => "pawn", "colour" => "black"}, "5,6" => %{"type" => "pawn", "colour" => "black"}
} }
assert Piece.attacked?(board, {4, 5}) assert Piece.attacked?(board, {4, 5})
@ -97,7 +97,7 @@ defmodule Chess.Moves.PieceTest do
test "piece is not attacked by a pawn directly in front" do test "piece is not attacked by a pawn directly in front" do
board = %{ board = %{
"4,5" => %{"type" => "king", "colour" => "white"}, "4,5" => %{"type" => "king", "colour" => "white"},
"4,6" => %{"type" => "pawn", "colour" => "black"}, "4,6" => %{"type" => "pawn", "colour" => "black"}
} }
refute Piece.attacked?(board, {4, 5}) refute Piece.attacked?(board, {4, 5})

View File

@ -7,10 +7,21 @@ defmodule Chess.Moves.Pieces.BishopTest do
board = %{"4,5" => %{"type" => "bishop", "colour" => "white"}} board = %{"4,5" => %{"type" => "bishop", "colour" => "white"}}
moves = Moves.available(board, {4, 5}) moves = Moves.available(board, {4, 5})
expected_moves = Enum.sort([ expected_moves =
{0, 1}, {1, 2}, {2, 3}, {3, 4}, {5, 6}, {6, 7}, Enum.sort([
{2, 7}, {3, 6}, {5, 4}, {6, 3}, {7, 2}, {0, 1},
]) {1, 2},
{2, 3},
{3, 4},
{5, 6},
{6, 7},
{2, 7},
{3, 6},
{5, 4},
{6, 3},
{7, 2}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
@ -18,39 +29,60 @@ defmodule Chess.Moves.Pieces.BishopTest do
board = %{"0,0" => %{"type" => "bishop", "colour" => "white"}} board = %{"0,0" => %{"type" => "bishop", "colour" => "white"}}
moves = Moves.available(board, {0, 0}) moves = Moves.available(board, {0, 0})
expected_moves = Enum.sort([ expected_moves =
{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, {7, 7}, Enum.sort([
]) {1, 1},
{2, 2},
{3, 3},
{4, 4},
{5, 5},
{6, 6},
{7, 7}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
test "bishops are blocked by pieces of their own colour" do test "bishops are blocked by pieces of their own colour" do
board = %{ board = %{
"0,0" => %{"type" => "bishop", "colour" => "white"}, "0,0" => %{"type" => "bishop", "colour" => "white"},
"5,5" => %{"type" => "king", "colour" => "white"}, "5,5" => %{"type" => "king", "colour" => "white"}
} }
moves = Moves.available(board, {0, 0}) moves = Moves.available(board, {0, 0})
expected_moves = Enum.sort([ expected_moves =
{1, 1}, {2, 2}, {3, 3}, {4, 4}, Enum.sort([
]) {1, 1},
{2, 2},
{3, 3},
{4, 4}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
test "bishops can take an opponents piece" do test "bishops can take an opponents piece" do
board = %{ board = %{
"0,0" => %{"type" => "bishop", "colour" => "white"}, "0,0" => %{"type" => "bishop", "colour" => "white"},
"5,5" => %{"type" => "knight", "colour" => "black"}, "5,5" => %{"type" => "knight", "colour" => "black"}
} }
moves = Moves.available(board, {0, 0}) moves = Moves.available(board, {0, 0})
expected_moves = Enum.sort([ expected_moves =
{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, Enum.sort([
]) {1, 1},
{2, 2},
{3, 3},
{4, 4},
{5, 5}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
def board do def board do
Chess.Board.default Chess.Board.default()
end end
end end

View File

@ -7,28 +7,42 @@ defmodule Chess.Moves.Pieces.King.CastlingTest do
test "king can move two spaces to castle with the king side rook" do test "king can move two spaces to castle with the king side rook" do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"7,0" => %{"type" => "rook", "colour" => "white"}, "7,0" => %{"type" => "rook", "colour" => "white"}
} }
moves = Moves.available(board, {4, 0}) moves = Moves.available(board, {4, 0})
expected_moves = Enum.sort([ expected_moves =
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1}, Enum.sort([
{6, 0}, {3, 0},
]) {5, 0},
{3, 1},
{4, 1},
{5, 1},
{6, 0}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
test "king can move two spaces to castle with the queen side rook" do test "king can move two spaces to castle with the queen side rook" do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"0,0" => %{"type" => "rook", "colour" => "white"}, "0,0" => %{"type" => "rook", "colour" => "white"}
} }
moves = Moves.available(board, {4, 0}) moves = Moves.available(board, {4, 0})
expected_moves = Enum.sort([ expected_moves =
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1}, Enum.sort([
{2, 0}, {3, 0},
]) {5, 0},
{3, 1},
{4, 1},
{5, 1},
{2, 0}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
@ -36,13 +50,19 @@ defmodule Chess.Moves.Pieces.King.CastlingTest do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"3,0" => %{"type" => "queen", "colour" => "white"}, "3,0" => %{"type" => "queen", "colour" => "white"},
"0,0" => %{"type" => "rook", "colour" => "white"}, "0,0" => %{"type" => "rook", "colour" => "white"}
} }
moves = Moves.available(board, {4, 0}) moves = Moves.available(board, {4, 0})
expected_moves = Enum.sort([ expected_moves =
{5, 0}, {3, 1}, {4, 1}, {5, 1}, Enum.sort([
]) {5, 0},
{3, 1},
{4, 1},
{5, 1}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
@ -50,13 +70,20 @@ defmodule Chess.Moves.Pieces.King.CastlingTest do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"0,0" => %{"type" => "rook", "colour" => "white"}, "0,0" => %{"type" => "rook", "colour" => "white"},
"2,7" => %{"type" => "queen", "colour" => "black"}, "2,7" => %{"type" => "queen", "colour" => "black"}
} }
moves = Moves.available(board, {4, 0}) moves = Moves.available(board, {4, 0})
expected_moves = Enum.sort([ expected_moves =
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1}, Enum.sort([
]) {3, 0},
{5, 0},
{3, 1},
{4, 1},
{5, 1}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
@ -64,88 +91,119 @@ defmodule Chess.Moves.Pieces.King.CastlingTest do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"0,0" => %{"type" => "rook", "colour" => "white"}, "0,0" => %{"type" => "rook", "colour" => "white"},
"3,7" => %{"type" => "queen", "colour" => "black"}, "3,7" => %{"type" => "queen", "colour" => "black"}
} }
moves = Moves.available(board, {4, 0}) moves = Moves.available(board, {4, 0})
expected_moves = Enum.sort([ expected_moves =
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1}, Enum.sort([
]) {3, 0},
{5, 0},
{3, 1},
{4, 1},
{5, 1}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
test "cannot castle if the king has moved" do test "cannot castle if the king has moved" do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"0,0" => %{"type" => "rook", "colour" => "white"}, "0,0" => %{"type" => "rook", "colour" => "white"}
} }
move_list = [ move_list = [
%Move{ %Move{
from: %{"file" => 4, "rank" => 0}, from: %{"file" => 4, "rank" => 0},
to: %{"file" => 4, "rank" => 1}, to: %{"file" => 4, "rank" => 1},
piece: %{"type" => "king", "colour" => "white"} piece: %{"type" => "king", "colour" => "white"}
}, },
%Move{ %Move{
from: %{"file" => 4, "rank" => 1}, from: %{"file" => 4, "rank" => 1},
to: %{"file" => 4, "rank" => 0}, to: %{"file" => 4, "rank" => 0},
piece: %{"type" => "king", "colour" => "white"} piece: %{"type" => "king", "colour" => "white"}
}, }
] ]
moves = Moves.available(board, {4, 0}, move_list) moves = Moves.available(board, {4, 0}, move_list)
expected_moves = Enum.sort([ expected_moves =
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1}, Enum.sort([
]) {3, 0},
{5, 0},
{3, 1},
{4, 1},
{5, 1}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
test "cannot castle if the queen side rook has moved" do test "cannot castle if the queen side rook has moved" do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"0,0" => %{"type" => "rook", "colour" => "white"}, "0,0" => %{"type" => "rook", "colour" => "white"}
} }
move_list = [ move_list = [
%Move{ %Move{
from: %{"file" => 0, "rank" => 0}, from: %{"file" => 0, "rank" => 0},
to: %{"file" => 0, "rank" => 1}, to: %{"file" => 0, "rank" => 1},
piece: %{"type" => "rook", "colour" => "white"} piece: %{"type" => "rook", "colour" => "white"}
}, },
%Move{ %Move{
from: %{"file" => 0, "rank" => 1}, from: %{"file" => 0, "rank" => 1},
to: %{"file" => 0, "rank" => 0}, to: %{"file" => 0, "rank" => 0},
piece: %{"type" => "rook", "colour" => "white"} piece: %{"type" => "rook", "colour" => "white"}
}, }
] ]
moves = Moves.available(board, {4, 0}, move_list) moves = Moves.available(board, {4, 0}, move_list)
expected_moves = Enum.sort([ expected_moves =
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1}, Enum.sort([
]) {3, 0},
{5, 0},
{3, 1},
{4, 1},
{5, 1}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
test "cannot castle if the king side rook has moved" do test "cannot castle if the king side rook has moved" do
board = %{ board = %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"7,0" => %{"type" => "rook", "colour" => "white"}, "7,0" => %{"type" => "rook", "colour" => "white"}
} }
move_list = [ move_list = [
%Move{ %Move{
from: %{"file" => 7, "rank" => 0}, from: %{"file" => 7, "rank" => 0},
to: %{"file" => 7, "rank" => 1}, to: %{"file" => 7, "rank" => 1},
piece: %{"type" => "rook", "colour" => "white"} piece: %{"type" => "rook", "colour" => "white"}
}, },
%Move{ %Move{
from: %{"file" => 7, "rank" => 1}, from: %{"file" => 7, "rank" => 1},
to: %{"file" => 7, "rank" => 0}, to: %{"file" => 7, "rank" => 0},
piece: %{"type" => "rook", "colour" => "white"} piece: %{"type" => "rook", "colour" => "white"}
}, }
] ]
moves = Moves.available(board, {4, 0}, move_list) moves = Moves.available(board, {4, 0}, move_list)
expected_moves = Enum.sort([ expected_moves =
{3, 0}, {5, 0}, {3, 1}, {4, 1}, {5, 1}, Enum.sort([
]) {3, 0},
{5, 0},
{3, 1},
{4, 1},
{5, 1}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
end end

View File

@ -7,9 +7,18 @@ defmodule Chess.Moves.Pieces.KingTest do
board = %{"4,5" => %{"type" => "king", "colour" => "white"}} board = %{"4,5" => %{"type" => "king", "colour" => "white"}}
moves = Moves.available(board, {4, 5}) moves = Moves.available(board, {4, 5})
expected_moves = Enum.sort([ expected_moves =
{3, 4}, {4, 4}, {5, 4}, {5, 5}, {5, 6}, {4, 6}, {3, 6}, {3, 5}, Enum.sort([
]) {3, 4},
{4, 4},
{5, 4},
{5, 5},
{5, 6},
{4, 6},
{3, 6},
{3, 5}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
@ -17,26 +26,34 @@ defmodule Chess.Moves.Pieces.KingTest do
board = %{"0,0" => %{"type" => "king", "colour" => "white"}} board = %{"0,0" => %{"type" => "king", "colour" => "white"}}
moves = Moves.available(board, {0, 0}) moves = Moves.available(board, {0, 0})
expected_moves = Enum.sort([ expected_moves =
{0, 1}, {1, 1}, {1, 0}, Enum.sort([
]) {0, 1},
{1, 1},
{1, 0}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
test "kings are blocked by pieces of the same colour" do test "kings are blocked by pieces of the same colour" do
board = %{ board = %{
"0,0" => %{"type" => "king", "colour" => "white"}, "0,0" => %{"type" => "king", "colour" => "white"},
"1,1" => %{"type" => "rook", "colour" => "white"}, "1,1" => %{"type" => "rook", "colour" => "white"}
} }
moves = Moves.available(board, {0, 0}) moves = Moves.available(board, {0, 0})
expected_moves = Enum.sort([ expected_moves =
{0, 1}, {1, 0}, Enum.sort([
]) {0, 1},
{1, 0}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
def board do def board do
Chess.Board.default Chess.Board.default()
end end
end end

View File

@ -7,9 +7,18 @@ defmodule Chess.Moves.Pieces.KnightTest do
board = %{"4,5" => %{"type" => "knight", "colour" => "white"}} board = %{"4,5" => %{"type" => "knight", "colour" => "white"}}
moves = Moves.available(board, {4, 5}) moves = Moves.available(board, {4, 5})
expected_moves = Enum.sort([ expected_moves =
{3, 7}, {5, 7}, {6, 6}, {6, 4}, {5, 3}, {3, 3}, {2, 4}, {2, 6}, Enum.sort([
]) {3, 7},
{5, 7},
{6, 6},
{6, 4},
{5, 3},
{3, 3},
{2, 4},
{2, 6}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
@ -17,26 +26,32 @@ defmodule Chess.Moves.Pieces.KnightTest do
board = %{"0,0" => %{"type" => "knight", "colour" => "white"}} board = %{"0,0" => %{"type" => "knight", "colour" => "white"}}
moves = Moves.available(board, {0, 0}) moves = Moves.available(board, {0, 0})
expected_moves = Enum.sort([ expected_moves =
{1, 2}, {2, 1} Enum.sort([
]) {1, 2},
{2, 1}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
test "knights are blocked by other pieces of the same colour" do test "knights are blocked by other pieces of the same colour" do
board = %{ board = %{
"0,0" => %{"type" => "knight", "colour" => "white"}, "0,0" => %{"type" => "knight", "colour" => "white"},
"1,2" => %{"type" => "king", "colour" => "white"}, "1,2" => %{"type" => "king", "colour" => "white"}
} }
moves = Moves.available(board, {0, 0}) moves = Moves.available(board, {0, 0})
expected_moves = Enum.sort([ expected_moves =
{2, 1}, Enum.sort([
]) {2, 1}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
def board do def board do
Chess.Board.default Chess.Board.default()
end end
end end

View File

@ -36,8 +36,9 @@ defmodule Chess.Moves.Pieces.PawnTest do
test "pawn is blocked from moving two squares by another piece" do test "pawn is blocked from moving two squares by another piece" do
board = %{ board = %{
"4,1" => %{"type" => "pawn", "colour" => "white"}, "4,1" => %{"type" => "pawn", "colour" => "white"},
"4,3" => %{"type" => "pawn", "colour" => "black"}, "4,3" => %{"type" => "pawn", "colour" => "black"}
} }
moves = Moves.available(board, {4, 1}) moves = Moves.available(board, {4, 1})
expected_moves = [{4, 2}] expected_moves = [{4, 2}]
@ -47,8 +48,9 @@ defmodule Chess.Moves.Pieces.PawnTest do
test "pawn is blocked from moving one or two squares by another piece" do test "pawn is blocked from moving one or two squares by another piece" do
board = %{ board = %{
"4,1" => %{"type" => "pawn", "colour" => "white"}, "4,1" => %{"type" => "pawn", "colour" => "white"},
"4,2" => %{"type" => "pawn", "colour" => "black"}, "4,2" => %{"type" => "pawn", "colour" => "black"}
} }
moves = Moves.available(board, {4, 1}) moves = Moves.available(board, {4, 1})
expected_moves = [] expected_moves = []
@ -58,8 +60,9 @@ defmodule Chess.Moves.Pieces.PawnTest do
test "pawn is blocked from moving one square by another piece" do test "pawn is blocked from moving one square by another piece" do
board = %{ board = %{
"4,2" => %{"type" => "pawn", "colour" => "white"}, "4,2" => %{"type" => "pawn", "colour" => "white"},
"4,3" => %{"type" => "pawn", "colour" => "black"}, "4,3" => %{"type" => "pawn", "colour" => "black"}
} }
moves = Moves.available(board, {4, 2}) moves = Moves.available(board, {4, 2})
expected_moves = [] expected_moves = []
@ -69,8 +72,9 @@ defmodule Chess.Moves.Pieces.PawnTest do
test "white pawn can take an opponents piece" do test "white pawn can take an opponents piece" do
board = %{ board = %{
"4,2" => %{"type" => "pawn", "colour" => "white"}, "4,2" => %{"type" => "pawn", "colour" => "white"},
"5,3" => %{"type" => "pawn", "colour" => "black"}, "5,3" => %{"type" => "pawn", "colour" => "black"}
} }
moves = Moves.available(board, {4, 2}) moves = Moves.available(board, {4, 2})
expected_moves = [{4, 3}, {5, 3}] expected_moves = [{4, 3}, {5, 3}]
@ -80,8 +84,9 @@ defmodule Chess.Moves.Pieces.PawnTest do
test "black pawn can take an opponents piece" do test "black pawn can take an opponents piece" do
board = %{ board = %{
"6,6" => %{"type" => "pawn", "colour" => "black"}, "6,6" => %{"type" => "pawn", "colour" => "black"},
"5,5" => %{"type" => "pawn", "colour" => "white"}, "5,5" => %{"type" => "pawn", "colour" => "white"}
} }
moves = Moves.available(board, {6, 6}) moves = Moves.available(board, {6, 6})
expected_moves = [{6, 5}, {6, 4}, {5, 5}] expected_moves = [{6, 5}, {6, 4}, {5, 5}]
@ -89,6 +94,6 @@ defmodule Chess.Moves.Pieces.PawnTest do
end end
def default_board do def default_board do
Chess.Board.default Chess.Board.default()
end end
end end

View File

@ -7,12 +7,35 @@ defmodule Chess.Moves.Pieces.QueenTest do
board = %{"4,5" => %{"type" => "queen", "colour" => "white"}} board = %{"4,5" => %{"type" => "queen", "colour" => "white"}}
moves = Moves.available(board, {4, 5}) moves = Moves.available(board, {4, 5})
expected_moves = Enum.sort([ expected_moves =
{4, 0}, {4, 1}, {4, 2}, {4, 3}, {4, 4}, {4, 6}, {4, 7}, Enum.sort([
{0, 5}, {1, 5}, {2, 5}, {3, 5}, {5, 5}, {6, 5}, {7, 5}, {4, 0},
{0, 1}, {1, 2}, {2, 3}, {3, 4}, {5, 6}, {6, 7}, {4, 1},
{2, 7}, {3, 6}, {5, 4}, {6, 3}, {7, 2}, {4, 2},
]) {4, 3},
{4, 4},
{4, 6},
{4, 7},
{0, 5},
{1, 5},
{2, 5},
{3, 5},
{5, 5},
{6, 5},
{7, 5},
{0, 1},
{1, 2},
{2, 3},
{3, 4},
{5, 6},
{6, 7},
{2, 7},
{3, 6},
{5, 4},
{6, 3},
{7, 2}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
@ -20,15 +43,30 @@ defmodule Chess.Moves.Pieces.QueenTest do
board = %{ board = %{
"0,0" => %{"type" => "queen", "colour" => "white"}, "0,0" => %{"type" => "queen", "colour" => "white"},
"0,5" => %{"type" => "king", "colour" => "white"}, "0,5" => %{"type" => "king", "colour" => "white"},
"5,0" => %{"type" => "bishop", "colour" => "white"}, "5,0" => %{"type" => "bishop", "colour" => "white"}
} }
moves = Moves.available(board, {0, 0}) moves = Moves.available(board, {0, 0})
expected_moves = Enum.sort([ expected_moves =
{0, 1}, {0, 2}, {0, 3}, {0, 4}, Enum.sort([
{1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 1},
{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, {7, 7}, {0, 2},
]) {0, 3},
{0, 4},
{1, 0},
{2, 0},
{3, 0},
{4, 0},
{1, 1},
{2, 2},
{3, 3},
{4, 4},
{5, 5},
{6, 6},
{7, 7}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
@ -36,19 +74,36 @@ defmodule Chess.Moves.Pieces.QueenTest do
board = %{ board = %{
"0,0" => %{"type" => "queen", "colour" => "white"}, "0,0" => %{"type" => "queen", "colour" => "white"},
"0,5" => %{"type" => "knight", "colour" => "black"}, "0,5" => %{"type" => "knight", "colour" => "black"},
"5,0" => %{"type" => "rook", "colour" => "black"}, "5,0" => %{"type" => "rook", "colour" => "black"}
} }
moves = Moves.available(board, {0, 0}) moves = Moves.available(board, {0, 0})
expected_moves = Enum.sort([ expected_moves =
{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, Enum.sort([
{1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {0, 1},
{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}, {7, 7}, {0, 2},
]) {0, 3},
{0, 4},
{0, 5},
{1, 0},
{2, 0},
{3, 0},
{4, 0},
{5, 0},
{1, 1},
{2, 2},
{3, 3},
{4, 4},
{5, 5},
{6, 6},
{7, 7}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
def board do def board do
Chess.Board.default Chess.Board.default()
end end
end end

View File

@ -7,10 +7,24 @@ defmodule Chess.Moves.Pieces.RookTest do
board = %{"4,5" => %{"type" => "rook", "colour" => "white"}} board = %{"4,5" => %{"type" => "rook", "colour" => "white"}}
moves = Moves.available(board, {4, 5}) moves = Moves.available(board, {4, 5})
expected_moves = Enum.sort([ expected_moves =
{4, 0}, {4, 1}, {4, 2}, {4, 3}, {4, 4}, {4, 6}, {4, 7}, Enum.sort([
{0, 5}, {1, 5}, {2, 5}, {3, 5}, {5, 5}, {6, 5}, {7, 5}, {4, 0},
]) {4, 1},
{4, 2},
{4, 3},
{4, 4},
{4, 6},
{4, 7},
{0, 5},
{1, 5},
{2, 5},
{3, 5},
{5, 5},
{6, 5},
{7, 5}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
@ -18,42 +32,81 @@ defmodule Chess.Moves.Pieces.RookTest do
board = %{"0,0" => %{"type" => "rook", "colour" => "white"}} board = %{"0,0" => %{"type" => "rook", "colour" => "white"}}
moves = Moves.available(board, {0, 0}) moves = Moves.available(board, {0, 0})
expected_moves = Enum.sort([ expected_moves =
{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, Enum.sort([
{1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0}, {0, 1},
]) {0, 2},
{0, 3},
{0, 4},
{0, 5},
{0, 6},
{0, 7},
{1, 0},
{2, 0},
{3, 0},
{4, 0},
{5, 0},
{6, 0},
{7, 0}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
test "rooks are blocked by other pieces of the same colour" do test "rooks are blocked by other pieces of the same colour" do
board = %{ board = %{
"0,0" => %{"type" => "rook", "colour" => "white"}, "0,0" => %{"type" => "rook", "colour" => "white"},
"0,5" => %{"type" => "king", "colour" => "white"}, "0,5" => %{"type" => "king", "colour" => "white"}
} }
moves = Moves.available(board, {0, 0}) moves = Moves.available(board, {0, 0})
expected_moves = Enum.sort([ expected_moves =
{0, 1}, {0, 2}, {0, 3}, {0, 4}, Enum.sort([
{1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0}, {0, 1},
]) {0, 2},
{0, 3},
{0, 4},
{1, 0},
{2, 0},
{3, 0},
{4, 0},
{5, 0},
{6, 0},
{7, 0}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
test "rooks can take an opponents piece" do test "rooks can take an opponents piece" do
board = %{ board = %{
"0,0" => %{"type" => "rook", "colour" => "white"}, "0,0" => %{"type" => "rook", "colour" => "white"},
"0,5" => %{"type" => "knight", "colour" => "black"}, "0,5" => %{"type" => "knight", "colour" => "black"}
} }
moves = Moves.available(board, {0, 0}) moves = Moves.available(board, {0, 0})
expected_moves = Enum.sort([ expected_moves =
{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, Enum.sort([
{1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0}, {0, 1},
]) {0, 2},
{0, 3},
{0, 4},
{0, 5},
{1, 0},
{2, 0},
{3, 0},
{4, 0},
{5, 0},
{6, 0},
{7, 0}
])
assert Enum.sort(moves) == expected_moves assert Enum.sort(moves) == expected_moves
end end
def board do def board do
Chess.Board.default Chess.Board.default()
end end
end end

View File

@ -7,51 +7,59 @@ defmodule Chess.Repo.QueriesTest do
describe "opponents" do describe "opponents" do
test "it finds a user on a partial name match" do test "it finds a user on a partial name match" do
user = insert(:user, %{ user =
name: "Link", insert(:user, %{
email: "link@hyrule.com", name: "Link",
password: "ilovezelda" email: "link@hyrule.com",
}) password: "ilovezelda"
opponent = insert(:user, %{ })
name: "Princess Zelda",
email: "zelda@hyrule.com", opponent =
password: "ganonsucks" insert(:user, %{
}) name: "Princess Zelda",
email: "zelda@hyrule.com",
password: "ganonsucks"
})
result = result =
user user
|> Queries.opponents("zelda") |> Queries.opponents("zelda")
|> Repo.one |> Repo.one()
assert result.id == opponent.id assert result.id == opponent.id
end end
test "it finds a user on a complete email match" do test "it finds a user on a complete email match" do
user = insert(:user, %{ user =
name: "Link", insert(:user, %{
email: "link@hyrule.com", name: "Link",
password: "ilovezelda" email: "link@hyrule.com",
}) password: "ilovezelda"
opponent = insert(:user, %{ })
name: "Princess Zelda",
email: "zelda@hyrule.com", opponent =
password: "ganonsucks" insert(:user, %{
}) name: "Princess Zelda",
email: "zelda@hyrule.com",
password: "ganonsucks"
})
result = result =
user user
|> Queries.opponents("zelda@hyrule.com") |> Queries.opponents("zelda@hyrule.com")
|> Repo.one |> Repo.one()
assert result.id == opponent.id assert result.id == opponent.id
end end
test "it does not find a user on a partial email" do test "it does not find a user on a partial email" do
user = insert(:user, %{ user =
name: "Link", insert(:user, %{
email: "link@hyrule.com", name: "Link",
password: "ilovezelda" email: "link@hyrule.com",
}) password: "ilovezelda"
})
insert(:user, %{ insert(:user, %{
name: "Princess Zelda", name: "Princess Zelda",
email: "zelda@hyrule.com", email: "zelda@hyrule.com",
@ -61,7 +69,7 @@ defmodule Chess.Repo.QueriesTest do
result = result =
user user
|> Queries.opponents("hyrule") |> Queries.opponents("hyrule")
|> Repo.one |> Repo.one()
assert result == nil assert result == nil
end end

View File

@ -14,29 +14,32 @@ defmodule Chess.Store.MoveTest do
user = insert(:user) user = insert(:user)
opponent = insert(:opponent) opponent = insert(:opponent)
game = insert(:game, %{ game =
board: Board.default, insert(:game, %{
user_id: user.id, board: Board.default(),
opponent_id: opponent.id, user_id: user.id,
}) opponent_id: opponent.id
})
changeset = Move.changeset(%Move{}, %{ changeset =
game_id: game.id, Move.changeset(%Move{}, %{
from: %{"file" => 4, "rank" => 1}, game_id: game.id,
to: %{"file" => 4, "rank" => 3}, from: %{"file" => 4, "rank" => 1},
piece: %{"type" => "pawn", "colour" => "white"}, to: %{"file" => 4, "rank" => 3},
}) piece: %{"type" => "pawn", "colour" => "white"}
})
assert changeset.valid? assert changeset.valid?
assert {:ok, _move} = Repo.insert(changeset) assert {:ok, _move} = Repo.insert(changeset)
end end
test "move is invalid without a game" do test "move is invalid without a game" do
changeset = Move.changeset(%Move{}, %{ changeset =
from: %{"file" => 4, "rank" => 1}, Move.changeset(%Move{}, %{
to: %{"file" => 4, "rank" => 3}, from: %{"file" => 4, "rank" => 1},
piece: %{"type" => "pawn", "colour" => "white"}, to: %{"file" => 4, "rank" => 3},
}) piece: %{"type" => "pawn", "colour" => "white"}
})
refute changeset.valid? refute changeset.valid?
end end
@ -45,16 +48,18 @@ defmodule Chess.Store.MoveTest do
user = insert(:user) user = insert(:user)
opponent = insert(:opponent) opponent = insert(:opponent)
game = insert(:game, %{ game =
board: Board.default, insert(:game, %{
user_id: user.id, board: Board.default(),
opponent_id: opponent.id, user_id: user.id,
}) opponent_id: opponent.id
})
changeset = Move.changeset(%Move{}, %{ changeset =
game_id: game.id, Move.changeset(%Move{}, %{
piece: %{"type" => "pawn", "colour" => "white"}, game_id: game.id,
}) piece: %{"type" => "pawn", "colour" => "white"}
})
refute changeset.valid? refute changeset.valid?
end end
@ -63,17 +68,19 @@ defmodule Chess.Store.MoveTest do
user = insert(:user) user = insert(:user)
opponent = insert(:opponent) opponent = insert(:opponent)
game = insert(:game, %{ game =
board: Board.default, insert(:game, %{
user_id: user.id, board: Board.default(),
opponent_id: opponent.id, user_id: user.id,
}) opponent_id: opponent.id
})
changeset = Move.changeset(%Move{}, %{ changeset =
game_id: game.id, Move.changeset(%Move{}, %{
from: %{"file" => 4, "rank" => 1}, game_id: game.id,
to: %{"file" => 4, "rank" => 3}, from: %{"file" => 4, "rank" => 1},
}) to: %{"file" => 4, "rank" => 3}
})
refute changeset.valid? refute changeset.valid?
end end
@ -83,16 +90,16 @@ defmodule Chess.Store.MoveTest do
piece: %{"type" => "pawn", "colour" => "white"}, piece: %{"type" => "pawn", "colour" => "white"},
piece_captured: %{"type" => "pawn", "colour" => "black"}, piece_captured: %{"type" => "pawn", "colour" => "black"},
from: %{"file" => 4, "rank" => 1}, from: %{"file" => 4, "rank" => 1},
to: %{"file" => 4, "rank" => 3}, to: %{"file" => 4, "rank" => 3}
} }
assert Move.transform(move) == %{ assert Move.transform(move) == %{
id: nil, id: nil,
piece: %{"type" => "pawn", "colour" => "white"}, piece: %{"type" => "pawn", "colour" => "white"},
piece_captured: %{"type" => "pawn", "colour" => "black"}, piece_captured: %{"type" => "pawn", "colour" => "black"},
from: "e2", from: "e2",
to: "e4" to: "e4"
} }
end end
end end
end end

View File

@ -8,10 +8,12 @@ defmodule ChessWeb.GameChannelTest do
test "assigns game_id to the socket after join" do test "assigns game_id to the socket after join" do
user = insert(:user) user = insert(:user)
game = insert(:game, %{
user_id: user.id, game =
opponent_id: insert(:opponent).id insert(:game, %{
}) user_id: user.id,
opponent_id: insert(:opponent).id
})
token = Phoenix.Token.sign(@endpoint, "game socket", user.id) token = Phoenix.Token.sign(@endpoint, "game socket", user.id)
{:ok, socket} = connect(UserSocket, %{"token" => token}) {:ok, socket} = connect(UserSocket, %{"token" => token})
@ -24,20 +26,22 @@ defmodule ChessWeb.GameChannelTest do
test "returns the game state after join" do test "returns the game state after join" do
user = insert(:user) user = insert(:user)
opponent = insert(:opponent, %{name: "Daruk"}) opponent = insert(:opponent, %{name: "Daruk"})
game = insert(:game, %{
user_id: user.id, game =
opponent_id: opponent.id insert(:game, %{
}) user_id: user.id,
opponent_id: opponent.id
})
token = Phoenix.Token.sign(@endpoint, "game socket", user.id) token = Phoenix.Token.sign(@endpoint, "game socket", user.id)
{:ok, socket} = connect(UserSocket, %{"token" => token}) {:ok, socket} = connect(UserSocket, %{"token" => token})
{:ok, _, _} = subscribe_and_join(socket, "game:#{game.id}", %{}) {:ok, _, _} = subscribe_and_join(socket, "game:#{game.id}", %{})
assert_push "game:update", %{ assert_push("game:update", %{
player: "white", player: "white",
opponent: "Daruk", opponent: "Daruk",
turn: "white", turn: "white"
} })
end end
end end

View File

@ -2,7 +2,7 @@ defmodule ChessWeb.SessionControllerTest do
use ChessWeb.ConnCase use ChessWeb.ConnCase
test "shows log in form", %{conn: conn} do test "shows log in form", %{conn: conn} do
conn = get conn, session_path(conn, :new) conn = get(conn, session_path(conn, :new))
assert html_response(conn, 200) =~ "Log in" assert html_response(conn, 200) =~ "Log in"
end end
end end

View File

@ -40,22 +40,24 @@ defmodule Chess.Features.GamesTest do
|> click(button("Create game")) |> click(button("Create game"))
session session
|> assert_has( |> assert_has(css(".help-block", text: "can't be blank"))
css(".help-block", text: "can't be blank")
)
end end
test "can only see own games", %{session: session} do test "can only see own games", %{session: session} do
opponent = insert(:user, %{ opponent =
name: "Urbosa", insert(:user, %{
email: "urbosa@gerudo.town", name: "Urbosa",
password: "gerudoqueen" email: "urbosa@gerudo.town",
}) password: "gerudoqueen"
user = insert(:user, %{ })
name: "Zelda",
email: "zelda@hyrule.com", user =
password: "ganonsucks" insert(:user, %{
}) name: "Zelda",
email: "zelda@hyrule.com",
password: "ganonsucks"
})
insert(:game, %{user_id: user.id, opponent_id: opponent.id}) insert(:game, %{user_id: user.id, opponent_id: opponent.id})
session session
@ -72,16 +74,20 @@ defmodule Chess.Features.GamesTest do
end end
test "can see games as an opponent", %{session: session} do test "can see games as an opponent", %{session: session} do
opponent = insert(:user, %{ opponent =
name: "Urbosa", insert(:user, %{
email: "urbosa@gerudo.town", name: "Urbosa",
password: "gerudoqueen" email: "urbosa@gerudo.town",
}) password: "gerudoqueen"
user = insert(:user, %{ })
name: "Zelda",
email: "zelda@hyrule.com", user =
password: "ganonsucks" insert(:user, %{
}) name: "Zelda",
email: "zelda@hyrule.com",
password: "ganonsucks"
})
insert(:game, %{user_id: user.id, opponent_id: opponent.id}) insert(:game, %{user_id: user.id, opponent_id: opponent.id})
session session

View File

@ -22,27 +22,28 @@ defmodule Chess.Features.MovesTest do
|> click(link("New game")) |> click(link("New game"))
|> select_opponent("Zelda") |> select_opponent("Zelda")
|> click(button("Create game")) |> click(button("Create game"))
|> click(css("#f4-r1")) |> click(css("#f4-r1"))
|> assert_has(square_selected("f4-r1")) |> assert_has(square_selected("f4-r1"))
|> assert_has(square_containing("f4-r1", %{type: "pawn", colour: "white"})) |> assert_has(square_containing("f4-r1", %{type: "pawn", colour: "white"}))
|> click(css("#f4-r3")) |> click(css("#f4-r3"))
|> assert_has(square_containing("f4-r3", %{type: "pawn", colour: "white"})) |> assert_has(square_containing("f4-r3", %{type: "pawn", colour: "white"}))
|> refute_has(square_containing("f4-r1", %{type: "pawn", colour: "white"})) |> refute_has(square_containing("f4-r1", %{type: "pawn", colour: "white"}))
end end
test "opponents recieves an email on move", %{session: session} do test "opponents recieves an email on move", %{session: session} do
user = insert(:user, %{ user =
name: "Link", insert(:user, %{
email: "link@hyrule.com", name: "Link",
password: "ilovezelda" email: "link@hyrule.com",
}) password: "ilovezelda"
opponent = insert(:user, %{ })
name: "Zelda",
email: "zelda@hyrule.com", opponent =
password: "ganondorfsucks" insert(:user, %{
}) name: "Zelda",
email: "zelda@hyrule.com",
password: "ganondorfsucks"
})
session session
|> login("link@hyrule.com", "ilovezelda") |> login("link@hyrule.com", "ilovezelda")
@ -88,6 +89,7 @@ defmodule Chess.Features.MovesTest do
email: "link@hyrule.com", email: "link@hyrule.com",
password: "ilovezelda" password: "ilovezelda"
}) })
insert(:user, %{ insert(:user, %{
name: "Zelda", name: "Zelda",
email: "zelda@hyrule.com", email: "zelda@hyrule.com",
@ -101,7 +103,8 @@ defmodule Chess.Features.MovesTest do
|> select_opponent("Zelda") |> select_opponent("Zelda")
|> click(button("Create game")) |> click(button("Create game"))
{:ok, session2} = Wallaby.start_session {:ok, session2} = Wallaby.start_session()
session2 session2
|> login("zelda@hyrule.com", "ganondorfsucks") |> login("zelda@hyrule.com", "ganondorfsucks")
|> click(link("Game with Link")) |> click(link("Game with Link"))
@ -117,6 +120,7 @@ defmodule Chess.Features.MovesTest do
email: "link@hyrule.com", email: "link@hyrule.com",
password: "ilovezelda" password: "ilovezelda"
}) })
insert(:user, %{ insert(:user, %{
name: "Zelda", name: "Zelda",
email: "zelda@hyrule.com", email: "zelda@hyrule.com",
@ -130,7 +134,8 @@ defmodule Chess.Features.MovesTest do
|> select_opponent("Zelda") |> select_opponent("Zelda")
|> click(button("Create game")) |> click(button("Create game"))
{:ok, session2} = Wallaby.start_session {:ok, session2} = Wallaby.start_session()
session2 session2
|> login("zelda@hyrule.com", "ganondorfsucks") |> login("zelda@hyrule.com", "ganondorfsucks")
|> click(link("Game with Link")) |> click(link("Game with Link"))
@ -147,25 +152,29 @@ defmodule Chess.Features.MovesTest do
test "cannot move the king into a position that would result in check", test "cannot move the king into a position that would result in check",
%{session: session} do %{session: session} do
user = insert(:user, %{ user =
name: "Link", insert(:user, %{
email: "link@hyrule.com", name: "Link",
password: "ilovezelda" email: "link@hyrule.com",
}) password: "ilovezelda"
opponent = insert(:user, %{ })
name: "Zelda",
email: "zelda@hyrule.com", opponent =
password: "ganondorfsucks" insert(:user, %{
}) name: "Zelda",
email: "zelda@hyrule.com",
password: "ganondorfsucks"
})
insert(:game, %{ insert(:game, %{
board: %{ board: %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"3,7" => %{"type" => "queen", "colour" => "black"}, "3,7" => %{"type" => "queen", "colour" => "black"},
"7,7" => %{"type" => "king", "colour" => "black"}, "7,7" => %{"type" => "king", "colour" => "black"}
}, },
user_id: user.id, user_id: user.id,
opponent_id: opponent.id, opponent_id: opponent.id,
turn: "white", turn: "white"
}) })
session session
@ -182,26 +191,30 @@ defmodule Chess.Features.MovesTest do
test "cannot make a move that would place the king in check", test "cannot make a move that would place the king in check",
%{session: session} do %{session: session} do
user = insert(:user, %{ user =
name: "Link", insert(:user, %{
email: "link@hyrule.com", name: "Link",
password: "ilovezelda" email: "link@hyrule.com",
}) password: "ilovezelda"
opponent = insert(:user, %{ })
name: "Zelda",
email: "zelda@hyrule.com", opponent =
password: "ganondorfsucks" insert(:user, %{
}) name: "Zelda",
email: "zelda@hyrule.com",
password: "ganondorfsucks"
})
insert(:game, %{ insert(:game, %{
board: %{ board: %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"4,1" => %{"type" => "rook", "colour" => "white"}, "4,1" => %{"type" => "rook", "colour" => "white"},
"4,7" => %{"type" => "queen", "colour" => "black"}, "4,7" => %{"type" => "queen", "colour" => "black"},
"7,7" => %{"type" => "king", "colour" => "black"}, "7,7" => %{"type" => "king", "colour" => "black"}
}, },
user_id: user.id, user_id: user.id,
opponent_id: opponent.id, opponent_id: opponent.id,
turn: "white", turn: "white"
}) })
session session
@ -217,25 +230,29 @@ defmodule Chess.Features.MovesTest do
end end
test "user is informed when the game is in check", %{session: session} do test "user is informed when the game is in check", %{session: session} do
user = insert(:user, %{ user =
name: "Link", insert(:user, %{
email: "link@hyrule.com", name: "Link",
password: "ilovezelda" email: "link@hyrule.com",
}) password: "ilovezelda"
opponent = insert(:user, %{ })
name: "Zelda",
email: "zelda@hyrule.com", opponent =
password: "ganondorfsucks" insert(:user, %{
}) name: "Zelda",
email: "zelda@hyrule.com",
password: "ganondorfsucks"
})
insert(:game, %{ insert(:game, %{
board: %{ board: %{
"4,0" => %{"type" => "king", "colour" => "white"}, "4,0" => %{"type" => "king", "colour" => "white"},
"3,7" => %{"type" => "queen", "colour" => "black"}, "3,7" => %{"type" => "queen", "colour" => "black"},
"7,7" => %{"type" => "king", "colour" => "black"}, "7,7" => %{"type" => "king", "colour" => "black"}
}, },
user_id: user.id, user_id: user.id,
opponent_id: opponent.id, opponent_id: opponent.id,
turn: "black", turn: "black"
}) })
session session

View File

@ -7,11 +7,12 @@ defmodule Chess.Features.PasswordTest do
import Chess.AuthenticationHelpers import Chess.AuthenticationHelpers
test "user can change their password", %{session: session} do test "user can change their password", %{session: session} do
user = insert(:user, %{ user =
name: "Link", insert(:user, %{
email: "link@hyrule.com", name: "Link",
password: "ilovezelda" email: "link@hyrule.com",
}) password: "ilovezelda"
})
session session
|> login(user.email, "ilovezelda") |> login(user.email, "ilovezelda")
@ -26,11 +27,12 @@ defmodule Chess.Features.PasswordTest do
end end
test "password cannot be blank", %{session: session} do test "password cannot be blank", %{session: session} do
user = insert(:user, %{ user =
name: "Link", insert(:user, %{
email: "link@hyrule.com", name: "Link",
password: "ilovezelda" email: "link@hyrule.com",
}) password: "ilovezelda"
})
session session
|> login(user.email, "ilovezelda") |> login(user.email, "ilovezelda")
@ -41,8 +43,6 @@ defmodule Chess.Features.PasswordTest do
|> click(button("Update Password")) |> click(button("Update Password"))
session session
|> assert_has( |> assert_has(css("[data-role='password-error']", text: "can't be blank"))
css("[data-role='password-error']", text: "can't be blank")
)
end end
end end

View File

@ -25,9 +25,7 @@ defmodule Chess.Features.RegistrationTest do
|> click(button("Register")) |> click(button("Register"))
session session
|> assert_has( |> assert_has(css("[data-role='name-error']", text: "can't be blank"))
css("[data-role='name-error']", text: "can't be blank")
)
end end
test "user cannot register without an email", %{session: session} do test "user cannot register without an email", %{session: session} do
@ -39,9 +37,7 @@ defmodule Chess.Features.RegistrationTest do
|> click(button("Register")) |> click(button("Register"))
session session
|> assert_has( |> assert_has(css("[data-role='email-error']", text: "can't be blank"))
css("[data-role='email-error']", text: "can't be blank")
)
end end
test "user cannot register without a password", %{session: session} do test "user cannot register without a password", %{session: session} do
@ -53,8 +49,6 @@ defmodule Chess.Features.RegistrationTest do
|> click(button("Register")) |> click(button("Register"))
session session
|> assert_has( |> assert_has(css("[data-role='password-error']", text: "can't be blank"))
css("[data-role='password-error']", text: "can't be blank")
)
end end
end end

View File

@ -5,7 +5,7 @@ defmodule Chess.FormHelpers do
import Wallaby.Query import Wallaby.Query
def select(session, name, [option: option]) do def select(session, name, option: option) do
session session
|> find(css("[name='#{name}']")) |> find(css("[name='#{name}']"))
|> click(option(option)) |> click(option(option))

View File

@ -18,7 +18,7 @@ defmodule Chess.Factory do
%User{} %User{}
|> User.changeset(params) |> User.changeset(params)
|> Repo.insert! |> Repo.insert!()
end end
def insert(:opponent, new_params) do def insert(:opponent, new_params) do
@ -32,12 +32,12 @@ defmodule Chess.Factory do
%User{} %User{}
|> User.changeset(params) |> User.changeset(params)
|> Repo.insert! |> Repo.insert!()
end end
def insert(:game, params) do def insert(:game, params) do
%Game{} %Game{}
|> Game.changeset(params) |> Game.changeset(params)
|> Repo.insert! |> Repo.insert!()
end end
end end

View File

@ -4,4 +4,4 @@ ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(Chess.Repo, {:shared, self()}) Ecto.Adapters.SQL.Sandbox.mode(Chess.Repo, {:shared, self()})
Application.put_env(:wallaby, :base_url, ChessWeb.Endpoint.url) Application.put_env(:wallaby, :base_url, ChessWeb.Endpoint.url())

View File

@ -8,16 +8,16 @@ defmodule Chess.ErrorViewTest do
test "renders 404.html" do test "renders 404.html" do
assert render_to_string(ErrorView, "404.html", []) == assert render_to_string(ErrorView, "404.html", []) ==
"Page not found" "Page not found"
end end
test "render 500.html" do test "render 500.html" do
assert render_to_string(ErrorView, "500.html", []) == assert render_to_string(ErrorView, "500.html", []) ==
"Internal server error" "Internal server error"
end end
test "render any other" do test "render any other" do
assert render_to_string(ErrorView, "505.html", []) == assert render_to_string(ErrorView, "505.html", []) ==
"Internal server error" "Internal server error"
end end
end end