Compare commits
10 commits
2197dd0c1d
...
56d45ad311
| Author | SHA1 | Date | |
|---|---|---|---|
| 56d45ad311 | |||
| ca5ad88fd2 | |||
| 81f047ef0c | |||
| f3e03e43c7 | |||
| 6bbdb9c348 | |||
| e11719b40f | |||
| bbeb1b6ba0 | |||
| a2352d19c2 | |||
| ee1c6a50e9 | |||
| e0afe65a1b |
14 changed files with 153 additions and 12 deletions
15
README.md
15
README.md
|
|
@ -1,6 +1,10 @@
|
|||
# Code Snippets
|
||||
|
||||
App to store my code snippets.
|
||||
Backend application to store my code snippets and make them available via REST API.
|
||||
|
||||
[CLI CMS Companion Project](https://git.sr.ht/~travisshears/code-snippets-cli-cms)
|
||||
|
||||
This project is written in [Clojure](https://clojure.org/) and data is stored in [XTDB](https://xtdb.dev/).
|
||||
|
||||
## Links
|
||||
|
||||
|
|
@ -16,3 +20,12 @@ App to store my code snippets.
|
|||
```
|
||||
$ clojure -M -m snippets.infra.api
|
||||
```
|
||||
|
||||
### How to create docker image
|
||||
|
||||
At this point I'm using a private AWS ECR repository for the project and deploying it in my homelab.
|
||||
|
||||
```shell
|
||||
$ export AWS_PROFILE=personal
|
||||
$ docker buildx build --platform linux/amd64,linux/arm64 -t 853019563312.dkr.ecr.eu-central-1.amazonaws.com/snippets-homelabstack:latest --push .
|
||||
```
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ meta {
|
|||
}
|
||||
|
||||
delete {
|
||||
url: {{host}}/api/snippet?id=90d00a80-78c4-4bc9-a066-01c988599d05
|
||||
url: {{host}}/api/snippet?id=d77d3463-c76e-4c53-a1d5-ecaf16c6c54e
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
params:query {
|
||||
id: 90d00a80-78c4-4bc9-a066-01c988599d05
|
||||
id: d77d3463-c76e-4c53-a1d5-ecaf16c6c54e
|
||||
}
|
||||
|
||||
body:json {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ params:query {
|
|||
|
||||
body:json {
|
||||
{
|
||||
"title": "Updated from Bruno",
|
||||
"tags": ["code", "mock"]
|
||||
"title": "quick way to push last jj commit to git",
|
||||
"tags": ["jj", "git"]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
23
bruno/CodeSnippets/get_snippet_by_slug.bru
Normal file
23
bruno/CodeSnippets/get_snippet_by_slug.bru
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
meta {
|
||||
name: get_snippet_by_slug
|
||||
type: http
|
||||
seq: 10
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/api/snippet-by-slug?slug=netcat-over-ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
params:query {
|
||||
slug: netcat-over-ping
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"title": "Test Snippet",
|
||||
"markdown": "## Cool Snippet\ndoes a cool thing",
|
||||
"tags": ["git", "jj"]
|
||||
}
|
||||
}
|
||||
|
|
@ -5,13 +5,13 @@ meta {
|
|||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/api/snippets?limit=100&skip=0
|
||||
url: {{host}}/api/snippets?limit=25&skip=0
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
params:query {
|
||||
limit: 100
|
||||
limit: 25
|
||||
skip: 0
|
||||
}
|
||||
|
||||
|
|
|
|||
23
bruno/CodeSnippets/get_tag.bru
Normal file
23
bruno/CodeSnippets/get_tag.bru
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
meta {
|
||||
name: get_tag
|
||||
type: http
|
||||
seq: 9
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/api/tag?tag=git
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
params:query {
|
||||
tag: git
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"title": "Test Snippet",
|
||||
"markdown": "## Cool Snippet\ndoes a cool thing",
|
||||
"tags": ["git", "jj"]
|
||||
}
|
||||
}
|
||||
19
bruno/CodeSnippets/get_tags.bru
Normal file
19
bruno/CodeSnippets/get_tags.bru
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
meta {
|
||||
name: get_tags
|
||||
type: http
|
||||
seq: 8
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/api/tags
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"title": "Test Snippet",
|
||||
"markdown": "## Cool Snippet\ndoes a cool thing",
|
||||
"tags": ["git", "jj"]
|
||||
}
|
||||
}
|
||||
16
build.sh
Executable file
16
build.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
export AWS_PROFILE=personal
|
||||
export AWS_REGION=eu-central-1
|
||||
|
||||
REPO_NAME="snippets-homelabstack"
|
||||
|
||||
if ! aws ecr describe-repositories --repository-names "$REPO_NAME" >/dev/null 2>&1; then
|
||||
aws ecr create-repository --repository-name "$REPO_NAME"
|
||||
fi
|
||||
|
||||
docker buildx build --platform linux/amd64,linux/arm64 -t "853019563312.dkr.ecr.eu-central-1.amazonaws.com/${REPO_NAME}:latest" --push .
|
||||
|
||||
echo "Docker image built and pushed to AWS ECR"
|
||||
4
deps.edn
4
deps.edn
|
|
@ -1,7 +1,7 @@
|
|||
{:paths ["src"]
|
||||
:deps {ring/ring-core {:mvn/version "1.13.0"}
|
||||
:deps {;; api
|
||||
ring/ring-core {:mvn/version "1.13.0"}
|
||||
ring/ring-jetty-adapter {:mvn/version "1.13.0"}
|
||||
;; logging, required by jetty:
|
||||
org.slf4j/slf4j-simple {:mvn/version "2.0.16"}
|
||||
|
||||
;; db
|
||||
|
|
|
|||
|
|
@ -47,6 +47,26 @@
|
|||
{:status 200
|
||||
:body (format "Deleted snippet with id: %s if it existed" id)}))
|
||||
|
||||
(defn handle-view-tags [_args]
|
||||
(let [tags (snippets.use-cases.view/view-tags)]
|
||||
{:status 200
|
||||
:body tags}))
|
||||
|
||||
(defn handle-view-snippets-by-tag [{params :query-params}]
|
||||
(let [tag (get params "tag")]
|
||||
{:status 200
|
||||
:body (snippets.use-cases.view/view-snippets-by-tag tag)}))
|
||||
|
||||
(defn handle-view-tags [_]
|
||||
(let [tags (snippets.use-cases.view/view-tags)]
|
||||
{:status 200
|
||||
:body tags}))
|
||||
|
||||
(defn handle-view-snippet-by-slug [{params :query-params}]
|
||||
(let [slug (get params "slug")]
|
||||
{:status 200
|
||||
:body (snippets.use-cases.view/view-snippet-by-slug slug)}))
|
||||
|
||||
(defn wrap [handler id]
|
||||
(fn [request]
|
||||
(update (handler request) :wrap (fnil conj '()) id)))
|
||||
|
|
@ -58,6 +78,9 @@
|
|||
mm/wrap-format
|
||||
[wrap :api]]}
|
||||
["/ping" {:get handle-ping}]
|
||||
["/tags" {:get handle-view-tags}]
|
||||
["/tag" {:get handle-view-snippets-by-tag}]
|
||||
["/snippet-by-slug" {:get handle-view-snippet-by-slug}]
|
||||
["/snippets" {:get handle-view-snippets}]
|
||||
["/snippet" {:post handle-create-snippet
|
||||
:get handle-view-snippet
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@
|
|||
(format "(quote (-> (from :snippets [title pub-date tags slug markdown {:xt/id id}]) (order-by {:val pub-date, :dir :desc, :nulls :last}) (offset %s) (limit %s)))" skip limit)))))
|
||||
|
||||
(defn get-snippet-by-id [snippet-id]
|
||||
(first (xt/q client ['#(from :snippets [{:xt/id %} slug title {:xt/id id} markdown pub-date]) snippet-id])))
|
||||
(first (xt/q client ['#(from :snippets [{:xt/id %} slug title tags {:xt/id id} markdown pub-date]) snippet-id])))
|
||||
|
||||
(defn get-snippet-by-slug [slug]
|
||||
(first (xt/q client ['#(from :snippets [{:xt/id id} {:slug %} slug title tags markdown pub-date]) slug])))
|
||||
|
||||
(defn put-snippet [id snippet]
|
||||
(t/log! {:level :info, :data {:snippet snippet :id id}} "Saving new snippet to db")
|
||||
|
|
@ -39,3 +42,12 @@
|
|||
(defn patch-snippet [id patch]
|
||||
(t/log! {:level :info, :data {:patch patch :id id}} "Patching snippet")
|
||||
(xt/execute-tx client [[:patch-docs :snippets (merge {:xt/id id} patch)]]))
|
||||
|
||||
(defn list-tags []
|
||||
;; (xt/q client '(-> (from :snippets [{:xt/id id} tags]) (unnest {:tag tags}) (without :tags) (aggregate tag {:ids (array-agg id)}))))
|
||||
(xt/q client '(-> (from :snippets [{:xt/id id} tags]) (unnest {:tag tags}) (without :tags) (aggregate tag {:count (count id)}))))
|
||||
|
||||
(defn get-snippets-by-tag [tag]
|
||||
(map #(dissoc % :tag)
|
||||
(xt/q client (eval (read-string
|
||||
(format "(quote (-> (from :snippets [title slug tags pub-date]) (unnest {:tag tags}) (without :tags) (where (= tag \"%s\"))))" tag))))))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
(ns snippets.main
|
||||
(:require [snippets.api :as api])
|
||||
(:require [snippets.infra.api :as api])
|
||||
(:gen-class))
|
||||
|
||||
(defn -main []
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
[:map {:closed true}
|
||||
[:markdown {:optional true} :string]
|
||||
[:title {:optional true} :string]
|
||||
[:tags [:seqable :string]]
|
||||
[:tags {:optional true} [:seqable :string]]
|
||||
[:slug {:optional true} :string]]))
|
||||
|
||||
(defn edit-snippet [id patch]
|
||||
|
|
|
|||
|
|
@ -9,3 +9,15 @@
|
|||
|
||||
(defn view-snippets [& args]
|
||||
(db/list-snippets args))
|
||||
|
||||
(defn view-tags []
|
||||
(t/log! {:level :info} "Viewing tags")
|
||||
(db/list-tags))
|
||||
|
||||
(defn view-snippets-by-tag [tag]
|
||||
(t/log! {:level :info :data {:tag tag}} "Viewing snippet by tag")
|
||||
(db/get-snippets-by-tag tag))
|
||||
|
||||
(defn view-snippet-by-slug [slug]
|
||||
(t/log! {:level :info :data {:slug slug}} "Viewing snippet by slug")
|
||||
(db/get-snippet-by-slug slug))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue