Skip to content
master
Switch branches/tags
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
bin
 
 
 
 
 
 
 
 
 
 
 
 
 
 

marklunds-api

This the content API that serves the marklunds Node web app or www.marklunds.com. This API is based on the versioned framework. The versioned framework provides a CMS REST API based on MongoDB with user authentication, JSON schema validation, versioning, publishing, and relationships.

Restore Dev DB from Production

bin/db-restore

Getting Started

First make sure you have Leiningen/Clojure and Mongodb installed.

Get the source:

git clone git@github.com:peter/versioned-example.git
cd versioned-example

Create an admin user:

lein repl
(require '[app.core :as marklunds])
(def system (marklunds/-main :start-web false))
(require '[versioned.models.users :as users])
(users/create (:app system) {:name "Peter Marklund" :email "admin@example.com" :password "admin" :permission "write"})
exit

Start the server:

lein run

In a different terminal, log in:

export BASE_URL=http://localhost:5000/v1

export BASE_URL=https://marklunds-api.herokuapp.com/v1

curl -i -X POST -H 'Content-Type: application/json' -d '{"email": "peter@marklunds.com", "password": ""}' $BASE_URL/login
export TOKEN=<token in header response above>

Single step login can looks something like this:

export TOKEN=$(curl -X POST -H 'Content-Type: application/json' -d '{"email": "peter@marklunds.com", "password": ""}' $BASE_URL/login | jsonq 'data.attributes.access_token')

Create a blog post:

echo '{"data": {"attributes": {"subject": "test post", "body": "test body"}}}' | http POST $BASE_URL/blog_posts Authorization:"Bearer $TOKEN"

http $BASE_URL/blog_posts/449 Authorization:"Bearer $TOKEN"

Create model schema:

echo '{"data": {"attributes": {"model_type": "blog_posts", "schema": {"type": "object", "properties": {"title": {"type": "string"}}}}}}' | http POST $BASE_URL/models Authorization:"Bearer $TOKEN"

Basic CRUD workflow:

# create
curl -i -X POST -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" -d '{"data": {"attributes": {"title": "hello world"}}}' $BASE_URL/blog_posts

# get
curl -i -H "Authorization: Bearer $TOKEN" $BASE_URL/blog_posts/1

# list
curl -i -H "Authorization: Bearer $TOKEN" $BASE_URL/blog_posts

# update
curl -i -X PUT -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" -d '{"data": {"attributes": {"title": "hello world EDIT"}}}' $BASE_URL/blog_posts/1

# delete
curl -i -X DELETE -H "Authorization: Bearer $TOKEN" $BASE_URL/blog_posts/1

Dropbox

(require '[app.core :as marklunds])
(def system (marklunds/-main :start-web false))
(require '[app.dropbox :as dropbox :reload-all true])
(dropbox/save (:app system) {:type "foobar" :id 1 :body "foobar"})

Get a Local Checkout of Versioned Library

To checkout the versioned library (if you haven't already):

cd <your-parent-src-dir>
git clone https://github.com/peter/versioned <your-src-dir>/versioned

Then, in this repository, do:

mkdir checkouts
ln -s <your-src-dir>/versioned checkouts/versioned

Now you can make changes in your local versioned checkout and they will be reflected in this app.

Importing Blog Posts

(require '[app.core :as marklunds])
(def system (marklunds/-main :start-web false))
(def app (:app system))
(require '[versioned.util.date :as d])
(require '[versioned.model-api :as model-api])
(require '[cheshire.core :as json])
(require '[clj-http.client :as client])
(require '[versioned.db-api :as db-api])
(db-api/delete (:database app) :blog_posts {})
(db-api/delete (:database app) :blog_posts_versions {})
(def file-url "https://www.dropbox.com/s/9g9wf8mh9i2n9ht/marklunds-postgresql-2018-02.json?dl=1")
(def file-path "/Users/peter/Dropbox/data/marklunds-postgresql-2018-02.json")
(def file-str (:body (client/get file-url)))
(def lines (as-> file-str v
                (clojure.string/replace v "\\\\" "\\")
                (clojure.string/split-lines v)))
; (seq (char-array (nth lines 0)))
(defn parse-date [date-str]
  (let [parsable-str (if (re-matches #".+\.\d\d\d$" date-str)
                       (str date-str "Z")
                       (str date-str ".000Z"))]
    (d/parse-datetime parsable-str)))
(defn parse-line [line]
  (as-> line v
        (json/parse-string v)
        ; id subject body comments_count created_at
        (clojure.set/rename-keys v {"created_at" "legacy_created_at"})
        (clojure.walk/keywordize-keys v)
        (merge v {:created_by "peter@marklunds.com"})
        (assoc v :legacy_created_at (parse-date (:legacy_created_at v)))))
(def docs (map parse-line lines))
(for [doc docs]
  (let [result (model-api/create app (get-in app [:models :blog_posts]) doc)]
    (println "result" result)))
; 327 blog posts
(require '[app.core :as marklunds])
(def system (marklunds/-main :start-web false))
(def app (:app system))
(require '[versioned.db-api :as db-api])
(def blog-posts (db-api/find (:database app) :blog_posts {} {:per-page 10000}))
(for [doc blog-posts]
  (let [query (select-keys doc [:id])
        update {:$set {:created_at (:legacy_created_at doc)}
                :$unset {:legacy_created_at ""}}]
    (db-api/update (:database app) :blog_posts query update)))
(require '[app.core :as marklunds])
(def system (marklunds/-main :start-web false))
(def app (:app system))
(require '[versioned.db-api :as db-api])
(def blog-posts (db-api/find (:database app) :blog_posts {} {:per-page 10000}))
(for [doc blog-posts]
  (let [query (select-keys doc [:id])
        update {:$set {:published_version (:version doc)}}]
    (db-api/update (:database app) :blog_posts query update)))

Import Diary Entries

heroku pg:backups:capture -a savorings
curl $(heroku pg:backups:url -a savorings) > ~/tmp/savorings-prod.sql
pg_restore --verbose --clean --no-acl --no-owner -d savorings_development  ~/tmp/savorings-prod.sql

psql savorings_development
COPY (SELECT ROW_TO_JSON(t)
      FROM (SELECT * FROM entries) t)
      TO '/Users/peter/Dropbox/data/savorings-diary-postgresql-2018-02.json';
(require '[app.core :as marklunds])
(def system (marklunds/-main :start-web false))
(def app (:app system))
(require '[versioned.util.date :as d])
(require '[versioned.model-api :as model-api])
(require '[cheshire.core :as json])
(require '[clj-http.client :as client])
(require '[versioned.db-api :as db-api])
(db-api/delete (:database app) :diary {})
(db-api/delete (:database app) :diary_versions {})
(def file-path "/Users/peter/Dropbox/data/savorings-diary-postgresql-2018-02.json")
(def file-url "https://www.dropbox.com/s/djw0fkbrqybd9j7/savorings-diary-postgresql-2018-02.json?dl=1")
(def file-str (:body (client/get file-url)))
(def lines (as-> file-str v
                (clojure.string/replace v "\\\\" "\\")
                (clojure.string/split-lines v)))
(defn parse-date [date-str]
  (let [parsable-str (if (re-matches #".+\.\d\d\d$" date-str)
                       (str date-str "Z")
                       (str date-str ".000Z"))]
    (d/parse-datetime parsable-str)))
(defn parse-line [line]
  (as-> line v
        (json/parse-string v)
        ; id subject body comments_count created_at
        (clojure.set/rename-keys v {"inserted_at" "legacy_created_at"})
        (clojure.walk/keywordize-keys v)
        (merge v {:created_by "peter@marklunds.com"})
        (assoc v :legacy_created_at (parse-date (:legacy_created_at v)))
        (dissoc v :updated_at)))
(def docs (map parse-line lines))
(for [doc docs]
  (let [result (model-api/create app (get-in app [:models :diary]) doc)]
    (println result)))
; 1037 diary entries (count lines)
(require '[app.core :as marklunds])
(def system (marklunds/-main :start-web false))
(def app (:app system))
(require '[versioned.db-api :as db-api])
(def diary-entries (db-api/find (:database app) :diary {} {:per-page 10000}))
(for [doc diary-entries]
  (let [query (select-keys doc [:id])
        update {:$set {:created_at (:legacy_created_at doc)}
                :$unset {:legacy_created_at ""}}]
    (db-api/update (:database app) :diary query update)))

About

Versioned CMS REST API for www.marklunds.com

Resources

License

Releases

No releases published

Packages

No packages published