Elixir 1.11 (#55)

This commit is contained in:
liamwhite 2020-10-26 17:01:29 -04:00 committed by GitHub
parent cd91fd8c9e
commit c7ace12132
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 507 additions and 562 deletions

View file

@ -5,50 +5,7 @@ on: push
jobs:
build:
runs-on: ubuntu-latest
container:
image: elixir:1.10.3
services:
db:
image: postgres:latest
ports: ['5432:5432']
env:
POSTGRES_PASSWORD: 'postgres'
POSTGRES_USER: 'postgres'
POSTGRES_DB: 'philomena_test'
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
elasticsearch:
image: elasticsearch:7.8.1
ports: ['9200:9200']
redis:
image: redis:5.0.9
ports: ['6379:6379']
steps:
- uses: actions/checkout@v1
- name: Install Ubuntu Dependencies
run: |
apt-get update
apt-get -yqq install libpq-dev postgresql-client
- name: Install Dependencies
env:
MIX_ENV: 'test'
run: |
mix local.rebar --force
mix local.hex --force
mix deps.get
- name: Run Tests
env:
MIX_ENV: 'test'
PGUSER: 'postgres'
PGPASSWORD: 'postgres'
PGDATABASE: 'philomena_test'
PGPORT: 5432
PGHOST: db
run: |
mix ecto.create
mix ecto.load
mix reindex_all
mix test
- uses: actions/checkout@v2
- name: Build and test
run: docker-compose run app run-test

186
assets/package-lock.json generated
View file

@ -3,9 +3,9 @@
"lockfileVersion": 1,
"dependencies": {
"@fortawesome/fontawesome-free": {
"version": "5.14.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.14.0.tgz",
"integrity": "sha512-OfdMsF+ZQgdKHP9jUbmDcRrP0eX90XXrsXIdyjLbkmSBzmMXPABB8eobUJtivaupucYaByz6WNe1PI1JuYm3qA=="
"version": "5.15.1",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.1.tgz",
"integrity": "sha512-OEdH7SyC1suTdhBGW91/zBfR6qaIhThbcN8PUXtXilY4GYnSBbVqOntdHbC1vXwsDnX0Qix2m2+DSU1J51ybOQ=="
},
"@nodelib/fs.scandir": {
"version": "2.1.3",
@ -262,9 +262,9 @@
"dev": true
},
"acorn": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz",
"integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w=="
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
},
"acorn-dynamic-import": {
"version": "4.0.0",
@ -2381,9 +2381,9 @@
"dev": true
},
"copy-webpack-plugin": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-6.1.0.tgz",
"integrity": "sha512-aWjIuLt1OVQxaDVffnt3bnGmLA8zGgAJaFwPA+a+QYVPh1vhIKjVfh3SbOFLV0kRPvGBITbw17n5CsmiBS4LQQ==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-6.2.1.tgz",
"integrity": "sha512-VH2ZTMIBsx4p++Lmpg77adZ0KUyM5gFR/9cuTrbneNnJlcQXUFvsNariPqq2dq2kV3F2skHiDGPQCyKWy1+U0Q==",
"dev": true,
"requires": {
"cacache": "^15.0.5",
@ -2394,15 +2394,21 @@
"loader-utils": "^2.0.0",
"normalize-path": "^3.0.0",
"p-limit": "^3.0.2",
"schema-utils": "^2.7.1",
"serialize-javascript": "^4.0.0",
"schema-utils": "^3.0.0",
"serialize-javascript": "^5.0.1",
"webpack-sources": "^1.4.3"
},
"dependencies": {
"@types/json-schema": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
"dev": true
},
"ajv": {
"version": "6.12.4",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
"integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==",
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
@ -2456,15 +2462,24 @@
}
},
"schema-utils": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
"integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
"integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.5",
"ajv": "^6.12.4",
"@types/json-schema": "^7.0.6",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
}
},
"serialize-javascript": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
"integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
"dev": true,
"requires": {
"randombytes": "^2.1.0"
}
}
}
},
@ -3319,12 +3334,20 @@
"dev": true
},
"esrecurse": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
"integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
"requires": {
"estraverse": "^4.1.0"
"estraverse": "^5.2.0"
},
"dependencies": {
"estraverse": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
"dev": true
}
}
},
"estraverse": {
@ -3610,19 +3633,25 @@
"dev": true
},
"file-loader": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.1.0.tgz",
"integrity": "sha512-26qPdHyTsArQ6gU4P1HJbAbnFTyT2r0pG7czh1GFAd9TZbj0n94wWbupgixZH/ET/meqi2/5+F7DhW4OAXD+Lg==",
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.1.1.tgz",
"integrity": "sha512-Klt8C4BjWSXYQAfhpYYkG4qHNTna4toMHEbWrI5IuVoxbU6uiDKeKAP99R8mmbJi3lvewn/jQBOgU4+NS3tDQw==",
"dev": true,
"requires": {
"loader-utils": "^2.0.0",
"schema-utils": "^2.7.1"
"schema-utils": "^3.0.0"
},
"dependencies": {
"@types/json-schema": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
"dev": true
},
"ajv": {
"version": "6.12.4",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
"integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==",
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
@ -3658,13 +3687,13 @@
}
},
"schema-utils": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
"integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
"integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.5",
"ajv": "^6.12.4",
"@types/json-schema": "^7.0.6",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
}
}
@ -7073,9 +7102,9 @@
}
},
"rollup": {
"version": "2.26.10",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.10.tgz",
"integrity": "sha512-dUnjCWOA0h9qNX6qtcHidyatz8FAFZxVxt1dbcGtKdlJkpSxGK3G9+DLCYvtZr9v94D129ij9zUhG+xbRoqepw==",
"version": "2.32.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.32.1.tgz",
"integrity": "sha512-Op2vWTpvK7t6/Qnm1TTh7VjEZZkN8RWgf0DHbkKzQBwNf748YhXbozHVefqpPp/Fuyk/PQPAnYsBxAEtlMvpUw==",
"dev": true,
"requires": {
"fsevents": "~2.1.2"
@ -7822,19 +7851,19 @@
}
},
"style-loader": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.2.1.tgz",
"integrity": "sha512-ByHSTQvHLkWE9Ir5+lGbVOXhxX10fbprhLvdg96wedFZb4NDekDPxVKv5Fwmio+QcMlkkNfuK+5W1peQ5CUhZg==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz",
"integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==",
"dev": true,
"requires": {
"loader-utils": "^2.0.0",
"schema-utils": "^2.6.6"
"schema-utils": "^2.7.0"
},
"dependencies": {
"ajv": {
"version": "6.12.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
"integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
@ -7843,6 +7872,12 @@
"uri-js": "^4.2.2"
}
},
"ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"dev": true
},
"json5": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
@ -7864,14 +7899,14 @@
}
},
"schema-utils": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
"integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
"integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.4",
"ajv": "^6.12.2",
"ajv-keywords": "^3.4.1"
"@types/json-schema": "^7.0.5",
"ajv": "^6.12.4",
"ajv-keywords": "^3.5.2"
}
}
}
@ -8147,9 +8182,9 @@
}
},
"tslib": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==",
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"tty-browserify": {
@ -8428,9 +8463,9 @@
},
"dependencies": {
"chokidar": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.1.tgz",
"integrity": "sha512-TQTJyr2stihpC4Sya9hs2Xh+O2wf+igjL36Y75xx2WdHuiICcn/XJza46Jwt0eT5hVpQOzo3FpY3cj3RVYLX0g==",
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
"integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
"dev": true,
"optional": true,
"requires": {
@ -8441,13 +8476,13 @@
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.4.0"
"readdirp": "~3.5.0"
}
},
"readdirp": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz",
"integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==",
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
"integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
"dev": true,
"optional": true,
"requires": {
@ -8648,9 +8683,9 @@
}
},
"webpack": {
"version": "4.44.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz",
"integrity": "sha512-4UOGAohv/VGUNQJstzEywwNxqX417FnjZgZJpJQegddzPmTvph37eBIRbRTfdySXzVtJXLJfbMN3mMYhM6GdmQ==",
"version": "4.44.2",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz",
"integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==",
"dev": true,
"requires": {
"@webassemblyjs/ast": "1.9.0",
@ -8679,9 +8714,9 @@
},
"dependencies": {
"acorn": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
"integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
"integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
"dev": true
},
"cacache": {
@ -8766,15 +8801,6 @@
"semver": "^5.6.0"
}
},
"serialize-javascript": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz",
"integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==",
"dev": true,
"requires": {
"randombytes": "^2.1.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@ -8791,16 +8817,16 @@
}
},
"terser-webpack-plugin": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.4.tgz",
"integrity": "sha512-U4mACBHIegmfoEe5fdongHESNJWqsGU+W0S/9+BmYGVQDw1+c2Ow05TpMhxjPK1sRb7cuYq1BPl1e5YHJMTCqA==",
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz",
"integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==",
"dev": true,
"requires": {
"cacache": "^12.0.2",
"find-cache-dir": "^2.1.0",
"is-wsl": "^1.1.0",
"schema-utils": "^1.0.0",
"serialize-javascript": "^3.1.0",
"serialize-javascript": "^4.0.0",
"source-map": "^0.6.1",
"terser": "^4.1.2",
"webpack-sources": "^1.4.0",

View file

@ -4,33 +4,33 @@
"watch": "webpack --watch"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^5.14.0",
"@fortawesome/fontawesome-free": "^5.15.1",
"brunch": "^3.0.0",
"copycat-brunch": "^1.1.1"
},
"devDependencies": {
"acorn": "^7.4.0",
"acorn": "^7.4.1",
"autoprefixer": "^9.8.6",
"copy-webpack-plugin": "^6.1.0",
"copy-webpack-plugin": "^6.2.1",
"cross-env": "^7.0.2",
"css-loader": "^3.6.0",
"extract-loader": "^5.1.0",
"file-loader": "^6.1.0",
"file-loader": "^6.1.1",
"node-sass": "^4.14.1",
"normalize-scss": "^7.0.1",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-loader": "^3.0.0",
"postcss-scss": "^2.1.1",
"rollup": "^2.26.10",
"rollup": "^2.32.1",
"rollup-plugin-buble": "^0.19.8",
"rollup-plugin-includepaths": "^0.2.4",
"rollup-plugin-multi-entry": "^2.1.0",
"rollup-plugin-virtual": "^1.0.1",
"sass-loader": "^8.0.2",
"source-map-support": "^0.5.19",
"style-loader": "^1.2.1",
"style-loader": "^1.3.0",
"terser-webpack-plugin": "^3.1.0",
"webpack": "^4.44.1",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12",
"webpack-rollup-loader": "^0.8.0"
}

View file

@ -7,44 +7,23 @@
# General application configuration
import Config
config :logger,
compile_time_purge_matching: [
[application: :remote_ip],
[application: :mint]
]
config :philomena,
ecto_repos: [Philomena.Repo],
elasticsearch_url: "http://localhost:9200",
redis_host: "localhost",
password_pepper: "dn2e0EpZrvBLoxUM3gfQveBhjf0bG/6/bYhrOyq3L3hV9hdo/bimJ+irbDWsuXLP",
otp_secret_key: "Wn7O/8DD+qxL0X4X7bvT90wOkVGcA90bIHww4twR03Ci//zq7PnMw8ypqyyT/b/C",
tumblr_api_key: "fuiKNFp9vQFvjLNvx4sUwti4Yb5yGutBN4Xh10LXZhhRKjWlV4",
image_url_root: "/img",
avatar_url_root: "/avatars",
advert_url_root: "/spns",
badge_url_root: "/media",
tag_url_root: "/media",
channel_url_root: "/media",
image_file_root: "priv/static/system/images",
advert_file_root: "priv/static/system/images/adverts",
avatar_file_root: "priv/static/system/images/avatars",
badge_file_root: "priv/static/system/images",
channel_image_file_root: "priv/static/system/images",
channel_banner_file_root: "priv/static/system/images",
tag_file_root: "priv/static/system/images",
hcaptcha_site_key: "10000000-ffff-ffff-ffff-000000000001",
hcaptcha_secret_key: "0x0000000000000000000000000000000000000000",
cdn_host: "",
proxy_host: nil,
app_dir: File.cwd!()
config :exq,
queues: [{"videos", 2}, {"images", 4}, {"indexing", 16}],
scheduler_enable: true,
max_retries: 1,
start_on_application: false
config :bcrypt_elixir,
log_rounds: 12
ecto_repos: [Philomena.Repo]
config :elastix,
json_codec: Jason
config :exq,
max_retries: 2,
scheduler_enable: true,
start_on_application: false
config :canary,
repo: Philomena.Repo,
unauthorized_handler: {PhilomenaWeb.NotAuthorizedPlug, :call},
@ -60,7 +39,6 @@ config :philomena, PhilomenaWeb.Endpoint,
config :phoenix, :template_engines,
slim: PhoenixSlime.Engine,
slime: PhoenixSlime.Engine,
# If you want to use LiveView
slimleex: PhoenixSlime.LiveViewEngine
config :tesla, adapter: Tesla.Adapter.Mint
@ -79,4 +57,4 @@ config :bamboo, :json_library, Jason
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"
import_config "#{config_env()}.exs"

View file

@ -1,20 +1,7 @@
import Config
# Configure your database
config :philomena, Philomena.Repo,
username: "postgres",
password: "postgres",
database: "philomena_dev",
hostname: "postgres",
show_sensitive_data_on_connection_error: true,
pool_size: 10
config :philomena,
elasticsearch_url: "http://elasticsearch:9200",
redis_host: "redis"
config :exq,
host: "redis"
config :philomena, Philomena.Repo, show_sensitive_data_on_connection_error: true
# For development, we disable any cache and enable
# debugging and code reloading.
@ -68,15 +55,6 @@ config :philomena, PhilomenaWeb.Endpoint,
# Do not include metadata nor timestamps in development logs
config :logger, :console, format: "[$level] $message\n"
config :logger, compile_time_purge_matching: [[application: :remote_ip], [application: :mint]]
# Set up mailer
config :philomena, Philomena.Mailer, adapter: Bamboo.LocalAdapter
config :philomena, :mailer_address, "noreply@philomena.lc"
# Use this to debug slime templates
# config :slime, :keep_lines, true
# Set a higher stacktrace during development. Avoid configuring such
# in production as building large stacktraces may be expensive.

View file

@ -9,9 +9,7 @@ import Config
# manifest is generated by the `mix phx.digest` task,
# which you should run after static files are built and
# before starting your production server.
config :philomena, PhilomenaWeb.Endpoint,
url: [host: "example.com", port: 80],
cache_static_manifest: "priv/static/cache_manifest.json"
config :philomena, PhilomenaWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json"
# Do not print debug messages in production
config :logger, level: :warn

View file

@ -1,62 +0,0 @@
import Config
# ## Using releases (Elixir v1.9+)
#
# If you are doing OTP releases, you need to instruct Phoenix
# to start each relevant endpoint:
#
# config :philomena, PhilomenaWeb.Endpoint, server: true
#
# Then you can assemble a release by calling `mix release`.
# See `mix help release` for more information.
config :bcrypt_elixir,
log_rounds: String.to_integer(System.get_env("BCRYPT_ROUNDS") || "12")
config :philomena,
channel_image_file_root: System.fetch_env!("CHANNEL_IMAGE_FILE_ROOT"),
channel_banner_file_root: System.fetch_env!("CHANNEL_BANNER_FILE_ROOT"),
anonymous_name_salt: System.fetch_env!("ANONYMOUS_NAME_SALT"),
hcaptcha_secret_key: System.fetch_env!("HCAPTCHA_SECRET_KEY"),
hcaptcha_site_key: System.fetch_env!("HCAPTCHA_SITE_KEY"),
elasticsearch_url: System.get_env("ELASTICSEARCH_URL") || "http://localhost:9200",
advert_file_root: System.fetch_env!("ADVERT_FILE_ROOT"),
avatar_file_root: System.fetch_env!("AVATAR_FILE_ROOT"),
channel_url_root: System.fetch_env!("CHANNEL_URL_ROOT"),
badge_file_root: System.fetch_env!("BADGE_FILE_ROOT"),
password_pepper: System.fetch_env!("PASSWORD_PEPPER"),
avatar_url_root: System.fetch_env!("AVATAR_URL_ROOT"),
advert_url_root: System.fetch_env!("ADVERT_URL_ROOT"),
image_file_root: System.fetch_env!("IMAGE_FILE_ROOT"),
tumblr_api_key: System.fetch_env!("TUMBLR_API_KEY"),
otp_secret_key: System.fetch_env!("OTP_SECRET_KEY"),
image_url_root: System.fetch_env!("IMAGE_URL_ROOT"),
badge_url_root: System.fetch_env!("BADGE_URL_ROOT"),
mailer_address: System.fetch_env!("MAILER_ADDRESS"),
tag_file_root: System.fetch_env!("TAG_FILE_ROOT"),
tag_url_root: System.fetch_env!("TAG_URL_ROOT"),
redis_host: System.get_env("REDIS_HOST") || "localhost",
proxy_host: System.get_env("PROXY_HOST"),
camo_host: System.fetch_env!("CAMO_HOST"),
camo_key: System.fetch_env!("CAMO_KEY"),
cdn_host: System.fetch_env!("CDN_HOST")
config :philomena, Philomena.Repo,
url: System.fetch_env!("DATABASE_URL"),
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "16")
config :philomena, Philomena.Mailer,
adapter: Bamboo.SMTPAdapter,
server: System.fetch_env!("SMTP_RELAY"),
hostname: System.fetch_env!("SMTP_DOMAIN"),
port: System.get_env("SMTP_PORT") || 587,
username: System.fetch_env!("SMTP_USERNAME"),
password: System.fetch_env!("SMTP_PASSWORD"),
tls: :always,
auth: :always
config :philomena, PhilomenaWeb.Endpoint,
http: [ip: {127, 0, 0, 1}, port: {:system, "PORT"}],
url: [host: System.fetch_env!("APP_HOSTNAME"), scheme: "https", port: 443],
secret_key_base: System.fetch_env!("SECRET_KEY_BASE"),
server: true

80
config/runtime.exs Normal file
View file

@ -0,0 +1,80 @@
import Config
# ## Using releases (Elixir v1.9+)
#
# If you are doing OTP releases, you can assemble a release
# by calling `mix release`.
#
# See `mix help release` for more information.
config :bcrypt_elixir,
log_rounds: String.to_integer(System.get_env("BCRYPT_ROUNDS", "12"))
config :philomena,
anonymous_name_salt: System.fetch_env!("ANONYMOUS_NAME_SALT"),
hcaptcha_secret_key: System.fetch_env!("HCAPTCHA_SECRET_KEY"),
hcaptcha_site_key: System.fetch_env!("HCAPTCHA_SITE_KEY"),
elasticsearch_url: System.get_env("ELASTICSEARCH_URL", "http://localhost:9200"),
advert_file_root: System.fetch_env!("ADVERT_FILE_ROOT"),
avatar_file_root: System.fetch_env!("AVATAR_FILE_ROOT"),
channel_url_root: System.fetch_env!("CHANNEL_URL_ROOT"),
badge_file_root: System.fetch_env!("BADGE_FILE_ROOT"),
password_pepper: System.fetch_env!("PASSWORD_PEPPER"),
avatar_url_root: System.fetch_env!("AVATAR_URL_ROOT"),
advert_url_root: System.fetch_env!("ADVERT_URL_ROOT"),
image_file_root: System.fetch_env!("IMAGE_FILE_ROOT"),
tumblr_api_key: System.fetch_env!("TUMBLR_API_KEY"),
otp_secret_key: System.fetch_env!("OTP_SECRET_KEY"),
image_url_root: System.fetch_env!("IMAGE_URL_ROOT"),
badge_url_root: System.fetch_env!("BADGE_URL_ROOT"),
mailer_address: System.fetch_env!("MAILER_ADDRESS"),
tag_file_root: System.fetch_env!("TAG_FILE_ROOT"),
tag_url_root: System.fetch_env!("TAG_URL_ROOT"),
redis_host: System.get_env("REDIS_HOST", "localhost"),
proxy_host: System.get_env("PROXY_HOST"),
camo_host: System.get_env("CAMO_HOST"),
camo_key: System.get_env("CAMO_KEY"),
cdn_host: System.fetch_env!("CDN_HOST"),
app_dir: System.get_env("APP_DIR", File.cwd!())
config :exq,
host: System.get_env("REDIS_HOST", "localhost"),
queues: [{"videos", 2}, {"images", 4}, {"indexing", 16}]
if is_nil(System.get_env("START_WORKER")) do
# Make queueing available but don't process any jobs
config :exq, queues: []
end
if config_env() != :test do
# Database config
config :philomena, Philomena.Repo,
url: System.fetch_env!("DATABASE_URL"),
pool_size: String.to_integer(System.get_env("POOL_SIZE", "16"))
end
if config_env() == :prod do
# Production mailer config
config :philomena, Philomena.Mailer,
adapter: Bamboo.SMTPAdapter,
server: System.fetch_env!("SMTP_RELAY"),
hostname: System.fetch_env!("SMTP_DOMAIN"),
port: System.get_env("SMTP_PORT") || 587,
username: System.fetch_env!("SMTP_USERNAME"),
password: System.fetch_env!("SMTP_PASSWORD"),
tls: :always,
auth: :always
# Production endpoint config
config :philomena, PhilomenaWeb.Endpoint,
http: [ip: {127, 0, 0, 1}, port: {:system, "PORT"}],
url: [host: System.fetch_env!("APP_HOSTNAME"), scheme: "https", port: 443],
secret_key_base: System.fetch_env!("SECRET_KEY_BASE"),
server: not is_nil(System.get_env("START_ENDPOINT"))
else
# Don't send email in development
config :philomena, Philomena.Mailer, adapter: Bamboo.LocalAdapter
# Use this to debug slime templates
# config :slime, :keep_lines, true
end

View file

@ -1,27 +1,17 @@
import Config
# Only in tests, remove the complexity from the password hashing algorithm
config :bcrypt_elixir, :log_rounds, 1
# Configure your database
config :philomena, Philomena.Repo,
hostname: "postgres",
username: "postgres",
password: "postgres",
database: "philomena_test",
pool: Ecto.Adapters.SQL.Sandbox
config :philomena,
elasticsearch_url: "http://elasticsearch:9200",
redis_host: "redis",
pwned_passwords: false,
captcha: false
config :exq,
host: "redis"
config :philomena, Philomena.Mailer, adapter: Bamboo.LocalAdapter
config :philomena, :mailer_address, "test@philomena.lc"
# We don't run a server during test. If one is required,
# you can enable the server option below.
config :philomena, PhilomenaWeb.Endpoint,

View file

@ -11,6 +11,29 @@ services:
environment:
- MIX_ENV=dev
- PGPASSWORD=postgres
- ANONYMOUS_NAME_SALT=2fmJRo0OgMFe65kyAJBxPT0QtkVes/jnKDdtP21fexsRqiw8TlSY7yO+uFyMZycp
- HCAPTCHA_SECRET_KEY=0x0000000000000000000000000000000000000000
- HCAPTCHA_SITE_KEY=10000000-ffff-ffff-ffff-000000000001
- PASSWORD_PEPPER=dn2e0EpZrvBLoxUM3gfQveBhjf0bG/6/bYhrOyq3L3hV9hdo/bimJ+irbDWsuXLP
- TUMBLR_API_KEY=fuiKNFp9vQFvjLNvx4sUwti4Yb5yGutBN4Xh10LXZhhRKjWlV4
- OTP_SECRET_KEY=Wn7O/8DD+qxL0X4X7bvT90wOkVGcA90bIHww4twR03Ci//zq7PnMw8ypqyyT/b/C
- ADVERT_FILE_ROOT=priv/static/system/images/adverts
- AVATAR_FILE_ROOT=priv/static/system/images/avatars
- BADGE_FILE_ROOT=priv/static/system/images
- IMAGE_FILE_ROOT=priv/static/system/images
- TAG_FILE_ROOT=priv/static/system/images
- CHANNEL_URL_ROOT=/media
- AVATAR_URL_ROOT=/avatars
- ADVERT_URL_ROOT=/spns
- IMAGE_URL_ROOT=/img
- BADGE_URL_ROOT=/media
- TAG_URL_ROOT=/media
- ELASTICSEARCH_URL=http://elasticsearch:9200
- REDIS_HOST=redis
- DATABASE_URL=ecto://postgres:postgres@postgres/philomena_dev
- CDN_HOST=
- MAILER_ADDRESS=noreply@philomena.local
- START_ENDPOINT=true
working_dir: /srv/philomena
tty: true
volumes:
@ -21,7 +44,7 @@ services:
- redis
postgres:
image: postgres:12.4
image: postgres:13.0
environment:
- POSTGRES_PASSWORD=postgres
volumes:
@ -30,7 +53,7 @@ services:
driver: "none"
elasticsearch:
image: elasticsearch:7.8.1
image: elasticsearch:7.9.3
volumes:
- elastic_data:/var/lib/elasticsearch
logging:
@ -43,7 +66,7 @@ services:
hard: 65536
redis:
image: redis:6.0.7
image: redis:6.0.8
logging:
driver: "none"

View file

@ -1,26 +1,30 @@
FROM elixir:1.10.4
FROM hexpm/elixir:1.11.1-erlang-23.1.1-ubuntu-focal-20200703
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get -qq -y install apt-transport-https \
&& echo "deb https://deb.nodesource.com/node_12.x stretch main" >> /etc/apt/sources.list \
&& echo "deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main" >> /etc/apt/sources.list \
&& apt-get -qq -y install apt-transport-https wget gnupg \
&& echo "deb https://deb.nodesource.com/node_12.x focal main" >> /etc/apt/sources.list \
&& echo "deb http://apt.postgresql.org/pub/repos/apt/ focal-pgdg main" >> /etc/apt/sources.list \
&& wget -qO - "https://www.postgresql.org/media/keys/ACCC4CF8.asc" | apt-key add - \
&& wget -qO - "https://deb.nodesource.com/gpgkey/nodesource.gpg.key" | apt-key add - \
&& apt-get update \
&& apt-get -qq -y install inotify-tools postgresql-client build-essential git ffmpeg libavformat-dev libavcodec-dev libswscale-dev nodejs libmagic-dev libpng-dev gifsicle optipng libjpeg-progs librsvg2-bin \
&& apt-get -qq -y dist-upgrade \
&& apt-get -qq -y install inotify-tools postgresql-client build-essential git ffmpeg libavformat-dev libavcodec-dev libswscale-dev nodejs libmagic-dev libpng-dev gifsicle optipng libjpeg-progs librsvg2-bin imagemagick \
&& mix local.hex --force \
&& mix local.rebar --force
ADD https://api.github.com/repos/derpibooru/cli_intensities/git/refs/heads/master /tmp/cli_intensities_version.json
RUN git clone https://github.com/derpibooru/cli_intensities /tmp/cli_intensities \
ADD https://api.github.com/repos/philomena-dev/cli_intensities/git/refs/heads/master /tmp/cli_intensities_version.json
RUN git clone https://github.com/philomena-dev/cli_intensities /tmp/cli_intensities \
&& cd /tmp/cli_intensities \
&& make install
ADD https://api.github.com/repos/derpibooru/mediatools/git/refs/heads/master /tmp/mediatools_version.json
RUN git clone https://github.com/derpibooru/mediatools /tmp/mediatools \
ADD https://api.github.com/repos/philomena-dev/mediatools/git/refs/heads/master /tmp/mediatools_version.json
RUN git clone https://github.com/philomena-dev/mediatools /tmp/mediatools \
&& cd /tmp/mediatools \
&& make install
COPY docker/app/run-development /usr/local/bin/run-development
COPY docker/app/run-test /usr/local/bin/run-test
COPY docker/app/safe-rsvg-convert /usr/local/bin/safe-rsvg-convert
CMD run-development

View file

@ -1,5 +1,15 @@
#!/bin/bash
background() {
while :; do
mix run -e 'Philomena.Release.update_channels()'
mix run -e 'Philomena.Release.verify_user_links()'
mix run -e 'Philomena.Release.update_stats()'
sleep 300
done
}
# Always install assets
(
cd /srv/philomena/assets
@ -27,5 +37,8 @@ createdb -h postgres -U postgres philomena_dev && mix ecto.setup_dev
# Reindex
mix reindex_all
# Run background jobs
background &
# Run the application
mix phx.server
START_WORKER=true mix phx.server

24
docker/app/run-test Executable file
View file

@ -0,0 +1,24 @@
#!/bin/bash
export MIX_ENV=test
# Always install mix dependencies
(cd /srv/philomena && mix deps.get)
# Sleep to allow Elasticsearch to finish initializing
# if it's not done doing whatever it does yet
echo -n "Waiting for Elasticsearch"
until wget -qO - elasticsearch:9200; do
echo -n "."
sleep 2
done
echo
# Create the database
mix ecto.create
mix ecto.load
# Test the application
mix test

View file

@ -1,4 +1,4 @@
FROM nginx:1.18.0
FROM nginx:1.19.3
ENV APP_DIR /srv/philomena
COPY docker/web/nginx.conf /tmp/docker.nginx
RUN envsubst '$APP_DIR' < /tmp/docker.nginx > /etc/nginx/conf.d/default.conf

View file

@ -18,14 +18,13 @@ defmodule Mix.Tasks.ReindexAll do
import Ecto.Query
@shortdoc "Destroys and recreates all Elasticsearch indices."
@requirements ["app.start"]
@impl Mix.Task
def run(args) do
if Mix.env() == :prod and not Enum.member?(args, "--i-know-what-im-doing") do
raise "do not run this task unless you know what you're doing"
end
{:ok, _apps} = Application.ensure_all_started(:philomena)
for {context, schema} <- [
{Images, Image},
{Comments, Comment},

View file

@ -16,16 +16,18 @@ defmodule Philomena.Application do
# Starts a worker by calling: Philomena.Worker.start_link(arg)
# {Philomena.Worker, arg},
Philomena.Servers.UserLinkUpdater,
Philomena.Servers.PicartoChannelUpdater,
Philomena.Servers.PiczelChannelUpdater,
Philomena.Servers.Config,
{Redix, name: :redix, host: Application.get_env(:philomena, :redis_host)},
{Phoenix.PubSub, [name: Philomena.PubSub, adapter: Phoenix.PubSub.PG2]},
{Phoenix.PubSub,
[
name: Philomena.PubSub,
adapter: Phoenix.PubSub.Redis,
host: Application.get_env(:philomena, :redis_host),
node_name: valid_node_name(node())
]},
# Start the endpoint when the application starts
PhilomenaWeb.AdvertUpdater,
PhilomenaWeb.StatsUpdater,
PhilomenaWeb.UserFingerprintUpdater,
PhilomenaWeb.UserIpUpdater,
PhilomenaWeb.Endpoint,
@ -46,4 +48,11 @@ defmodule Philomena.Application do
PhilomenaWeb.Endpoint.config_change(changed, removed)
:ok
end
# Redis adapter really really wants you to have a unique node name,
# so just fake one if iex is being started
defp valid_node_name(node) when node in [nil, :nonode@nohost],
do: Base.encode16(:crypto.strong_rand_bytes(6))
defp valid_node_name(node), do: node
end

View file

@ -7,19 +7,48 @@ defmodule Philomena.Channels do
alias Philomena.Repo
alias Philomena.Channels.Channel
alias Philomena.Channels.PicartoChannel
alias Philomena.Channels.PiczelChannel
alias Philomena.Notifications
@doc """
Returns the list of channels.
## Examples
iex> list_channels()
[%Channel{}, ...]
Updates all the tracked channels for which an update
scheme is known.
"""
def list_channels do
Repo.all(Channel)
def update_tracked_channels! do
now = DateTime.utc_now() |> DateTime.truncate(:second)
picarto_channels = PicartoChannel.live_channels(now)
live_picarto_channels = Map.keys(picarto_channels)
piczel_channels = PiczelChannel.live_channels(now)
live_piczel_channels = Map.keys(piczel_channels)
# Update all channels which are offline to reflect offline status
offline_query =
from c in Channel,
where: c.type == "PicartoChannel" and c.short_name not in ^live_picarto_channels,
or_where: c.type == "PiczelChannel" and c.short_name not in ^live_piczel_channels
Repo.update_all(offline_query, set: [is_live: false, updated_at: now])
# Update all channels which are online to reflect online status using
# changeset functions
online_query =
from c in Channel,
where: c.type == "PicartoChannel" and c.short_name in ^live_picarto_channels,
or_where: c.type == "PiczelChannel" and c.short_name in ^live_picarto_channels
online_query
|> Repo.all()
|> Enum.map(fn
%{type: "PicartoChannel", short_name: name} = channel ->
Channel.update_changeset(channel, Map.get(picarto_channels, name, []))
%{type: "PiczelChannel", short_name: name} = channel ->
Channel.update_changeset(channel, Map.get(piczel_channels, name, []))
end)
|> Enum.map(&Repo.update!/1)
end
@doc """

View file

@ -49,4 +49,16 @@ defmodule Philomena.Channels.Channel do
|> validate_inclusion(:type, ["PicartoChannel", "PiczelChannel"])
|> put_change(:associated_artist_tag_id, tag_id)
end
def update_changeset(channel, attrs) do
cast(channel, attrs, [
:title,
:is_live,
:nsfw,
:viewers,
:thumbnail_url,
:last_fetched_at,
:last_live_at
])
end
end

View file

@ -0,0 +1,31 @@
defmodule Philomena.Channels.PicartoChannel do
@api_online "https://api.picarto.tv/v1/online?adult=true&gaming=true"
@spec live_channels(DateTime.t()) :: map()
def live_channels(now) do
@api_online
|> Philomena.Http.get()
|> case do
{:ok, %Tesla.Env{body: body, status: 200}} ->
body
|> Jason.decode!()
|> Map.new(&{&1["name"], fetch(&1, now)})
_error ->
%{}
end
end
defp fetch(api, now) do
%{
title: api["title"],
is_live: true,
nsfw: api["adult"],
viewers: api["viewers"],
thumbnail_url: api["thumbnails"]["web"],
last_fetched_at: now,
last_live_at: now,
description: nil
}
end
end

View file

@ -0,0 +1,30 @@
defmodule Philomena.Channels.PiczelChannel do
@api_online "https://api.piczel.tv/api/streams"
@spec live_channels(DateTime.t()) :: map()
def live_channels(now) do
@api_online
|> Philomena.Http.get()
|> case do
{:ok, %Tesla.Env{body: body, status: 200}} ->
body
|> Jason.decode!()
|> Map.new(&{&1["slug"], fetch(&1, now)})
_error ->
%{}
end
end
defp fetch(api, now) do
%{
title: api["title"],
is_live: api["live"],
nsfw: api["adult"],
viewers: api["viewers"],
thumbnail_url: api["user"]["avatar"]["avatar"]["url"],
last_fetched_at: now,
last_live_at: now
}
end
end

View file

@ -14,6 +14,21 @@ defmodule Philomena.Release do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
end
def update_channels do
start_app()
Philomena.Channels.update_tracked_channels!()
end
def verify_user_links do
start_app()
Philomena.UserLinks.automatic_verify!()
end
def update_stats do
start_app()
PhilomenaWeb.StatsUpdater.update_stats!()
end
defp repos do
Application.fetch_env!(@app, :ecto_repos)
end
@ -21,4 +36,8 @@ defmodule Philomena.Release do
defp load_app do
Application.load(@app)
end
defp start_app do
Application.ensure_all_started(@app)
end
end

View file

@ -1,70 +0,0 @@
defmodule Philomena.Servers.PicartoChannelUpdater do
alias Philomena.Channels.Channel
alias Philomena.Repo
import Ecto.Query
@api_online "https://api.picarto.tv/v1/online?adult=true&gaming=true"
def child_spec([]) do
%{
id: Philomena.Servers.PicartoChannelUpdater,
start: {Philomena.Servers.PicartoChannelUpdater, :start_link, [[]]}
}
end
def start_link([]) do
{:ok, spawn_link(&run/0)}
end
defp run do
:timer.sleep(:timer.seconds(60))
now = DateTime.utc_now() |> DateTime.truncate(:second)
@api_online
|> Philomena.Http.get()
|> handle_response(now)
run()
end
defp handle_response({:ok, %Tesla.Env{body: body, status: 200}}, now) do
resp =
body
|> Jason.decode!()
|> Map.new(&{&1["name"], &1})
live_channel_names = Map.keys(resp)
Channel
|> where([c], c.type == "PicartoChannel" and c.short_name not in ^live_channel_names)
|> Repo.update_all([set: [is_live: false, updated_at: now]], log: false)
Channel
|> where([c], c.type == "PicartoChannel" and c.short_name in ^live_channel_names)
|> Repo.all(log: false)
|> Enum.map(&fetch(&1, resp[&1.short_name], now))
end
defp handle_response(_response, _now), do: nil
defp fetch(channel, api_response, now) do
Channel
|> where(id: ^channel.id)
|> Repo.update_all(
[
set: [
title: api_response["title"],
is_live: true,
nsfw: api_response["adult"],
viewers: api_response["viewers"],
thumbnail_url: api_response["thumbnails"]["web"],
last_fetched_at: now,
last_live_at: now,
description: nil
]
],
log: false
)
end
end

View file

@ -1,70 +0,0 @@
defmodule Philomena.Servers.PiczelChannelUpdater do
alias Philomena.Channels.Channel
alias Philomena.Repo
import Ecto.Query
@api_online "https://api.piczel.tv/api/streams"
def child_spec([]) do
%{
id: Philomena.Servers.PiczelChannelUpdater,
start: {Philomena.Servers.PiczelChannelUpdater, :start_link, [[]]}
}
end
def start_link([]) do
{:ok, spawn_link(&run/0)}
end
defp run do
:timer.sleep(:timer.seconds(60))
now = DateTime.utc_now() |> DateTime.truncate(:second)
@api_online
|> Philomena.Http.get()
|> handle_response(now)
run()
end
defp handle_response({:ok, %Tesla.Env{body: body, status: 200}}, now) do
resp =
body
|> Jason.decode!()
|> Map.new(&{&1["slug"], &1})
live_channel_names = Map.keys(resp)
Channel
|> where([c], c.type == "PiczelChannel" and c.short_name not in ^live_channel_names)
|> Repo.update_all([set: [is_live: false, updated_at: now]], log: false)
Channel
|> where([c], c.type == "PiczelChannel" and c.short_name in ^live_channel_names)
|> Repo.all(log: false)
|> Enum.map(&fetch(&1, resp[&1.short_name], now))
end
defp handle_response(_response, _now), do: nil
defp fetch(channel, api_response, now) do
Channel
|> where(id: ^channel.id)
|> Repo.update_all(
[
set: [
title: api_response["title"],
is_live: api_response["live"],
nsfw: api_response["adult"],
viewers: api_response["viewers"],
thumbnail_url: api_response["user"]["avatar"]["avatar"]["url"],
last_fetched_at: now,
last_live_at: now,
description: nil
]
],
log: false
)
end
end

View file

@ -1,79 +0,0 @@
defmodule Philomena.Servers.UserLinkUpdater do
alias Philomena.UserLinks.UserLink
alias Philomena.Repo
import Ecto.Query
@seven_days 7 * 24 * 60 * 60
@three_days 3 * 24 * 60 * 60
@twelve_hours 12 * 60 * 60
@one_hour 60 * 60
@two_minutes 2 * 60
def child_spec([]) do
%{
id: Philomena.Servers.UserLinkUpdater,
start: {Philomena.Servers.UserLinkUpdater, :start_link, [[]]}
}
end
def start_link([]) do
{:ok, spawn_link(&run/0)}
end
defp run do
now = DateTime.utc_now()
UserLink
|> where([ul], ul.aasm_state == "unverified" and ul.next_check_at < ^now)
|> Repo.all(log: false)
|> Enum.map(&automatic_verify/1)
:timer.sleep(:timer.seconds(120))
run()
end
defp automatic_verify(user_link) do
now = DateTime.utc_now() |> DateTime.truncate(:second)
diff = DateTime.diff(now, DateTime.from_naive!(user_link.created_at, "Etc/UTC"), :second)
# Set next check time according to how long link has been pending
next_check_at =
cond do
diff > @seven_days ->
DateTime.add(now, @seven_days)
diff > @three_days ->
DateTime.add(now, @twelve_hours)
diff > @one_hour ->
DateTime.add(now, @one_hour)
true ->
DateTime.add(now, @two_minutes)
end
UserLink
|> where(id: ^user_link.id)
|> Repo.update_all(set: [next_check_at: next_check_at])
user_link
|> Map.get(:uri)
|> Philomena.Http.get()
|> handle_response(user_link)
end
defp handle_response({:ok, %Tesla.Env{body: body, status: 200}}, user_link) do
case :binary.match(body, user_link.verification_code) do
:nomatch ->
nil
_match ->
UserLink
|> where(id: ^user_link.id)
|> Repo.update_all(set: [next_check_at: nil, aasm_state: "link_verified"])
end
end
defp handle_response(_, _user_link), do: nil
end

View file

@ -8,21 +8,33 @@ defmodule Philomena.UserLinks do
alias Philomena.Repo
alias Philomena.UserLinks.UserLink
alias Philomena.UserLinks.AutomaticVerifier
alias Philomena.Badges.Badge
alias Philomena.Badges.Award
alias Philomena.Tags.Tag
@doc """
Returns the list of user_links.
## Examples
iex> list_user_links()
[%UserLink{}, ...]
Check links pending verification to see if the user placed
the appropriate code on the page.
"""
def list_user_links do
Repo.all(UserLink)
def automatic_verify! do
now = DateTime.utc_now() |> DateTime.truncate(:second)
# Automatically retry in an hour if we don't manage to
# successfully verify any given link
recheck_time = DateTime.add(now, 3600, :second)
recheck_query =
from ul in UserLink,
where: ul.aasm_state == "unverified",
where: ul.next_check_at < ^now
recheck_query
|> Repo.all()
|> Enum.map(fn link ->
UserLink.automatic_verify_changeset(link, AutomaticVerifier.check_link(link, recheck_time))
end)
|> Enum.map(&Repo.update!/1)
end
@doc """

View file

@ -0,0 +1,22 @@
defmodule Philomena.UserLinks.AutomaticVerifier do
def check_link(user_link, recheck_time) do
user_link.uri
|> Philomena.Http.get()
|> contains_verification_code?(user_link.verification_code)
|> case do
true ->
%{next_check_at: nil, aasm_state: "link_verified"}
false ->
%{next_check_at: recheck_time}
end
end
defp contains_verification_code?({:ok, %Tesla.Env{body: body, status: 200}}, code) do
String.contains?(body, code)
end
defp contains_verification_code?(_response, _code) do
false
end
end

View file

@ -63,6 +63,10 @@ defmodule Philomena.UserLinks.UserLink do
change(user_link, aasm_state: "rejected")
end
def automatic_verify_changeset(user_link, attrs) do
cast(user_link, attrs, [:next_check_at, :aasm_state])
end
def verify_changeset(user_link, user) do
change(user_link)
|> put_change(:verified_by_user_id, user.id)

View file

@ -28,7 +28,7 @@ defmodule PhilomenaWeb.Profile.CommissionController do
items =
commission.items
|> Enum.sort(&(Decimal.cmp(&1.base_price, &2.base_price) != :gt))
|> Enum.sort(&(Decimal.compare(&1.base_price, &2.base_price) != :gt))
item_descriptions =
items

View file

@ -16,20 +16,7 @@ defmodule PhilomenaWeb.StatsUpdater do
alias Philomena.Repo
import Ecto.Query
def child_spec([]) do
%{
id: PhilomenaWeb.StatsUpdater,
start: {PhilomenaWeb.StatsUpdater, :start_link, [[]]}
}
end
def start_link([]) do
{:ok, spawn_link(&run/0)}
end
defp run do
:timer.sleep(:timer.seconds(300))
def update_stats! do
{gallery_count, gallery_size, distinct_creators, images_in_galleries} = galleries()
{open_reports, report_count, response_time} = moderation()
{open_commissions, commission_items} = commissions()
@ -73,8 +60,6 @@ defmodule PhilomenaWeb.StatsUpdater do
on_conflict: {:replace, [:body, :updated_at]},
conflict_target: :slug
)
run()
end
defp aggregations do

View file

@ -45,6 +45,7 @@ defmodule Philomena.MixProject do
{:jason, "~> 1.1"},
{:plug_cowboy, "~> 2.3"},
{:phoenix_slime, "~> 0.13"},
{:phoenix_pubsub_redis, "~> 3.0"},
{:ecto_network, "~> 1.3"},
{:bcrypt_elixir, "~> 2.0"},
{:pot, "~> 0.11"},

View file

@ -1,65 +1,67 @@
%{
"artificery": {:hex, :artificery, "0.4.3", "0bc4260f988dcb9dda4b23f9fc3c6c8b99a6220a331534fdf5bf2fd0d4333b02", [:mix], [], "hexpm", "12e95333a30e20884e937abdbefa3e7f5e05609c2ba8cf37b33f000b9ffc0504"},
"bamboo": {:hex, :bamboo, "1.5.0", "1926107d58adba6620450f254dfe8a3686637a291851fba125686fa8574842af", [:mix], [{:hackney, ">= 1.13.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "d5f3d04d154e80176fd685e2531e73870d8700679f14d25a567e448abce6298d"},
"bamboo": {:hex, :bamboo, "1.6.0", "adfb583bef028923aae6f22deaea6667290561da1246058556ecaeb0fec5a175", [:mix], [{:hackney, ">= 1.13.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "454e67feacbc9b6e00553ce1d2fba003c861e0035600d59b09d6159985b17f9b"},
"bamboo_smtp": {:hex, :bamboo_smtp, "2.1.0", "4be58f3c51d9f7875dc169ae58a1d2f08e5b718bf3895f70d130548c0598f422", [:mix], [{:bamboo, "~> 1.2", [hex: :bamboo, repo: "hexpm", optional: false]}, {:gen_smtp, "~> 0.15.0", [hex: :gen_smtp, repo: "hexpm", optional: false]}], "hexpm", "0aad00ef93d0e0c83a0e1ca6998fea070c8a720a990fbda13ce834136215ee49"},
"bcrypt_elixir": {:hex, :bcrypt_elixir, "2.2.0", "3df902b81ce7fa8867a2ae30d20a1da6877a2c056bfb116fd0bc8a5f0190cea4", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "762be3fcb779f08207531bc6612cca480a338e4b4357abb49f5ce00240a77d1e"},
"briefly": {:hex, :briefly, "0.3.0", "16e6b76d2070ebc9cbd025fa85cf5dbaf52368c4bd896fb482b5a6b95a540c2f", [:mix], [], "hexpm", "c6ebf8fc3dcd4950dd10c03e953fb4f553a8bcf0ff4c8c40d71542434cd7e046"},
"canada": {:hex, :canada, "1.0.2", "040e4c47609b0a67d5773ac1fbe5e99f840cef173d69b739beda7c98453e0770", [:mix], [], "hexpm", "4269f74153fe89583fe50bd4d5de57bfe01f31258a6b676d296f3681f1483c68"},
"canary": {:hex, :canary, "1.1.1", "4138d5e05db8497c477e4af73902eb9ae06e49dceaa13c2dd9f0b55525ded48b", [:mix], [{:canada, "~> 1.0.1", [hex: :canada, repo: "hexpm", optional: false]}, {:ecto, ">= 1.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f348d9848693c830a65b707bba9e4dfdd6434e8c356a8d4477e4535afb0d653b"},
"castore": {:hex, :castore, "0.1.7", "1ca19eee705cde48c9e809e37fdd0730510752cc397745e550f6065a56a701e9", [:mix], [], "hexpm", "a2ae2c13d40e9c308387f1aceb14786dca019ebc2a11484fb2a9f797ea0aa0d8"},
"castore": {:hex, :castore, "0.1.8", "1b61eaba71bb755b756ac42d4741f4122f8beddb92456a84126d6177ec0af1fc", [:mix], [], "hexpm", "23ab8305baadb057bc689adc0088309f808cb2247dc9a48b87849bb1d242bb6c"},
"certifi": {:hex, :certifi, "2.5.2", "b7cfeae9d2ed395695dd8201c57a2d019c0c43ecaf8b8bcb9320b40d6662f340", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "3b3b5f36493004ac3455966991eaf6e768ce9884693d9968055aeeeb1e575040"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"comeonin": {:hex, :comeonin, "5.3.1", "7fe612b739c78c9c1a75186ef2d322ce4d25032d119823269d0aa1e2f1e20025", [:mix], [], "hexpm", "d6222483060c17f0977fad1b7401ef0c5863c985a64352755f366aee3799c245"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"},
"cowboy": {:hex, :cowboy, "2.8.0", "f3dc62e35797ecd9ac1b50db74611193c29815401e53bac9a5c0577bd7bc667d", [:rebar3], [{:cowlib, "~> 2.9.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "4643e4fba74ac96d4d152c75803de6fad0b3fa5df354c71afdd6cbeeb15fac8a"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.0", "69fdb5cf92df6373e15675eb4018cf629f5d8e35e74841bb637d6596cb797bbc", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "42868c229d9a2900a1501c5d0355bfd46e24c862c322b0b4f5a6f14fe0216753"},
"cowlib": {:hex, :cowlib, "2.9.1", "61a6c7c50cf07fdd24b2f45b89500bb93b6686579b069a89f88cb211e1125c78", [:rebar3], [], "hexpm", "e4175dc240a70d996156160891e1c62238ede1729e45740bdd38064dad476170"},
"db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"},
"decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"},
"db_connection": {:hex, :db_connection, "2.3.0", "d56ef906956a37959bcb385704fc04035f4f43c0f560dd23e00740daf8028c49", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "dcc082b8f723de9a630451b49fdbd7a59b065c4b38176fb147aaf773574d4520"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"},
"ecto": {:hex, :ecto, "3.4.6", "08f7afad3257d6eb8613309af31037e16c36808dfda5a3cd0cb4e9738db030e4", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6f13a9e2a62e75c2dcfc7207bfc65645ab387af8360db4c89fee8b5a4bf3f70b"},
"ecto": {:hex, :ecto, "3.5.3", "64aa70c6a64b8ee6a28ee186083b317b082beac8fed4d55bcc3f23199667a2f3", [: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", "c481b220bb080e94fd1ab528c3b62bdfdd29188c74aef44fc2b204efa8769532"},
"ecto_network": {:hex, :ecto_network, "1.3.0", "1e77fa37c20e0f6a426d3862732f3317b0fa4c18f123d325f81752a491d7304e", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 0.0.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.14.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "053a5e46ef2837e8ea5ea97c82fa0f5494699209eddd764e663c85f11b2865bd"},
"ecto_sql": {:hex, :ecto_sql, "3.4.5", "30161f81b167d561a9a2df4329c10ae05ff36eca7ccc84628f2c8b9fa1e43323", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "31990c6a3579b36a3c0841d34a94c275e727de8b84f58509da5f1b2032c98ac2"},
"ecto_sql": {:hex, :ecto_sql, "3.5.1", "7c03f302caa3c2bbc4f5397281a5d0d8653f246d47c353e3cd46750b16ad310c", [: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", "338150ecb2398f013f98e4a70d5413b70fed4b6383d4f7c400314d315cdf87a9"},
"elastix": {:hex, :elastix, "0.8.0", "09b7ce7f0541bdd26225e29ade6360e3cf0c0e26088367b97b798e2f40e6c038", [:mix], [{:httpoison, "~> 1.4", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, "~> 4.0", [hex: :poison, repo: "hexpm", optional: true]}, {:retry, "~> 0.8", [hex: :retry, repo: "hexpm", optional: false]}], "hexpm", "8e7efc4bf6daf37bc99e2253a7f540c4e40464725a1ed3667a81de6ab5ed58d6"},
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
"elixir_make": {:hex, :elixir_make, "0.6.1", "8faa29a5597faba999aeeb72bbb9c91694ef8068f0131192fb199f98d32994ef", [:mix], [], "hexpm", "35d33270680f8d839a4003c3e9f43afb595310a592405a00afc12de4c7f55a18"},
"elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"exq": {:hex, :exq, "0.14.0", "2ed2efa9abd94d7ed89ab95bf39395dbef1a1e35633954772158b6c57e78b402", [:mix], [{:elixir_uuid, ">= 1.2.0", [hex: :elixir_uuid, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0 or ~> 2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:redix, ">= 0.9.0", [hex: :redix, repo: "hexpm", optional: false]}], "hexpm", "4f3edea5626813c90fda061b4c844b42ce4576ee0d1e7b34257242e9e89300ab"},
"file_system": {:hex, :file_system, "0.2.8", "f632bd287927a1eed2b718f22af727c5aeaccc9a98d8c2bd7bff709e851dc986", [:mix], [], "hexpm", "97a3b6f8d63ef53bd0113070102db2ce05352ecf0d25390eb8d747c2bde98bca"},
"file_system": {:hex, :file_system, "0.2.9", "545b9c9d502e8bfa71a5315fac2a923bd060fd9acb797fe6595f54b0f975fd32", [:mix], [], "hexpm", "3cf87a377fe1d93043adeec4889feacf594957226b4f19d5897096d6f61345d8"},
"gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"},
"gettext": {:hex, :gettext, "0.18.1", "89e8499b051c7671fa60782faf24409b5d2306aa71feb43d79648a8bc63d0522", [:mix], [], "hexpm", "e70750c10a5f88cb8dc026fc28fa101529835026dec4a06dba3b614f2a99c7a9"},
"gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"},
"hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"},
"httpoison": {:hex, :httpoison, "1.7.0", "abba7d086233c2d8574726227b6c2c4f6e53c4deae7fe5f6de531162ce9929a0", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "975cc87c845a103d3d1ea1ccfd68a2700c211a434d8428b10c323dc95dc5b980"},
"idna": {:hex, :idna, "6.0.1", "1d038fb2e7668ce41fbf681d2c45902e52b3cb9e9c77b55334353b222c2ee50c", [:rebar3], [{:unicode_util_compat, "0.5.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a02c8a1c4fd601215bb0b0324c8a6986749f807ce35f25449ec9e69758708122"},
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"},
"jason": {:hex, :jason, "1.2.1", "12b22825e22f468c02eb3e4b9985f3d0cb8dc40b9bd704730efa11abd2708c44", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b659b8571deedf60f79c5a608e15414085fa141344e2716fbd6988a084b5f993"},
"jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "1.4.0", "5066f14944b470286146047d2f73518cf5cca82f8e4815cf35d196b58cf07c47", [:mix], [], "hexpm", "75fa42c4228ea9a23f70f123c74ba7cece6a03b1fd474fe13f6a7a85c6ea4ff6"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mint": {:hex, :mint, "1.1.0", "1fd0189edd9e3ffdbd7fcd8bc3835902b987a63ec6c4fd1aa8c2a56e2165f252", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bfd316c3789340b682d5679a8116bcf2112e332447bdc20c1d62909ee45f48d"},
"mint": {:hex, :mint, "1.2.0", "65e9d75c60c456a5fb1b800febb88f061f56157d103d755b99fcaeaeb3e956f3", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "19cbb3a5be91b7df4a35377ba94b26199481a541add055cf5d1d4299b55125ab"},
"neotoma": {:hex, :neotoma, "1.7.3", "d8bd5404b73273989946e4f4f6d529e5c2088f5fa1ca790b4dbe81f4be408e61", [:rebar], [], "hexpm", "2da322b9b1567ffa0706a7f30f6bbbde70835ae44a1050615f4b4a3d436e0f28"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
"pbkdf2": {:hex, :pbkdf2, "2.0.0", "11c23279fded5c0027ab3996cfae77805521d7ef4babde2bd7ec04a9086cf499", [:rebar3], [], "hexpm", "1e793ce6fdb0576613115714deae9dfc1d1537eaba74f07efb36de139774488d"},
"phoenix": {:hex, :phoenix, "1.5.4", "0fca9ce7e960f9498d6315e41fcd0c80bfa6fbeb5fa3255b830c67fdfb7e703f", [: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", "4e516d131fde87b568abd62e1b14aa07ba7d5edfd230bab4e25cc9dedbb39135"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.2.0", "4ac3300a22240a37ed54dfe6c0be1b5623304385d1a2c210a70f011d9e7af7ac", [: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", "59e7e2a550d7ea082a665c0fc29485f06f55d1a51dd02f513aafdb9d16fc72c4"},
"phoenix": {:hex, :phoenix, "1.5.6", "8298cdb4e0f943242ba8410780a6a69cbbe972fef199b341a36898dd751bdd66", [: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", "0dc4d39af1306b6aa5122729b0a95ca779e42c708c6fe7abbb3d336d5379e956"},
"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.2", "b8a3899a72050f3f48a36430da507dd99caf0ac2d06c77529b1646964f3d563e", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "58061c8dfd25da5df1ea0ca47c972f161beb6c875cd293917045b92ffe1bf617"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.4", "940c0344b1d66a2e46eef02af3a70e0c5bb45a4db0bf47917add271b76cd3914", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "38f9308357dea4cc77f247e216da99fcb0224e05ada1469167520bed4cb8cccd"},
"phoenix_mtm": {:hex, :phoenix_mtm, "1.0.0", "36a2292f84f0712aa4fa029cb6618d9388371d70951b0269bdf372df576aab56", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "ab2126fb6079e391874fb2e089a4e5658ab3e9bc88fa0ab94f14fdc1eb8be957"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
"phoenix_pubsub_redis": {:hex, :phoenix_pubsub_redis, "3.0.0", "75a3f3908210196c499a961ab7cf7202e68947ba33994f9219dc153367ac8662", [:mix], [{:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5.1 or ~> 1.6", [hex: :poolboy, repo: "hexpm", optional: false]}, {:redix, "~> 0.10.0", [hex: :redix, repo: "hexpm", optional: false]}], "hexpm", "57b4ac98239600340ae485976ae5400f39f48ce8741105e1709f4e16d0d60e92"},
"phoenix_slime": {:hex, :phoenix_slime, "0.13.1", "a5d4d8febb87a618b02d690519f7106832c8bd0b4d1937fbba73d6e8666f2891", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:slime, "~> 1.0", [hex: :slime, repo: "hexpm", optional: false]}], "hexpm", "ff818744be2c903fb0174ba22b230c1c335238578fccf274b1d95d08f4844377"},
"plug": {:hex, :plug, "1.10.4", "41eba7d1a2d671faaf531fa867645bd5a3dce0957d8e2a3f398ccff7d2ef017f", [: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", "ad1e233fe73d2eec56616568d260777b67f53148a999dc2d048f4eb9778fe4a0"},
"plug_cowboy": {:hex, :plug_cowboy, "2.3.0", "149a50e05cb73c12aad6506a371cd75750c0b19a32f81866e1a323dda9e0e99d", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bc595a1870cef13f9c1e03df56d96804db7f702175e4ccacdb8fc75c02a7b97e"},
"plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm", "6b8b608f895b6ffcfad49c37c7883e8df98ae19c6a28113b02aa1e9c5b22d6b5"},
"postgrex": {:hex, :postgrex, "0.15.5", "aec40306a622d459b01bff890fa42f1430dac61593b122754144ad9033a2152f", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "ed90c81e1525f65a2ba2279dbcebf030d6d13328daa2f8088b9661eb9143af7f"},
"plug_cowboy": {:hex, :plug_cowboy, "2.4.0", "e936ef151751f386804c51f87f7300f5aaae6893cdad726559c3930c6c032948", [: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", "e25ddcfc06b1b76e55af79d078b03cbc86bbcb99ce4e5e0a5e4a8114ee039be6"},
"plug_crypto": {:hex, :plug_crypto, "1.2.0", "1cb20793aa63a6c619dd18bb33d7a3aa94818e5fd39ad357051a67f26dfa2df6", [:mix], [], "hexpm", "a48b538ae8bf381ffac344520755f3007cc10bd8e90b240af98ea29b69683fc2"},
"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"},
"pot": {:hex, :pot, "0.11.0", "61bad869a94534739dd4614a25a619bc5c47b9970e9a0ea5bef4628036fc7a16", [:rebar3], [], "hexpm", "57ee6ee6bdeb639661ffafb9acefe3c8f966e45394de6a766813bb9e1be4e54b"},
"qrcode": {:hex, :qrcode, "0.1.5", "551271830515c150f34568345b060c625deb0e6691db2a01b0a6de3aafc93886", [:mix], [], "hexpm", "a266b7fb7be0d3b713912055dde3575927eca920e5d604ded45cd534f6b7a447"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},
"ranch_connection_drainer": {:hex, :ranch_connection_drainer, "0.1.4", "d6af517b42944a60ca65f0e4a0e76ad4fa81b241f9bad4c26a22d3a7a7767f85", [:mix], [{:ranch, "~> 1.6", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "f3621b1a486f33e24fa25f7e249a65d05eb75d8fe32fc5d009c39228343c5545"},
"redix": {:hex, :redix, "0.11.2", "f6c696928bc0c81f9a04ea53299c353f7552ae3f4c5d1e884f3a6257098b9d66", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ae74e25026c4a0d17cad3c12814b313b28ac4277f3725220ae1df2f96320c38d"},
"redix": {:hex, :redix, "0.10.7", "758916c71fc09e223e18d6715344581d7768c430983dabf77e792ba2087729e6", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "73fdf73c0472278dc040dcd1a5da91d4febe218201ae8ac0454b37e136886c34"},
"remote_ip": {:hex, :remote_ip, "0.2.1", "cd27cd8ea54ecaaf3532776ff4c5e353b3804e710302e88c01eadeaaf42e7e24", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:inet_cidr, "~> 1.0", [hex: :inet_cidr, repo: "hexpm", optional: false]}, {:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2e7ab1a461cc3cd5719f37e116a08f45c8b8493923063631b164315d6b7ee8e0"},
"retry": {:hex, :retry, "0.14.0", "751c0f6db0b5127acf346ea6f6c363ec4588320db785c62aa51776b4d280bf07", [:mix], [], "hexpm", "5c158bccf5e4de2a13d044b9930ceb7e7499c29e3fccd7c96f131a6b83a1cff3"},
"retry": {:hex, :retry, "0.14.1", "722d1b0cf87096b71213f5801d99fface7ca76adc83fc9dbf3e1daee952aef10", [:mix], [], "hexpm", "b3a609f286f6fe4f6b2c15f32cd4a8a60427d78d05d7b68c2dd9110981111ae0"},
"scrivener": {:hex, :scrivener, "2.7.0", "fa94cdea21fad0649921d8066b1833d18d296217bfdf4a5389a2f45ee857b773", [:mix], [], "hexpm", "30da36a427f2519cf75993271fb7c5aad1759682a70f90d880a85c3d743d2c57"},
"scrivener_ecto": {:hex, :scrivener_ecto, "2.5.0", "0fb56e243ce228b8f0f2b4ba36a370d8c21570a264a6f9fac3f322e2e114519f", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:scrivener, "~> 2.4", [hex: :scrivener, repo: "hexpm", optional: false]}], "hexpm", "e3d2a57db3d5508b50dcb8a75d2a88b8e6360c050970a85917fc5e9c864ae7e9"},
"scrivener_ecto": {:hex, :scrivener_ecto, "2.6.0", "81a83b6f29fdc6f85735fa0b77f23f1ddb6d27350c31ff143f67934d5a23969d", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:scrivener, "~> 2.4", [hex: :scrivener, repo: "hexpm", optional: false]}], "hexpm", "717f8f373bcc1b8c12eba30737dc34af63e7ea8650ff736ced4c8e3da37cb2c9"},
"secure_compare": {:hex, :secure_compare, "0.1.0", "01b3c93c8edb696e8a5b38397ed48e10958c8a5ec740606656445bcbec0aadb8", [:mix], [], "hexpm", "6391a49eb4a6182f0d7425842fc774bbed715e78b2bfb0c83b99c94e02c78b5c"},
"slime": {:hex, :slime, "1.2.1", "71e036056051f0a6fae136af34eaa1322e8e11cdd2da3a56196fd31bca34dd49", [:mix], [{:neotoma, "~> 1.7", [hex: :neotoma, repo: "hexpm", optional: false]}], "hexpm", "298568e64291fed4eb690be094f6c46400daa03b594bab34fcaa0167e139c263"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},