oauth test

This commit is contained in:
CJ_Clippy 2025-01-16 12:23:58 -08:00
parent 1469545429
commit c3f5d612c3
30 changed files with 543 additions and 139 deletions

View File

@ -1,16 +1,14 @@
devbox for shareable development environment tooling
git monorepo for housing separate node packages within a single repository
TypeScript
git monorepo for housing separate packages within a single repository (see ./services and ./packages)
pnpm for package management and workspaces (separate node packages.)
Kubernetes for Development using Tiltfile
Phoenix framework
Kubernetes for Production, deployed using FluxCD
docker-compose for containerized development
Kubernetes deployed to Hetzner using https://github.com/kube-hetzner/terraform-hcloud-kube-hetzner
Kamal for deployments
ggshield for preventing git commits containing secrets

View File

@ -8,16 +8,19 @@ See ./ARCHITECTURE.md for an overview of the infrastructure components.
## Getting Started
I'm working towards a better development experience with devbox and Tilt. This process is in a state of flux and is likely to be broken.
The main gist is as follows.
The main gist is as follows
1. Install [devbox](https://www.jetify.com/devbox/docs/installing_devbox/)
1. install [docker](https://docs.docker.com/engine/install) `wget -O- get.docker.com | bash`
1. Install [devbox](https://www.jetify.com/devbox/docs/installing_devbox/) `curl -fsSL https://get.jetify.com/devbox | bash`
2. Install development environment & packages using devbox.
devbox install
3.
3. Run `docker compose up --watch`
4. Visit http://localhost:4000
If all went well, editing source code will automatically affect the website running in your browser.
## backup/restore dev database
@ -38,8 +41,7 @@ Use devbox helper script
Keeping track of metrics we want to scrape using Prometheus
### Uppy
https://uppy.fp.sbtp.xyz/metrics

View File

@ -2,150 +2,150 @@
"lockfile_version": "1",
"packages": {
"ffmpeg@latest": {
"last_modified": "2024-07-24T00:53:51Z",
"resolved": "github:NixOS/nixpkgs/4f02464258baaf54992debfd010a7a3662a25536#ffmpeg",
"last_modified": "2025-01-07T09:15:50Z",
"resolved": "github:NixOS/nixpkgs/8c9fd3e564728e90829ee7dbac6edc972971cd0f#ffmpeg",
"source": "devbox-search",
"version": "6.1.1",
"version": "7.1",
"systems": {
"aarch64-darwin": {
"outputs": [
{
"name": "bin",
"path": "/nix/store/7jl394717pnlj5jy8n46jq65sw1gwb20-ffmpeg-6.1.1-bin",
"path": "/nix/store/m48ypyjnl04mqigi6fbxa7k2c5bsvazz-ffmpeg-7.1-bin",
"default": true
},
{
"name": "man",
"path": "/nix/store/ma1ssbkbwrasdgsyp0y3x6jbc72pp9s7-ffmpeg-6.1.1-man",
"path": "/nix/store/10ncvfz8srnzckq16bn14wffcx8j04ki-ffmpeg-7.1-man",
"default": true
},
{
"name": "out",
"path": "/nix/store/smq7vi0562incbgwf4cbx10i0y46jsbc-ffmpeg-6.1.1"
},
{
"name": "data",
"path": "/nix/store/289ikv8ld8whmixs3r4qd4r878mkjmm9-ffmpeg-6.1.1-data"
"path": "/nix/store/rqbsc9zyzi988hwcd423qdh1vh40zlzc-ffmpeg-7.1-data"
},
{
"name": "dev",
"path": "/nix/store/r8y6va82y6libjw065gkn5gr51715gac-ffmpeg-6.1.1-dev"
"path": "/nix/store/6ml3pn92nbmnc40s5jfpr84y65ysizk3-ffmpeg-7.1-dev"
},
{
"name": "doc",
"path": "/nix/store/yasff9ggma6myg47sm805idfxnz0zkac-ffmpeg-6.1.1-doc"
"path": "/nix/store/ni6gri7m1pavfjxx0yfj1msvb0cfasgg-ffmpeg-7.1-doc"
},
{
"name": "lib",
"path": "/nix/store/pmv9jg541b2valk47vh7q40m1p8xr7ik-ffmpeg-6.1.1-lib"
"path": "/nix/store/2v2rr9dmq4grzwmg4zcsxrmbdcshks7m-ffmpeg-7.1-lib"
},
{
"name": "out",
"path": "/nix/store/nvccyp4dra8f92ywd00lk3ra121gj162-ffmpeg-7.1"
}
],
"store_path": "/nix/store/7jl394717pnlj5jy8n46jq65sw1gwb20-ffmpeg-6.1.1-bin"
"store_path": "/nix/store/m48ypyjnl04mqigi6fbxa7k2c5bsvazz-ffmpeg-7.1-bin"
},
"aarch64-linux": {
"outputs": [
{
"name": "bin",
"path": "/nix/store/6ydyry316fcc59iy80zpnxnsrh9f18ki-ffmpeg-6.1.1-bin",
"path": "/nix/store/lj99z3ldzka2slgm94w2yl8cjkphn4m3-ffmpeg-7.1-bin",
"default": true
},
{
"name": "man",
"path": "/nix/store/k1frp52lx3ycwbdgliwcrmb81zm4n10n-ffmpeg-6.1.1-man",
"path": "/nix/store/gisda8d2pifrrjw0yirrs0x2cyn6b96i-ffmpeg-7.1-man",
"default": true
},
{
"name": "dev",
"path": "/nix/store/rdh4mv7fnmj79a4dp9rfqnd711y9inpv-ffmpeg-6.1.1-dev"
},
{
"name": "doc",
"path": "/nix/store/vam8a1591x7bkqjljvwsral2v72xwa77-ffmpeg-6.1.1-doc"
},
{
"name": "lib",
"path": "/nix/store/k2mdb9lh6qjb63pizcc0lv7kzakgvcm1-ffmpeg-6.1.1-lib"
},
{
"name": "out",
"path": "/nix/store/6z17gry0dn1yxr3r36fk87sxnddcjg66-ffmpeg-6.1.1"
"path": "/nix/store/pc332zx12j2fqf5m9mdhhs1rwksbk2fk-ffmpeg-7.1"
},
{
"name": "data",
"path": "/nix/store/qxyrrzdl4svxs3dfszsmi2mky4vrzvfa-ffmpeg-6.1.1-data"
"path": "/nix/store/4yhsn6lrfn91dk1kq9wyyd71p4hcfans-ffmpeg-7.1-data"
},
{
"name": "dev",
"path": "/nix/store/71103mmkxhzzmbj9mpzsrzbp988z3p98-ffmpeg-7.1-dev"
},
{
"name": "doc",
"path": "/nix/store/k9cc4d60frcn27zapkzhag5h9r0ig5xa-ffmpeg-7.1-doc"
},
{
"name": "lib",
"path": "/nix/store/dgcmpc8az51a4d2bxgrmfz8zlmvqxwa5-ffmpeg-7.1-lib"
}
],
"store_path": "/nix/store/6ydyry316fcc59iy80zpnxnsrh9f18ki-ffmpeg-6.1.1-bin"
"store_path": "/nix/store/lj99z3ldzka2slgm94w2yl8cjkphn4m3-ffmpeg-7.1-bin"
},
"x86_64-darwin": {
"outputs": [
{
"name": "bin",
"path": "/nix/store/84yjd9p94kknxpdn974ksb7y28l6paq4-ffmpeg-6.1.1-bin",
"path": "/nix/store/z44kr817zx99vi2cc204i06cnmz83f1n-ffmpeg-7.1-bin",
"default": true
},
{
"name": "man",
"path": "/nix/store/r1g3627b14nqpz4aqfp87ba0fh49ar5k-ffmpeg-6.1.1-man",
"path": "/nix/store/slrha22nqrx2xw009hd37svv2nvpp26i-ffmpeg-7.1-man",
"default": true
},
{
"name": "data",
"path": "/nix/store/dv5lc67c3xykza11q5pwk4vivnsdswmw-ffmpeg-6.1.1-data"
"path": "/nix/store/n3xm2rr1k1ari7ysbp9jhg65pih28x6x-ffmpeg-7.1-data"
},
{
"name": "dev",
"path": "/nix/store/f0qcama09w9kri8hqvn0lk89zck4978v-ffmpeg-6.1.1-dev"
"path": "/nix/store/59gcv4rfg38rqnazv1iq9jssjak2l3ih-ffmpeg-7.1-dev"
},
{
"name": "doc",
"path": "/nix/store/7sg26fama7a6gpdm0kkphblzc2x03dfx-ffmpeg-6.1.1-doc"
"path": "/nix/store/2cqa3lc75ciqzgmxjm36fd733f3gjgil-ffmpeg-7.1-doc"
},
{
"name": "lib",
"path": "/nix/store/rhq35qgr8yvhygpj24wm14anidf9gmmc-ffmpeg-6.1.1-lib"
"path": "/nix/store/ir47x8skj54wilcyz2x59am4y085lf6l-ffmpeg-7.1-lib"
},
{
"name": "out",
"path": "/nix/store/31q5qklv5jmv91sjs4ljmq45smi7ngxy-ffmpeg-6.1.1"
"path": "/nix/store/gqw958wdgrbfsxczqf56vnq1iffg5qv1-ffmpeg-7.1"
}
],
"store_path": "/nix/store/84yjd9p94kknxpdn974ksb7y28l6paq4-ffmpeg-6.1.1-bin"
"store_path": "/nix/store/z44kr817zx99vi2cc204i06cnmz83f1n-ffmpeg-7.1-bin"
},
"x86_64-linux": {
"outputs": [
{
"name": "bin",
"path": "/nix/store/wnmy246m582splkkqwpgza390sa4m1k1-ffmpeg-6.1.1-bin",
"path": "/nix/store/d1lv3x7iq129vb19ba9ph6k0yhy4fv34-ffmpeg-7.1-bin",
"default": true
},
{
"name": "man",
"path": "/nix/store/hqq9mmrwrbazfdcsmd2dd3jgpvpsyj5p-ffmpeg-6.1.1-man",
"path": "/nix/store/qqgvvfw2gqp47zl5v9jhdsl8mb77l909-ffmpeg-7.1-man",
"default": true
},
{
"name": "doc",
"path": "/nix/store/gmfj9af6za9i2830cgbj1qazz2nir2vs-ffmpeg-7.1-doc"
},
{
"name": "lib",
"path": "/nix/store/5jynrssm1bvrj3kskwgyyhb2069f8dwv-ffmpeg-6.1.1-lib"
"path": "/nix/store/x8j2nr5qmikfaggl34wpm1dlldb7ik06-ffmpeg-7.1-lib"
},
{
"name": "out",
"path": "/nix/store/xdb4w2ccvig6020ish7qpl88i8fqg2ai-ffmpeg-6.1.1"
"path": "/nix/store/cx89mypnxgk0q4dibacg7dsrb4w66mv9-ffmpeg-7.1"
},
{
"name": "data",
"path": "/nix/store/sw8wxzscsnxnvrwqzq4fqxvggcd1xic7-ffmpeg-6.1.1-data"
"path": "/nix/store/5y8zk8fqpaammsnz2svgpdsayn4zlsn2-ffmpeg-7.1-data"
},
{
"name": "dev",
"path": "/nix/store/p6jd7041xggbkwyfzrgsm8ccj370w1hz-ffmpeg-6.1.1-dev"
},
{
"name": "doc",
"path": "/nix/store/1dfla14f5g5xwmw3w5cjfnwdfr64qw7z-ffmpeg-6.1.1-doc"
"path": "/nix/store/qdz8aidi7rksr4g5cpxgz9iivrlsa247-ffmpeg-7.1-dev"
}
],
"store_path": "/nix/store/wnmy246m582splkkqwpgza390sa4m1k1-ffmpeg-6.1.1-bin"
"store_path": "/nix/store/d1lv3x7iq129vb19ba9ph6k0yhy4fv34-ffmpeg-7.1-bin"
}
}
},
@ -246,124 +246,124 @@
}
},
"nodejs@20": {
"last_modified": "2024-07-07T07:43:47Z",
"last_modified": "2024-12-23T21:10:33Z",
"plugin_version": "0.0.2",
"resolved": "github:NixOS/nixpkgs/b60793b86201040d9dee019a05089a9150d08b5b#nodejs_20",
"resolved": "github:NixOS/nixpkgs/de1864217bfa9b5845f465e771e0ecb48b30e02d#nodejs_20",
"source": "devbox-search",
"version": "20.14.0",
"version": "20.18.1",
"systems": {
"aarch64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/sqnbldm1fjw88v23yq4v6531y4m7v2fh-nodejs-20.14.0",
"path": "/nix/store/q49zbi0pzjhg4zn085h9hyz9m1k3hvpb-nodejs-20.18.1",
"default": true
},
{
"name": "libv8",
"path": "/nix/store/1i0rb2axkrxvsq5pz8s2q07ard2p36a1-nodejs-20.14.0-libv8"
"path": "/nix/store/l08rljd2yr7i1q4x778qazcys2l4ja23-nodejs-20.18.1-libv8"
}
],
"store_path": "/nix/store/sqnbldm1fjw88v23yq4v6531y4m7v2fh-nodejs-20.14.0"
"store_path": "/nix/store/q49zbi0pzjhg4zn085h9hyz9m1k3hvpb-nodejs-20.18.1"
},
"aarch64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/r1nwmlbsn67f5rhayr7jjjdmiflxpk92-nodejs-20.14.0",
"path": "/nix/store/4m1ql1hsd6kqmzr8a657qhipjgssrr0c-nodejs-20.18.1",
"default": true
},
{
"name": "libv8",
"path": "/nix/store/5ii3xkbd3iv0xvqqvjg3agsm0dinidgm-nodejs-20.14.0-libv8"
"path": "/nix/store/r8s1xalb4rpy1r44i413j84i4ny6mnsc-nodejs-20.18.1-libv8"
}
],
"store_path": "/nix/store/r1nwmlbsn67f5rhayr7jjjdmiflxpk92-nodejs-20.14.0"
"store_path": "/nix/store/4m1ql1hsd6kqmzr8a657qhipjgssrr0c-nodejs-20.18.1"
},
"x86_64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/wzgnws4r1c98vzj5q6gq4drz2jfq7d5q-nodejs-20.14.0",
"path": "/nix/store/7ky0mn6k33731jwzhsxq6a6dsbjqamqs-nodejs-20.18.1",
"default": true
},
{
"name": "libv8",
"path": "/nix/store/gc2gnkc8hvkh51ab3a29fvgzy2qsqb2s-nodejs-20.14.0-libv8"
"path": "/nix/store/jw62k3wxl38r8fcbvxaxrm696ivv3imr-nodejs-20.18.1-libv8"
}
],
"store_path": "/nix/store/wzgnws4r1c98vzj5q6gq4drz2jfq7d5q-nodejs-20.14.0"
"store_path": "/nix/store/7ky0mn6k33731jwzhsxq6a6dsbjqamqs-nodejs-20.18.1"
},
"x86_64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/ilkfhnqz4xczrliqjva8770x2svbfznd-nodejs-20.14.0",
"path": "/nix/store/j7dx1n6m5axf9r2bvly580x2ixx546wq-nodejs-20.18.1",
"default": true
},
{
"name": "libv8",
"path": "/nix/store/2qaf68dzimr8as4bgli0xmsn11c0ah2j-nodejs-20.14.0-libv8"
"path": "/nix/store/qljmc2skrldj0g94rib6nl4jq84193fa-nodejs-20.18.1-libv8"
}
],
"store_path": "/nix/store/ilkfhnqz4xczrliqjva8770x2svbfznd-nodejs-20.14.0"
"store_path": "/nix/store/j7dx1n6m5axf9r2bvly580x2ixx546wq-nodejs-20.18.1"
}
}
},
"python310@latest": {
"last_modified": "2024-07-07T07:43:47Z",
"last_modified": "2024-12-23T21:10:33Z",
"plugin_version": "0.0.4",
"resolved": "github:NixOS/nixpkgs/b60793b86201040d9dee019a05089a9150d08b5b#python310",
"resolved": "github:NixOS/nixpkgs/de1864217bfa9b5845f465e771e0ecb48b30e02d#python310",
"source": "devbox-search",
"version": "3.10.14",
"version": "3.10.16",
"systems": {
"aarch64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/n0gcjj86qjx7w59bwpzqvzdwrjdc7bwy-python3-3.10.14",
"path": "/nix/store/382cajdyw7qsgrzjf8y79hssg8ggv18x-python3-3.10.16",
"default": true
}
],
"store_path": "/nix/store/n0gcjj86qjx7w59bwpzqvzdwrjdc7bwy-python3-3.10.14"
"store_path": "/nix/store/382cajdyw7qsgrzjf8y79hssg8ggv18x-python3-3.10.16"
},
"aarch64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/pzpn4j6hh8ayy15cb36s7i8v0mkavy0z-python3-3.10.14",
"path": "/nix/store/bvvky8yghyl23vwdhf6dmq6w1a4nm1mg-python3-3.10.16",
"default": true
},
{
"name": "debug",
"path": "/nix/store/h873y0nbzqlmsda6m2vfdcjw1v6c660f-python3-3.10.14-debug"
"path": "/nix/store/msw7k25qw8wfqjrdv6j2sydqxddmaw32-python3-3.10.16-debug"
}
],
"store_path": "/nix/store/pzpn4j6hh8ayy15cb36s7i8v0mkavy0z-python3-3.10.14"
"store_path": "/nix/store/bvvky8yghyl23vwdhf6dmq6w1a4nm1mg-python3-3.10.16"
},
"x86_64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/3ia1741fyzlcjgp3kg01hlk3z1jlp9x0-python3-3.10.14",
"path": "/nix/store/2dnz9rwscr6d1pma8h5q7ckfavsrvhb1-python3-3.10.16",
"default": true
}
],
"store_path": "/nix/store/3ia1741fyzlcjgp3kg01hlk3z1jlp9x0-python3-3.10.14"
"store_path": "/nix/store/2dnz9rwscr6d1pma8h5q7ckfavsrvhb1-python3-3.10.16"
},
"x86_64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/handws5bj8l411asgs68s3bj8f05qnn5-python3-3.10.14",
"path": "/nix/store/rv4ykblb2w9qc7w7a10dbw4r1am7zm9n-python3-3.10.16",
"default": true
},
{
"name": "debug",
"path": "/nix/store/sl3yyz93mar0jk6cnw0lqv4xrvsbas0a-python3-3.10.14-debug"
"path": "/nix/store/l0fx7jgxq5pn27n74haq9c5bhwvbkpab-python3-3.10.16-debug"
}
],
"store_path": "/nix/store/handws5bj8l411asgs68s3bj8f05qnn5-python3-3.10.14"
"store_path": "/nix/store/rv4ykblb2w9qc7w7a10dbw4r1am7zm9n-python3-3.10.16"
}
}
},
@ -518,66 +518,66 @@
}
},
"yt-dlp@latest": {
"last_modified": "2024-07-18T22:08:26Z",
"resolved": "github:NixOS/nixpkgs/cfa5366588c940ab6ee3bee399b337175545c664#yt-dlp",
"last_modified": "2025-01-03T14:51:55Z",
"resolved": "github:NixOS/nixpkgs/a27871180d30ebee8aa6b11bf7fef8a52f024733#yt-dlp",
"source": "devbox-search",
"version": "2024.7.16",
"version": "2024.12.23",
"systems": {
"aarch64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/sb1129rd65qynmf5pqshr2885g54hjdz-python3.12-yt-dlp-2024.7.16",
"path": "/nix/store/8fmy039278i7q31zyyrfmr4z5k35xvp6-yt-dlp-2024.12.23",
"default": true
},
{
"name": "dist",
"path": "/nix/store/7c75jyvxvqhnhlb8iv99m0m2gzaz1562-python3.12-yt-dlp-2024.7.16-dist"
"path": "/nix/store/v9mplambvs7hlcpcpnvmf7c30pk5cx8d-yt-dlp-2024.12.23-dist"
}
],
"store_path": "/nix/store/sb1129rd65qynmf5pqshr2885g54hjdz-python3.12-yt-dlp-2024.7.16"
"store_path": "/nix/store/8fmy039278i7q31zyyrfmr4z5k35xvp6-yt-dlp-2024.12.23"
},
"aarch64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/rzr6pr2axf653258rnlrldx540wag1h0-python3.12-yt-dlp-2024.7.16",
"path": "/nix/store/wzna2q40a81qj4icma4q20q9fjg9md76-yt-dlp-2024.12.23",
"default": true
},
{
"name": "dist",
"path": "/nix/store/js7w9zzcydsf020njvhy3dbvarv4c9qj-python3.12-yt-dlp-2024.7.16-dist"
"path": "/nix/store/z0b0nv6a2wl0565f5ffrzhg2zcqflvrl-yt-dlp-2024.12.23-dist"
}
],
"store_path": "/nix/store/rzr6pr2axf653258rnlrldx540wag1h0-python3.12-yt-dlp-2024.7.16"
"store_path": "/nix/store/wzna2q40a81qj4icma4q20q9fjg9md76-yt-dlp-2024.12.23"
},
"x86_64-darwin": {
"outputs": [
{
"name": "out",
"path": "/nix/store/q3sqpq348nj1zhlwsfmbwcqnmkfglmlj-python3.12-yt-dlp-2024.7.16",
"path": "/nix/store/mpbp9jar45hk22ddldm0bbk60vz5w643-yt-dlp-2024.12.23",
"default": true
},
{
"name": "dist",
"path": "/nix/store/f6i4bq4fbcd1s7k660fkqr15g0lzrfvx-python3.12-yt-dlp-2024.7.16-dist"
"path": "/nix/store/gq4l9yfs7fjb05qkl97hmsq69s3k4shr-yt-dlp-2024.12.23-dist"
}
],
"store_path": "/nix/store/q3sqpq348nj1zhlwsfmbwcqnmkfglmlj-python3.12-yt-dlp-2024.7.16"
"store_path": "/nix/store/mpbp9jar45hk22ddldm0bbk60vz5w643-yt-dlp-2024.12.23"
},
"x86_64-linux": {
"outputs": [
{
"name": "out",
"path": "/nix/store/m47znwi2bc09g66j2kn6k7fvfx9cvr38-python3.12-yt-dlp-2024.7.16",
"path": "/nix/store/wqcs5crm36p603fkh9j2k868zzb8q79c-yt-dlp-2024.12.23",
"default": true
},
{
"name": "dist",
"path": "/nix/store/7laiz6ilsx4xzk6xni7yl8g3g04wyl55-python3.12-yt-dlp-2024.7.16-dist"
"path": "/nix/store/j452c5bii2slx1biix7lfc5k0aqg2rvs-yt-dlp-2024.12.23-dist"
}
],
"store_path": "/nix/store/m47znwi2bc09g66j2kn6k7fvfx9cvr38-python3.12-yt-dlp-2024.7.16"
"store_path": "/nix/store/wqcs5crm36p603fkh9j2k868zzb8q79c-yt-dlp-2024.12.23"
}
}
}

View File

@ -76,17 +76,36 @@ services:
- db
# volumes:
# - ./services/bright/lib:/app/lib
# volumes:
# - /home/cj/Documents/ueberauth_patreon:/app/contrib/ueberauth_patreon
develop:
watch:
- action: sync
path: ./services/bright/
- path: ./services/bright/
target: /app/
- action: sync+restart
path: ./services/bright/application.ex
action: sync
- path: ./services/bright/application.ex
target: /app/lib/bright/application.ex
- action: sync+restart
path: ./services/bright/mix.exs
action: sync+restart
- path: ./services/bright/config/config.exs
target: /app/lib/bright/config/config.exs
action: sync+restart
- path: ./services/bright/config/runtime.exs
target: /app/lib/bright/config/runtime.exs
action: sync+restart
# @todo we need "docker@27.5.0" in devbox.json because we need docker compose >= `v2.32.0` for `sync+exec` feature.
# For now, we don't have `sync+exec` support which means docker image rebuilds are required when updating mix.exs
# - path: ./services/bright/mix.exs
# action: sync+exec
# target: /app/mix.exs
# exec:
# command: mix deps.get
- path: ./services/bright/mix.exs
target: /app/mix.exs
action: sync+restart
# - path: /home/cj/Documents/ueberauth_patreon
# action: sync
# target: /app/contrib/ueberauth_patreon
db:
image: postgres:15

View File

@ -41,12 +41,16 @@ RUN echo MIX_ENV=$MIX_ENV
COPY ./services/bright/mix.exs ./services/bright/mix.lock ./
RUN mix deps.get --only $MIX_ENV
RUN mkdir config
RUN mkdir contrib
# copy compile-time config files before we compile dependencies
# to ensure any relevant config change will trigger the dependencies
# to be re-compiled.
COPY ./services/bright/config/config.exs ./services/bright/config/${MIX_ENV}.exs config/
RUN ls -la config/
# COPY ./packages/ueberauth_patreon /app/contrib/ueberauth_patreon
# COPY ./packages/ueberauth_github /app/contrib/ueberauth_github
RUN ls -la /app/contrib/
RUN mix deps.compile
COPY ./services/bright/priv priv
@ -55,6 +59,7 @@ COPY ./services/bright/lib lib
COPY ./services/bright/assets assets
# compile assets
RUN mix assets.deploy
@ -70,8 +75,8 @@ RUN mix release
## dev target
FROM builder AS dev
# RUN mix ecto.setup
RUN echo "balls. that is all."
RUN ls -la ./contrib/
CMD [ "mix", "phx.server" ]
@ -94,7 +99,9 @@ WORKDIR "/app"
RUN chown nobody /app
# set runner ENV
ENV MIX_ENV="prod"
ARG MIX_ENV
ENV MIX_ENV $MIX_ENV
RUN echo MIX_ENV=$MIX_ENV
# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/bright ./

View File

@ -32,6 +32,16 @@ config :bright, Oban,
{Oban.Plugins.Lifeline, rescue_after: :timer.minutes(30)}
]
# @see https://github.com/ueberauth/ueberauth
config :ueberauth, Ueberauth,
providers: [
github: {Ueberauth.Strategy.Github, [default_scope: "user:email"]},
patreon: {Ueberauth.Strategy.Patreon, []}
]
config :ueberauth, Ueberauth.Strategy.Github.OAuth,
client_id: System.get_env("GITHUB_CLIENT_ID"),
client_secret: System.get_env("GITHUB_CLIENT_SECRET")
# Configures the mailer
#

View File

@ -65,6 +65,18 @@ if config_env() == :prod do
],
secret_key_base: secret_key_base
# config :ueberauth, Ueberauth.Strategy.Patreon.OAuth,
# client_id: System.get_env("PATREON_CLIENT_ID"),
# client_secret: System.get_env("PATREON_CLIENT_SECRET")
# config :ueberauth, Ueberauth.Strategy.Github.OAuth,
# client_id: System.get_env("GITHUB_CLIENT_ID"),
# client_secret: System.get_env("GITHUB_CLIENT_SECRET")
# config :ueberauth, Ueberauth.Strategy.Github.OAuth,
# client_id: {:system, "GITHUB_CLIENT_ID"},
# client_secret: {:system, "GITHUB_CLIENT_SECRET"}
# ## SSL Support
#
# To get SSL working, you will need to add the `https` key

View File

@ -10,6 +10,8 @@ defmodule Bright.Accounts do
## Database getters
@doc """
Gets a user by email.
@ -157,6 +159,8 @@ defmodule Bright.Accounts do
|> Ecto.Multi.delete_all(:tokens, UserToken.by_user_and_contexts_query(user, [context]))
end
@doc ~S"""
Delivers the update email instructions to the given user.

View File

@ -8,6 +8,7 @@ defmodule Bright.Accounts.User do
field :hashed_password, :string, redact: true
field :current_password, :string, virtual: true, redact: true
field :confirmed_at, :utc_datetime
field :provider, :string
timestamps(type: :utc_datetime)
end
@ -44,7 +45,7 @@ defmodule Bright.Accounts.User do
defp validate_email(changeset, opts) do
changeset
|> validate_required([:email])
|> validate_required([:email, :provider])
|> validate_format(:email, ~r/^[^\s]+@[^\s]+$/, message: "must have the @ sign and no spaces")
|> validate_length(:email, max: 160)
|> maybe_validate_unique_email(opts)

View File

@ -1,12 +1,19 @@
defmodule Bright.User do
use Ecto.Schema
import Ecto.Changeset
alias Bright.Repo
schema "users" do
field :name, :string
field :email, :string
field :bio, :string
field :number_of_pets, :integer
field :is_admin, :boolean
field :auth_token, :string
field :auth_token_expires_at, :utc_datetime
field :signed_in_at, :utc_datetime
field :joined_at, :utc_datetime
field :patreon_handle, :string
field :github_handle, :string
timestamps(type: :utc_datetime)
end
@ -14,7 +21,29 @@ defmodule Bright.User do
@doc false
def changeset(user, attrs) do
user
|> cast(attrs, [:name, :email, :bio, :number_of_pets])
|> cast(attrs, [:name, :email, :bio, :number_of_pets, :is_admin])
|> validate_required([:name, :email, :bio, :number_of_pets])
end
def get_by_ueberauth(%{provider: :github, info: %{nickname: handle}}) do
Repo.get_by(__MODULE__, github_handle: handle)
end
def get_by_ueberauth(%{provider: :patreon, info: %{nickname: handle}}) do
Repo.get_by(__MODULE__, patreon_handle: handle)
end
def get_by_ueberauth(_), do: nil
def sign_in_changes(user) do
change(user, %{
auth_token: nil,
auth_token_expires_at: nil,
signed_in_at: now_in_seconds(),
joined_at: user.joined_at || now_in_seconds()
})
end
defp now_in_seconds, do: Timex.now() |> DateTime.truncate(:second)
end

View File

@ -0,0 +1,70 @@
defmodule Bright.UserFromAuth do
@moduledoc """
Retrieve the user information from an auth request
"""
require Logger
require Jason
alias Ueberauth.Auth
def find_or_create(%Auth{provider: :identity} = auth) do
case validate_pass(auth.credentials) do
:ok ->
{:ok, basic_info(auth)}
{:error, reason} ->
{:error, reason}
end
end
def find_or_create(%Auth{} = auth) do
{:ok, basic_info(auth)}
end
# github does it this way
defp avatar_from_auth(%{info: %{urls: %{avatar_url: image}}}), do: image
# facebook does it this way
defp avatar_from_auth(%{info: %{image: image}}), do: image
# default case if nothing matches
defp avatar_from_auth(auth) do
Logger.warn("#{auth.provider} needs to find an avatar URL!")
Logger.debug(Jason.encode!(auth))
nil
end
defp basic_info(auth) do
%{id: auth.uid, name: name_from_auth(auth), avatar: avatar_from_auth(auth)}
end
defp name_from_auth(auth) do
if auth.info.name do
auth.info.name
else
name =
[auth.info.first_name, auth.info.last_name]
|> Enum.filter(&(&1 != nil and &1 != ""))
if Enum.empty?(name) do
auth.info.nickname
else
Enum.join(name, " ")
end
end
end
defp validate_pass(%{other: %{password: nil}}) do
{:error, "Password required"}
end
defp validate_pass(%{other: %{password: pw, password_confirmation: pw}}) do
:ok
end
defp validate_pass(%{other: %{password: _}}) do
{:error, "Passwords do not match"}
end
defp validate_pass(_), do: {:error, "Password Required"}
end

View File

@ -21,7 +21,7 @@ defmodule BrightWeb do
def router do
quote do
use Phoenix.Router, helpers: false
use Phoenix.Router, helpers: true
# Import common connection and controller functions to use in pipelines
import Plug.Conn

View File

@ -112,7 +112,6 @@ defmodule BrightWeb.CoreComponents do
<div
:if={msg = render_slot(@inner_block) || Phoenix.Flash.get(@flash, @kind)}
id={@id}
phx-click={JS.push("lv:clear-flash", value: %{key: @kind}) |> hide("##{@id}")}
role="alert"
class={[
"mb-5 notification",
@ -121,7 +120,12 @@ defmodule BrightWeb.CoreComponents do
]}
{@rest}
>
<button type="button" class="delete" aria-label={gettext("close")}></button>
<button
type="button"
class="delete"
aria-label={gettext("close")}
phx-click={JS.push("lv:clear-flash", value: %{key: @kind}) |> hide("##{@id}")}
></button>
<p :if={@title} class="has-text-weight-bold">
<%= @title %>
</p>

View File

@ -97,7 +97,7 @@
<!-- <%= if @current_user do %>
<%= if @current_user do %>
<.link
href={~p"/profile"}
class="navbar-item">
@ -123,13 +123,19 @@
>
Register
</.link>
<.link
href={~p"/users/log_in"}
<%# <.link
href={~p"/auth/github"}
class="navbar-item"
>
Log in
</.link>
<% end %> -->
<.link
href={~p"/auth/github"}
class="navbar-item"
>
Log in via GH
</.link> %>
<% end %>
</div>
</div>

View File

@ -0,0 +1,92 @@
defmodule BrightWeb.AuthController do
@moduledoc """
Auth controller responsible for handling Ueberauth responses
"""
require Logger
use BrightWeb, :controller
plug Ueberauth
alias Ueberauth.Strategy.Helpers
alias Bright.UserFromAuth
alias Bright.User
def delete(conn, _params) do
conn
|> put_flash(:info, "You have been logged out!")
|> clear_session()
|> redirect(to: "/")
end
def callback(%{assigns: %{ueberauth_failure: _fails}} = conn, _params) do
conn
|> put_flash(:error, "Failed to authenticate.")
|> redirect(to: "/")
end
# def callback(conn, %{"provider" => provider}) do
# end
def callback(conn = %{assigns: %{ueberauth_auth: auth}}, _params) do
if user = User.get_by_ueberauth(auth) do
sign_in_and_redirect(conn, user, ~p"/~")
else
conn
|> put_flash(:success, "Almost there! Please complete your profile now.")
|> redirect(to: ~p"/join?#{params_from_ueberauth(auth)}")
end
end
defp sign_in_and_redirect(conn, user, route) do
user
|> User.sign_in_changes()
|> Repo.update()
conn
|> assign(:current_user, user)
|> put_flash(:success, "Welcome!")
|> put_session("id", user.id)
|> configure_session(renew: true)
|> redirect(to: route)
end
defp params_from_ueberauth(%{provider: :github, info: info}) do
%{name: info.name, handle: info.nickname, github_handle: info.nickname}
end
defp params_from_ueberauth(%{provider: :patreon, info: info}) do
%{name: info.name, handle: info.nickname, patreon_handle: info.nickname}
end
# case Ueberauth.Auth.fetch!(conn) do
# {:ok, auth} ->
# Logger.info("auth is as follows: #{inspect(auth)}")
# {:error, reason} ->
# conn
# |> put_flash(:error, "Auth failed! #{reason}")
# |> redirect(to: ~p"/")
# end
# case UserFromAuth.find_or_create(auth) do
# {:ok, user} ->
# conn
# |> put_flash(:info, "Successfully authenticated #{inspect(user)}")
# |> put_session(:current_user, user)
# |> configure_session(renew: true)
# |> redirect(to: "/")
# {:error, reason} ->
# conn
# |> put_flash(:error, reason)
# |> redirect(to: "/")
# end
end

View File

@ -0,0 +1,7 @@
defmodule BrightWeb.AuthHTML do
use BrightWeb, :html
embed_templates "auth_html/*"
end

View File

@ -0,0 +1 @@
<p>hello this is request.html</p>

View File

@ -6,6 +6,7 @@
<p class="title is-2">
The Galaxy's Best VTuber Hentai Site
</p>
@ -25,6 +26,20 @@
</div>
<!--<%= inspect(@current_user) %>
<%= if @current_user do %>
<div>
<h1>Welcome, <%= @current_user[:name] %>!</h1>
<p>ID: <%= @current_user[:id] %></p>
<p>Avatar: <%= @current_user[:avatar] %></p>
</div>
<% else %>
<div>
<p>You are not logged in. Please <a href="/auth/github">log in</a>.</p>
</div>
<% end %>-->

View File

@ -0,0 +1,15 @@
defmodule BrightWeb.UserController do
use BrightWeb, :controller
def index(conn, _params) do
render(conn, :index)
end
def show(conn) do
conn
|> render(:show)
end
end

View File

@ -0,0 +1,4 @@
defmodule BrightWeb.UserHTML do
use BrightWeb, :html
embed_templates "user_html/*"
end

View File

@ -0,0 +1,11 @@
<.header>
Visitor Profile
</.header>
<%= if @current_user do %>
<p>@current_user is {@current_user}</p>
<% else %>
<p>there is no @current_user</p>
<% end %>

View File

@ -24,16 +24,27 @@ defmodule BrightWeb.Router do
plug :accepts, ["json"]
end
# scope "/" do
# pipe_through [:browser, :require_authenticated_user, :require_admin_user]
# ## !!! DANGER, platforms must only be writable by admins, (unless we implement SVG sanitizing)
# get "/platforms/new", PlatformController, :new
# post "/platforms", PlatformController, :create
# get "/platforms/:id/edit", PlatformController, :edit
# patch "/platforms/:id", PlatformController, :update
# put "/platforms/:id", PlatformController, :update
# end
scope "/" do
pipe_through [:browser, :require_authenticated_user, :require_admin_user]
## !!! DANGER, platforms must only be writable by admins, (unless we implement SVG sanitizing)
get "/platforms/new", PlatformController, :new
post "/platforms", PlatformController, :create
get "/platforms/:id/edit", PlatformController, :edit
patch "/platforms/:id", PlatformController, :update
put "/platforms/:id", PlatformController, :update
end
scope "/auth", BrightWeb do
pipe_through :browser
get "/:provider", AuthController, :request
get "/:provider/callback", AuthController, :callback
post "/:provider/callback", AuthController, :callback
delete "/logout", AuthController, :delete
end
scope "/" do
@ -58,6 +69,8 @@ defmodule BrightWeb.Router do
# get "/vtubers/:id/edit", VtuberController, :edit
# end
get "/profile", UserController, :show
get "/tags/new", TagController, :new
post "/tags", TagController, :create
@ -82,8 +95,6 @@ defmodule BrightWeb.Router do
get "/streams", StreamController, :index
get "/streams/:id", StreamController, :show
# get "/vods", VodController, :index
# get "/vods/:id", VodController, :show
resources "/vods", VodController
get "/vods/:id", VodController, :show

View File

@ -5,6 +5,7 @@ defmodule BrightWeb.UserAuth do
import Phoenix.Controller
alias Bright.Accounts
alias Bright.User
# Make the remember me cookie valid for 60 days.
# If you want bump or reduce this value, also change
@ -208,11 +209,37 @@ defmodule BrightWeb.UserAuth do
conn
|> put_flash(:error, "You must log in to access this page.")
|> maybe_store_return_to()
|> redirect(to: ~p"/users/log_in")
|> redirect(to: ~p"/auth/github")
|> halt()
end
end
@doc """
Used for routes that require the user to be an administrator.
"""
def require_admin_user(conn, _opts) do
Logger.info("con.assigns[:current_user] as follows. #{inspect(conn.assigns)}")
case conn.assigns[:current_user] do
%User{is_admin: true} -> # Assuming the user struct has an `is_admin` field
conn
%User{} ->
conn
|> put_flash(:error, "You do not have permission to access this page.")
|> redirect(to: ~p"/")
|> halt()
nil ->
conn
|> put_flash(:error, "You must log in to access this page.")
|> maybe_store_return_to()
|> redirect(to: ~p"/auth/github")
|> halt()
end
end
defp put_token_in_session(conn, token) do
conn
|> put_session(:user_token, token)

View File

@ -56,7 +56,10 @@ defmodule Bright.MixProject do
{:bandit, "~> 1.5"},
{:oban, "~> 2.17"},
{:mox, "~> 0.5.0", only: :test},
{:httpoison, "~> 2.0"}
{:httpoison, "~> 2.0"},
{:ueberauth, "~> 0.7.0"},
{:ueberauth_github, "~> 0.8"},
{:timex, "~> 3.0"},
]
end

View File

@ -4,6 +4,7 @@
"bulma": {:hex, :bulma, "1.0.2", "50dfffe8d28b0bd527418560223b407f9e80e990e187e1653b17eff818f8fcbe", [:mix], [], "hexpm", "27745727ff7f451d140a2438c0ca4448bc8ca73e0a6d2d4f24e1b5b9ced8a774"},
"castore": {:hex, :castore, "1.0.10", "43bbeeac820f16c89f79721af1b3e092399b3a1ecc8df1a472738fd853574911", [:mix], [], "hexpm", "1b0b7ea14d889d9ea21202c43a4fa015eb913021cb535e8ed91946f4b77a8848"},
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"comeonin": {:hex, :comeonin, "5.5.0", "364d00df52545c44a139bad919d7eacb55abf39e86565878e17cebb787977368", [:mix], [], "hexpm", "6287fc3ba0aad34883cbe3f7949fc1d1e738e5ccdce77165bc99490aa69f47fb"},
"dart_sass": {:hex, :dart_sass, "0.7.0", "7979e056cb74fd6843e1c72db763cffc7726a9192a657735b7d24c0d9c26a1ce", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "4a8e70bca41aa00846398abdf5ad8a64d7907a0f7bf40145cd2e40d5971629f2"},
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
@ -31,6 +32,7 @@
"mox": {:hex, :mox, "0.5.2", "55a0a5ba9ccc671518d068c8dddd20eeb436909ea79d1799e2209df7eaa98b6c", [:mix], [], "hexpm", "df4310628cd628ee181df93f50ddfd07be3e5ecc30232d3b6aadf30bdfe6092b"},
"nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
"oauth2": {:hex, :oauth2, "2.1.0", "beb657f393814a3a7a8a15bd5e5776ecae341fd344df425342a3b6f1904c2989", [:mix], [{:tesla, "~> 1.5", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "8ac07f85b3307dd1acfeb0ec852f64161b22f57d0ce0c15e616a1dfc8ebe2b41"},
"oban": {:hex, :oban, "2.18.3", "1608c04f8856c108555c379f2f56bc0759149d35fa9d3b825cb8a6769f8ae926", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "36ca6ca84ef6518f9c2c759ea88efd438a3c81d667ba23b02b062a0aa785475e"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
"phoenix": {:hex, :phoenix, "1.7.18", "5310c21443514be44ed93c422e15870aef254cf1b3619e4f91538e7529d2b2e4", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, 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]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "1797fcc82108442a66f2c77a643a62980f342bfeb63d6c9a515ab8294870004e"},
@ -52,7 +54,12 @@
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
"telemetry_metrics": {:hex, :telemetry_metrics, "1.0.0", "29f5f84991ca98b8eb02fc208b2e6de7c95f8bb2294ef244a176675adc7775df", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f23713b3847286a534e005126d4c959ebcca68ae9582118ce436b521d1d47d5d"},
"telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
"tesla": {:hex, :tesla, "1.12.3", "7189f71ac607169a1bb2dfcf8747dedd4d9384ec00cec6c7b38c5f03811a73c7", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [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.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [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", "4dfb0d6a81ca79c8662a4f03884843a5b3251825ba47ea6f9ab84dcc354fdeec"},
"thousand_island": {:hex, :thousand_island, "1.3.7", "1da7598c0f4f5f50562c097a3f8af308ded48cd35139f0e6f17d9443e4d0c9c5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0139335079953de41d381a6134d8b618d53d084f558c734f2662d1a72818dd12"},
"timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
"tzdata": {:hex, :tzdata, "1.1.2", "45e5f1fcf8729525ec27c65e163be5b3d247ab1702581a94674e008413eef50b", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "cec7b286e608371602318c414f344941d5eb0375e14cfdab605cca2fe66cba8b"},
"ueberauth": {:hex, :ueberauth, "0.7.0", "9c44f41798b5fa27f872561b6f7d2bb0f10f03fdd22b90f454232d7b087f4b75", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2efad9022e949834f16cc52cd935165049d81fa9e925690f91035c2e4b58d905"},
"ueberauth_github": {:hex, :ueberauth_github, "0.8.3", "1c478629b4c1dae446c68834b69194ad5cead3b6c67c913db6fdf64f37f0328f", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "ae0ab2879c32cfa51d7287a48219b262bfdab0b7ec6629f24160564247493cc6"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
"websock_adapter": {:hex, :websock_adapter, "0.5.8", "3b97dc94e407e2d1fc666b2fb9acf6be81a1798a2602294aac000260a7c4a47d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "315b9a1865552212b5f35140ad194e67ce31af45bcee443d4ecb96b5fd3f3782"},

View File

@ -0,0 +1,9 @@
defmodule Bright.Repo.Migrations.AddPlatformToUser do
use Ecto.Migration
def change do
alter table(:users) do
add :is_admin, :boolean, default: false, null: false
end
end
end

View File

@ -0,0 +1,9 @@
defmodule Bright.Repo.Migrations.AddIsAdminToUser do
use Ecto.Migration
def change do
alter table(:users) do
add :is_admin, :boolean, default: false, null: false
end
end
end

View File

@ -0,0 +1,12 @@
defmodule Bright.Repo.Migrations.AddAuthTokenToUser do
use Ecto.Migration
def change do
alter table(:users) do
add :auth_token, :string
add :auth_token_expires_at, :utc_datetime
add :joined_at, :utc_datetime
add :signed_in_at, :utc_datetime
end
end
end

View File

@ -0,0 +1,10 @@
defmodule Bright.Repo.Migrations.AddProviderHandlesToUser do
use Ecto.Migration
def change do
alter table(:users) do
add :patreon_handle, :string
add :github_handle, :string
end
end
end

View File

@ -0,0 +1,9 @@
defmodule Bright.Repo.Migrations.AddNameToUser do
use Ecto.Migration
def change do
alter table(:users) do
add :name, :string
end
end
end