update
This commit is contained in:
parent
e2967f68b2
commit
ef2a6c41b4
39 changed files with 2349 additions and 30 deletions
|
|
@ -16,29 +16,42 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
|
// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
|
||||||
import "phoenix_html"
|
import "phoenix_html";
|
||||||
// Establish Phoenix Socket and LiveView configuration.
|
// Establish Phoenix Socket and LiveView configuration.
|
||||||
import {Socket} from "phoenix"
|
import { Socket } from "phoenix";
|
||||||
import {LiveSocket} from "phoenix_live_view"
|
import { LiveSocket } from "phoenix_live_view";
|
||||||
import topbar from "../vendor/topbar"
|
import topbar from "../vendor/topbar";
|
||||||
|
|
||||||
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
|
window.addEventListener("phx:copy", (event) => {
|
||||||
|
let button = event.detail.dispatcher;
|
||||||
|
let text = event.target.innerText;
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
|
button.innerText = "Copied!";
|
||||||
|
setTimeout(() => {
|
||||||
|
button.innerText = "Copy";
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let csrfToken = document
|
||||||
|
.querySelector("meta[name='csrf-token']")
|
||||||
|
.getAttribute("content");
|
||||||
let liveSocket = new LiveSocket("/live", Socket, {
|
let liveSocket = new LiveSocket("/live", Socket, {
|
||||||
longPollFallbackMs: 2500,
|
longPollFallbackMs: 2500,
|
||||||
params: {_csrf_token: csrfToken}
|
params: { _csrf_token: csrfToken },
|
||||||
})
|
});
|
||||||
|
|
||||||
// Show progress bar on live navigation and form submits
|
// Show progress bar on live navigation and form submits
|
||||||
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
|
topbar.config({ barColors: { 0: "#29d" }, shadowColor: "rgba(0, 0, 0, .3)" });
|
||||||
window.addEventListener("phx:page-loading-start", _info => topbar.show(300))
|
window.addEventListener("phx:page-loading-start", (_info) => topbar.show(300));
|
||||||
window.addEventListener("phx:page-loading-stop", _info => topbar.hide())
|
window.addEventListener("phx:page-loading-stop", (_info) => topbar.hide());
|
||||||
|
|
||||||
// connect if there are any LiveViews on the page
|
// connect if there are any LiveViews on the page
|
||||||
liveSocket.connect()
|
liveSocket.connect();
|
||||||
|
|
||||||
// expose liveSocket on window for web console debug logs and latency simulation:
|
// expose liveSocket on window for web console debug logs and latency simulation:
|
||||||
// >> liveSocket.enableDebug()
|
// >> liveSocket.enableDebug()
|
||||||
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
|
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
|
||||||
// >> liveSocket.disableLatencySim()
|
// >> liveSocket.disableLatencySim()
|
||||||
window.liveSocket = liveSocket
|
window.liveSocket = liveSocket;
|
||||||
|
|
||||||
|
|
|
||||||
503
assets/package-lock.json
generated
503
assets/package-lock.json
generated
|
|
@ -13,7 +13,12 @@
|
||||||
"phoenix": "^1.7.14",
|
"phoenix": "^1.7.14",
|
||||||
"phoenix_html": "^3.3.4",
|
"phoenix_html": "^3.3.4",
|
||||||
"phoenix_live_view": "^1.0.0-rc.7",
|
"phoenix_live_view": "^1.0.0-rc.7",
|
||||||
|
"shiki": "^1.22.0",
|
||||||
"tailwindcss": "^3.4.14"
|
"tailwindcss": "^3.4.14"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/phoenix": "^1.6.5",
|
||||||
|
"@types/phoenix_live_view": "^0.18.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@alloc/quick-lru": {
|
"node_modules/@alloc/quick-lru": {
|
||||||
|
|
@ -530,6 +535,57 @@
|
||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@shikijs/core": {
|
||||||
|
"version": "1.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.22.0.tgz",
|
||||||
|
"integrity": "sha512-S8sMe4q71TJAW+qG93s5VaiihujRK6rqDFqBnxqvga/3LvqHEnxqBIOPkt//IdXVtHkQWKu4nOQNk0uBGicU7Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@shikijs/engine-javascript": "1.22.0",
|
||||||
|
"@shikijs/engine-oniguruma": "1.22.0",
|
||||||
|
"@shikijs/types": "1.22.0",
|
||||||
|
"@shikijs/vscode-textmate": "^9.3.0",
|
||||||
|
"@types/hast": "^3.0.4",
|
||||||
|
"hast-util-to-html": "^9.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@shikijs/engine-javascript": {
|
||||||
|
"version": "1.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.22.0.tgz",
|
||||||
|
"integrity": "sha512-AeEtF4Gcck2dwBqCFUKYfsCq0s+eEbCEbkUuFou53NZ0sTGnJnJ/05KHQFZxpii5HMXbocV9URYVowOP2wH5kw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@shikijs/types": "1.22.0",
|
||||||
|
"@shikijs/vscode-textmate": "^9.3.0",
|
||||||
|
"oniguruma-to-js": "0.4.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@shikijs/engine-oniguruma": {
|
||||||
|
"version": "1.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.22.0.tgz",
|
||||||
|
"integrity": "sha512-5iBVjhu/DYs1HB0BKsRRFipRrD7rqjxlWTj4F2Pf+nQSPqc3kcyqFFeZXnBMzDf0HdqaFVvhDRAGiYNvyLP+Mw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@shikijs/types": "1.22.0",
|
||||||
|
"@shikijs/vscode-textmate": "^9.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@shikijs/types": {
|
||||||
|
"version": "1.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.22.0.tgz",
|
||||||
|
"integrity": "sha512-Fw/Nr7FGFhlQqHfxzZY8Cwtwk5E9nKDUgeLjZgt3UuhcM3yJR9xj3ZGNravZZok8XmEZMiYkSMTPlPkULB8nww==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@shikijs/vscode-textmate": "^9.3.0",
|
||||||
|
"@types/hast": "^3.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@shikijs/vscode-textmate": {
|
||||||
|
"version": "9.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.3.0.tgz",
|
||||||
|
"integrity": "sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@tailwindcss/forms": {
|
"node_modules/@tailwindcss/forms": {
|
||||||
"version": "0.5.9",
|
"version": "0.5.9",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.9.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.9.tgz",
|
||||||
|
|
@ -542,6 +598,53 @@
|
||||||
"tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20"
|
"tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/hast": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/mdast": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/phoenix": {
|
||||||
|
"version": "1.6.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.5.tgz",
|
||||||
|
"integrity": "sha512-xegpDuR+z0UqG9fwHqNoy3rI7JDlvaPh2TY47Fl80oq6g+hXT+c/LEuE43X48clZ6lOfANl5WrPur9fYO1RJ/w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/phoenix_live_view": {
|
||||||
|
"version": "0.18.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/phoenix_live_view/-/phoenix_live_view-0.18.5.tgz",
|
||||||
|
"integrity": "sha512-mxj3KVkp+wX+hLFAILTbfIx5Q890TBgs/jxc6nmmVv6bW6Z9qer/5tZtGOcL3IES75QqqOHSTrjwwz0iZBs0lw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/phoenix": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/unist": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@ungap/structured-clone": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/ansi-regex": {
|
"node_modules/ansi-regex": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||||
|
|
@ -639,6 +742,36 @@
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ccount": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/character-entities-html4": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/character-entities-legacy": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||||
|
|
@ -693,6 +826,16 @@
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/comma-separated-tokens": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/commander": {
|
"node_modules/commander": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
||||||
|
|
@ -728,6 +871,28 @@
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dequal": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/devlop": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dequal": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/didyoumean": {
|
"node_modules/didyoumean": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||||
|
|
@ -923,6 +1088,52 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/hast-util-to-html": {
|
||||||
|
"version": "9.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.3.tgz",
|
||||||
|
"integrity": "sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^3.0.0",
|
||||||
|
"@types/unist": "^3.0.0",
|
||||||
|
"ccount": "^2.0.0",
|
||||||
|
"comma-separated-tokens": "^2.0.0",
|
||||||
|
"hast-util-whitespace": "^3.0.0",
|
||||||
|
"html-void-elements": "^3.0.0",
|
||||||
|
"mdast-util-to-hast": "^13.0.0",
|
||||||
|
"property-information": "^6.0.0",
|
||||||
|
"space-separated-tokens": "^2.0.0",
|
||||||
|
"stringify-entities": "^4.0.0",
|
||||||
|
"zwitch": "^2.0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/hast-util-whitespace": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^3.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/html-void-elements": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-binary-path": {
|
"node_modules/is-binary-path": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
|
|
@ -1040,6 +1251,27 @@
|
||||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/mdast-util-to-hast": {
|
||||||
|
"version": "13.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz",
|
||||||
|
"integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^3.0.0",
|
||||||
|
"@types/mdast": "^4.0.0",
|
||||||
|
"@ungap/structured-clone": "^1.0.0",
|
||||||
|
"devlop": "^1.0.0",
|
||||||
|
"micromark-util-sanitize-uri": "^2.0.0",
|
||||||
|
"trim-lines": "^3.0.0",
|
||||||
|
"unist-util-position": "^5.0.0",
|
||||||
|
"unist-util-visit": "^5.0.0",
|
||||||
|
"vfile": "^6.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/merge2": {
|
"node_modules/merge2": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||||
|
|
@ -1049,6 +1281,95 @@
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/micromark-util-character": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "GitHub Sponsors",
|
||||||
|
"url": "https://github.com/sponsors/unifiedjs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "OpenCollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"micromark-util-symbol": "^2.0.0",
|
||||||
|
"micromark-util-types": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/micromark-util-encode": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "GitHub Sponsors",
|
||||||
|
"url": "https://github.com/sponsors/unifiedjs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "OpenCollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/micromark-util-sanitize-uri": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "GitHub Sponsors",
|
||||||
|
"url": "https://github.com/sponsors/unifiedjs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "OpenCollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"micromark-util-character": "^2.0.0",
|
||||||
|
"micromark-util-encode": "^2.0.0",
|
||||||
|
"micromark-util-symbol": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/micromark-util-symbol": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "GitHub Sponsors",
|
||||||
|
"url": "https://github.com/sponsors/unifiedjs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "OpenCollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/micromark-util-types": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "GitHub Sponsors",
|
||||||
|
"url": "https://github.com/sponsors/unifiedjs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "OpenCollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/micromatch": {
|
"node_modules/micromatch": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||||
|
|
@ -1151,6 +1472,18 @@
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/oniguruma-to-js": {
|
||||||
|
"version": "0.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/oniguruma-to-js/-/oniguruma-to-js-0.4.3.tgz",
|
||||||
|
"integrity": "sha512-X0jWUcAlxORhOqqBREgPMgnshB7ZGYszBNspP+tS9hPD3l13CdaXcHbgImoHUHlrvGx/7AvFEkTRhAGYh+jzjQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"regex": "^4.3.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/package-json-from-dist": {
|
"node_modules/package-json-from-dist": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||||
|
|
@ -1396,6 +1729,16 @@
|
||||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/property-information": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
|
@ -1437,6 +1780,12 @@
|
||||||
"node": ">=8.10.0"
|
"node": ">=8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/regex": {
|
||||||
|
"version": "4.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/regex/-/regex-4.3.3.tgz",
|
||||||
|
"integrity": "sha512-r/AadFO7owAq1QJVeZ/nq9jNS1vyZt+6t1p/E59B56Rn2GCya+gr1KSyOzNL/er+r+B7phv5jG2xU2Nz1YkmJg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.8",
|
"version": "1.22.8",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||||
|
|
@ -1508,6 +1857,20 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/shiki": {
|
||||||
|
"version": "1.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/shiki/-/shiki-1.22.0.tgz",
|
||||||
|
"integrity": "sha512-/t5LlhNs+UOKQCYBtl5ZsH/Vclz73GIqT2yQsCBygr8L/ppTdmpL4w3kPLoZJbMKVWtoG77Ue1feOjZfDxvMkw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@shikijs/core": "1.22.0",
|
||||||
|
"@shikijs/engine-javascript": "1.22.0",
|
||||||
|
"@shikijs/engine-oniguruma": "1.22.0",
|
||||||
|
"@shikijs/types": "1.22.0",
|
||||||
|
"@shikijs/vscode-textmate": "^9.3.0",
|
||||||
|
"@types/hast": "^3.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/signal-exit": {
|
"node_modules/signal-exit": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||||
|
|
@ -1529,6 +1892,16 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/space-separated-tokens": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/string-width": {
|
"node_modules/string-width": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||||
|
|
@ -1588,6 +1961,20 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stringify-entities": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"character-entities-html4": "^2.0.0",
|
||||||
|
"character-entities-legacy": "^3.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/strip-ansi": {
|
"node_modules/strip-ansi": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||||
|
|
@ -1729,18 +2116,124 @@
|
||||||
"node": ">=8.0"
|
"node": ">=8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/trim-lines": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ts-interface-checker": {
|
"node_modules/ts-interface-checker": {
|
||||||
"version": "0.1.13",
|
"version": "0.1.13",
|
||||||
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
||||||
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/unist-util-is": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^3.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/unist-util-position": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^3.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/unist-util-stringify-position": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^3.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/unist-util-visit": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^3.0.0",
|
||||||
|
"unist-util-is": "^6.0.0",
|
||||||
|
"unist-util-visit-parents": "^6.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/unist-util-visit-parents": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^3.0.0",
|
||||||
|
"unist-util-is": "^6.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/util-deprecate": {
|
"node_modules/util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/vfile": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^3.0.0",
|
||||||
|
"vfile-message": "^4.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vfile-message": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^3.0.0",
|
||||||
|
"unist-util-stringify-position": "^4.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
@ -1858,6 +2351,16 @@
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14"
|
"node": ">= 14"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zwitch": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,14 @@
|
||||||
"@esbuild/linux-x64": "^0.24.0",
|
"@esbuild/linux-x64": "^0.24.0",
|
||||||
"@tailwindcss/forms": "^0.5.9",
|
"@tailwindcss/forms": "^0.5.9",
|
||||||
"esbuild": "^0.24.0",
|
"esbuild": "^0.24.0",
|
||||||
"phoenix": "^1.7.14",
|
"phoenix": "file:../deps/phoenix",
|
||||||
"phoenix_html": "^3.3.4",
|
"phoenix_html": "file:../deps/phoenix_html",
|
||||||
"phoenix_live_view": "^1.0.0-rc.7",
|
"phoenix_live_view": "file:../deps/phoenix_live_view",
|
||||||
|
"shiki": "^1.22.0",
|
||||||
"tailwindcss": "^3.4.14"
|
"tailwindcss": "^3.4.14"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/phoenix": "^1.6.5",
|
||||||
|
"@types/phoenix_live_view": "^0.18.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,22 @@ config :tailwind,
|
||||||
cd: Path.expand("../assets", __DIR__)
|
cd: Path.expand("../assets", __DIR__)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
config :ex_aws,
|
||||||
|
access_key_id: System.get_env("MINIO_ACCESS_KEY", "PvV9r38q0lA8CmT5bqpU"),
|
||||||
|
secret_access_key:
|
||||||
|
System.get_env("MINIO_SECRET_KEY", "wrEhRQ4ughUPw06lKxRlo9Bv4ciBa7i7BDJsRP0o"),
|
||||||
|
json_codec: Jason
|
||||||
|
|
||||||
|
config :ex_aws, :s3,
|
||||||
|
scheme: "https://",
|
||||||
|
host: "s3.zoeys.computer",
|
||||||
|
port: 443,
|
||||||
|
region: "us-east-1"
|
||||||
|
|
||||||
|
config :nanoid,
|
||||||
|
size: 21,
|
||||||
|
alphabet: "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
# Configures Elixir's Logger
|
# Configures Elixir's Logger
|
||||||
config :logger, :console,
|
config :logger, :console,
|
||||||
format: "$time $metadata[$level] $message\n",
|
format: "$time $metadata[$level] $message\n",
|
||||||
|
|
|
||||||
192
deps.nix
192
deps.nix
|
|
@ -154,6 +154,21 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
certifi =
|
||||||
|
let
|
||||||
|
version = "2.12.0";
|
||||||
|
in
|
||||||
|
buildRebar3 {
|
||||||
|
inherit version;
|
||||||
|
name = "certifi";
|
||||||
|
|
||||||
|
src = fetchHex {
|
||||||
|
inherit version;
|
||||||
|
pkg = "certifi";
|
||||||
|
sha256 = "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
comeonin =
|
comeonin =
|
||||||
let
|
let
|
||||||
version = "5.5.0";
|
version = "5.5.0";
|
||||||
|
|
@ -281,7 +296,7 @@ let
|
||||||
sha256 = "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040";
|
sha256 = "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040";
|
||||||
};
|
};
|
||||||
|
|
||||||
beamDeps = [ castore ];
|
beamDeps = [ castore certifi ];
|
||||||
};
|
};
|
||||||
|
|
||||||
esbuild =
|
esbuild =
|
||||||
|
|
@ -301,6 +316,40 @@ let
|
||||||
beamDeps = [ castore jason ];
|
beamDeps = [ castore jason ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ex_aws =
|
||||||
|
let
|
||||||
|
version = "2.5.6";
|
||||||
|
in
|
||||||
|
buildMix {
|
||||||
|
inherit version;
|
||||||
|
name = "ex_aws";
|
||||||
|
|
||||||
|
src = fetchHex {
|
||||||
|
inherit version;
|
||||||
|
pkg = "ex_aws";
|
||||||
|
sha256 = "c69eec59e31fdd89d0beeb1d97e16518dd1b23ad95b3d5c9f1dcfec23d97f960";
|
||||||
|
};
|
||||||
|
|
||||||
|
beamDeps = [ hackney jason mime sweet_xml telemetry ];
|
||||||
|
};
|
||||||
|
|
||||||
|
ex_aws_s3 =
|
||||||
|
let
|
||||||
|
version = "2.5.4";
|
||||||
|
in
|
||||||
|
buildMix {
|
||||||
|
inherit version;
|
||||||
|
name = "ex_aws_s3";
|
||||||
|
|
||||||
|
src = fetchHex {
|
||||||
|
inherit version;
|
||||||
|
pkg = "ex_aws_s3";
|
||||||
|
sha256 = "c06e7f68b33f7c0acba1361dbd951c79661a28f85aa2e0582990fccca4425355";
|
||||||
|
};
|
||||||
|
|
||||||
|
beamDeps = [ ex_aws sweet_xml ];
|
||||||
|
};
|
||||||
|
|
||||||
expo =
|
expo =
|
||||||
let
|
let
|
||||||
version = "1.1.0";
|
version = "1.1.0";
|
||||||
|
|
@ -350,6 +399,23 @@ let
|
||||||
beamDeps = [ expo ];
|
beamDeps = [ expo ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
hackney =
|
||||||
|
let
|
||||||
|
version = "1.20.1";
|
||||||
|
in
|
||||||
|
buildRebar3 {
|
||||||
|
inherit version;
|
||||||
|
name = "hackney";
|
||||||
|
|
||||||
|
src = fetchHex {
|
||||||
|
inherit version;
|
||||||
|
pkg = "hackney";
|
||||||
|
sha256 = "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3";
|
||||||
|
};
|
||||||
|
|
||||||
|
beamDeps = [ certifi idna metrics mimerl parse_trans ssl_verify_fun unicode_util_compat ];
|
||||||
|
};
|
||||||
|
|
||||||
hpax =
|
hpax =
|
||||||
let
|
let
|
||||||
version = "1.0.0";
|
version = "1.0.0";
|
||||||
|
|
@ -365,6 +431,23 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
idna =
|
||||||
|
let
|
||||||
|
version = "6.1.1";
|
||||||
|
in
|
||||||
|
buildRebar3 {
|
||||||
|
inherit version;
|
||||||
|
name = "idna";
|
||||||
|
|
||||||
|
src = fetchHex {
|
||||||
|
inherit version;
|
||||||
|
pkg = "idna";
|
||||||
|
sha256 = "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea";
|
||||||
|
};
|
||||||
|
|
||||||
|
beamDeps = [ unicode_util_compat ];
|
||||||
|
};
|
||||||
|
|
||||||
jason =
|
jason =
|
||||||
let
|
let
|
||||||
version = "1.4.4";
|
version = "1.4.4";
|
||||||
|
|
@ -382,6 +465,21 @@ let
|
||||||
beamDeps = [ decimal ];
|
beamDeps = [ decimal ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
metrics =
|
||||||
|
let
|
||||||
|
version = "1.0.1";
|
||||||
|
in
|
||||||
|
buildRebar3 {
|
||||||
|
inherit version;
|
||||||
|
name = "metrics";
|
||||||
|
|
||||||
|
src = fetchHex {
|
||||||
|
inherit version;
|
||||||
|
pkg = "metrics";
|
||||||
|
sha256 = "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
mime =
|
mime =
|
||||||
let
|
let
|
||||||
version = "2.0.6";
|
version = "2.0.6";
|
||||||
|
|
@ -397,6 +495,21 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mimerl =
|
||||||
|
let
|
||||||
|
version = "1.3.0";
|
||||||
|
in
|
||||||
|
buildRebar3 {
|
||||||
|
inherit version;
|
||||||
|
name = "mimerl";
|
||||||
|
|
||||||
|
src = fetchHex {
|
||||||
|
inherit version;
|
||||||
|
pkg = "mimerl";
|
||||||
|
sha256 = "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
mint =
|
mint =
|
||||||
let
|
let
|
||||||
version = "1.6.2";
|
version = "1.6.2";
|
||||||
|
|
@ -414,6 +527,21 @@ let
|
||||||
beamDeps = [ castore hpax ];
|
beamDeps = [ castore hpax ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nanoid =
|
||||||
|
let
|
||||||
|
version = "2.1.0";
|
||||||
|
in
|
||||||
|
buildMix {
|
||||||
|
inherit version;
|
||||||
|
name = "nanoid";
|
||||||
|
|
||||||
|
src = fetchHex {
|
||||||
|
inherit version;
|
||||||
|
pkg = "nanoid";
|
||||||
|
sha256 = "ebc7a342d02d213534a7f93a091d569b9fea7f26fcd3a638dc655060fc1f76ac";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
nimble_options =
|
nimble_options =
|
||||||
let
|
let
|
||||||
version = "1.1.1";
|
version = "1.1.1";
|
||||||
|
|
@ -444,6 +572,21 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
parse_trans =
|
||||||
|
let
|
||||||
|
version = "3.4.1";
|
||||||
|
in
|
||||||
|
buildRebar3 {
|
||||||
|
inherit version;
|
||||||
|
name = "parse_trans";
|
||||||
|
|
||||||
|
src = fetchHex {
|
||||||
|
inherit version;
|
||||||
|
pkg = "parse_trans";
|
||||||
|
sha256 = "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
phoenix =
|
phoenix =
|
||||||
let
|
let
|
||||||
version = "1.7.14";
|
version = "1.7.14";
|
||||||
|
|
@ -608,6 +751,36 @@ let
|
||||||
beamDeps = [ db_connection decimal jason ];
|
beamDeps = [ db_connection decimal jason ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ssl_verify_fun =
|
||||||
|
let
|
||||||
|
version = "1.1.7";
|
||||||
|
in
|
||||||
|
buildMix {
|
||||||
|
inherit version;
|
||||||
|
name = "ssl_verify_fun";
|
||||||
|
|
||||||
|
src = fetchHex {
|
||||||
|
inherit version;
|
||||||
|
pkg = "ssl_verify_fun";
|
||||||
|
sha256 = "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sweet_xml =
|
||||||
|
let
|
||||||
|
version = "0.7.4";
|
||||||
|
in
|
||||||
|
buildMix {
|
||||||
|
inherit version;
|
||||||
|
name = "sweet_xml";
|
||||||
|
|
||||||
|
src = fetchHex {
|
||||||
|
inherit version;
|
||||||
|
pkg = "sweet_xml";
|
||||||
|
sha256 = "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
swoosh =
|
swoosh =
|
||||||
let
|
let
|
||||||
version = "1.17.2";
|
version = "1.17.2";
|
||||||
|
|
@ -622,7 +795,7 @@ let
|
||||||
sha256 = "de914359f0ddc134dc0d7735e28922d49d0503f31e4bd66b44e26039c2226d39";
|
sha256 = "de914359f0ddc134dc0d7735e28922d49d0503f31e4bd66b44e26039c2226d39";
|
||||||
};
|
};
|
||||||
|
|
||||||
beamDeps = [ bandit finch jason mime plug telemetry ];
|
beamDeps = [ bandit ex_aws finch hackney jason mime plug telemetry ];
|
||||||
};
|
};
|
||||||
|
|
||||||
table_rex =
|
table_rex =
|
||||||
|
|
@ -723,6 +896,21 @@ let
|
||||||
beamDeps = [ telemetry ];
|
beamDeps = [ telemetry ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unicode_util_compat =
|
||||||
|
let
|
||||||
|
version = "0.7.0";
|
||||||
|
in
|
||||||
|
buildRebar3 {
|
||||||
|
inherit version;
|
||||||
|
name = "unicode_util_compat";
|
||||||
|
|
||||||
|
src = fetchHex {
|
||||||
|
inherit version;
|
||||||
|
pkg = "unicode_util_compat";
|
||||||
|
sha256 = "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
websock =
|
websock =
|
||||||
let
|
let
|
||||||
version = "0.5.3";
|
version = "0.5.3";
|
||||||
|
|
|
||||||
BIN
img.png
Normal file
BIN
img.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
132
lib/zoeyscomputer/api_keys.ex
Normal file
132
lib/zoeyscomputer/api_keys.ex
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
defmodule Zoeyscomputer.ApiKeys do
|
||||||
|
@moduledoc """
|
||||||
|
The ApiKeys context.
|
||||||
|
"""
|
||||||
|
require Logger
|
||||||
|
|
||||||
|
import Ecto.Query, warn: false
|
||||||
|
alias Hex.API.User
|
||||||
|
alias Zoeyscomputer.ApiKeys.ApiKey
|
||||||
|
alias Zoeyscomputer.Repo
|
||||||
|
alias Zoeyscomputer.Users.User
|
||||||
|
|
||||||
|
alias Zoeyscomputer.ApiKeys.ApiKey
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns the list of api_keys.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> list_api_keys()
|
||||||
|
[%ApiKey{}, ...]
|
||||||
|
|
||||||
|
"""
|
||||||
|
def list_api_keys do
|
||||||
|
Repo.all(ApiKey)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Gets a single api_key.
|
||||||
|
|
||||||
|
Raises `Ecto.NoResultsError` if the Api key does not exist.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> get_api_key!(123)
|
||||||
|
%ApiKey{}
|
||||||
|
|
||||||
|
iex> get_api_key!(456)
|
||||||
|
** (Ecto.NoResultsError)
|
||||||
|
|
||||||
|
"""
|
||||||
|
def get_api_key!(id), do: Repo.get!(ApiKey, id)
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Gets an API key by its token
|
||||||
|
"""
|
||||||
|
def get_api_key_by_token(token) do
|
||||||
|
Repo.get_by(ApiKey, token: token)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Creates an API key for a user.
|
||||||
|
"""
|
||||||
|
def create_api_key(user, attrs \\ %{}) do
|
||||||
|
# Convert attrs to string keys and add user_id with string key
|
||||||
|
attrs = Map.put(attrs, "user_id", user.id)
|
||||||
|
|
||||||
|
result =
|
||||||
|
%ApiKey{}
|
||||||
|
|> ApiKey.changeset(attrs)
|
||||||
|
|> Repo.insert()
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Updates a api_key.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> update_api_key(api_key, %{field: new_value})
|
||||||
|
{:ok, %ApiKey{}}
|
||||||
|
|
||||||
|
iex> update_api_key(api_key, %{field: bad_value})
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def update_api_key(%ApiKey{} = api_key, attrs) do
|
||||||
|
api_key
|
||||||
|
|> ApiKey.changeset(attrs)
|
||||||
|
|> Repo.update()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
List all API Keys for a given user
|
||||||
|
"""
|
||||||
|
def list_api_keys(%User{} = user) do
|
||||||
|
ApiKey
|
||||||
|
|> where([a], a.user_id == ^user.id)
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Deletes a api_key.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> delete_api_key(api_key)
|
||||||
|
{:ok, %ApiKey{}}
|
||||||
|
|
||||||
|
iex> delete_api_key(api_key)
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def delete_api_key(%ApiKey{} = api_key) do
|
||||||
|
Repo.delete(api_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns an `%Ecto.Changeset{}` for tracking api_key changes.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> change_api_key(api_key)
|
||||||
|
%Ecto.Changeset{data: %ApiKey{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def change_api_key(%ApiKey{} = api_key, attrs \\ %{}) do
|
||||||
|
ApiKey.changeset(api_key, attrs)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Validates an API key token and returns associated user.
|
||||||
|
Returns nil if token is invalid
|
||||||
|
"""
|
||||||
|
def authenticate_api_key(token) when is_binary(token) do
|
||||||
|
case get_api_key_by_token(token) do
|
||||||
|
%ApiKey{} = key -> Repo.preload(key, :user).user
|
||||||
|
nil -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
36
lib/zoeyscomputer/api_keys/api_key.ex
Normal file
36
lib/zoeyscomputer/api_keys/api_key.ex
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
defmodule Zoeyscomputer.ApiKeys.ApiKey do
|
||||||
|
use Ecto.Schema
|
||||||
|
import Ecto.Changeset
|
||||||
|
alias Zoeyscomputer.Users.User
|
||||||
|
|
||||||
|
schema "api_keys" do
|
||||||
|
field :name, :string
|
||||||
|
field :token, :string
|
||||||
|
belongs_to :user, User
|
||||||
|
|
||||||
|
timestamps(type: :utc_datetime)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def changeset(api_key, attrs) do
|
||||||
|
api_key
|
||||||
|
# Make sure both fields are in cast
|
||||||
|
|> cast(attrs, [:name, :user_id])
|
||||||
|
|> validate_required([:name, :user_id])
|
||||||
|
# This needs to happen before validation
|
||||||
|
|> put_token()
|
||||||
|
# Add token to required fields
|
||||||
|
|> validate_required([:token])
|
||||||
|
end
|
||||||
|
|
||||||
|
defp put_token(changeset) do
|
||||||
|
case changeset do
|
||||||
|
%Ecto.Changeset{valid?: true} ->
|
||||||
|
token = :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false)
|
||||||
|
put_change(changeset, :token, token)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
changeset
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
125
lib/zoeyscomputer/images.ex
Normal file
125
lib/zoeyscomputer/images.ex
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
defmodule Zoeyscomputer.Images do
|
||||||
|
@moduledoc """
|
||||||
|
The Images context.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import Ecto.Query, warn: false
|
||||||
|
alias Ecto.Repo
|
||||||
|
alias Zoeyscomputer.Users.User
|
||||||
|
alias Zoeyscomputer.Repo
|
||||||
|
|
||||||
|
alias Zoeyscomputer.Images.Image
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns the list of images.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> list_images()
|
||||||
|
[%Image{}, ...]
|
||||||
|
|
||||||
|
"""
|
||||||
|
def list_images do
|
||||||
|
Repo.all(Image)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
List Images uploaded by user
|
||||||
|
"""
|
||||||
|
|
||||||
|
def list_images_by_user(%User{} = user) do
|
||||||
|
Image
|
||||||
|
|> where([a], a.user_id == ^user.id)
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Gets a single image.
|
||||||
|
|
||||||
|
Raises `Ecto.NoResultsError` if the Image does not exist.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> get_image!(123)
|
||||||
|
%Image{}
|
||||||
|
|
||||||
|
iex> get_image!(456)
|
||||||
|
** (Ecto.NoResultsError)
|
||||||
|
|
||||||
|
"""
|
||||||
|
def get_image!(id), do: Repo.get!(Image, id)
|
||||||
|
|
||||||
|
def get_image_by!(file) do
|
||||||
|
Image
|
||||||
|
|> Repo.get_by!(file: file)
|
||||||
|
|> Repo.preload(:user)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Creates a image.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> create_image(%{field: value})
|
||||||
|
{:ok, %Image{}}
|
||||||
|
|
||||||
|
iex> create_image(%{field: bad_value})
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def create_image(attrs \\ %{}) do
|
||||||
|
# attrs = Map.put(attrs, "user_id", user.id)
|
||||||
|
# attrs = Map.put(attrs, "s3_key", s3_key)
|
||||||
|
|
||||||
|
%Image{}
|
||||||
|
|> Image.changeset(attrs)
|
||||||
|
|> Repo.insert()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Updates a image.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> update_image(image, %{field: new_value})
|
||||||
|
{:ok, %Image{}}
|
||||||
|
|
||||||
|
iex> update_image(image, %{field: bad_value})
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def update_image(%Image{} = image, attrs) do
|
||||||
|
image
|
||||||
|
|> Image.changeset(attrs)
|
||||||
|
|> Repo.update()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Deletes a image.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> delete_image(image)
|
||||||
|
{:ok, %Image{}}
|
||||||
|
|
||||||
|
iex> delete_image(image)
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def delete_image(%Image{} = image) do
|
||||||
|
Repo.delete(image)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns an `%Ecto.Changeset{}` for tracking image changes.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> change_image(image)
|
||||||
|
%Ecto.Changeset{data: %Image{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def change_image(%Image{} = image, attrs \\ %{}) do
|
||||||
|
Image.changeset(image, attrs)
|
||||||
|
end
|
||||||
|
end
|
||||||
20
lib/zoeyscomputer/images/image.ex
Normal file
20
lib/zoeyscomputer/images/image.ex
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
defmodule Zoeyscomputer.Images.Image do
|
||||||
|
use Ecto.Schema
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@derive {Jason.Encoder, only: [:id, :file, :inserted_at, :updated_at]}
|
||||||
|
|
||||||
|
schema "images" do
|
||||||
|
field(:file, :string)
|
||||||
|
belongs_to :user, Zoeyscomputer.Users.User
|
||||||
|
|
||||||
|
timestamps(type: :utc_datetime)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def changeset(image, attrs) do
|
||||||
|
image
|
||||||
|
|> cast(attrs, [:file, :user_id])
|
||||||
|
|> validate_required([:file, :user_id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -50,7 +50,11 @@ defmodule ZoeyscomputerWeb.CoreComponents do
|
||||||
data-cancel={JS.exec(@on_cancel, "phx-remove")}
|
data-cancel={JS.exec(@on_cancel, "phx-remove")}
|
||||||
class="relative z-50 hidden"
|
class="relative z-50 hidden"
|
||||||
>
|
>
|
||||||
<div id={"#{@id}-bg"} class="bg-zinc-50/90 fixed inset-0 transition-opacity" aria-hidden="true" />
|
<div
|
||||||
|
id={"#{@id}-bg"}
|
||||||
|
class="bg-ctp-base/90 fixed inset-0 transition-opacity"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
class="fixed inset-0 overflow-y-auto"
|
class="fixed inset-0 overflow-y-auto"
|
||||||
aria-labelledby={"#{@id}-title"}
|
aria-labelledby={"#{@id}-title"}
|
||||||
|
|
@ -429,10 +433,10 @@ defmodule ZoeyscomputerWeb.CoreComponents do
|
||||||
~H"""
|
~H"""
|
||||||
<header class={[@actions != [] && "flex items-center justify-between gap-6", @class]}>
|
<header class={[@actions != [] && "flex items-center justify-between gap-6", @class]}>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-lg font-semibold leading-8">
|
<h1 class="text-lg font-semibold text-ctp-text leading-8">
|
||||||
<%= render_slot(@inner_block) %>
|
<%= render_slot(@inner_block) %>
|
||||||
</h1>
|
</h1>
|
||||||
<p :if={@subtitle != []} class="mt-2 text-sm leading-6 text-ctp-overlay2">
|
<p :if={@subtitle != []} class="mt-2 text-sm leading-6 text-ctp-subtext0">
|
||||||
<%= render_slot(@subtitle) %>
|
<%= render_slot(@subtitle) %>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -441,6 +445,26 @@ defmodule ZoeyscomputerWeb.CoreComponents do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
attr :id, :string, required: true
|
||||||
|
attr :content, :string, required: true
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Copy to clipboard button.
|
||||||
|
"""
|
||||||
|
def copy_button(assigns) do
|
||||||
|
~H"""
|
||||||
|
<button
|
||||||
|
id={@id}
|
||||||
|
content={@content}
|
||||||
|
phx-click={JS.dispatch("phx:copy", to: "##{@content}")}
|
||||||
|
type="button"
|
||||||
|
class="rounded-md inline-flex items-center bg-white px-2.5 py-1.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
|
||||||
|
>
|
||||||
|
Copy
|
||||||
|
</button>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
@doc ~S"""
|
@doc ~S"""
|
||||||
Renders a table with generic styling.
|
Renders a table with generic styling.
|
||||||
|
|
||||||
|
|
|
||||||
25
lib/zoeyscomputer_web/controllers/changeset_json.ex
Normal file
25
lib/zoeyscomputer_web/controllers/changeset_json.ex
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
defmodule ZoeyscomputerWeb.ChangesetJSON do
|
||||||
|
@doc """
|
||||||
|
Renders changeset errors.
|
||||||
|
"""
|
||||||
|
def error(%{changeset: changeset}) do
|
||||||
|
# When encoded, the changeset returns its errors
|
||||||
|
# as a JSON object. So we just pass it forward.
|
||||||
|
%{errors: Ecto.Changeset.traverse_errors(changeset, &translate_error/1)}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp translate_error({msg, opts}) do
|
||||||
|
# You can make use of gettext to translate error messages by
|
||||||
|
# uncommenting and adjusting the following code:
|
||||||
|
|
||||||
|
# if count = opts[:count] do
|
||||||
|
# Gettext.dngettext(ZoeyscomputerWeb.Gettext, "errors", msg, msg, count, opts)
|
||||||
|
# else
|
||||||
|
# Gettext.dgettext(ZoeyscomputerWeb.Gettext, "errors", msg, opts)
|
||||||
|
# end
|
||||||
|
|
||||||
|
Enum.reduce(opts, msg, fn {key, value}, acc ->
|
||||||
|
String.replace(acc, "%{#{key}}", fn _ -> to_string(value) end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
24
lib/zoeyscomputer_web/controllers/fallback_controller.ex
Normal file
24
lib/zoeyscomputer_web/controllers/fallback_controller.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
defmodule ZoeyscomputerWeb.FallbackController do
|
||||||
|
@moduledoc """
|
||||||
|
Translates controller action results into valid `Plug.Conn` responses.
|
||||||
|
|
||||||
|
See `Phoenix.Controller.action_fallback/1` for more details.
|
||||||
|
"""
|
||||||
|
use ZoeyscomputerWeb, :controller
|
||||||
|
|
||||||
|
# This clause handles errors returned by Ecto's insert/update/delete.
|
||||||
|
def call(conn, {:error, %Ecto.Changeset{} = changeset}) do
|
||||||
|
conn
|
||||||
|
|> put_status(:unprocessable_entity)
|
||||||
|
|> put_view(json: ZoeyscomputerWeb.ChangesetJSON)
|
||||||
|
|> render(:error, changeset: changeset)
|
||||||
|
end
|
||||||
|
|
||||||
|
# This clause is an example of how to handle resources that cannot be found.
|
||||||
|
def call(conn, {:error, :not_found}) do
|
||||||
|
conn
|
||||||
|
|> put_status(:not_found)
|
||||||
|
|> put_view(html: ZoeyscomputerWeb.ErrorHTML, json: ZoeyscomputerWeb.ErrorJSON)
|
||||||
|
|> render(:"404")
|
||||||
|
end
|
||||||
|
end
|
||||||
103
lib/zoeyscomputer_web/controllers/image_controller.ex
Normal file
103
lib/zoeyscomputer_web/controllers/image_controller.ex
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
defmodule ZoeyscomputerWeb.ImageController do
|
||||||
|
use ZoeyscomputerWeb, :controller
|
||||||
|
|
||||||
|
alias Zoeyscomputer.Images
|
||||||
|
alias Zoeyscomputer.Images.Image
|
||||||
|
|
||||||
|
action_fallback ZoeyscomputerWeb.FallbackController
|
||||||
|
|
||||||
|
def index(conn, _params) do
|
||||||
|
images = Images.list_images()
|
||||||
|
render(conn, :index, images: images)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create(conn, %{"file" => upload}) do
|
||||||
|
user = conn.assigns.current_user
|
||||||
|
|
||||||
|
case handle_upload(upload) do
|
||||||
|
{:ok, s3_key} ->
|
||||||
|
# Fixed: create_image takes one argument (the params map)
|
||||||
|
case Images.create_image(%{file: s3_key, user_id: user.id}) do
|
||||||
|
{:ok, image} ->
|
||||||
|
conn
|
||||||
|
|> put_status(:created)
|
||||||
|
|> put_resp_header("location", ~p"/api/images/#{image}")
|
||||||
|
|> json(%{
|
||||||
|
message: "File uploaded successfully",
|
||||||
|
url: get_public_url(s3_key),
|
||||||
|
image: image
|
||||||
|
})
|
||||||
|
|
||||||
|
{:error, changeset} ->
|
||||||
|
conn
|
||||||
|
|> put_status(:unprocessable_entity)
|
||||||
|
|> json(%{
|
||||||
|
error: "Database save failed",
|
||||||
|
details: changeset_error_to_string(changeset)
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
{:error, reason} ->
|
||||||
|
conn
|
||||||
|
|> put_status(:unprocessable_entity)
|
||||||
|
|> json(%{
|
||||||
|
error: "Upload failed",
|
||||||
|
reason: inspect(reason)
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp changeset_error_to_string(changeset) do
|
||||||
|
Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} ->
|
||||||
|
Enum.reduce(opts, msg, fn {key, value}, acc ->
|
||||||
|
String.replace(acc, "%{#{key}}", to_string(value))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_upload(upload) do
|
||||||
|
extension = Path.extname(upload.filename)
|
||||||
|
id = Nanoid.generate(7)
|
||||||
|
key = "uploads/#{id}#{extension}"
|
||||||
|
bucket = "imgs"
|
||||||
|
|
||||||
|
{:ok, file_binary} = File.read(upload.path)
|
||||||
|
|
||||||
|
case ExAws.S3.put_object(bucket, key, file_binary)
|
||||||
|
|> ExAws.request() do
|
||||||
|
{:ok, _response} -> {:ok, id}
|
||||||
|
{:error, reason} -> {:error, reason}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_public_url(key) do
|
||||||
|
"https://zoeys.computer/images/#{key}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def show(conn, %{"id" => id}) do
|
||||||
|
image = Images.get_image!(id)
|
||||||
|
render(conn, :show, image: image)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(conn, %{"id" => id, "image" => image_params}) do
|
||||||
|
image = Images.get_image!(id)
|
||||||
|
|
||||||
|
with {:ok, %Image{} = image} <- Images.update_image(image, image_params) do
|
||||||
|
render(conn, :show, image: image)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(conn, %{"id" => id}) do
|
||||||
|
image = Images.get_image!(id)
|
||||||
|
|
||||||
|
case ExAws.S3.delete_object("imgs", image.file)
|
||||||
|
|> ExAws.request() do
|
||||||
|
{:ok, _response} -> {:ok, image.file}
|
||||||
|
{:error, reason} -> {:error, reason}
|
||||||
|
end
|
||||||
|
|
||||||
|
with {:ok, %Image{}} <- Images.delete_image(image) do
|
||||||
|
send_resp(conn, :no_content, "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
24
lib/zoeyscomputer_web/controllers/image_json.ex
Normal file
24
lib/zoeyscomputer_web/controllers/image_json.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
defmodule ZoeyscomputerWeb.ImageJSON do
|
||||||
|
alias Zoeyscomputer.Images.Image
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Renders a list of images.
|
||||||
|
"""
|
||||||
|
def index(%{images: images}) do
|
||||||
|
%{data: for(image <- images, do: data(image))}
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Renders a single image.
|
||||||
|
"""
|
||||||
|
def show(%{image: image}) do
|
||||||
|
%{data: data(image)}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp data(%Image{} = image) do
|
||||||
|
%{
|
||||||
|
id: image.id,
|
||||||
|
file: image.file
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
70
lib/zoeyscomputer_web/live/api_key_live/form_component.ex
Normal file
70
lib/zoeyscomputer_web/live/api_key_live/form_component.ex
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
defmodule ZoeyscomputerWeb.ApiKeyLive.FormComponent do
|
||||||
|
use ZoeyscomputerWeb, :live_component
|
||||||
|
|
||||||
|
alias Zoeyscomputer.ApiKeys
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def render(assigns) do
|
||||||
|
~H"""
|
||||||
|
<div>
|
||||||
|
<.header>
|
||||||
|
<%= @title %>
|
||||||
|
<:subtitle>Create an API key to access the API</:subtitle>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.simple_form
|
||||||
|
for={@form}
|
||||||
|
id="api-key-form"
|
||||||
|
phx-target={@myself}
|
||||||
|
phx-change="validate"
|
||||||
|
phx-submit="save"
|
||||||
|
>
|
||||||
|
<.input field={@form[:name]} type="text" label="Name" />
|
||||||
|
<:actions>
|
||||||
|
<.button phx-disable-with="Saving...">Save Api key</.button>
|
||||||
|
</:actions>
|
||||||
|
</.simple_form>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def update(%{api_key: api_key} = assigns, socket) do
|
||||||
|
changeset = ApiKeys.change_api_key(api_key)
|
||||||
|
|
||||||
|
{:ok,
|
||||||
|
socket
|
||||||
|
|> assign(assigns)
|
||||||
|
|> assign_form(changeset)}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_event("validate", %{"api_key" => api_key_params}, socket) do
|
||||||
|
changeset =
|
||||||
|
socket.assigns.api_key
|
||||||
|
|> ApiKeys.change_api_key(api_key_params)
|
||||||
|
|> Map.put(:action, :validate)
|
||||||
|
|
||||||
|
{:noreply, assign_form(socket, changeset)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_event("save", %{"api_key" => api_key_params}, socket) do
|
||||||
|
case ApiKeys.create_api_key(socket.assigns.current_user, api_key_params) do
|
||||||
|
{:ok, api_key} ->
|
||||||
|
notify_parent({:saved, api_key})
|
||||||
|
|
||||||
|
{:noreply,
|
||||||
|
socket
|
||||||
|
|> put_flash(:info, "API key created successfully")}
|
||||||
|
|
||||||
|
{:error, %Ecto.Changeset{} = changeset} ->
|
||||||
|
{:noreply, assign_form(socket, changeset)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp assign_form(socket, %Ecto.Changeset{} = changeset) do
|
||||||
|
assign(socket, :form, to_form(changeset))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
|
||||||
|
end
|
||||||
54
lib/zoeyscomputer_web/live/api_key_live/index.ex
Normal file
54
lib/zoeyscomputer_web/live/api_key_live/index.ex
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
defmodule ZoeyscomputerWeb.ApiKeyLive.Index do
|
||||||
|
use ZoeyscomputerWeb, :live_view
|
||||||
|
|
||||||
|
alias Zoeyscomputer.ApiKeys
|
||||||
|
alias Zoeyscomputer.ApiKeys.ApiKey
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def mount(_params, _session, socket) do
|
||||||
|
if connected?(socket) && socket.assigns.current_user do
|
||||||
|
{:ok, stream(socket, :api_keys, ApiKeys.list_api_keys())}
|
||||||
|
else
|
||||||
|
{:ok, stream(socket, :api_keys, [])}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_params(params, _url, socket) do
|
||||||
|
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp apply_action(socket, :edit, %{"id" => id}) do
|
||||||
|
socket
|
||||||
|
|> assign(:page_title, "Edit Api key")
|
||||||
|
|> assign(:api_key, ApiKeys.get_api_key!(id))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp apply_action(socket, :new, _params) do
|
||||||
|
socket
|
||||||
|
|> assign(:page_title, "New API Key")
|
||||||
|
|> assign(:api_key, %ApiKey{})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp apply_action(socket, :index, _params) do
|
||||||
|
socket
|
||||||
|
|> assign(:page_title, "API Keys")
|
||||||
|
|> assign(:api_key, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_info({ZoeyscomputerWeb.ApiKeyLive.FormComponent, {:saved, api_key}}, socket) do
|
||||||
|
{:noreply,
|
||||||
|
socket
|
||||||
|
|> stream_insert(:api_keys, api_key)
|
||||||
|
|> push_patch(to: ~p"/api-keys")}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_event("delete", %{"id" => id}, socket) do
|
||||||
|
api_key = ApiKeys.get_api_key!(id)
|
||||||
|
{:ok, _} = ApiKeys.delete_api_key(api_key)
|
||||||
|
|
||||||
|
{:noreply, stream_delete(socket, :api_keys, api_key)}
|
||||||
|
end
|
||||||
|
end
|
||||||
49
lib/zoeyscomputer_web/live/api_key_live/index.html.heex
Normal file
49
lib/zoeyscomputer_web/live/api_key_live/index.html.heex
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
<.header>
|
||||||
|
API Keys
|
||||||
|
<:actions>
|
||||||
|
<.link patch={~p"/api-keys/new"}>
|
||||||
|
<.button>New API Key</.button>
|
||||||
|
</.link>
|
||||||
|
</:actions>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.table
|
||||||
|
id="api_keys"
|
||||||
|
rows={@streams.api_keys}
|
||||||
|
row_click={fn {_id, api_key} -> JS.navigate(~p"/api-keys/#{api_key}") end}
|
||||||
|
>
|
||||||
|
<:col :let={{_id, api_key}} label="Name"><%= api_key.name %></:col>
|
||||||
|
<:col :let={{_id, api_key}} label="Created">
|
||||||
|
<%= Calendar.strftime(api_key.inserted_at, "%Y-%m-%d %H:%M:%S") %>
|
||||||
|
</:col>
|
||||||
|
<:action :let={{_id, api_key}}>
|
||||||
|
<div class="sr-only">
|
||||||
|
<.link navigate={~p"/api-keys/#{api_key}"}>Show</.link>
|
||||||
|
</div>
|
||||||
|
</:action>
|
||||||
|
<:action :let={{id, api_key}}>
|
||||||
|
<.link
|
||||||
|
phx-click={JS.push("delete", value: %{id: api_key.id}) |> hide("##{id}")}
|
||||||
|
data-confirm="Are you sure?"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</.link>
|
||||||
|
</:action>
|
||||||
|
</.table>
|
||||||
|
|
||||||
|
<.modal
|
||||||
|
:if={@live_action in [:new, :edit]}
|
||||||
|
id="api-key-modal"
|
||||||
|
show
|
||||||
|
on_cancel={JS.patch(~p"/api-keys")}
|
||||||
|
>
|
||||||
|
<.live_component
|
||||||
|
module={ZoeyscomputerWeb.ApiKeyLive.FormComponent}
|
||||||
|
current_user={@current_user}
|
||||||
|
id={@api_key.id || :new}
|
||||||
|
title={@page_title}
|
||||||
|
action={@live_action}
|
||||||
|
api_key={@api_key}
|
||||||
|
patch={~p"/api-keys"}
|
||||||
|
/>
|
||||||
|
</.modal>
|
||||||
40
lib/zoeyscomputer_web/live/api_key_live/show.ex
Normal file
40
lib/zoeyscomputer_web/live/api_key_live/show.ex
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
defmodule ZoeyscomputerWeb.ApiKeyLive.Show do
|
||||||
|
use ZoeyscomputerWeb, :live_view
|
||||||
|
|
||||||
|
alias Zoeyscomputer.ApiKeys
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def mount(_params, _session, socket) do
|
||||||
|
if connected?(socket) do
|
||||||
|
IO.puts("LiveView Connected")
|
||||||
|
end
|
||||||
|
|
||||||
|
{:ok, socket}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_params(%{"id" => id}, _, socket) do
|
||||||
|
api_key = ApiKeys.get_api_key!(id)
|
||||||
|
|
||||||
|
# Ensure users can only view their own API keys
|
||||||
|
if api_key.user_id == socket.assigns.current_user.id do
|
||||||
|
{:noreply,
|
||||||
|
socket
|
||||||
|
|> assign(:page_title, "API Key Details")
|
||||||
|
|> assign(:api_key, api_key)}
|
||||||
|
else
|
||||||
|
{:noreply,
|
||||||
|
socket
|
||||||
|
|> put_flash(:error, "Not authorized")
|
||||||
|
|> push_navigate(to: ~p"/api-keys")}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_event("copy_token", _, socket) do
|
||||||
|
IO.puts("Copy token event received")
|
||||||
|
token = socket.assigns.api_key.token
|
||||||
|
IO.puts("Token to copy: #{token}")
|
||||||
|
{:noreply, push_event(socket, "copy", %{text: token})}
|
||||||
|
end
|
||||||
|
end
|
||||||
47
lib/zoeyscomputer_web/live/api_key_live/show.html.heex
Normal file
47
lib/zoeyscomputer_web/live/api_key_live/show.html.heex
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
<.header>
|
||||||
|
API Key Details
|
||||||
|
<:actions>
|
||||||
|
<.link patch={~p"/api-keys"}>
|
||||||
|
<.button>Back to API keys</.button>
|
||||||
|
</.link>
|
||||||
|
</:actions>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.list>
|
||||||
|
<:item title="Name"><%= @api_key.name %></:item>
|
||||||
|
<:item title="Token">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<code class="bg-ctp-crust border border-ctp-mauve p-2 rounded" id="api-token">
|
||||||
|
<%= @api_key.token %>
|
||||||
|
</code>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="text-sm text-ctp-mauve hover:text-ctp-pink"
|
||||||
|
phx-click={JS.dispatch("phx:copy", to: "#{@api_key.token}")}
|
||||||
|
>
|
||||||
|
Copy
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</:item>
|
||||||
|
<:item title="Created">
|
||||||
|
<%= Calendar.strftime(@api_key.inserted_at, "%Y-%m-%d %H:%M:%S") %>
|
||||||
|
</:item>
|
||||||
|
</.list>
|
||||||
|
|
||||||
|
<.back navigate={~p"/api-keys"}>Back to api_keys</.back>
|
||||||
|
|
||||||
|
<.modal
|
||||||
|
:if={@live_action == :edit}
|
||||||
|
id="api_key-modal"
|
||||||
|
show
|
||||||
|
on_cancel={JS.patch(~p"/api-keys/#{@api_key}")}
|
||||||
|
>
|
||||||
|
<.live_component
|
||||||
|
module={ZoeyscomputerWeb.ApiKeyLive.FormComponent}
|
||||||
|
id={@api_key.id}
|
||||||
|
title={@page_title}
|
||||||
|
action={@live_action}
|
||||||
|
api_key={@api_key}
|
||||||
|
patch={~p"/api-keys/#{@api_key}"}
|
||||||
|
/>
|
||||||
|
</.modal>
|
||||||
82
lib/zoeyscomputer_web/live/image_live/form_component.ex
Normal file
82
lib/zoeyscomputer_web/live/image_live/form_component.ex
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
defmodule ZoeyscomputerWeb.ImageLive.FormComponent do
|
||||||
|
use ZoeyscomputerWeb, :live_component
|
||||||
|
|
||||||
|
alias Zoeyscomputer.Images
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def render(assigns) do
|
||||||
|
~H"""
|
||||||
|
<div>
|
||||||
|
<.header>
|
||||||
|
<%= @title %>
|
||||||
|
<:subtitle>Use this form to manage image records in your database.</:subtitle>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.simple_form
|
||||||
|
for={@form}
|
||||||
|
id="image-form"
|
||||||
|
phx-target={@myself}
|
||||||
|
phx-change="validate"
|
||||||
|
phx-submit="save"
|
||||||
|
>
|
||||||
|
<.input field={@form[:file]} type="text" label="File" />
|
||||||
|
<:actions>
|
||||||
|
<.button phx-disable-with="Saving...">Save Image</.button>
|
||||||
|
</:actions>
|
||||||
|
</.simple_form>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def update(%{image: image} = assigns, socket) do
|
||||||
|
{:ok,
|
||||||
|
socket
|
||||||
|
|> assign(assigns)
|
||||||
|
|> assign_new(:form, fn ->
|
||||||
|
to_form(Images.change_image(image))
|
||||||
|
end)}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_event("validate", %{"image" => image_params}, socket) do
|
||||||
|
changeset = Images.change_image(socket.assigns.image, image_params)
|
||||||
|
{:noreply, assign(socket, form: to_form(changeset, action: :validate))}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_event("save", %{"image" => image_params}, socket) do
|
||||||
|
save_image(socket, socket.assigns.action, image_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp save_image(socket, :edit, image_params) do
|
||||||
|
case Images.update_image(socket.assigns.image, image_params) do
|
||||||
|
{:ok, image} ->
|
||||||
|
notify_parent({:saved, image})
|
||||||
|
|
||||||
|
{:noreply,
|
||||||
|
socket
|
||||||
|
|> put_flash(:info, "Image updated successfully")
|
||||||
|
|> push_patch(to: socket.assigns.patch)}
|
||||||
|
|
||||||
|
{:error, %Ecto.Changeset{} = changeset} ->
|
||||||
|
{:noreply, assign(socket, form: to_form(changeset))}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp save_image(socket, :new, image_params) do
|
||||||
|
case Images.create_image(image_params) do
|
||||||
|
{:ok, image} ->
|
||||||
|
notify_parent({:saved, image})
|
||||||
|
|
||||||
|
{:noreply,
|
||||||
|
socket
|
||||||
|
|> put_flash(:info, "Image created successfully")
|
||||||
|
|> push_patch(to: socket.assigns.patch)}
|
||||||
|
|
||||||
|
{:error, %Ecto.Changeset{} = changeset} ->
|
||||||
|
{:noreply, assign(socket, form: to_form(changeset))}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
|
||||||
|
end
|
||||||
48
lib/zoeyscomputer_web/live/image_live/index.ex
Normal file
48
lib/zoeyscomputer_web/live/image_live/index.ex
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
defmodule ZoeyscomputerWeb.ImageLive.Index do
|
||||||
|
use ZoeyscomputerWeb, :live_view
|
||||||
|
|
||||||
|
alias Zoeyscomputer.Images
|
||||||
|
alias Zoeyscomputer.Images.Image
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def mount(_params, _session, socket) do
|
||||||
|
current_user = socket.assigns.current_user
|
||||||
|
{:ok, stream(socket, :images, Images.list_images_by_user(current_user))}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_params(params, _url, socket) do
|
||||||
|
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp apply_action(socket, :edit, %{"id" => id}) do
|
||||||
|
socket
|
||||||
|
|> assign(:page_title, "Edit Image")
|
||||||
|
|> assign(:image, Images.get_image!(id))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp apply_action(socket, :new, _params) do
|
||||||
|
socket
|
||||||
|
|> assign(:page_title, "New Image")
|
||||||
|
|> assign(:image, %Image{})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp apply_action(socket, :index, _params) do
|
||||||
|
socket
|
||||||
|
|> assign(:page_title, "Listing Images")
|
||||||
|
|> assign(:image, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_info({ZoeyscomputerWeb.ImageLive.FormComponent, {:saved, image}}, socket) do
|
||||||
|
{:noreply, stream_insert(socket, :images, image)}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_event("delete", %{"id" => id}, socket) do
|
||||||
|
image = Images.get_image!(id)
|
||||||
|
{:ok, _} = Images.delete_image(image)
|
||||||
|
|
||||||
|
{:noreply, stream_delete(socket, :images, image)}
|
||||||
|
end
|
||||||
|
end
|
||||||
56
lib/zoeyscomputer_web/live/image_live/index.html.heex
Normal file
56
lib/zoeyscomputer_web/live/image_live/index.html.heex
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
<.header>
|
||||||
|
Listing Images
|
||||||
|
<:actions>
|
||||||
|
<.link patch={~p"/images/new"}>
|
||||||
|
<.button>New Image</.button>
|
||||||
|
</.link>
|
||||||
|
</:actions>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<%!-- <.table --%>
|
||||||
|
<%!-- id="images" --%>
|
||||||
|
<%!-- rows={@streams.images} --%>
|
||||||
|
<%!-- row_click={fn {_id, image} -> JS.navigate(~p"/images/#{image.file}") end} --%>
|
||||||
|
<%!-- > --%>
|
||||||
|
<%!-- <:col :let={{_id, image}} label="File"><%= image.file %></:col> --%>
|
||||||
|
<%!-- <:action :let={{_id, image}}> --%>
|
||||||
|
<%!-- <div class="sr-only"> --%>
|
||||||
|
<%!-- <.link navigate={~p"/images/#{image.file}"}>Show</.link> --%>
|
||||||
|
<%!-- </div> --%>
|
||||||
|
<%!-- <.link patch={~p"/images/#{image}/edit"}>Edit</.link> --%>
|
||||||
|
<%!-- </:action> --%>
|
||||||
|
<%!-- <:action :let={{id, image}}> --%>
|
||||||
|
<%!-- <.link --%>
|
||||||
|
<%!-- phx-click={JS.push("delete", value: %{id: image.id}) |> hide("##{id}")} --%>
|
||||||
|
<%!-- data-confirm="Are you sure?" --%>
|
||||||
|
<%!-- > --%>
|
||||||
|
<%!-- Delete --%>
|
||||||
|
<%!-- </.link> --%>
|
||||||
|
<%!-- </:action> --%>
|
||||||
|
<%!-- </.table> --%>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-3 gap-4">
|
||||||
|
<img
|
||||||
|
:for={{dom_id, image} <- @streams.images}
|
||||||
|
src={"https://s3.zoeys.computer/imgs/uploads/#{image.file}.png"}
|
||||||
|
phx-click={JS.navigate(~p"/images/#{image.file}")}
|
||||||
|
class="cursor-pointer hover:shadow-lg transition duration-300 hover:scale-105 rounded-lg ease-out border-2 border-ctp-base hover:border-ctp-mauve"
|
||||||
|
id={dom_id}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<.modal
|
||||||
|
:if={@live_action in [:new, :edit]}
|
||||||
|
id="image-modal"
|
||||||
|
show
|
||||||
|
on_cancel={JS.patch(~p"/images")}
|
||||||
|
>
|
||||||
|
<.live_component
|
||||||
|
module={ZoeyscomputerWeb.ImageLive.FormComponent}
|
||||||
|
id={@image.id || :new}
|
||||||
|
title={@page_title}
|
||||||
|
action={@live_action}
|
||||||
|
image={@image}
|
||||||
|
patch={~p"/images"}
|
||||||
|
/>
|
||||||
|
</.modal>
|
||||||
21
lib/zoeyscomputer_web/live/image_live/show.ex
Normal file
21
lib/zoeyscomputer_web/live/image_live/show.ex
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
defmodule ZoeyscomputerWeb.ImageLive.Show do
|
||||||
|
use ZoeyscomputerWeb, :live_view
|
||||||
|
|
||||||
|
alias Zoeyscomputer.Images
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def mount(_params, _session, socket) do
|
||||||
|
{:ok, socket}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_params(%{"id" => id}, _, socket) do
|
||||||
|
{:noreply,
|
||||||
|
socket
|
||||||
|
|> assign(:page_title, page_title(socket.assigns.live_action))
|
||||||
|
|> assign(:image, Images.get_image_by!(id))}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp page_title(:show), do: "Show Image"
|
||||||
|
defp page_title(:edit), do: "Edit Image"
|
||||||
|
end
|
||||||
30
lib/zoeyscomputer_web/live/image_live/show.html.heex
Normal file
30
lib/zoeyscomputer_web/live/image_live/show.html.heex
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<.header>
|
||||||
|
uploaded by <%= @image.user.email %>
|
||||||
|
<:actions>
|
||||||
|
<%= if(@image.user.email == @current_user.email) do %>
|
||||||
|
<.link patch={~p"/images/#{@image.file}/show/edit"} phx-click={JS.push_focus()}>
|
||||||
|
<.button>Edit image</.button>
|
||||||
|
</.link>
|
||||||
|
<% end %>
|
||||||
|
</:actions>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<img src={"https://s3.zoeys.computer/imgs/uploads/#{@image.file}.png"} />
|
||||||
|
|
||||||
|
<.back navigate={~p"/images"}>Back to images</.back>
|
||||||
|
|
||||||
|
<.modal
|
||||||
|
:if={@live_action == :edit}
|
||||||
|
id="image-modal"
|
||||||
|
show
|
||||||
|
on_cancel={JS.patch(~p"/images/#{@image.file}")}
|
||||||
|
>
|
||||||
|
<.live_component
|
||||||
|
module={ZoeyscomputerWeb.ImageLive.FormComponent}
|
||||||
|
id={@image.id}
|
||||||
|
title={@page_title}
|
||||||
|
action={@live_action}
|
||||||
|
image={@image}
|
||||||
|
patch={~p"/images/#{@image.file}"}
|
||||||
|
/>
|
||||||
|
</.modal>
|
||||||
39
lib/zoeyscomputer_web/plugs/api_authentication.ex
Normal file
39
lib/zoeyscomputer_web/plugs/api_authentication.ex
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
defmodule ZoeyscomputerWeb.Plugs.ApiAuthentication do
|
||||||
|
alias Zoeyscomputer.ApiKeys
|
||||||
|
import Plug.Conn
|
||||||
|
|
||||||
|
def init(opts), do: opts
|
||||||
|
|
||||||
|
def call(conn, _opts) do
|
||||||
|
case get_auth_token(conn) do
|
||||||
|
nil ->
|
||||||
|
handle_unauthorized(conn)
|
||||||
|
|
||||||
|
token ->
|
||||||
|
case ApiKeys.authenticate_api_key(token) do
|
||||||
|
nil ->
|
||||||
|
handle_unauthorized(conn)
|
||||||
|
|
||||||
|
user ->
|
||||||
|
conn
|
||||||
|
|> assign(:current_user, user)
|
||||||
|
|> assign(:authenticated_with_api_key, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_auth_token(conn) do
|
||||||
|
case get_req_header(conn, "authorization") do
|
||||||
|
["Bearer " <> token] -> token
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_unauthorized(conn) do
|
||||||
|
conn
|
||||||
|
|> put_status(:unauthorized)
|
||||||
|
|> Phoenix.Controller.put_view(ZoeyscomputerWeb.ErrorJSON)
|
||||||
|
|> Phoenix.Controller.render(:"401")
|
||||||
|
|> halt()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -13,22 +13,22 @@ defmodule ZoeyscomputerWeb.Router do
|
||||||
plug :fetch_current_user
|
plug :fetch_current_user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
pipeline :api_authentication do
|
||||||
|
plug ZoeyscomputerWeb.Plugs.ApiAuthentication
|
||||||
|
end
|
||||||
|
|
||||||
pipeline :api do
|
pipeline :api do
|
||||||
plug :accepts, ["json"]
|
plug :accepts, ["json"]
|
||||||
end
|
end
|
||||||
|
|
||||||
# scope "/", ZoeyscomputerWeb do
|
|
||||||
# pipe_through :browser
|
|
||||||
#
|
|
||||||
# live_session :current_user,
|
|
||||||
# on_mount: [{ZoeyscomputerWeb.UserAuth, :mount_current_user}] do
|
|
||||||
# live "/", HomeLive, :index
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
|
|
||||||
# Other scopes may use custom stacks.
|
# Other scopes may use custom stacks.
|
||||||
scope "/api", ZoeyscomputerWeb do
|
scope "/api", ZoeyscomputerWeb do
|
||||||
pipe_through :api
|
pipe_through :api
|
||||||
|
|
||||||
|
resources "/images", ImageController, except: [:create, :edit]
|
||||||
|
|
||||||
|
pipe_through [:api_authentication]
|
||||||
|
post "/images/create", ImageController, :create
|
||||||
end
|
end
|
||||||
|
|
||||||
# Enable LiveDashboard and Swoosh mailbox preview in development
|
# Enable LiveDashboard and Swoosh mailbox preview in development
|
||||||
|
|
@ -76,6 +76,18 @@ defmodule ZoeyscomputerWeb.Router do
|
||||||
live "/users/settings/confirm_email/:token", UserSettingsLive, :confirm_email
|
live "/users/settings/confirm_email/:token", UserSettingsLive, :confirm_email
|
||||||
live "/links", LinkLive.Index
|
live "/links", LinkLive.Index
|
||||||
live "/links/new", LinkLive.New
|
live "/links/new", LinkLive.New
|
||||||
|
|
||||||
|
live "/images/new", ImageLive.Index, :new
|
||||||
|
live "/images/:id/edit", ImageLive.Index, :edit
|
||||||
|
|
||||||
|
live "/images/:id/show/edit", ImageLive.Show, :edit
|
||||||
|
|
||||||
|
live "/api-keys", ApiKeyLive.Index, :index
|
||||||
|
live "/api-keys/new", ApiKeyLive.Index, :new
|
||||||
|
live "/api-keys/:id/edit", ApiKeyLive.Index, :edit
|
||||||
|
|
||||||
|
live "/api-keys/:id", ApiKeyLive.Show, :show
|
||||||
|
live "/api-keys/:id/show/edit", ApiKeyLive.Show, :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -89,6 +101,9 @@ defmodule ZoeyscomputerWeb.Router do
|
||||||
live "/users/confirm/:token", UserConfirmationLive, :edit
|
live "/users/confirm/:token", UserConfirmationLive, :edit
|
||||||
live "/users/confirm", UserConfirmationInstructionsLive, :new
|
live "/users/confirm", UserConfirmationInstructionsLive, :new
|
||||||
live "/", HomeLive, :index
|
live "/", HomeLive, :index
|
||||||
|
|
||||||
|
live "/images", ImageLive.Index, :index
|
||||||
|
live "/images/:id", ImageLive.Show, :show
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
5
mix.exs
5
mix.exs
|
|
@ -54,6 +54,11 @@ defmodule Zoeyscomputer.MixProject do
|
||||||
compile: false,
|
compile: false,
|
||||||
depth: 1},
|
depth: 1},
|
||||||
{:swoosh, "~> 1.5"},
|
{:swoosh, "~> 1.5"},
|
||||||
|
{:nanoid, "~> 2.1.0"},
|
||||||
|
{:ex_aws, "~> 2.1"},
|
||||||
|
{:ex_aws_s3, "~> 2.0"},
|
||||||
|
{:hackney, "~> 1.9"},
|
||||||
|
{:sweet_xml, "~> 0.6"},
|
||||||
{:finch, "~> 0.13"},
|
{:finch, "~> 0.13"},
|
||||||
{:telemetry_metrics, "~> 1.0"},
|
{:telemetry_metrics, "~> 1.0"},
|
||||||
{:telemetry_poller, "~> 1.0"},
|
{:telemetry_poller, "~> 1.0"},
|
||||||
|
|
|
||||||
13
mix.lock
13
mix.lock
|
|
@ -2,6 +2,7 @@
|
||||||
"bandit": {:hex, :bandit, "1.5.7", "6856b1e1df4f2b0cb3df1377eab7891bec2da6a7fd69dc78594ad3e152363a50", [:mix], [{:hpax, "~> 1.0.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "f2dd92ae87d2cbea2fa9aa1652db157b6cba6c405cb44d4f6dd87abba41371cd"},
|
"bandit": {:hex, :bandit, "1.5.7", "6856b1e1df4f2b0cb3df1377eab7891bec2da6a7fd69dc78594ad3e152363a50", [:mix], [{:hpax, "~> 1.0.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "f2dd92ae87d2cbea2fa9aa1652db157b6cba6c405cb44d4f6dd87abba41371cd"},
|
||||||
"bcrypt_elixir": {:hex, :bcrypt_elixir, "3.2.0", "feab711974beba4cb348147170346fe097eea2e840db4e012a145e180ed4ab75", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "563e92a6c77d667b19c5f4ba17ab6d440a085696bdf4c68b9b0f5b30bc5422b8"},
|
"bcrypt_elixir": {:hex, :bcrypt_elixir, "3.2.0", "feab711974beba4cb348147170346fe097eea2e840db4e012a145e180ed4ab75", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "563e92a6c77d667b19c5f4ba17ab6d440a085696bdf4c68b9b0f5b30bc5422b8"},
|
||||||
"castore": {:hex, :castore, "1.0.9", "5cc77474afadf02c7c017823f460a17daa7908e991b0cc917febc90e466a375c", [:mix], [], "hexpm", "5ea956504f1ba6f2b4eb707061d8e17870de2bee95fb59d512872c2ef06925e7"},
|
"castore": {:hex, :castore, "1.0.9", "5cc77474afadf02c7c017823f460a17daa7908e991b0cc917febc90e466a375c", [:mix], [], "hexpm", "5ea956504f1ba6f2b4eb707061d8e17870de2bee95fb59d512872c2ef06925e7"},
|
||||||
|
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
|
||||||
"comeonin": {:hex, :comeonin, "5.5.0", "364d00df52545c44a139bad919d7eacb55abf39e86565878e17cebb787977368", [:mix], [], "hexpm", "6287fc3ba0aad34883cbe3f7949fc1d1e738e5ccdce77165bc99490aa69f47fb"},
|
"comeonin": {:hex, :comeonin, "5.5.0", "364d00df52545c44a139bad919d7eacb55abf39e86565878e17cebb787977368", [:mix], [], "hexpm", "6287fc3ba0aad34883cbe3f7949fc1d1e738e5ccdce77165bc99490aa69f47fb"},
|
||||||
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
|
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
|
||||||
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
|
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
|
||||||
|
|
@ -12,18 +13,26 @@
|
||||||
"ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 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", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"},
|
"ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 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", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"},
|
||||||
"elixir_make": {:hex, :elixir_make, "0.8.4", "4960a03ce79081dee8fe119d80ad372c4e7badb84c493cc75983f9d3bc8bde0f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040"},
|
"elixir_make": {:hex, :elixir_make, "0.8.4", "4960a03ce79081dee8fe119d80ad372c4e7badb84c493cc75983f9d3bc8bde0f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040"},
|
||||||
"esbuild": {:hex, :esbuild, "0.8.2", "5f379dfa383ef482b738e7771daf238b2d1cfb0222bef9d3b20d4c8f06c7a7ac", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "558a8a08ed78eb820efbfda1de196569d8bfa9b51e8371a1934fbb31345feda7"},
|
"esbuild": {:hex, :esbuild, "0.8.2", "5f379dfa383ef482b738e7771daf238b2d1cfb0222bef9d3b20d4c8f06c7a7ac", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "558a8a08ed78eb820efbfda1de196569d8bfa9b51e8371a1934fbb31345feda7"},
|
||||||
|
"ex_aws": {:hex, :ex_aws, "2.5.6", "6f642e0f82eff10a9b470044f084b81a791cf15b393d647ea5f3e65da2794e3d", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:req, "~> 0.3", [hex: :req, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c69eec59e31fdd89d0beeb1d97e16518dd1b23ad95b3d5c9f1dcfec23d97f960"},
|
||||||
|
"ex_aws_s3": {:hex, :ex_aws_s3, "2.5.4", "87aaf4a2f24a48f516d7f5aaced9d128dd5d0f655c4431f9037a11a85c71109c", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "c06e7f68b33f7c0acba1361dbd951c79661a28f85aa2e0582990fccca4425355"},
|
||||||
"expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"},
|
"expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"},
|
||||||
"file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"},
|
"file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"},
|
||||||
"finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"},
|
"finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"},
|
||||||
"floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"},
|
"floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"},
|
||||||
"gettext": {:hex, :gettext, "0.26.1", "38e14ea5dcf962d1fc9f361b63ea07c0ce715a8ef1f9e82d3dfb8e67e0416715", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "01ce56f188b9dc28780a52783d6529ad2bc7124f9744e571e1ee4ea88bf08734"},
|
"gettext": {:hex, :gettext, "0.26.1", "38e14ea5dcf962d1fc9f361b63ea07c0ce715a8ef1f9e82d3dfb8e67e0416715", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "01ce56f188b9dc28780a52783d6529ad2bc7124f9744e571e1ee4ea88bf08734"},
|
||||||
|
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.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.4.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", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
|
||||||
"heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized", depth: 1]},
|
"heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized", depth: 1]},
|
||||||
"hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"},
|
"hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"},
|
||||||
|
"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.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
|
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
|
||||||
|
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
|
||||||
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
|
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
|
||||||
|
"mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
|
||||||
"mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"},
|
"mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"},
|
||||||
|
"nanoid": {:hex, :nanoid, "2.1.0", "d192a5bf1d774258bc49762b480fca0e3128178fa6d35a464af2a738526607fd", [:mix], [], "hexpm", "ebc7a342d02d213534a7f93a091d569b9fea7f26fcd3a638dc655060fc1f76ac"},
|
||||||
"nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
|
"nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
|
||||||
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
|
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
|
||||||
|
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
|
||||||
"phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"},
|
"phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"},
|
||||||
"phoenix_ecto": {:hex, :phoenix_ecto, "4.6.2", "3b83b24ab5a2eb071a20372f740d7118767c272db386831b2e77638c4dcc606d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "3f94d025f59de86be00f5f8c5dd7b5965a3298458d21ab1c328488be3b5fcd59"},
|
"phoenix_ecto": {:hex, :phoenix_ecto, "4.6.2", "3b83b24ab5a2eb071a20372f740d7118767c272db386831b2e77638c4dcc606d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "3f94d025f59de86be00f5f8c5dd7b5965a3298458d21ab1c328488be3b5fcd59"},
|
||||||
"phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"},
|
"phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"},
|
||||||
|
|
@ -35,6 +44,8 @@
|
||||||
"plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
|
"plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
|
||||||
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
|
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
|
||||||
"postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [: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", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"},
|
"postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [: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", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"},
|
||||||
|
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
|
||||||
|
"sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"},
|
||||||
"swoosh": {:hex, :swoosh, "1.17.2", "73611f08fc7cb9fa15f4909db36eeb12b70727d5c8b6a7fa0d4a31c6575db29e", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {: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]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "de914359f0ddc134dc0d7735e28922d49d0503f31e4bd66b44e26039c2226d39"},
|
"swoosh": {:hex, :swoosh, "1.17.2", "73611f08fc7cb9fa15f4909db36eeb12b70727d5c8b6a7fa0d4a31c6575db29e", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {: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]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "de914359f0ddc134dc0d7735e28922d49d0503f31e4bd66b44e26039c2226d39"},
|
||||||
"table_rex": {:hex, :table_rex, "4.0.0", "3c613a68ebdc6d4d1e731bc973c233500974ec3993c99fcdabb210407b90959b", [:mix], [], "hexpm", "c35c4d5612ca49ebb0344ea10387da4d2afe278387d4019e4d8111e815df8f55"},
|
"table_rex": {:hex, :table_rex, "4.0.0", "3c613a68ebdc6d4d1e731bc973c233500974ec3993c99fcdabb210407b90959b", [:mix], [], "hexpm", "c35c4d5612ca49ebb0344ea10387da4d2afe278387d4019e4d8111e815df8f55"},
|
||||||
"tailwind": {:hex, :tailwind, "0.2.4", "5706ec47182d4e7045901302bf3a333e80f3d1af65c442ba9a9eed152fb26c2e", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "c6e4a82b8727bab593700c998a4d98cf3d8025678bfde059aed71d0000c3e463"},
|
"tailwind": {:hex, :tailwind, "0.2.4", "5706ec47182d4e7045901302bf3a333e80f3d1af65c442ba9a9eed152fb26c2e", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "c6e4a82b8727bab593700c998a4d98cf3d8025678bfde059aed71d0000c3e463"},
|
||||||
|
|
@ -42,6 +53,8 @@
|
||||||
"telemetry_metrics": {:hex, :telemetry_metrics, "1.0.0", "29f5f84991ca98b8eb02fc208b2e6de7c95f8bb2294ef244a176675adc7775df", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f23713b3847286a534e005126d4c959ebcca68ae9582118ce436b521d1d47d5d"},
|
"telemetry_metrics": {:hex, :telemetry_metrics, "1.0.0", "29f5f84991ca98b8eb02fc208b2e6de7c95f8bb2294ef244a176675adc7775df", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f23713b3847286a534e005126d4c959ebcca68ae9582118ce436b521d1d47d5d"},
|
||||||
"telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
|
"telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
|
||||||
"thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"},
|
"thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"},
|
||||||
|
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
|
||||||
|
"uuid": {:hex, :uuid, "1.1.8", "e22fc04499de0de3ed1116b770c7737779f226ceefa0badb3592e64d5cfb4eb9", [:mix], [], "hexpm", "c790593b4c3b601f5dc2378baae7efaf5b3d73c4c6456ba85759905be792f2ac"},
|
||||||
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
||||||
"websock_adapter": {:hex, :websock_adapter, "0.5.7", "65fa74042530064ef0570b75b43f5c49bb8b235d6515671b3d250022cb8a1f9e", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "d0f478ee64deddfec64b800673fd6e0c8888b079d9f3444dd96d2a98383bdbd1"},
|
"websock_adapter": {:hex, :websock_adapter, "0.5.7", "65fa74042530064ef0570b75b43f5c49bb8b235d6515671b3d250022cb8a1f9e", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "d0f478ee64deddfec64b800673fd6e0c8888b079d9f3444dd96d2a98383bdbd1"},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
priv/repo/migrations/20241022022614_create_images.exs
Normal file
11
priv/repo/migrations/20241022022614_create_images.exs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
defmodule Zoeyscomputer.Repo.Migrations.CreateImages do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
create table(:images) do
|
||||||
|
add :file, :string
|
||||||
|
|
||||||
|
timestamps(type: :utc_datetime)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
16
priv/repo/migrations/20241022033717_create_api_keys.exs
Normal file
16
priv/repo/migrations/20241022033717_create_api_keys.exs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
defmodule Zoeyscomputer.Repo.Migrations.CreateApiKeys do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
create table(:api_keys) do
|
||||||
|
add :token, :string
|
||||||
|
add :name, :string
|
||||||
|
add :user_id, references(:users, on_delete: :nothing)
|
||||||
|
|
||||||
|
timestamps(type: :utc_datetime)
|
||||||
|
end
|
||||||
|
|
||||||
|
create unique_index(:api_keys, [:token])
|
||||||
|
create index(:api_keys, [:user_id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
defmodule Zoeyscomputer.Repo.Migrations.AddUserImageField do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
alter table(:images) do
|
||||||
|
add :user_id, references(:users, on_delete: :nothing)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
26
test/support/fixtures/api_keys_fixtures.ex
Normal file
26
test/support/fixtures/api_keys_fixtures.ex
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
defmodule Zoeyscomputer.ApiKeysFixtures do
|
||||||
|
@moduledoc """
|
||||||
|
This module defines test helpers for creating
|
||||||
|
entities via the `Zoeyscomputer.ApiKeys` context.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Generate a unique api_key token.
|
||||||
|
"""
|
||||||
|
def unique_api_key_token, do: "some token#{System.unique_integer([:positive])}"
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Generate a api_key.
|
||||||
|
"""
|
||||||
|
def api_key_fixture(attrs \\ %{}) do
|
||||||
|
{:ok, api_key} =
|
||||||
|
attrs
|
||||||
|
|> Enum.into(%{
|
||||||
|
name: "some name",
|
||||||
|
token: unique_api_key_token()
|
||||||
|
})
|
||||||
|
|> Zoeyscomputer.ApiKeys.create_api_key()
|
||||||
|
|
||||||
|
api_key
|
||||||
|
end
|
||||||
|
end
|
||||||
20
test/support/fixtures/images_fixtures.ex
Normal file
20
test/support/fixtures/images_fixtures.ex
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
defmodule Zoeyscomputer.ImagesFixtures do
|
||||||
|
@moduledoc """
|
||||||
|
This module defines test helpers for creating
|
||||||
|
entities via the `Zoeyscomputer.Images` context.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Generate a image.
|
||||||
|
"""
|
||||||
|
def image_fixture(attrs \\ %{}) do
|
||||||
|
{:ok, image} =
|
||||||
|
attrs
|
||||||
|
|> Enum.into(%{
|
||||||
|
file: "some file"
|
||||||
|
})
|
||||||
|
|> Zoeyscomputer.Images.create_image()
|
||||||
|
|
||||||
|
image
|
||||||
|
end
|
||||||
|
end
|
||||||
61
test/zoeyscomputer/api_keys_test.exs
Normal file
61
test/zoeyscomputer/api_keys_test.exs
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
defmodule Zoeyscomputer.ApiKeysTest do
|
||||||
|
use Zoeyscomputer.DataCase
|
||||||
|
|
||||||
|
alias Zoeyscomputer.ApiKeys
|
||||||
|
|
||||||
|
describe "api_keys" do
|
||||||
|
alias Zoeyscomputer.ApiKeys.ApiKey
|
||||||
|
|
||||||
|
import Zoeyscomputer.ApiKeysFixtures
|
||||||
|
|
||||||
|
@invalid_attrs %{name: nil, token: nil}
|
||||||
|
|
||||||
|
test "list_api_keys/0 returns all api_keys" do
|
||||||
|
api_key = api_key_fixture()
|
||||||
|
assert ApiKeys.list_api_keys() == [api_key]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "get_api_key!/1 returns the api_key with given id" do
|
||||||
|
api_key = api_key_fixture()
|
||||||
|
assert ApiKeys.get_api_key!(api_key.id) == api_key
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create_api_key/1 with valid data creates a api_key" do
|
||||||
|
valid_attrs = %{name: "some name", token: "some token"}
|
||||||
|
|
||||||
|
assert {:ok, %ApiKey{} = api_key} = ApiKeys.create_api_key(valid_attrs)
|
||||||
|
assert api_key.name == "some name"
|
||||||
|
assert api_key.token == "some token"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create_api_key/1 with invalid data returns error changeset" do
|
||||||
|
assert {:error, %Ecto.Changeset{}} = ApiKeys.create_api_key(@invalid_attrs)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "update_api_key/2 with valid data updates the api_key" do
|
||||||
|
api_key = api_key_fixture()
|
||||||
|
update_attrs = %{name: "some updated name", token: "some updated token"}
|
||||||
|
|
||||||
|
assert {:ok, %ApiKey{} = api_key} = ApiKeys.update_api_key(api_key, update_attrs)
|
||||||
|
assert api_key.name == "some updated name"
|
||||||
|
assert api_key.token == "some updated token"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "update_api_key/2 with invalid data returns error changeset" do
|
||||||
|
api_key = api_key_fixture()
|
||||||
|
assert {:error, %Ecto.Changeset{}} = ApiKeys.update_api_key(api_key, @invalid_attrs)
|
||||||
|
assert api_key == ApiKeys.get_api_key!(api_key.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "delete_api_key/1 deletes the api_key" do
|
||||||
|
api_key = api_key_fixture()
|
||||||
|
assert {:ok, %ApiKey{}} = ApiKeys.delete_api_key(api_key)
|
||||||
|
assert_raise Ecto.NoResultsError, fn -> ApiKeys.get_api_key!(api_key.id) end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "change_api_key/1 returns a api_key changeset" do
|
||||||
|
api_key = api_key_fixture()
|
||||||
|
assert %Ecto.Changeset{} = ApiKeys.change_api_key(api_key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
59
test/zoeyscomputer/images_test.exs
Normal file
59
test/zoeyscomputer/images_test.exs
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
defmodule Zoeyscomputer.ImagesTest do
|
||||||
|
use Zoeyscomputer.DataCase
|
||||||
|
|
||||||
|
alias Zoeyscomputer.Images
|
||||||
|
|
||||||
|
describe "images" do
|
||||||
|
alias Zoeyscomputer.Images.Image
|
||||||
|
|
||||||
|
import Zoeyscomputer.ImagesFixtures
|
||||||
|
|
||||||
|
@invalid_attrs %{file: nil}
|
||||||
|
|
||||||
|
test "list_images/0 returns all images" do
|
||||||
|
image = image_fixture()
|
||||||
|
assert Images.list_images() == [image]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "get_image!/1 returns the image with given id" do
|
||||||
|
image = image_fixture()
|
||||||
|
assert Images.get_image!(image.id) == image
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create_image/1 with valid data creates a image" do
|
||||||
|
valid_attrs = %{file: "some file"}
|
||||||
|
|
||||||
|
assert {:ok, %Image{} = image} = Images.create_image(valid_attrs)
|
||||||
|
assert image.file == "some file"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create_image/1 with invalid data returns error changeset" do
|
||||||
|
assert {:error, %Ecto.Changeset{}} = Images.create_image(@invalid_attrs)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "update_image/2 with valid data updates the image" do
|
||||||
|
image = image_fixture()
|
||||||
|
update_attrs = %{file: "some updated file"}
|
||||||
|
|
||||||
|
assert {:ok, %Image{} = image} = Images.update_image(image, update_attrs)
|
||||||
|
assert image.file == "some updated file"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "update_image/2 with invalid data returns error changeset" do
|
||||||
|
image = image_fixture()
|
||||||
|
assert {:error, %Ecto.Changeset{}} = Images.update_image(image, @invalid_attrs)
|
||||||
|
assert image == Images.get_image!(image.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "delete_image/1 deletes the image" do
|
||||||
|
image = image_fixture()
|
||||||
|
assert {:ok, %Image{}} = Images.delete_image(image)
|
||||||
|
assert_raise Ecto.NoResultsError, fn -> Images.get_image!(image.id) end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "change_image/1 returns a image changeset" do
|
||||||
|
image = image_fixture()
|
||||||
|
assert %Ecto.Changeset{} = Images.change_image(image)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
84
test/zoeyscomputer_web/controllers/image_controller_test.exs
Normal file
84
test/zoeyscomputer_web/controllers/image_controller_test.exs
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
defmodule ZoeyscomputerWeb.ImageControllerTest do
|
||||||
|
use ZoeyscomputerWeb.ConnCase
|
||||||
|
|
||||||
|
import Zoeyscomputer.ImagesFixtures
|
||||||
|
|
||||||
|
alias Zoeyscomputer.Images.Image
|
||||||
|
|
||||||
|
@create_attrs %{
|
||||||
|
file: "some file"
|
||||||
|
}
|
||||||
|
@update_attrs %{
|
||||||
|
file: "some updated file"
|
||||||
|
}
|
||||||
|
@invalid_attrs %{file: nil}
|
||||||
|
|
||||||
|
setup %{conn: conn} do
|
||||||
|
{:ok, conn: put_req_header(conn, "accept", "application/json")}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "index" do
|
||||||
|
test "lists all images", %{conn: conn} do
|
||||||
|
conn = get(conn, ~p"/api/images")
|
||||||
|
assert json_response(conn, 200)["data"] == []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "create image" do
|
||||||
|
test "renders image when data is valid", %{conn: conn} do
|
||||||
|
conn = post(conn, ~p"/api/images", image: @create_attrs)
|
||||||
|
assert %{"id" => id} = json_response(conn, 201)["data"]
|
||||||
|
|
||||||
|
conn = get(conn, ~p"/api/images/#{id}")
|
||||||
|
|
||||||
|
assert %{
|
||||||
|
"id" => ^id,
|
||||||
|
"file" => "some file"
|
||||||
|
} = json_response(conn, 200)["data"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders errors when data is invalid", %{conn: conn} do
|
||||||
|
conn = post(conn, ~p"/api/images", image: @invalid_attrs)
|
||||||
|
assert json_response(conn, 422)["errors"] != %{}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "update image" do
|
||||||
|
setup [:create_image]
|
||||||
|
|
||||||
|
test "renders image when data is valid", %{conn: conn, image: %Image{id: id} = image} do
|
||||||
|
conn = put(conn, ~p"/api/images/#{image}", image: @update_attrs)
|
||||||
|
assert %{"id" => ^id} = json_response(conn, 200)["data"]
|
||||||
|
|
||||||
|
conn = get(conn, ~p"/api/images/#{id}")
|
||||||
|
|
||||||
|
assert %{
|
||||||
|
"id" => ^id,
|
||||||
|
"file" => "some updated file"
|
||||||
|
} = json_response(conn, 200)["data"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders errors when data is invalid", %{conn: conn, image: image} do
|
||||||
|
conn = put(conn, ~p"/api/images/#{image}", image: @invalid_attrs)
|
||||||
|
assert json_response(conn, 422)["errors"] != %{}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "delete image" do
|
||||||
|
setup [:create_image]
|
||||||
|
|
||||||
|
test "deletes chosen image", %{conn: conn, image: image} do
|
||||||
|
conn = delete(conn, ~p"/api/images/#{image}")
|
||||||
|
assert response(conn, 204)
|
||||||
|
|
||||||
|
assert_error_sent 404, fn ->
|
||||||
|
get(conn, ~p"/api/images/#{image}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp create_image(_) do
|
||||||
|
image = image_fixture()
|
||||||
|
%{image: image}
|
||||||
|
end
|
||||||
|
end
|
||||||
113
test/zoeyscomputer_web/live/api_key_live_test.exs
Normal file
113
test/zoeyscomputer_web/live/api_key_live_test.exs
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
defmodule ZoeyscomputerWeb.ApiKeyLiveTest do
|
||||||
|
use ZoeyscomputerWeb.ConnCase
|
||||||
|
|
||||||
|
import Phoenix.LiveViewTest
|
||||||
|
import Zoeyscomputer.ApiKeysFixtures
|
||||||
|
|
||||||
|
@create_attrs %{name: "some name", token: "some token"}
|
||||||
|
@update_attrs %{name: "some updated name", token: "some updated token"}
|
||||||
|
@invalid_attrs %{name: nil, token: nil}
|
||||||
|
|
||||||
|
defp create_api_key(_) do
|
||||||
|
api_key = api_key_fixture()
|
||||||
|
%{api_key: api_key}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Index" do
|
||||||
|
setup [:create_api_key]
|
||||||
|
|
||||||
|
test "lists all api_keys", %{conn: conn, api_key: api_key} do
|
||||||
|
{:ok, _index_live, html} = live(conn, ~p"/api_keys")
|
||||||
|
|
||||||
|
assert html =~ "Listing Api keys"
|
||||||
|
assert html =~ api_key.name
|
||||||
|
end
|
||||||
|
|
||||||
|
test "saves new api_key", %{conn: conn} do
|
||||||
|
{:ok, index_live, _html} = live(conn, ~p"/api_keys")
|
||||||
|
|
||||||
|
assert index_live |> element("a", "New Api key") |> render_click() =~
|
||||||
|
"New Api key"
|
||||||
|
|
||||||
|
assert_patch(index_live, ~p"/api_keys/new")
|
||||||
|
|
||||||
|
assert index_live
|
||||||
|
|> form("#api_key-form", api_key: @invalid_attrs)
|
||||||
|
|> render_change() =~ "can't be blank"
|
||||||
|
|
||||||
|
assert index_live
|
||||||
|
|> form("#api_key-form", api_key: @create_attrs)
|
||||||
|
|> render_submit()
|
||||||
|
|
||||||
|
assert_patch(index_live, ~p"/api_keys")
|
||||||
|
|
||||||
|
html = render(index_live)
|
||||||
|
assert html =~ "Api key created successfully"
|
||||||
|
assert html =~ "some name"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "updates api_key in listing", %{conn: conn, api_key: api_key} do
|
||||||
|
{:ok, index_live, _html} = live(conn, ~p"/api_keys")
|
||||||
|
|
||||||
|
assert index_live |> element("#api_keys-#{api_key.id} a", "Edit") |> render_click() =~
|
||||||
|
"Edit Api key"
|
||||||
|
|
||||||
|
assert_patch(index_live, ~p"/api_keys/#{api_key}/edit")
|
||||||
|
|
||||||
|
assert index_live
|
||||||
|
|> form("#api_key-form", api_key: @invalid_attrs)
|
||||||
|
|> render_change() =~ "can't be blank"
|
||||||
|
|
||||||
|
assert index_live
|
||||||
|
|> form("#api_key-form", api_key: @update_attrs)
|
||||||
|
|> render_submit()
|
||||||
|
|
||||||
|
assert_patch(index_live, ~p"/api_keys")
|
||||||
|
|
||||||
|
html = render(index_live)
|
||||||
|
assert html =~ "Api key updated successfully"
|
||||||
|
assert html =~ "some updated name"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "deletes api_key in listing", %{conn: conn, api_key: api_key} do
|
||||||
|
{:ok, index_live, _html} = live(conn, ~p"/api_keys")
|
||||||
|
|
||||||
|
assert index_live |> element("#api_keys-#{api_key.id} a", "Delete") |> render_click()
|
||||||
|
refute has_element?(index_live, "#api_keys-#{api_key.id}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Show" do
|
||||||
|
setup [:create_api_key]
|
||||||
|
|
||||||
|
test "displays api_key", %{conn: conn, api_key: api_key} do
|
||||||
|
{:ok, _show_live, html} = live(conn, ~p"/api_keys/#{api_key}")
|
||||||
|
|
||||||
|
assert html =~ "Show Api key"
|
||||||
|
assert html =~ api_key.name
|
||||||
|
end
|
||||||
|
|
||||||
|
test "updates api_key within modal", %{conn: conn, api_key: api_key} do
|
||||||
|
{:ok, show_live, _html} = live(conn, ~p"/api_keys/#{api_key}")
|
||||||
|
|
||||||
|
assert show_live |> element("a", "Edit") |> render_click() =~
|
||||||
|
"Edit Api key"
|
||||||
|
|
||||||
|
assert_patch(show_live, ~p"/api_keys/#{api_key}/show/edit")
|
||||||
|
|
||||||
|
assert show_live
|
||||||
|
|> form("#api_key-form", api_key: @invalid_attrs)
|
||||||
|
|> render_change() =~ "can't be blank"
|
||||||
|
|
||||||
|
assert show_live
|
||||||
|
|> form("#api_key-form", api_key: @update_attrs)
|
||||||
|
|> render_submit()
|
||||||
|
|
||||||
|
assert_patch(show_live, ~p"/api_keys/#{api_key}")
|
||||||
|
|
||||||
|
html = render(show_live)
|
||||||
|
assert html =~ "Api key updated successfully"
|
||||||
|
assert html =~ "some updated name"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
113
test/zoeyscomputer_web/live/image_live_test.exs
Normal file
113
test/zoeyscomputer_web/live/image_live_test.exs
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
defmodule ZoeyscomputerWeb.ImageLiveTest do
|
||||||
|
use ZoeyscomputerWeb.ConnCase
|
||||||
|
|
||||||
|
import Phoenix.LiveViewTest
|
||||||
|
import Zoeyscomputer.ImagesFixtures
|
||||||
|
|
||||||
|
@create_attrs %{file: "some file"}
|
||||||
|
@update_attrs %{file: "some updated file"}
|
||||||
|
@invalid_attrs %{file: nil}
|
||||||
|
|
||||||
|
defp create_image(_) do
|
||||||
|
image = image_fixture()
|
||||||
|
%{image: image}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Index" do
|
||||||
|
setup [:create_image]
|
||||||
|
|
||||||
|
test "lists all images", %{conn: conn, image: image} do
|
||||||
|
{:ok, _index_live, html} = live(conn, ~p"/images")
|
||||||
|
|
||||||
|
assert html =~ "Listing Images"
|
||||||
|
assert html =~ image.file
|
||||||
|
end
|
||||||
|
|
||||||
|
test "saves new image", %{conn: conn} do
|
||||||
|
{:ok, index_live, _html} = live(conn, ~p"/images")
|
||||||
|
|
||||||
|
assert index_live |> element("a", "New Image") |> render_click() =~
|
||||||
|
"New Image"
|
||||||
|
|
||||||
|
assert_patch(index_live, ~p"/images/new")
|
||||||
|
|
||||||
|
assert index_live
|
||||||
|
|> form("#image-form", image: @invalid_attrs)
|
||||||
|
|> render_change() =~ "can't be blank"
|
||||||
|
|
||||||
|
assert index_live
|
||||||
|
|> form("#image-form", image: @create_attrs)
|
||||||
|
|> render_submit()
|
||||||
|
|
||||||
|
assert_patch(index_live, ~p"/images")
|
||||||
|
|
||||||
|
html = render(index_live)
|
||||||
|
assert html =~ "Image created successfully"
|
||||||
|
assert html =~ "some file"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "updates image in listing", %{conn: conn, image: image} do
|
||||||
|
{:ok, index_live, _html} = live(conn, ~p"/images")
|
||||||
|
|
||||||
|
assert index_live |> element("#images-#{image.id} a", "Edit") |> render_click() =~
|
||||||
|
"Edit Image"
|
||||||
|
|
||||||
|
assert_patch(index_live, ~p"/images/#{image}/edit")
|
||||||
|
|
||||||
|
assert index_live
|
||||||
|
|> form("#image-form", image: @invalid_attrs)
|
||||||
|
|> render_change() =~ "can't be blank"
|
||||||
|
|
||||||
|
assert index_live
|
||||||
|
|> form("#image-form", image: @update_attrs)
|
||||||
|
|> render_submit()
|
||||||
|
|
||||||
|
assert_patch(index_live, ~p"/images")
|
||||||
|
|
||||||
|
html = render(index_live)
|
||||||
|
assert html =~ "Image updated successfully"
|
||||||
|
assert html =~ "some updated file"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "deletes image in listing", %{conn: conn, image: image} do
|
||||||
|
{:ok, index_live, _html} = live(conn, ~p"/images")
|
||||||
|
|
||||||
|
assert index_live |> element("#images-#{image.id} a", "Delete") |> render_click()
|
||||||
|
refute has_element?(index_live, "#images-#{image.id}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Show" do
|
||||||
|
setup [:create_image]
|
||||||
|
|
||||||
|
test "displays image", %{conn: conn, image: image} do
|
||||||
|
{:ok, _show_live, html} = live(conn, ~p"/images/#{image}")
|
||||||
|
|
||||||
|
assert html =~ "Show Image"
|
||||||
|
assert html =~ image.file
|
||||||
|
end
|
||||||
|
|
||||||
|
test "updates image within modal", %{conn: conn, image: image} do
|
||||||
|
{:ok, show_live, _html} = live(conn, ~p"/images/#{image}")
|
||||||
|
|
||||||
|
assert show_live |> element("a", "Edit") |> render_click() =~
|
||||||
|
"Edit Image"
|
||||||
|
|
||||||
|
assert_patch(show_live, ~p"/images/#{image}/show/edit")
|
||||||
|
|
||||||
|
assert show_live
|
||||||
|
|> form("#image-form", image: @invalid_attrs)
|
||||||
|
|> render_change() =~ "can't be blank"
|
||||||
|
|
||||||
|
assert show_live
|
||||||
|
|> form("#image-form", image: @update_attrs)
|
||||||
|
|> render_submit()
|
||||||
|
|
||||||
|
assert_patch(show_live, ~p"/images/#{image}")
|
||||||
|
|
||||||
|
html = render(show_live)
|
||||||
|
assert html =~ "Image updated successfully"
|
||||||
|
assert html =~ "some updated file"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Add table
Add a link
Reference in a new issue