Compare commits

...

64 Commits

Author SHA1 Message Date
ebd9f7f52c
feat(pastes): add new page to show owned pastes
Signed-off-by: SphericalKat <amolele@gmail.com>
2024-05-09 19:29:13 +05:30
f0efa78b89
feat(menu): use a dropdown menu
Signed-off-by: SphericalKat <amolele@gmail.com>
2024-05-09 19:13:26 +05:30
ca905d46aa
fix(web): remove deprecated options
Signed-off-by: SphericalKat <amolele@gmail.com>
2024-05-09 18:41:47 +05:30
5ea437b9f1
fix(phoenix): remove deprecated items
Signed-off-by: SphericalKat <amolele@gmail.com>
2024-05-09 18:39:59 +05:30
4554b672af
fix(pastes): update schema with timestamps macro
Signed-off-by: Sphericalkat <amolele@gmail.com>
2024-05-07 01:16:52 +05:30
5eb22fdb9c
feat: add timestamps to paste table
Signed-off-by: Sphericalkat <amolele@gmail.com>
2024-05-07 01:06:18 +05:30
e1f66f9895
fix(config): increase concurrency limit
Signed-off-by: Sphericalkat <amolele@gmail.com>
2024-02-02 15:54:53 +05:30
8eed2f1423
fix(layout): update personal site link 2023-10-04 02:11:18 +05:30
cc01b781d8
Merge pull request #28 from SphericalKat/renovate/tailwindcss-3.x 2023-06-28 22:59:49 +05:30
renovate[bot]
22982cf296
chore(deps): update dependency tailwindcss to v3 2023-06-27 16:14:38 +00:00
c87ce27844
Merge pull request #27 from SphericalKat/renovate/postcss-import-15.x 2023-06-27 21:43:54 +05:30
70e783c4e6
Merge pull request #30 from SphericalKat/dependabot/npm_and_yarn/assets/decode-uri-component-0.2.2 2023-06-27 21:42:08 +05:30
dependabot[bot]
73070a081e
chore(deps): bump decode-uri-component from 0.2.0 to 0.2.2 in /assets
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-27 16:11:34 +00:00
0fa93a70a5 fix(native): correct rustler version and feature for the latest erl versions
Signed-off-by: Sphericalkat <amolele@gmail.com>
2023-06-27 21:40:40 +05:30
16e5ae9bec fix(deps): fix lockfile conflicts
Signed-off-by: Sphericalkat <amolele@gmail.com>
2023-06-27 21:03:37 +05:30
renovate[bot]
2bbbec248c
chore(deps): update dependency postcss-import to v15 2023-02-27 11:39:35 +00:00
dd33c1eb64
Merge pull request #22 from SphericalKat/renovate/phoenix_live_view-0.x 2023-02-27 17:08:02 +05:30
f408734070
Merge pull request #24 from SphericalKat/renovate/actions-checkout-3.x 2023-02-27 17:07:44 +05:30
6163a43127
fix: *sigh* 2023-02-27 16:56:22 +05:30
fee202137c
fix: unpin alpine, use latest everywhere 2023-02-27 16:53:04 +05:30
edbee59f23
fix: pin elixir upstream image 2023-02-27 16:46:01 +05:30
d5cf0cac2b
fix: pin elixir alpine image 2023-02-27 16:43:57 +05:30
renovate[bot]
10f907e9f9
chore(deps): update actions/checkout action to v3 2023-02-26 19:38:39 +00:00
renovate[bot]
8e309e5a6c
chore(deps): update dependency phoenix_live_view to ~> 0.18.0 2023-02-26 15:19:29 +00:00
28af6df793
Merge pull request #13 from SphericalKat/renovate/configure 2023-02-26 14:01:10 +05:30
renovate[bot]
fb90029bc7
chore(deps): add renovate.json 2022-06-26 10:02:13 +00:00
54d5dd5c39
fix(api): add CORS plug to router
Signed-off-by: Amogh Lele <amolele@gmail.com>
2022-05-28 11:20:26 +05:30
4fcf5489da
fix(pastes): attempt getting a non-split version of the paste id
Signed-off-by: Amogh Lele <amolele@gmail.com>
2022-05-28 10:58:17 +05:30
94451e37d8
Merge pull request #12 from gargakshit/feature/title
feat: add support for custom page titles
2022-05-28 10:40:07 +05:30
97aa091b9a
Merge branch 'develop' into feature/title 2022-05-28 10:39:47 +05:30
106ae8398e
feat: implement custom URLs
Signed-off-by: Amogh Lele <amolele@gmail.com>
2022-05-28 10:29:47 +05:30
Amogh Lele
5a0995b991
fix(endpoint): increase parser limit to 10mb
Signed-off-by: Amogh Lele <amogh@dyte.io>
2022-05-23 16:44:51 +05:30
Amogh Lele
b76d005a22
ci(actions): set up automated deploys using github actions
Signed-off-by: Amogh Lele <amogh@dyte.io>
2022-05-23 09:22:27 +05:30
Amogh Lele
76c7bd4a34
feat: add meta tags for SEO and improved UX
Signed-off-by: Amogh Lele <amogh@dyte.io>
2022-05-23 09:02:39 +05:30
Amogh Lele
dbe75a5065
feat(shorten): improve ux by showing users what the shortened url is
Signed-off-by: Amogh Lele <amogh@dyte.io>
2022-05-21 16:21:02 +05:30
Amogh Lele
20a0b45954
feat(pastes): add REST routes to view and create pastes
Signed-off-by: Amogh Lele <amogh@dyte.io>
2022-05-07 00:04:59 +05:30
Amogh Lele
bf50e4264d
fix(config): enable ipv6 for fly databases
Signed-off-by: Amogh Lele <amogh@dyte.io>
2022-05-06 21:14:21 +05:30
Amogh Lele
82e4d19e6c
feat: set up deploys with fly
Signed-off-by: Amogh Lele <amogh@dyte.io>
2022-05-06 19:54:58 +05:30
Amogh Lele
f67e8cf6f9
chore(config): upgrade deprecated config modules
Signed-off-by: Amogh Lele <amogh@dyte.io>
2022-05-06 17:11:47 +05:30
Amogh Lele
dd609b5d84
chore(deps): update dependencies
Signed-off-by: Amogh Lele <amogh@dyte.io>
2022-05-06 16:55:57 +05:30
Akshit Garg
bec57794fa
feat: add paste id for showlink 2022-02-16 16:37:05 +05:30
Akshit Garg
5820652ac1
feat: add support for custom page titles
Also put the paste ID in the title for the show page
2022-02-16 16:30:30 +05:30
de365b36ad
chore(build): add image to push dependencies
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-12-08 23:12:17 +05:30
24a1a91824
refactor(footer): update repo url
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-12-08 22:35:26 +05:30
56852f43be
Merge github.com:SphericalKat/katbin-elixir into develop 2021-12-08 22:34:15 +05:30
Udo Kramer
b1d4455cb8 Tweak rust linker flags 2021-12-08 22:32:35 +05:30
TruncatedDinosour
33272ee23d Fixed a typo 2021-12-08 22:31:29 +05:30
1ecb497199
fix(paste): prevent \r \n characters from interfering with url redirects
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-11-01 18:34:32 +05:30
ec4661fe44
fix(pastes): add stricter sanitization for markdown content
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-08 02:19:58 +05:30
8e6cbc647e
chore: remove leftover paste controller references
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-08 02:03:23 +05:30
3f424a41c1
chore: migrate to prod
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-08 01:56:42 +05:30
9b2da2dbf1
feat(ui): use custom scrollbars
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-07 09:10:54 +05:30
ae8cee8ccf
fix(build): don't purge used styles
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-07 09:06:08 +05:30
bca77b0ff6
refactor(markdown): improve styling
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-07 06:39:22 +05:30
8121ea2cf0
fix!(markdown): prevent html injection
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-07 06:20:50 +05:30
dd089f13f9
feat(pastes): add support for markdown
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-07 06:18:10 +05:30
1d0b8cc4d5
feat(pastes): allow form submission using Ctrl/Cmd + S
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-07 06:08:25 +05:30
8f4672b516
refactor(auth): use heex templates
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-07 05:58:00 +05:30
2ddccce85d
refactor(layout): use heex templates
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-07 05:54:37 +05:30
2fa19381dc
refactor(home): use heex templates
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-07 05:52:14 +05:30
9b18d5186d
refactor(paste): switch to heex templates
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-07 05:42:24 +05:30
8b7073145d
chore(deps): bump phoenix and other package versions
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-10-07 05:29:22 +05:30
b4eb5c7f2f
chore: add sample env file
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-09-16 23:50:58 +05:30
d19fe38aee
docs(readme): add information about self hosting
Signed-off-by: SphericalKat <amolele@gmail.com>
2021-09-16 23:48:42 +05:30
64 changed files with 2045 additions and 2077 deletions

12
.github/workflows/fly.yml vendored Normal file
View File

@ -0,0 +1,12 @@
name: Fly Deploy
on: [push]
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
jobs:
deploy:
name: Deploy to fly.io
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only

View File

@ -34,7 +34,7 @@ RUN mix phx.digest
RUN mix do compile, release RUN mix do compile, release
# prepare release image # prepare release image
FROM alpine:3.9 AS app FROM alpine AS app
RUN apk add --no-cache openssl ncurses-libs libstdc++ RUN apk add --no-cache openssl ncurses-libs libstdc++
WORKDIR /app WORKDIR /app

View File

@ -3,5 +3,5 @@ image:
docker build -t atechnohazard/katbin-elixir . docker build -t atechnohazard/katbin-elixir .
.PHONY: push .PHONY: push
push: push: image
docker push atechnohazard/katbin-elixir docker push atechnohazard/katbin-elixir

View File

@ -1,4 +1,4 @@
# Ketbin # Katbin
To start your Phoenix server: To start your Phoenix server:
@ -11,7 +11,37 @@ To start your Phoenix server:
Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). # Self hosting
We recommend using our [official docker image](https://hub.docker.com/r/atechnohazard/katbin-elixir). If you wish to build your own docker image, the provided Dockerfile should work out of the box. If you run into any problems, please open an issue.
## Populating the environment
Copy the provided `sample.env` file to `.env`
```sh
cp sample.env .env
```
Fill in this new file with the required environment variables.
## Using the official docker image
```sh
docker run --env-file .env atechnohazard/katbin-elixir
```
## Building the docker image
```sh
git clone https://github.com/SphericalKat/katbin
cd katbin
docker build -t <username>/katbin .
```
## Running the built docker image
```sh
docker run --env-file .env <username>/katbin
```
For other methods of self hosting, please check the [official Phoenix deployment guides](https://hexdocs.pm/phoenix/deployment.html).
## Learn more ## Learn more

View File

@ -13,7 +13,7 @@ fs.copySync("static/", "../priv/static/");
console.log("[build.js] [info] Copying static files from static/"); console.log("[build.js] [info] Copying static files from static/");
if (!productionBuild) { if (!productionBuild) {
console.log("[build.js] [info] Starting to watching assets for changes"); console.log("[build.js] [info] Starting to watch assets for changes");
} else { } else {
console.log("[build.js] [info] Building assets in production mode"); console.log("[build.js] [info] Building assets in production mode");
} }

View File

@ -3,63 +3,126 @@
@import "tailwindcss/components"; @import "tailwindcss/components";
@import "tailwindcss/utilities"; @import "tailwindcss/utilities";
@import "./highlight.css"; @import "./highlight.css";
@import "./markdown.css";
@font-face { @font-face {
font-family: "JetBrains Mono"; font-family: "JetBrains Mono";
src: url(/fonts/jetbrains_mono_variable.ttf); src: url(/fonts/jetbrains_mono_variable.ttf);
font-weight: 100 1000; font-weight: 100 1000;
font-stretch: 25% 151%; font-stretch: 25% 151%;
} }
* { * {
font-family: "JetBrains Mono", monospace; font-family: "JetBrains Mono", monospace;
color: white; color: white;
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
}
@layer base {
h1 {
font-size: 2em;
font-weight: bold;
}
h2 {
font-size: 1.5em;
font-weight: bold;
}
h3 {
font-size: 1.17em;
font-weight: bold;
}
h4 {
font-weight: bold;
}
h5 {
font-size: 0.83em;
font-weight: bold;
}
h6 {
font-size: 0.67em;
font-weight: bold;
}
h1,
h2,
h3 {
margin-top: 20px;
margin-bottom: 10px
}
img {
display: inline;
}
} }
html, html,
body { body {
width: 100%; width: 100%;
height: 100%; height: 100%;
}
a {
color: #ff9800;
} }
a:hover { a:hover {
color: #ff9800; color: #ff9800;
text-decoration: underline;
} }
header { header {
background-color: #1a1a1a; background-color: #1a1a1a;
} }
code { code {
font-family: "JetBrains Mono", monospace; font-family: "JetBrains Mono", monospace;
} }
code { code {
white-space: pre; white-space: pre;
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
} }
textarea { textarea {
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
}
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-corner,
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
border-radius: 8px;
@apply bg-amber;
} }
.alert { .alert {
width: 100%; width: 100%;
text-align: center; text-align: center;
} }
.alert-info { .alert-info {
background-color: #1ed98e; background-color: #1ed98e;
color: black; color: black;
font-weight: bold; font-weight: bold;
} }
.alert-danger { .alert-danger {
background-color: #ff9800; background-color: #ff9800;
color: black; color: black;
font-weight: bold; font-weight: bold;
} }

179
assets/css/markdown.css Normal file
View File

@ -0,0 +1,179 @@
.markdown p {
font-family: sans-serif;
font-weight: 400;
}
.markdown p > * {
font-family: sans-serif;
font-weight: 400;
}
.markdown h1,
h2,
h3 {
margin-top: 20px;
margin-bottom: 10px;
}
.markdown h1 {
font-size: 2em;
@apply text-amber;
}
.markdown h2 {
font-size: 1.5em;
@apply text-amber;
}
.markdown h3 {
font-size: 1.17em;
@apply text-amber;
}
.markdown h4 {
font-size: 1em;
@apply text-amber;
margin-bottom: 10px;
}
.markdown h5 {
font-size: 0.83em;
@apply text-amber;
margin-bottom: 10px;
}
.markdown h6 {
font-size: 0.75em;
@apply text-amber;
margin-bottom: 10px;
}
.markdown blockquote {
padding: 0 1em;
margin: 0 0 20px;
font-size: 17.5px;
border-left: 4px solid #8b949e;
}
.markdown img {
max-width: 35%;
vertical-align: middle;
display: inline;
}
.markdown table {
width: 100%;
max-width: 100%;
margin-bottom: 20px;
margin-top: 10px;
}
tbody > tr:nth-child(odd) > td,
.table-striped > tbody > tr:nth-child(odd) > th {
background-color: #1b1b1b;
}
.table-striped > tbody > tr:nth-child(odd) > td,
.table-striped > tbody > tr:nth-child(odd) > th {
background-color: #1b1b1b;
}
table > thead > tr > th,
table > tbody > tr > th,
table > tfoot > tr > th,
table > thead > tr > td,
table > tbody > tr > td,
table > tfoot > tr > td {
padding: 8px;
line-height: 1.42857143;
vertical-align: top;
border: 1px solid #3b434b;
}
.markdown hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #3b434b;
}
.markdown {
/* border: 1px solid #3b434b; */
border-radius: 6px;
padding-right: 32px;
padding-left: 32px;
}
.markdown pre {
padding: 12px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: #1b1b1b;
border-radius: 6px;
margin: 10px 0;
}
.markdown code pre tt {
font-family: "JetbrainsMono", SFMono-Regular, Consolas, Liberation Mono, Menlo,
monospace;
}
.markdown blockquote > :last-child {
margin-bottom: 0;
}
.markdown blockquote,
.markdown p,
.markdown ol,
.markdown pre,
.markdown table,
.markdown ul {
margin-top: 0;
margin-bottom: 16px;
}
h1,
h2 {
padding-bottom: 0.3em;
border-bottom: 1px solid #3b434b;
}
.markdown li {
display: list-item;
text-align: -webkit-match-parent;
font-family: sans-serif;
font-weight: 400;
}
.markdown ol {
list-style-type: decimal;
}
.markdown ol,
ul {
padding: 0;
margin-left: 40px;
}
.markdown strong {
font-family: sans-serif;
}
.markdown code.inline {
font-family: "JetBrains Mono", monospace;
background-color: rgb(240 246 252 / 15%);
font-weight: bold;
border-radius: 4px;
font-size: 80%;
margin: 0;
padding: 0.1em 0.4em;
}
.markdown ul {
list-style: disc;
}
.markdown ol {
list-style: decimal;
}
.markdown ul, ol {
padding: 0;
margin-left: 40px;
}

2463
assets/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@
"esbuild-plugin-postcss2": "0.0.9", "esbuild-plugin-postcss2": "0.0.9",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",
"postcss": "^8.3.6", "postcss": "^8.3.6",
"postcss-import": "^14.0.2", "postcss-import": "^15.0.0",
"tailwindcss": "^2.2.7" "tailwindcss": "^3.4.3"
} }
} }

View File

@ -1,18 +1,19 @@
module.exports = { module.exports = {
purge: [ content: [
"../lib/**/*.ex", "../lib/**/*.ex",
"../lib/**/*.leex", "../lib/**/*.leex",
"../lib/**/*.eex", "../lib/**/*.eex",
"../lib/**/*.heex",
"./js/**/*.js", "./js/**/*.js",
], ],
darkMode: false, // or 'media' or 'class' darkMode: 'media', // or 'media' or 'class'
theme: { theme: {
extend: { extend: {
colors: { colors: {
amber: '#ff9800', amber: "#ff9800",
'light-grey': '#212121', "light-grey": "#212121",
}, },
}, },
}, },
variants: { variants: {
extend: {}, extend: {},

View File

@ -5,7 +5,7 @@
# is restricted to this project. # is restricted to this project.
# General application configuration # General application configuration
use Mix.Config import Config
config :ketbin, config :ketbin,
ecto_repos: [Ketbin.Repo] ecto_repos: [Ketbin.Repo]

View File

@ -1,4 +1,4 @@
use Mix.Config import Config
# For development, we disable any cache and enable # For development, we disable any cache and enable
# debugging and code reloading. # debugging and code reloading.

View File

@ -1,4 +1,4 @@
use Mix.Config import Config
# For production, don't forget to configure the url host # For production, don't forget to configure the url host
# to something meaningful, Phoenix uses this information # to something meaningful, Phoenix uses this information
@ -10,7 +10,7 @@ use Mix.Config
# which you should run after static files are built and # which you should run after static files are built and
# before starting your production server. # before starting your production server.
config :ketbin, KetbinWeb.Endpoint, config :ketbin, KetbinWeb.Endpoint,
url: [host: "dev.katb.in", port: 80], url: [host: "katb.in", port: 80],
cache_static_manifest: "priv/static/cache_manifest.json" cache_static_manifest: "priv/static/cache_manifest.json"
# Do not print debug messages in production # Do not print debug messages in production

View File

@ -12,12 +12,12 @@ database_url =
""" """
config :ketbin, Ketbin.Repo, config :ketbin, Ketbin.Repo,
ssl: true, ssl: false,
verify: :verify_peer, # verify: :verify_peer,
socket_options: [:inet6],
url: database_url, url: database_url,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")
cacertfile: "priv/cert.pem" # cacertfile: "priv/cert.pem"
secret_key_base = secret_key_base =
System.get_env("SECRET_KEY_BASE") || System.get_env("SECRET_KEY_BASE") ||
raise """ raise """
@ -33,31 +33,34 @@ config :ketbin, KetbinWeb.Endpoint,
secret_key_base: secret_key_base, secret_key_base: secret_key_base,
server: true server: true
smtp_relay = smtp_relay =
System.get_env("SWOOSH_SMTP_RELAY") || System.get_env("SWOOSH_SMTP_RELAY") ||
raise """ raise """
environment variable SWOOSH_SMTP_RELAY is missing. environment variable SWOOSH_SMTP_RELAY is missing.
""" """
username =
System.get_env("SWOOSH_USERNAME") || username =
raise """ System.get_env("SWOOSH_USERNAME") ||
environment variable SWOOSH_USERNAME is missing. raise """
""" environment variable SWOOSH_USERNAME is missing.
password = """
System.get_env("SWOOSH_PASSWORD") ||
raise """ password =
environment variable SWOOSH_PASSWORD is missing. System.get_env("SWOOSH_PASSWORD") ||
""" raise """
environment variable SWOOSH_PASSWORD is missing.
"""
# configure mailer
config :ketbin, Ketbin.Mailer,
adapter: Swoosh.Adapters.SMTP,
relay: smtp_relay,
username: username,
password: password,
tls: :always,
auth: :always,
port: 587
# configure mailer
config :ketbin, Ketbin.Mailer,
adapter: Swoosh.Adapters.SMTP,
relay: smtp_relay,
username: username,
password: password,
tls: :always,
auth: :always,
port: 587
# ## Using releases (Elixir v1.9+) # ## Using releases (Elixir v1.9+)
# #
# If you are doing OTP releases, you need to instruct Phoenix # If you are doing OTP releases, you need to instruct Phoenix

View File

@ -1,4 +1,4 @@
use Mix.Config import Config
# Only in tests, remove the complexity from the password hashing algorithm # Only in tests, remove the complexity from the password hashing algorithm
config :bcrypt_elixir, :log_rounds, 1 config :bcrypt_elixir, :log_rounds, 1

45
fly.toml Normal file
View File

@ -0,0 +1,45 @@
# fly.toml file generated for katbin on 2022-05-06T17:46:21+05:30
app = "katbin"
kill_signal = "SIGTERM"
kill_timeout = 5
processes = []
# [deploy]
# release_command = "/app/bin/migrate"
[env]
PHX_HOST = "katbin.fly.dev"
PORT = "8080"
[experimental]
allowed_public_ports = []
auto_rollback = true
[[services]]
http_checks = []
internal_port = 8080
processes = ["app"]
protocol = "tcp"
script_checks = []
[services.concurrency]
hard_limit = 10000
soft_limit = 6000
type = "connections"
[[services.ports]]
force_https = true
handlers = ["http"]
port = 80
[[services.ports]]
handlers = ["tls", "http"]
port = 443
[[services.tcp_checks]]
grace_period = "1s"
interval = "15s"
restart_limit = 0
timeout = "2s"

View File

@ -21,6 +21,10 @@ defmodule Ketbin.Pastes do
Repo.all(Paste) Repo.all(Paste)
end end
def list_pastes_by_user(user_id) do
Repo.all(from(p in Paste, where: p.belongs_to == ^user_id))
end
@doc """ @doc """
Gets a single paste. Gets a single paste.

View File

@ -1,6 +1,7 @@
defmodule Ketbin.Pastes.Paste do defmodule Ketbin.Pastes.Paste do
use Ecto.Schema use Ecto.Schema
import Ecto.Changeset import Ecto.Changeset
@derive {Jason.Encoder, only: [:content, :is_url, :belongs_to]}
@primary_key {:id, :string, autogenerate: false} @primary_key {:id, :string, autogenerate: false}
@derive {Phoenix.Param, key: :id} @derive {Phoenix.Param, key: :id}
@ -8,6 +9,8 @@ defmodule Ketbin.Pastes.Paste do
field :content, :string field :content, :string
field :is_url, :boolean, default: false field :is_url, :boolean, default: false
field :belongs_to, :id field :belongs_to, :id
timestamps()
end end
@doc false @doc false
@ -15,5 +18,6 @@ defmodule Ketbin.Pastes.Paste do
paste paste
|> cast(attrs, [:is_url, :content, :id, :belongs_to]) |> cast(attrs, [:is_url, :content, :id, :belongs_to])
|> validate_required([:is_url, :content]) |> validate_required([:is_url, :content])
|> unique_constraint(:id, name: :pastes_pkey)
end end
end end

View File

@ -13,14 +13,19 @@ defmodule Ketbin.Pastes.Utils do
def generate_key(length \\ 10) do def generate_key(length \\ 10) do
random = Enum.random([0, 1]) random = Enum.random([0, 1])
Enum.map(0..length, fn i -> if Integer.mod(i, 2) == random, do: rand_consonant(), else: rand_vowel() end)
|> List.to_string Enum.map(0..length, fn i ->
if Integer.mod(i, 2) == random, do: rand_consonant(), else: rand_vowel()
end)
|> List.to_string()
end end
def is_url?(url) do def is_url?(url) do
try do try do
uri = URI.parse(url) uri = URI.parse(url)
uri.scheme != nil && uri.host =~ "." && Enum.member?(["https", "http", "mailto"], uri.scheme) && !(uri.host =~ "katb.in")
uri.scheme != nil && uri.host =~ "." &&
Enum.member?(["https", "http", "mailto"], uri.scheme) && !(uri.host =~ "katb.in")
rescue rescue
FunctionClauseError -> false FunctionClauseError -> false
end end

View File

@ -0,0 +1,45 @@
defmodule KetbinWeb.Api.PasteController do
use KetbinWeb, :controller
alias Ketbin.Pastes
alias Ketbin.Pastes.Utils
def show(conn, %{"id" => id}) do
[head | _tail] = String.split(id, ".")
# fetch paste from db
paste = Pastes.get_paste!(head)
render(conn, "paste.json", paste: paste)
end
def create(%{assigns: %{current_user: current_user}} = conn, %{"paste" => paste_params}) do
# generate phonetic key
id = Utils.generate_key()
# check if content is a url
is_url =
Map.get(paste_params, "content")
|> Utils.is_url?()
# put id and is_url values into changeset
paste_params =
Map.put(paste_params, "id", id)
|> Map.put("is_url", is_url)
|> Map.put("belongs_to", current_user && current_user.id)
# attempt to create a paste
case Pastes.create_paste(paste_params) do
# all good
{:ok, paste} ->
conn
|> put_status(:created)
|> render("paste.json", paste: paste)
# something went wrong, bail
{:error, %Ecto.Changeset{} = _changeset} ->
conn
|> put_status(:internal_server_error)
|> render("error.json")
end
end
end

View File

@ -16,21 +16,40 @@ defmodule KetbinWeb.PageController do
[head | tail] = String.split(id, ".") [head | tail] = String.split(id, ".")
# fetch paste from db # fetch paste from db
paste = Pastes.get_paste!(head) paste =
try do
Pastes.get_paste!(head)
rescue
Ecto.NoResultsError ->
Pastes.get_paste!(id)
end
# paste is a url, redirect # paste is a url, redirect
# regular paste, show content # regular paste, show content
if paste.is_url do if paste.is_url do
redirect(conn, external: paste.content) redirect(conn,
external: paste.content |> String.replace("\r", "") |> String.replace("\n", "")
)
else else
render(conn, "show.html", paste: paste, show_edit: show_edit, extension: List.first(tail) || "") render(conn, "show.html",
paste: paste,
show_edit: show_edit,
extension: List.first(tail) || "",
page_title: paste.id
)
end end
end end
def showlink(%{assigns: %{show_edit: show_edit}} = conn, %{"id" => id}) do def showlink(%{assigns: %{show_edit: show_edit}} = conn, %{"id" => id}) do
[head | tail] = String.split(id, ".") [head | tail] = String.split(id, ".")
paste = Pastes.get_paste!(head) paste = Pastes.get_paste!(head)
render(conn, "show.html", paste: paste, show_edit: show_edit, extension: (if tail == [], do: "", else: tail))
render(conn, "shorten.html",
paste: paste,
show_edit: show_edit,
extension: if(tail == [], do: "", else: tail),
page_title: paste.id
)
end end
def raw(conn, %{"id" => id}) do def raw(conn, %{"id" => id}) do
@ -39,8 +58,12 @@ defmodule KetbinWeb.PageController do
end end
def create(%{assigns: %{current_user: current_user}} = conn, %{"paste" => paste_params}) do def create(%{assigns: %{current_user: current_user}} = conn, %{"paste" => paste_params}) do
# generate phonetic key # if custom url exists, use it as id, else generate phonetic id
id = Utils.generate_key() id =
case Map.get(paste_params, "custom_url", "") do
custom_url when custom_url != "" -> custom_url
_ -> Utils.generate_key()
end
# check if content is a url # check if content is a url
is_url = is_url =
@ -69,7 +92,13 @@ defmodule KetbinWeb.PageController do
# something went wrong, bail # something went wrong, bail
{:error, %Ecto.Changeset{} = changeset} -> {:error, %Ecto.Changeset{} = changeset} ->
render(conn, "index.html", changeset: changeset) case changeset.errors[:id] do
{"has already been taken", _} ->
render(conn, "index.html", changeset: changeset, already_taken: true)
_ ->
render(conn, "index.html", changeset: changeset)
end
end end
end end
@ -105,4 +134,9 @@ defmodule KetbinWeb.PageController do
render(conn, "edit.html", paste: paste, changeset: changeset) render(conn, "edit.html", paste: paste, changeset: changeset)
end end
end end
def pastes(%{assigns: %{current_user: current_user}} = conn, _params) do
pastes = Pastes.list_pastes_by_user(current_user.id)
render(conn, "pastes.html", pastes: pastes)
end
end end

View File

@ -1,63 +0,0 @@
defmodule KetbinWeb.PasteController do
use KetbinWeb, :controller
alias Ketbin.Pastes
alias Ketbin.Pastes.Paste
def index(conn, _params) do
pastes = Pastes.list_pastes()
render(conn, "index.html", pastes: pastes)
end
def new(conn, _params) do
changeset = Pastes.change_paste(%Paste{})
render(conn, "new.html", changeset: changeset)
end
def create(conn, %{"paste" => paste_params}) do
# paste_params = Map.put(paste_params, "id", s)
case Pastes.create_paste(paste_params) do
{:ok, paste} ->
conn
|> put_flash(:info, "Paste created successfully.")
|> redirect(to: Routes.paste_path(conn, :show, paste))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "new.html", changeset: changeset)
end
end
def show(conn, %{"id" => id}) do
paste = Pastes.get_paste!(id)
render(conn, "show.html", paste: paste)
end
def edit(conn, %{"id" => id}) do
paste = Pastes.get_paste!(id)
changeset = Pastes.change_paste(paste)
render(conn, "edit.html", paste: paste, changeset: changeset)
end
def update(conn, %{"id" => id, "paste" => paste_params}) do
paste = Pastes.get_paste!(id)
case Pastes.update_paste(paste, paste_params) do
{:ok, paste} ->
conn
|> put_flash(:info, "Paste updated successfully.")
|> redirect(to: Routes.paste_path(conn, :show, paste))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "edit.html", paste: paste, changeset: changeset)
end
end
def delete(conn, %{"id" => id}) do
paste = Pastes.get_paste!(id)
{:ok, _paste} = Pastes.delete_paste(paste)
conn
|> put_flash(:info, "Paste deleted successfully.")
|> redirect(to: Routes.paste_path(conn, :index))
end
end

View File

@ -97,15 +97,24 @@ defmodule KetbinWeb.UserAuth do
end end
def owns_paste(%{params: %{"id" => id}, assigns: %{current_user: user}} = conn, _params) do def owns_paste(%{params: %{"id" => id}, assigns: %{current_user: user}} = conn, _params) do
[head|_tail] = String.split(id, ".") [head | _tail] = String.split(id, ".")
paste = Pastes.get_paste!(head)
paste =
try do
Pastes.get_paste!(head)
rescue
Ecto.NoResultsError ->
Pastes.get_paste!(id)
end
assign(conn, :show_edit, (user && user.id == paste.belongs_to) || false) assign(conn, :show_edit, (user && user.id == paste.belongs_to) || false)
end end
def ensure_owns_paste(%{params: %{"id" => id}, assigns: %{current_user: user}} = conn, _params) do def ensure_owns_paste(%{params: %{"id" => id}, assigns: %{current_user: user}} = conn, _params) do
[head|_tail] = String.split(id, ".") [head | _tail] = String.split(id, ".")
paste = Pastes.get_paste!(head) paste = Pastes.get_paste!(head)
allow_edit = (user && user.id == paste.belongs_to) || false allow_edit = (user && user.id == paste.belongs_to) || false
unless allow_edit do unless allow_edit do
conn conn
|> put_flash(:error, "You don't own this paste!") |> put_flash(:error, "You don't own this paste!")

View File

@ -22,5 +22,7 @@ defmodule KetbinWeb.UserSessionController do
conn conn
|> put_flash(:info, "Logged out successfully.") |> put_flash(:info, "Logged out successfully.")
|> UserAuth.log_out_user() |> UserAuth.log_out_user()
conn
end end
end end

View File

@ -45,6 +45,8 @@ defmodule KetbinWeb.UserSettingsController do
|> put_session(:user_return_to, Routes.user_settings_path(conn, :edit)) |> put_session(:user_return_to, Routes.user_settings_path(conn, :edit))
|> UserAuth.log_in_user(user) |> UserAuth.log_in_user(user)
conn
{:error, changeset} -> {:error, changeset} ->
render(conn, "edit.html", password_changeset: changeset) render(conn, "edit.html", password_changeset: changeset)
end end

View File

@ -44,11 +44,13 @@ defmodule KetbinWeb.Endpoint do
plug Plug.Parsers, plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json], parsers: [:urlencoded, :multipart, :json],
length: 10_000_000,
pass: ["*/*"], pass: ["*/*"],
json_decoder: Phoenix.json_library() json_decoder: Phoenix.json_library()
plug Plug.MethodOverride plug Plug.MethodOverride
plug Plug.Head plug Plug.Head
plug Plug.Session, @session_options plug Plug.Session, @session_options
plug CORSPlug
plug KetbinWeb.Router plug KetbinWeb.Router
end end

View File

@ -14,6 +14,15 @@ defmodule KetbinWeb.Router do
pipeline :api do pipeline :api do
plug :accepts, ["json"] plug :accepts, ["json"]
plug :fetch_session
plug :fetch_current_user
end
# scope to ensure user is authenticated
scope "/", KetbinWeb do
pipe_through [:browser, :require_authenticated_user]
get "/pastes", PageController, :pastes
end end
scope "/", KetbinWeb do scope "/", KetbinWeb do
@ -42,6 +51,12 @@ defmodule KetbinWeb.Router do
put "/:id", PageController, :update put "/:id", PageController, :update
end end
scope "/api", KetbinWeb.Api, as: :api do
pipe_through :api
resources "/paste", PasteController, only: [:show, :index, :create]
end
# Other scopes may use custom stacks. # Other scopes may use custom stacks.
# scope "/api", KetbinWeb do # scope "/api", KetbinWeb do
# pipe_through :api # pipe_through :api
@ -96,6 +111,5 @@ defmodule KetbinWeb.Router do
post "/users/confirm", UserConfirmationController, :create post "/users/confirm", UserConfirmationController, :create
get "/users/confirm/:token", UserConfirmationController, :confirm get "/users/confirm/:token", UserConfirmationController, :confirm
resources "/pastes", PasteController
end end
end end

View File

@ -1,10 +0,0 @@
<ul>
<%= if @current_user do %>
<li><%= @current_user.email %></li>
<li><%= link "Settings", to: Routes.user_settings_path(@conn, :edit) %></li>
<li><%= link "Log out", to: Routes.user_session_path(@conn, :delete), method: :delete %></li>
<% else %>
<li><%= link "Register", to: Routes.user_registration_path(@conn, :new) %></li>
<li><%= link "Log in", to: Routes.user_session_path(@conn, :new) %></li>
<% end %>
</ul>

View File

@ -0,0 +1,30 @@
<script>
function toggleDropdown() {
const dropdown = document.querySelector('#dropdown');
const dropdownLabel = document.querySelector('#dropdown-label');
if (dropdown.classList.contains('hidden')) {
dropdown.classList.remove('hidden');
dropdown.classList.add('absolute');
dropdownLabel.innerHTML = dropdownLabel.innerHTML.replace('▼', '▲');
} else {
dropdown.classList.add('hidden');
dropdown.classList.remove('absolute');
dropdownLabel.innerHTML = dropdownLabel.innerHTML.replace('▲', '▼');
}
}
</script>
<ul>
<%= if @current_user do %>
<div class="relative">
<li id="dropdown-label" onclick="toggleDropdown()" class="text-[#ff9800] cursor-pointer select-none"><%= @current_user.email %> ▼</li>
<div id="dropdown" class="hidden right-0 z-50 bg-[#313131] px-4 py-2">
<li><%= link "Settings", to: Routes.user_settings_path(@conn, :edit) %></li>
<li><%= link "Log out", to: Routes.user_session_path(@conn, :delete), method: :delete %></li>
<li><%= link "My Pastes", to: Routes.page_path(@conn, :pastes) %></li>
</div>
</div>
<% else %>
<li><%= link "Register", to: Routes.user_registration_path(@conn, :new) %></li>
<li><%= link "Log in", to: Routes.user_session_path(@conn, :new) %></li>
<% end %>
</ul>

View File

@ -1,47 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Katbin</title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/assets/app.css") %>"/>
<script defer type="text/javascript" src="<%= Routes.static_path(@conn, "/assets/app.js") %>"></script>
</head>
<body class="flex flex-col ">
<header class="flex w-full justify-between items-center py-3 px-6">
<a href="<%= Routes.page_path(@conn, :index) %>">
<span class="font-semibold text-xl tracking-tight">
<span class="text-amber text-xl">&lt;Kat</span>bin/&gt;
</span>
</a>
<nav role="navigation">
<ul>
<%= if function_exported?(Routes, :live_dashboard_path, 2) do %>
<li>
<%# <%= link "LiveDashboard", to: Routes.live_dashboard_path(@conn, :home) %>
</li>
<% end %>
</ul>
<%= render "_user_menu.html", assigns %>
</nav>
</header>
<main class="flex flex-col w-full h-full max-h-full overflow-hidden bg-light-grey" role="main">
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
<%= @inner_content %>
</main>
<footer class="font-bold">
<div class="flex px-4 py-1 text-xs sm:text-base justify-between text-amber" style="background: #1a1a1a; font-family: JetbrainsMono">
<a href="https://sphericalk.at">
© <%= DateTime.utc_now().year %> SphericalKat
</a>
<a href="https://github.com/sphericalkat/katbin-elixir">
Fork me!
</a>
</div>
</footer>
</body>
</html>

View File

@ -0,0 +1,100 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<%= if Map.has_key?(assigns, :page_title) do %>
<title>Katbin - <%= @page_title %></title>
<% else %>
<title>Katbin</title>
<% end %>
<title itemprop="name">Katbin</title>
<meta property="og:type" content="object">
<meta property="og:title" content="Katbin">
<meta property="og:image" content="/favicon.ico">
<meta name="twitter:title" content="Katbin">
<meta itemprop="name" content="Katbin">
<meta name="application-name" content="Katbin">
<meta property="og:site_name" content="Katbin">
<meta name="theme-color" content="#1a1a1a">
<meta property="og:locale" content="en">
<meta name="language" content="en">
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@Spherical_Kat">
<meta name="twitter:image" content="/favicon.ico">
<meta name="robots" content="index,follow">
<meta name="googlebot" content="index,follow">
<meta name="keywords" content="paste,pastebin,url,urlshortener,url-shortener,code,programming,bin,cat,kat,paste,share,save,login">
<meta name="coverage" content="Worldwide">
<meta name="distribution" content="Global">
<meta name="HandheldFriendly" content="True">
<meta name="HandheldFriendly" content="True">
<meta name="apple-mobile-web-app-title" content="Katbin">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-touch-fullscreen" content="yes">
<%= if assigns[:paste] do %>
<meta name="description" content={@paste.content}>
<meta itemprop="description" content={@paste.content}>
<meta property="og:description" content={@paste.content}>
<meta name="twitter:description" content={@paste.content}>
<meta name="url" content={"https://katb.in/#{@paste.id}"}>
<meta name="twitter:url" content={"https://katb.in/#{@paste.id}"}>
<meta property="og:url" content={"https://katb.in/#{@paste.id}"}>
<% else %>
<meta name="description" content="Paste, save, share! A pastebin and URL shortener for all your needs.">
<meta property="og:description" content="Paste, save, share! A pastebin and URL shortener for all your needs.">
<meta itemprop="og:description" content="Paste, save, share! A pastebin and URL shortener for all your needs.">
<meta name="twitter:description" content="Paste, save, share! A pastebin and URL shortener for all your needs.">
<meta name="url" content="https://katb.in">
<meta name="twitter:url" content="https://katb.in">
<meta property="og:url" content="https://katb.in">
<% end %>
<link rel="stylesheet" href={ Routes.static_path(@conn, "/assets/app.css") }/>
<script defer type="text/javascript" src={ Routes.static_path(@conn, "/assets/app.js") }></script>
</head>
<body class="flex flex-col ">
<header class="flex w-full justify-between items-center py-3 px-6">
<a href={ Routes.page_path(@conn, :index) }>
<span class="font-semibold text-xl tracking-tight">
<span class="text-amber text-xl">&lt;Kat</span>bin/&gt;
</span>
</a>
<nav role="navigation">
<ul>
<%= if function_exported?(Routes, :live_dashboard_path, 2) do %>
<li>
<%# <%= link "LiveDashboard", to: Routes.live_dashboard_path(@conn, :home) %>
</li>
<% end %>
</ul>
<%= render "_user_menu.html", assigns %>
</nav>
</header>
<main class="flex flex-col w-full h-full max-h-full overflow-hidden bg-light-grey" role="main">
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
<%= @inner_content %>
</main>
<footer class="font-bold">
<div class="flex px-4 py-1 text-xs sm:text-base justify-between text-amber" style="background: #1a1a1a; font-family: JetbrainsMono">
<a href="https://kat.bio">
© <%= DateTime.utc_now().year %> SphericalKat
</a>
<a href="https://github.com/sphericalkat/katbin">
Fork me!
</a>
</div>
</footer>
</body>
</html>

View File

@ -1 +1 @@
<%= render "form.html", Map.put(assigns, :action, Routes.page_path(@conn, :update, @paste)) %> <%= render "form.html", Map.put(assigns, :action, Routes.page_path(@conn, :update, @paste)) |> Map.put(:is_edit, true) %>

View File

@ -1,13 +1,32 @@
<%= form_for @changeset, @action, [class: "flex flex-col w-full h-full relative"], fn f -> %> <%= form_for @changeset, @action, [class: "flex flex-col w-full h-full relative", id: "page_form"], fn f -> %>
<script>
document.addEventListener("keydown", function(e) {
if ((window.navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) && e.keyCode == 83) {
e.preventDefault();
document.getElementById("page_form").submit()
}
}, false);
</script>
<%= if @changeset.action do %> <%= if @changeset.action do %>
<div class="w-full text-center bg-amber"> <div class="w-full text-center bg-amber">
<p>Oops, something went wrong!</p> <p>Oops, something went wrong!</p>
</div> </div>
<% end %> <% end %>
<%= if assigns[:already_taken] do %>
<div class="w-full text-center bg-amber">
<p>This custom URL has already been taken.</p>
</div>
<% end %>
<div class="w-full h-full"> <div class="w-full h-full">
<%= textarea f, :content, [class: "w-full h-full px-6 py-4 outline-none bg-light-grey font-bold resize-none", placeholder: "> Paste, save, share! (Pasting just a URL will shorten it!)"] %> <%= textarea f, :content, [class: "w-full h-full px-6 py-4 outline-none bg-light-grey font-bold resize-none", placeholder: "> Paste, save, share! (Pasting just a URL will shorten it!)"] %>
<div class="flex absolute top-0 right-0 p-4"> <div class="flex absolute top-0 right-0 p-4">
<%= if @current_user && !assigns[:is_edit] do %>
<div>
<%= text_input f, :custom_url, [class: "px-2 mr-2 outline-none text-black px-2 py-1", placeholder: "Custom URL"] %>
</div>
<% end %>
<button type="submit"> <button type="submit">
<svg <svg
class="h-6 w-6 cursor-pointer fill-current text-white hover:text-amber" class="h-6 w-6 cursor-pointer fill-current text-white hover:text-amber"

View File

@ -0,0 +1,11 @@
<div class="flex relative flex-col w-full h-full">
<ul class="break-word py-4 h-full w-full overflow-y-auto">
<%= for paste <- @pastes do %>
<li class="flex flex-row items-center justify-between">
<a href={ Routes.page_path(@conn, :show, paste) } class="">
https://katb.in/v/<%= paste.id %>
</a>
</li>
<% end %>
</ul>
</div>

View File

@ -1,12 +1,16 @@
<div class="flex relative flex-col w-full h-full"> <div class="flex relative flex-col w-full h-full">
<div class="flex absolute top-0 right-0 p-4"> <div class="flex absolute top-0 right-0 p-4">
<%= if @show_edit do%> <%= if @show_edit do%>
<a href="<%= Routes.page_path(@conn, :edit, @paste.id) %>" class="text-white hover:text-amber"> <a href={ Routes.page_path(@conn, :edit, @paste.id) } class="text-white hover:text-amber">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-6 w-6 cursor-pointer fill-current"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-6 w-6 cursor-pointer fill-current">
<path d="M3 17.46v3.04c0 .28.22.5.5.5h3.04c.13 0 .26-.05.35-.15L17.81 9.94l-3.75-3.75L3.15 17.1c-.1.1-.15.22-.15.36zM20.71 7.04a.996.996 0 0 0 0-1.41l-2.34-2.34a.996.996 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path> <path d="M3 17.46v3.04c0 .28.22.5.5.5h3.04c.13 0 .26-.05.35-.15L17.81 9.94l-3.75-3.75L3.15 17.1c-.1.1-.15.22-.15.36zM20.71 7.04a.996.996 0 0 0 0-1.41l-2.34-2.34a.996.996 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path>
</svg> </svg>
</a> </a>
<% end %> <% end %>
</div> </div>
<code class="break-word px-6 py-4 h-full w-full nomarkdown overflow-y-auto"><%= raw Ketbin.Utils.Syntax.highlight_text(@paste.content, @extension) |> HtmlSanitizeEx.html5 %></code> <div class="break-word px-6 py-4 h-full w-full overflow-y-auto">
<span>
Your shortened url is: <a href={Routes.page_path(@conn, :show, @paste.id) }>https://katb.in/<%= @paste.id %></a>
</span>
</div>
</div> </div>

View File

@ -0,0 +1,16 @@
<div class="flex relative flex-col w-full h-full">
<div class="flex absolute top-0 right-0 p-4">
<%= if @show_edit do%>
<a href={ Routes.page_path(@conn, :edit, @paste.id) } class="text-white hover:text-amber">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-6 w-6 cursor-pointer fill-current">
<path d="M3 17.46v3.04c0 .28.22.5.5.5h3.04c.13 0 .26-.05.35-.15L17.81 9.94l-3.75-3.75L3.15 17.1c-.1.1-.15.22-.15.36zM20.71 7.04a.996.996 0 0 0 0-1.41l-2.34-2.34a.996.996 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path>
</svg>
</a>
<% end %>
</div>
<%= if @extension == "md" do%>
<div class="break-word px-6 py-4 h-full w-full markdown overflow-y-auto"><%= raw Earmark.as_html!(@paste.content, escape: true, gfm_tables: true) |> HtmlSanitizeEx.markdown_html %></div>
<% else %>
<code class="break-word px-6 py-4 h-full w-full overflow-y-auto"><%= raw Ketbin.Utils.Syntax.highlight_text(@paste.content, @extension) |> HtmlSanitizeEx.html5 %></code>
<% end %>
</div>

View File

@ -1,5 +0,0 @@
<h1>Edit Paste</h1>
<%= render "form.html", Map.put(assigns, :action, Routes.paste_path(@conn, :update, @paste)) %>
<span><%= link "Back", to: Routes.paste_path(@conn, :index) %></span>

View File

@ -1,19 +0,0 @@
<%= form_for @changeset, @action, fn f -> %>
<%= if @changeset.action do %>
<div class="alert alert-danger">
<p>Oops, something went wrong! Please check the errors below.</p>
</div>
<% end %>
<%= label f, :is_url %>
<%= checkbox f, :is_url %>
<%= error_tag f, :is_url %>
<%= label f, :content %>
<%= textarea f, :content %>
<%= error_tag f, :content %>
<div>
<%= submit "Save" %>
</div>
<% end %>

View File

@ -1,28 +0,0 @@
<h1>Listing Pastes</h1>
<table>
<thead>
<tr>
<th>Is url</th>
<th>Content</th>
<th></th>
</tr>
</thead>
<tbody>
<%= for paste <- @pastes do %>
<tr>
<td><%= paste.is_url %></td>
<td><%= paste.content %></td>
<td>
<span><%= link "Show", to: Routes.paste_path(@conn, :show, paste) %></span>
<span><%= link "Edit", to: Routes.paste_path(@conn, :edit, paste) %></span>
<span><%= link "Delete", to: Routes.paste_path(@conn, :delete, paste), method: :delete, data: [confirm: "Are you sure?"] %></span>
</td>
</tr>
<% end %>
</tbody>
</table>
<span><%= link "New Paste", to: Routes.paste_path(@conn, :new) %></span>

View File

@ -1 +0,0 @@
<%= render "form.html", Map.put(assigns, :action, Routes.paste_path(@conn, :create)) %>

View File

@ -1,18 +0,0 @@
<h1>Show Paste</h1>
<ul>
<li>
<strong>Is url:</strong>
<%= @paste.is_url %>
</li>
<li>
<strong>Content:</strong>
<%= @paste.content %>
</li>
</ul>
<span><%= link "Edit", to: Routes.paste_path(@conn, :edit, @paste) %></span>
<span><%= link "Back", to: Routes.paste_path(@conn, :index) %></span>

View File

@ -1,4 +1,4 @@
<h1 class="font-bold text-4xl text-amber pt-4 w-full text-center">Settings</h1> <h1 class="font-bold text-4xl text-amber pt-4 w-full text-center">Settings</h1>
<div class="flex w-full h-full justify-center items-center"> <div class="flex w-full h-full justify-center items-center">
<%= form_for @email_changeset, Routes.user_settings_path(@conn, :update), [class: "flex flex-col h-full justify-center items-start m-auto"], fn f -> %> <%= form_for @email_changeset, Routes.user_settings_path(@conn, :update), [class: "flex flex-col h-full justify-center items-start m-auto"], fn f -> %>
@ -63,4 +63,4 @@
<%= submit "Change password" %> <%= submit "Change password" %>
</div> </div>
<% end %> <% end %>
<div> </div>

View File

@ -0,0 +1,18 @@
defmodule KetbinWeb.Api.PasteView do
use KetbinWeb, :view
def render("paste.json", %{paste: paste}) do
%{
id: paste.id,
content: paste.content,
is_url: paste.is_url
}
end
def render("error.json", _assigns) do
%{
success: false,
msg: "Something went wrong"
}
end
end

View File

@ -1,3 +0,0 @@
defmodule KetbinWeb.PasteView do
use KetbinWeb, :view
end

36
mix.exs
View File

@ -5,9 +5,9 @@ defmodule Ketbin.MixProject do
[ [
app: :ketbin, app: :ketbin,
version: "0.1.0", version: "0.1.0",
elixir: "~> 1.7", elixir: "~> 1.12",
elixirc_paths: elixirc_paths(Mix.env()), elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(), compilers: [:phoenix] ++ Mix.compilers(),
start_permanent: Mix.env() == :prod, start_permanent: Mix.env() == :prod,
aliases: aliases(), aliases: aliases(),
deps: deps() deps: deps()
@ -20,7 +20,7 @@ defmodule Ketbin.MixProject do
def application do def application do
[ [
mod: {Ketbin.Application, []}, mod: {Ketbin.Application, []},
extra_applications: [:logger, :runtime_tools, :ssl], extra_applications: [:logger, :runtime_tools, :ssl]
] ]
end end
@ -34,24 +34,26 @@ defmodule Ketbin.MixProject do
defp deps do defp deps do
[ [
{:bcrypt_elixir, "~> 2.0"}, {:bcrypt_elixir, "~> 2.0"},
{:phoenix, "~> 1.5.10"}, {:phoenix, "~> 1.6.7"},
{:phoenix_ecto, "~> 4.1"}, {:phoenix_ecto, "~> 4.4"},
{:ecto_sql, "~> 3.4"}, {:ecto_sql, "~> 3.7"},
{:postgrex, ">= 0.0.0"}, {:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 2.11"}, {:phoenix_html, "~> 3.0"},
{:phoenix_live_reload, "~> 1.2", only: :dev}, {:phoenix_live_view, "~> 0.18.0"},
{:phoenix_live_dashboard, "~> 0.4"}, {:phoenix_live_reload, "~> 1.3", only: :dev},
{:telemetry_metrics, "~> 0.4"}, {:phoenix_live_dashboard, "~> 0.5"},
{:telemetry_poller, "~> 0.4"}, {:telemetry_metrics, "~> 0.6"},
{:gettext, "~> 0.11"}, {:telemetry_poller, "~> 0.5"},
{:jason, "~> 1.0"}, {:gettext, "~> 0.18"},
{:plug_cowboy, "~> 2.0"}, {:jason, "~> 1.2"},
{:phx_gen_auth, "~> 0.7", only: [:dev], runtime: false}, {:plug_cowboy, "~> 2.5"},
{:rustler, "~> 0.22-rc"}, {:cors_plug, "~> 3.0"},
{:rustler, "~> 0.25"},
{:html_sanitize_ex, "~> 1.4"}, {:html_sanitize_ex, "~> 1.4"},
{:hackney, "~> 1.17"}, {:hackney, "~> 1.17"},
{:swoosh, "~> 1.5"}, {:swoosh, "~> 1.5"},
{:gen_smtp, "~> 1.1"} {:gen_smtp, "~> 1.1"},
{:earmark, "~> 1.4"}
] ]
end end

View File

@ -1,49 +1,52 @@
%{ %{
"bcrypt_elixir": {:hex, :bcrypt_elixir, "2.3.0", "6cb662d5c1b0a8858801cf20997bd006e7016aa8c52959c9ef80e0f34fb60b7a", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2c81d61d4f6ed0e5cf7bf27a9109b791ff216a1034b3d541327484f46dd43769"}, "bcrypt_elixir": {:hex, :bcrypt_elixir, "2.3.1", "5114d780459a04f2b4aeef52307de23de961b69e13a5cd98a911e39fda13f420", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "42182d5f46764def15bf9af83739e3bf4ad22661b1c34fc3e88558efced07279"},
"certifi": {:hex, :certifi, "2.6.1", "dbab8e5e155a0763eea978c913ca280a6b544bfa115633fa20249c3d396d9493", [:rebar3], [], "hexpm", "524c97b4991b3849dd5c17a631223896272c6b0af446778ba4675a1dff53bb7e"}, "castore": {:hex, :castore, "1.0.3", "7130ba6d24c8424014194676d608cb989f62ef8039efd50ff4b3f33286d06db8", [:mix], [], "hexpm", "680ab01ef5d15b161ed6a95449fac5c6b8f60055677a8e79acf01b27baa4390b"},
"comeonin": {:hex, :comeonin, "5.3.2", "5c2f893d05c56ae3f5e24c1b983c2d5dfb88c6d979c9287a76a7feb1e1d8d646", [:mix], [], "hexpm", "d0993402844c49539aeadb3fe46a3c9bd190f1ecf86b6f9ebd71957534c95f04"}, "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, "comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"},
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, "cors_plug": {:hex, :cors_plug, "3.0.3", "7c3ac52b39624bc616db2e937c282f3f623f25f8d550068b6710e58d04a0e330", [:mix], [{:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3f2d759e8c272ed3835fab2ef11b46bddab8c1ab9528167bd463b6452edf830d"},
"cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"},
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"},
"db_connection": {:hex, :db_connection, "2.4.0", "d04b1b73795dae60cead94189f1b8a51cc9e1f911c234cc23074017c43c031e5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad416c21ad9f61b3103d254a71b63696ecadb6a917b36f563921e0de00d7d7c8"}, "db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"ecto": {:hex, :ecto, "3.6.2", "efdf52acfc4ce29249bab5417415bd50abd62db7b0603b8bab0d7b996548c2bc", [: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", "efad6dfb04e6f986b8a3047822b0f826d9affe8e4ebdd2aeedbfcb14fd48884e"}, "earmark": {:hex, :earmark, "1.4.38", "ba8fda946c259c6e8f6759d3647d448e9216e2c0afed8c6ae7f8ce1f7072a497", [:mix], [{:earmark_parser, "~> 1.4.32", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "f938e30de4167e7d8f3bf588b01dc041138278dda1e5a13fb9ec89b43dd5ec7f"},
"ecto_sql": {:hex, :ecto_sql, "3.6.2", "9526b5f691701a5181427634c30655ac33d11e17e4069eff3ae1176c764e0ba3", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.6.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 1.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", "5ec9d7e6f742ea39b63aceaea9ac1d1773d574ea40df5a53ef8afbd9242fdb6b"}, "earmark_parser": {:hex, :earmark_parser, "1.4.32", "fa739a0ecfa34493de19426681b23f6814573faee95dfd4b4aafe15a7b5b32c6", [:mix], [], "hexpm", "b8b0dd77d60373e77a3d7e8afa598f325e49e8663a51bcc2b88ef41838cca755"},
"elixir_make": {:hex, :elixir_make, "0.6.2", "7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm", "03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"}, "ecto": {:hex, :ecto, "3.10.2", "6b887160281a61aa16843e47735b8a266caa437f80588c3ab80a8a960e6abe37", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6a895778f0d7648a4b34b486af59a1c8009041fbdf2b17f1ac215eb829c60235"},
"ecto_sql": {:hex, :ecto_sql, "3.10.1", "6ea6b3036a0b0ca94c2a02613fd9f742614b5cfe494c41af2e6571bb034dd94c", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f6a25bdbbd695f12c8171eaff0851fa4c8e72eec1e98c7364402dda9ce11c56b"},
"elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
"expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"gen_smtp": {:hex, :gen_smtp, "1.1.1", "bf9303c31735100631b1d708d629e4c65944319d1143b5c9952054f4a1311d85", [:rebar3], [{:hut, "1.3.0", [hex: :hut, repo: "hexpm", optional: false]}, {:ranch, ">= 1.7.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "51bc50cc017efd4a4248cbc39ea30fb60efa7d4a49688986fafad84434ff9ab7"}, "gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"},
"gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"}, "gettext": {:hex, :gettext, "0.22.2", "6bfca374de34ecc913a28ba391ca184d88d77810a3e427afa8454a71a51341ac", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "8a2d389673aea82d7eae387e6a2ccc12660610080ae7beb19452cfdc1ec30f60"},
"hackney": {:hex, :hackney, "1.17.4", "99da4674592504d3fb0cfef0db84c3ba02b4508bae2dff8c0108baa0d6e0977c", [:rebar3], [{:certifi, "~>2.6.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "de16ff4996556c8548d512f4dbe22dd58a587bf3332e7fd362430a7ef3986b16"}, "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.4.2", "c479398b6de798c03eb5d04a0a9a9159d73508f83f6590a00b8eacba3619cf4c", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm", "aef6c28585d06a9109ad591507e508854c5559561f950bbaea773900dd369b0e"},
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.4.1", "e8a67da405fe9f0d1be121a40a60f70811192033a5b8d00a95dddd807f5e053e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm", "68d92656f47cd73598c45ad2394561f025c8c65d146001b955fd7b517858962a"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"hut": {:hex, :hut, "1.3.0", "71f2f054e657c03f959cf1acc43f436ea87580696528ca2a55c8afb1b06c85e7", [:"erlang.mk", :rebar, :rebar3], [], "hexpm", "7e15d28555d8a1f2b5a3a931ec120af0753e4853a4c66053db354f35bf9ab563"}, "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mochiweb": {:hex, :mochiweb, "2.21.0", "3fe5c3403606726d7bc6dabbf36f9d634d5364ce7f33ce73442937fa54feec37", [:rebar3], [], "hexpm", "f848bfa1b75c32d56da9d2730245e34df4b39079c5d45d7b966b072ba53f8a13"}, "mochiweb": {:hex, :mochiweb, "2.22.0", "f104d6747c01a330c38613561977e565b788b9170055c5241ac9dd6e4617cba5", [:rebar3], [], "hexpm", "cbbd1fd315d283c576d1c8a13e0738f6dafb63dc840611249608697502a07655"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"phoenix": {:hex, :phoenix, "1.5.10", "3ee7d5c17ff9626d72d374d8fc8909bf00f4323fd15549fbe3abbbd38b5299c8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f9c2eaa5a8fe5a412610c6aa84ccdb6f3e92f333d4df7fbaeb0d5a157dbfb48d"}, "phoenix": {:hex, :phoenix, "1.6.16", "e5bdd18c7a06da5852a25c7befb72246de4ddc289182285f8685a40b7b5f5451", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e15989ff34f670a96b95ef6d1d25bad0d9c50df5df40b671d8f4a669e050ac39"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.3.0", "2c69a452c2e0ee8c93345ae1cdc1696ef4877ff9cbb15c305def41960c3c4ebf", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "0ac491924217550c8f42c81c1f390b5d81517d12ceaf9abf3e701156760a848e"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.2", "b21bd01fdeffcfe2fab49e4942aa938b6d3e89e93a480d4aee58085560a0bc0d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "70242edd4601d50b69273b057ecf7b684644c19ee750989fd555625ae4ce8f5d"},
"phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"}, "phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.4.0", "87990e68b60213d7487e65814046f9a2bed4a67886c943270125913499b3e5c3", [:mix], [{:ecto_psql_extras, "~> 0.4.1 or ~> 0.5", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.14.1 or ~> 2.15", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.15.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.4.0 or ~> 0.5.0 or ~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "8d52149e58188e9e4497cc0d8900ab94d9b66f96998ec38c47c7a4f8f4f50e57"}, "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [: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", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.15.7", "09720b8e5151b3ca8ef739cd7626d4feb987c69ba0b509c9bbdb861d5a365881", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.5.7", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 0.5", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a756cf662420272d0f1b3b908cce5222163b5a95aa9bab404f9d29aff53276e"}, "phoenix_live_view": {:hex, :phoenix_live_view, "0.18.18", "1f38fbd7c363723f19aad1a04b5490ff3a178e37daaf6999594d5f34796c47fc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a5810d0472f3189ede6d2a95bda7f31c6113156b91784a3426cb0ab6a6d85214"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
"phx_gen_auth": {:hex, :phx_gen_auth, "0.7.0", "2e10e9527b6b71abbfbb4601c7dc4aa4fb9f2db6f9a6be457c468b7f2b0f6319", [:mix], [{:phoenix, "~> 1.5.2", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b9dc3e3b866e67c5db8f00f4a2adb28fc8636e794f78600e35aba0e55bdac209"}, "phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"},
"plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"}, "phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"},
"plug_cowboy": {:hex, :plug_cowboy, "2.5.1", "7cc96ff645158a94cf3ec9744464414f02287f832d6847079adfe0b58761cbd0", [: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 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "107d0a5865fa92bcb48e631cc0729ae9ccfa0a9f9a1bd8f01acb513abf1c2d64"}, "plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"},
"plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"},
"postgrex": {:hex, :postgrex, "0.15.10", "2809dee1b1d76f7cbabe570b2a9285c2e7b41be60cf792f5f2804a54b838a067", [: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", "1560ca427542f6b213f8e281633ae1a3b31cdbcd84ebd7f50628765b8f6132be"}, "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"},
"postgrex": {:hex, :postgrex, "0.17.1", "01c29fd1205940ee55f7addb8f1dc25618ca63a8817e56fac4f6846fc2cddcbe", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "14b057b488e73be2beee508fb1955d8db90d6485c6466428fe9ccf1d6692a555"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"rustler": {:hex, :rustler, "0.22.0", "e2930f9d6933e910f87526bb0a7f904e32b62a7e838a3ca4a884ee7fdfb957ed", [:mix], [{:toml, "~> 0.5.2", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "01f5989dd511ebec09be481e07d3c59773d5373c5061e09d3ebc3ef61811b49d"}, "rustler": {:hex, :rustler, "0.29.0", "46b7792dfecfd8aab323d1bbf417086b67f1d394733a7e67808b20cd2d455a36", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "3fec912e623c111745dcc768e28784dfba6aabae13d0d41f1f07bbd8a52a957a"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"swoosh": {:hex, :swoosh, "1.5.0", "2be4cfc1be10f2203d1854c85b18d8c7be0321445a782efd53ef0b2b88f03ce4", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b53891359e3ddca263ece784051243de84c9244c421a0dee1bff1d52fc5ca420"}, "swoosh": {:hex, :swoosh, "1.11.2", "39dd1e44f75bc03a34366d5f830599d248de2b9caaf05704dc76c0507a58c6a1", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4c43f4591503e7d5bf028314af8ac7c06d1c4d340aa23faeefabfa2543fa726e"},
"telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"}, "telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
"telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"}, "telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"},
"toml": {:hex, :toml, "0.5.2", "e471388a8726d1ce51a6b32f864b8228a1eb8edc907a0edf2bb50eab9321b526", [:mix], [], "hexpm", "f1e3dabef71fb510d015fad18c0e05e7c57281001141504c6b69d94e99750a07"}, "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
} }

View File

@ -1,4 +1,4 @@
[target.x86_64-apple-darwin] [target.'cfg(target_os = "macos")']
rustflags = [ rustflags = [
"-C", "link-arg=-undefined", "-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup", "-C", "link-arg=dynamic_lookup",

View File

@ -9,16 +9,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]] [[package]]
name = "autocfg" name = "aho-corasick"
version = "1.0.1" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
dependencies = [
"memchr",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.13.0" version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
[[package]] [[package]]
name = "bincode" name = "bincode"
@ -37,9 +46,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.69" version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -47,34 +56,22 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"num-integer",
"num-traits",
]
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.2.1" version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.20" version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
dependencies = [ dependencies = [
"cfg-if",
"crc32fast", "crc32fast",
"libc",
"miniz_oxide", "miniz_oxide",
] ]
@ -86,24 +83,21 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.11.2" version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.3.3" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
dependencies = [
"unicode-segmentation",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.7.0" version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@ -111,9 +105,9 @@ dependencies = [
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.7" version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]] [[package]]
name = "ketbin_utils_syntax" name = "ketbin_utils_syntax"
@ -137,9 +131,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.99" version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]] [[package]]
name = "line-wrap" name = "line-wrap"
@ -152,56 +146,48 @@ dependencies = [
[[package]] [[package]]
name = "linked-hash-map" name = "linked-hash-map"
version = "0.5.4" version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.4.4" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [ dependencies = [
"adler", "adler",
"autocfg",
] ]
[[package]] [[package]]
name = "num-integer" name = "once_cell"
version = "0.1.44" version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "onig" name = "onig"
version = "6.2.0" version = "6.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16fd3c0e73b516af509c13c4ba76ec0c987ce20d78b38cff356b8d01fc6a6c0" checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"lazy_static",
"libc", "libc",
"once_cell",
"onig_sys", "onig_sys",
] ]
[[package]] [[package]]
name = "onig_sys" name = "onig_sys"
version = "69.7.0" version = "69.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fd9442a09e4fbd08d196ddf419b2c79a43c3a46c800320cc841d45c2449a240" checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7"
dependencies = [ dependencies = [
"cc", "cc",
"pkg-config", "pkg-config",
@ -209,53 +195,79 @@ dependencies = [
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.19" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]] [[package]]
name = "plist" name = "plist"
version = "1.2.1" version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a38d026d73eeaf2ade76309d0c65db5a35ecf649e3cec428db316243ea9d6711" checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590"
dependencies = [ dependencies = [
"base64", "base64",
"chrono",
"indexmap", "indexmap",
"line-wrap", "line-wrap",
"quick-xml",
"serde", "serde",
"xml-rs", "time",
] ]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.28" version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
dependencies = [ dependencies = [
"unicode-xid", "unicode-ident",
]
[[package]]
name = "quick-xml"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1"
dependencies = [
"memchr",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.9" version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]] [[package]]
name = "regex-syntax" name = "regex"
version = "0.6.25" version = "1.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.7.2",
]
[[package]]
name = "regex-syntax"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
[[package]] [[package]]
name = "rustler" name = "rustler"
version = "0.22.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b787d3b2a80007f41cd4c0c310cdeb3936192768159585f65ecc7e96faf97fc3" checksum = "095fb0fb2864560480609c5b1427fe9f3872f6b3e400036f5531e8f06ff33026"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"rustler_codegen", "rustler_codegen",
@ -264,9 +276,9 @@ dependencies = [
[[package]] [[package]]
name = "rustler_codegen" name = "rustler_codegen"
version = "0.22.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a1f867002b6f0130f47abf215cac4405646db6f5d7b009b21c890980490aa4" checksum = "a8911f25973c1d68a3ffdea53d664026f6b0877c949bd3f9f5bc263385c33553"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
@ -276,18 +288,19 @@ dependencies = [
[[package]] [[package]]
name = "rustler_sys" name = "rustler_sys"
version = "2.1.1" version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cb382fde4f421c51555919e9920b058c0286f6bf59e53d02eb4d281eae6758b" checksum = "0b311902a5c224452d0d8e1821a4b682d43f58248a2c559f613a7b52e0980075"
dependencies = [ dependencies = [
"regex",
"unreachable", "unreachable",
] ]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.5" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
[[package]] [[package]]
name = "safemem" name = "safemem"
@ -306,15 +319,15 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.127" version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.127" version = "1.0.164"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -323,9 +336,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.66" version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@ -334,13 +347,13 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.74" version = "2.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"unicode-xid", "unicode-ident",
] ]
[[package]] [[package]]
@ -357,7 +370,7 @@ dependencies = [
"lazycell", "lazycell",
"onig", "onig",
"plist", "plist",
"regex-syntax", "regex-syntax 0.6.29",
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
@ -366,16 +379,37 @@ dependencies = [
] ]
[[package]] [[package]]
name = "unicode-segmentation" name = "time"
version = "1.8.0" version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd"
dependencies = [
"itoa",
"serde",
"time-core",
"time-macros",
]
[[package]] [[package]]
name = "unicode-xid" name = "time-core"
version = "0.2.2" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
[[package]]
name = "time-macros"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
dependencies = [
"time-core",
]
[[package]]
name = "unicode-ident"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
[[package]] [[package]]
name = "unreachable" name = "unreachable"
@ -394,12 +428,11 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.3.2" version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
dependencies = [ dependencies = [
"same-file", "same-file",
"winapi",
"winapi-util", "winapi-util",
] ]
@ -434,12 +467,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xml-rs"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
[[package]] [[package]]
name = "yaml-rust" name = "yaml-rust"
version = "0.4.5" version = "0.4.5"

View File

@ -10,5 +10,5 @@ path = "src/lib.rs"
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
rustler = "0.22.0" rustler = { version = "*", features = ["nif_version_2_17"] }
syntect = "4.6" syntect = "4.6"

View File

@ -4,16 +4,16 @@ defmodule Ketbin.Repo.Migrations.CreateUsersAuthTables do
def change do def change do
execute "CREATE EXTENSION IF NOT EXISTS citext", "" execute "CREATE EXTENSION IF NOT EXISTS citext", ""
create table(:users) do create_if_not_exists table(:users) do
add :email, :citext, null: false add :email, :citext, null: false
add :hashed_password, :string, null: false add :hashed_password, :string, null: false
add :confirmed_at, :naive_datetime add :confirmed_at, :naive_datetime
timestamps() timestamps()
end end
create unique_index(:users, [:email]) create_if_not_exists unique_index(:users, [:email])
create table(:users_tokens) do create_if_not_exists table(:users_tokens) do
add :user_id, references(:users, on_delete: :delete_all), null: false add :user_id, references(:users, on_delete: :delete_all), null: false
add :token, :binary, null: false add :token, :binary, null: false
add :context, :string, null: false add :context, :string, null: false
@ -21,7 +21,7 @@ defmodule Ketbin.Repo.Migrations.CreateUsersAuthTables do
timestamps(updated_at: false) timestamps(updated_at: false)
end end
create index(:users_tokens, [:user_id]) create_if_not_exists index(:users_tokens, [:user_id])
create unique_index(:users_tokens, [:context, :token]) create_if_not_exists unique_index(:users_tokens, [:context, :token])
end end
end end

View File

@ -2,13 +2,13 @@ defmodule Ketbin.Repo.Migrations.CreatePastes do
use Ecto.Migration use Ecto.Migration
def change do def change do
create table(:pastes, primary_key: false) do create_if_not_exists table(:pastes, primary_key: false) do
add :id, :string, primary_key: true add :id, :string, primary_key: true
add :is_url, :boolean, default: false, null: false add :is_url, :boolean, default: false, null: false
add :content, :text, null: false add :content, :text, null: false
add :belongs_to, references(:users, on_delete: :delete_all) add :belongs_to, references(:users, on_delete: :delete_all)
end end
create index(:pastes, [:belongs_to]) create_if_not_exists index(:pastes, [:belongs_to])
end end
end end

View File

@ -0,0 +1,10 @@
defmodule Ketbin.Repo.Migrations.AddTimestampsPastes do
use Ecto.Migration
def change do
alter table(:pastes) do
add :inserted_at, :naive_datetime, null: false, default: fragment("CURRENT_TIMESTAMP")
add :updated_at, :naive_datetime, null: false, default: fragment("CURRENT_TIMESTAMP")
end
end
end

220
priv/repo/structure.sql Normal file
View File

@ -0,0 +1,220 @@
--
-- PostgreSQL database dump
--
-- Dumped from database version 13.4 (Debian 13.4-1.pgdg100+1)
-- Dumped by pg_dump version 13.4
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
--
-- Name: citext; Type: EXTENSION; Schema: -; Owner: -
--
CREATE EXTENSION IF NOT EXISTS citext WITH SCHEMA public;
--
-- Name: EXTENSION citext; Type: COMMENT; Schema: -; Owner: -
--
COMMENT ON EXTENSION citext IS 'data type for case-insensitive character strings';
SET default_tablespace = '';
SET default_table_access_method = heap;
--
-- Name: pastes; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.pastes (
id character varying(255) NOT NULL,
is_url boolean DEFAULT false NOT NULL,
content text NOT NULL,
belongs_to bigint
);
--
-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.schema_migrations (
version bigint NOT NULL,
inserted_at timestamp(0) without time zone
);
--
-- Name: users; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.users (
id bigint NOT NULL,
email public.citext NOT NULL,
hashed_password character varying(255) NOT NULL,
confirmed_at timestamp(0) without time zone,
inserted_at timestamp(0) without time zone NOT NULL,
updated_at timestamp(0) without time zone NOT NULL
);
--
-- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.users_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id;
--
-- Name: users_tokens; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.users_tokens (
id bigint NOT NULL,
user_id bigint NOT NULL,
token bytea NOT NULL,
context character varying(255) NOT NULL,
sent_to character varying(255),
inserted_at timestamp(0) without time zone NOT NULL
);
--
-- Name: users_tokens_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.users_tokens_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: users_tokens_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.users_tokens_id_seq OWNED BY public.users_tokens.id;
--
-- Name: users id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass);
--
-- Name: users_tokens id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.users_tokens ALTER COLUMN id SET DEFAULT nextval('public.users_tokens_id_seq'::regclass);
--
-- Name: pastes pastes_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.pastes
ADD CONSTRAINT pastes_pkey PRIMARY KEY (id);
--
-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.schema_migrations
ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);
--
-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.users
ADD CONSTRAINT users_pkey PRIMARY KEY (id);
--
-- Name: users_tokens users_tokens_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.users_tokens
ADD CONSTRAINT users_tokens_pkey PRIMARY KEY (id);
--
-- Name: pastes_belongs_to_index; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX pastes_belongs_to_index ON public.pastes USING btree (belongs_to);
--
-- Name: users_email_index; Type: INDEX; Schema: public; Owner: -
--
CREATE UNIQUE INDEX users_email_index ON public.users USING btree (email);
--
-- Name: users_tokens_context_token_index; Type: INDEX; Schema: public; Owner: -
--
CREATE UNIQUE INDEX users_tokens_context_token_index ON public.users_tokens USING btree (context, token);
--
-- Name: users_tokens_user_id_index; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX users_tokens_user_id_index ON public.users_tokens USING btree (user_id);
--
-- Name: pastes pastes_belongs_to_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.pastes
ADD CONSTRAINT pastes_belongs_to_fkey FOREIGN KEY (belongs_to) REFERENCES public.users(id) ON DELETE CASCADE;
--
-- Name: users_tokens users_tokens_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.users_tokens
ADD CONSTRAINT users_tokens_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
--
-- PostgreSQL database dump complete
--
INSERT INTO public."schema_migrations" (version) VALUES (20210811065554);
INSERT INTO public."schema_migrations" (version) VALUES (20210811213141);

3
rel/overlays/bin/server Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
cd -P -- "$(dirname -- "$0")"
PHX_SERVER=true exec ./ketbin start

2
rel/overlays/bin/server.bat Executable file
View File

@ -0,0 +1,2 @@
set PHX_SERVER=true
call "%~dp0\ketbin" start

6
renovate.json Normal file
View File

@ -0,0 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base"
]
}

5
sample.env Normal file
View File

@ -0,0 +1,5 @@
DATABASE_URL='<insert db url here>'
SECRET_KEY_BASE='<insert secret key here>'
SWOOSH_USERNAME='noreply@katb.in'
SWOOSH_PASSWORD='<insert your password here>'
SWOOSH_SMTP_RELAY='smtp.example.com'

View File

@ -75,6 +75,7 @@ defmodule KetbinWeb.PasteControllerTest do
test "deletes chosen paste", %{conn: conn, paste: paste} do test "deletes chosen paste", %{conn: conn, paste: paste} do
conn = delete(conn, Routes.paste_path(conn, :delete, paste)) conn = delete(conn, Routes.paste_path(conn, :delete, paste))
assert redirected_to(conn) == Routes.paste_path(conn, :index) assert redirected_to(conn) == Routes.paste_path(conn, :index)
assert_error_sent 404, fn -> assert_error_sent 404, fn ->
get(conn, Routes.paste_path(conn, :show, paste)) get(conn, Routes.paste_path(conn, :show, paste))
end end